package Interpreter; import java.util.ArrayList; import java.util.List; public class TokenScanner { private String sourceCode; List tokens = new ArrayList<>(); private int tokenStart=0; private int currentLoc=0; //Extract tokens from the source code by reading character by character List extractTokens(String sourceCode){ this.sourceCode=sourceCode; while (!checkEOF()){ tokenStart=currentLoc; readToken(); } return tokens; } //Extract a single token private void readToken(){ char checkChar = sourceCode.charAt(currentLoc); switch(checkChar){ case '(': createTokenNull(TokenType.LEFT_PAREN); break; case ')': createTokenNull(TokenType.RIGHT_PAREN); break; case '+': createTokenNull(TokenType.PLUS); break; case '-': createTokenNull(TokenType.MINUS); break; case '*': createTokenNull(TokenType.STAR); break; case '/': createTokenNull(TokenType.SLASH); break; //Some tokens are multiple characters long (==, <=) etc //so need to check next char as well case '=': if (checkNextChar('=')){ createTokenNull(TokenType.EQUALITY); break; } else { createTokenNull(TokenType.EQUALS); break; } case '<': if (checkNextChar('=')){ createTokenNull(TokenType.LESS_EQUAL); break; } else { createTokenNull(TokenType.LESS); break; } case '>': if (checkNextChar('=')){ createTokenNull(TokenType.GREATER_EQUAL); break; } else { createTokenNull(TokenType.GREATER); break; } default: //Check for numer if (checkIsDigit(checkChar)){ while (checkIsDigit(lookAhead())){ currentLoc++; } //Check if number contains a decimal point if (lookAhead()=='.' && checkIsDigit(lookTwoAhead())){ currentLoc++; while (checkIsDigit(lookAhead())){ currentLoc++; } } createToken(TokenType.NUMBER, Double.parseDouble(sourceCode.substring(tokenStart, currentLoc+1))); } } currentLoc++; } //Test for end of file private boolean checkEOF(){ return currentLoc>=sourceCode.length(); } //Create a token without a value private void createTokenNull(TokenType type){ createToken(type, null); } //Create token private void createToken(TokenType type, Object value){ String tokenText = sourceCode.substring(tokenStart, currentLoc+1); tokens.add(new Token(type, tokenText, value)); } //Check if the next char matches a given char private boolean checkNextChar(char matchChar){ if (checkEOF()){ return false; } if (sourceCode.charAt(currentLoc+1)==matchChar){ currentLoc++; return true; } return false; } //Look at the next char in the source code private char lookAhead(){ if (currentLoc+1>=sourceCode.length()){ return ' '; } else { return sourceCode.charAt(currentLoc+1); } } //Look 2 chars ahead in the source code private char lookTwoAhead(){ if (currentLoc+2>=sourceCode.length()){ return ' '; } else { return sourceCode.charAt(currentLoc+2); } } //Check if a given char is a digit private boolean checkIsDigit(char checkChar){ return checkChar>='0' && checkChar<='9'; } }