/** TinyScanner.java scanner that gets tokens for TINY a simple language that is not very complex for a few examples of TINY programs see http://www.cs.stedwards.edu/~lbaker/cosc4342/CcompilerBookcode/sample.tny and s1.tny, s2.tny, sample1.tny in same directory @author COSC 4342 @version 1.0 */ import java.util.*; import java.io.*; public class TinyScanner { // various states in the scanner. public final char EOF = (char) -1; public final int START=1; public final int INASSIGN=2; public final int INCOMMENT=3; public final int INNUM=4; public final int INID=5; public final int DONE=6; // various token definitions public static final int // op codes for the individual tokens EOFtok = -1, IFtok = 0, THENtok = 1, ELSEtok = 2, ENDtok=3, REPEATtok = 4, UNTILtok = 5, READtok = 6, WRITEtok = 7, NUMtok = 9, IDtok = 10, LPARENtok = 11, /* ( */ RPARENtok = 12, /* ) */ SEMItok = 13, /* ; */ EQtok = 14, /* = */ LTtok = 15, /* < */ ASSIGNtok = 16, /* := */ PLUStok = 17, MINUStok = 18, /* + - */ DIVtok = 19, MULtok = 20, /* / * */ ERRORtok = 21; public final String reservedWords[]= { "if","then", "else", "end", "repeat", "until", "read", "write" }; public final int numReservedWords = reservedWords.length; String tokenString; String lineBuf=""; // stores each input line of scanned file int lineno=0; // line number of scanned file int linepos=0; // position in the line BufferedReader bufRdr; // input file buffered reader File inFile; // source file to scan public static void main(String args[]) { if(args.length == 0) { System.out.println( "You must give a filename to scan on the" + " command line such as java TinyScanner file1.tny " + ", now exiting program. "); return; } TinyScanner myScanner = new TinyScanner (args[0]); Token tok = myScanner.getToken(); while( tok.getNumber()!= TinyScanner.EOFtok ){ System.out.println("token: " + tok.toString()); tok = myScanner.getToken(); } System.out.println("*** Scanning is complete, End-of-File reached. ***"); } /** * Returns the next character from the input buffer * @param none * * @return the next char from the line Buffer * @see * */ char getNextChar() { char ch=EOF; if( lineBuf == "" || lineBuf==null || (linepos >= lineBuf.length())) { linepos=0; try { lineBuf=bufRdr.readLine(); lineno++; // we must try to get another line // check if we found end of file, set char to EOF if(lineBuf==null) { ch = EOF; } else if (lineBuf.equals("")) // we found a blank line { System.out.println(lineno+" : " + lineBuf); lineBuf=lineBuf+"\n"; // put newline onto line ch = getNextChar(); } else { System.out.println(lineno + " : " + lineBuf); lineBuf = lineBuf + "\n"; // add newline to lineBuf linepos = 0; ch = lineBuf.charAt(linepos++); } } catch(IOException e) { System.out.println("IOException in getchar: " + e ); } } else // we have a character on current line to read ch = (char) lineBuf.charAt(linepos++); return ch; } /** * this function simulates putting a char back into the input buffer * it does this by decrementing the line position index * @param none * @returns nothing */ void ungetNextChar() { linepos--; } /** constructs this with fname as file name to use as file to open tries to open file @param fname - name of file to read (scan) from */ public TinyScanner(String fname) { inFile=new File(fname); try{ bufRdr = new BufferedReader(new FileReader(inFile)); }catch(FileNotFoundException e) { System.out.println("error opening file: " + fname + " for input. " ); } } /** * Returns the location of String s in the reserved words table * @param s - the String to look for as a reserved word * * @return location (index) in table if found, -1 if not found * * */ int reservedLookup(String s) { int i; for(i=0; i< numReservedWords; i++) { if(reservedWords[i].equals(s)) return i; } return -1; } /** * returns the next Token from the input buffer * repeatedly calls getNextChar() until a token is recognized * @param none * @return next Token which could be the EOFtok */ Token getToken() { boolean save=true; Token currentToken=null; int state=START; int loc =0; char c= EOF; tokenString = ""; while(state != DONE) { c = getNextChar(); save=true; switch(state) { case START: if(Character.isLetter(c)) // is it alpha? state=INID; else if(Character.isDigit(c)) // is it a digit? state=INNUM; else if(c==':') state=INASSIGN; else if (c=='{') { save=false; state=INCOMMENT; } else if (Character.isWhitespace(c)) save=false; else { state = DONE; save=false; switch(c) { case '=': currentToken=new Token(EQtok); break; case '<': currentToken= new Token (LTtok); break; case '+': currentToken= new Token (PLUStok); break; case '-': currentToken = new Token (MINUStok); break; case '*': currentToken = new Token (MULtok); break; case '/': currentToken = new Token (DIVtok); break; case '(': currentToken = new Token (LPARENtok); break; case ')': currentToken = new Token (RPARENtok); break; case ';': currentToken = new Token (SEMItok); break; case EOF: currentToken = new Token (EOFtok); break; default: currentToken = new Token (ERRORtok); break; } } break; case INCOMMENT: save = false; if (c == '}') state = START; break; case INASSIGN: state = DONE; if (c == '=') currentToken = new Token(ASSIGNtok); else { /* backup in the input */ ungetNextChar(); save = false; currentToken = new Token (ERRORtok); } break; case INNUM: if (!(c>='0' && c <='9')) { /* backup in the input */ ungetNextChar(); save = false; state = DONE; currentToken = new Token(NUMtok); currentToken.setValue(tokenString); } break; case INID: if (!((c>='A' && c <='Z')|| (c >='a' && c<='z'))) { /* backup in the input */ ungetNextChar(); save = false; state = DONE; currentToken = new Token(IDtok); currentToken.setValue(tokenString); } break; default: /* should never happen */ System.out.println("Scanner Bug: state= " + state); state = DONE; currentToken = new Token(ERRORtok); break; } // end of switch if (save) tokenString=tokenString + c; } // endwhile currentToken.setValue(tokenString); // check to see if we have an identifier, if so check if reserved word if (currentToken.getNumber() == (IDtok)) { loc = this.reservedLookup(tokenString); // set token number according to location in reserved word table if(loc>=0&&loc<=7) currentToken.setNumber(loc); } return currentToken; } /** class Token * stores the token number and the string value of the token * */ class Token { private int number; // number of the token (used by parser really ) private String value; // characters of the token /** * creates a default token with number 0 and empty string of chars. * @param none * * @return Token built with default values * @see * */ public Token() { value=""; number=0; } /** * creates a Token with given number and empty string of chars. * @param num - the token number (assumed valid) * * @return Token built with given number * @see * */ public Token(int num) { number = num; value = ""; } /** * creates a Token with given number and String * @param num - the token number (assumed valid) * @param s - string value to store corresponds to name or value of token * @return Token built with given number * @see * */ public Token(int num, String s) { value = ""; number=num; if (num == NUMtok) value = s; else if(num == IDtok) value = s; } int getNumber() { return number; } String getValue() { return value; } void setValue(String v) { value = v; } void setNumber(int n) { number = n; } /** Returns a printable version of Token * @param : none * @returns: printable version of Token with name */ public String toString() { switch(number) { case -1: value="EOFtok"; break; case 0: value="IFtok"; break; case 1: value="THENtok"; break; case 2: value="ELSEtok"; break; case 3: value="ENDtok"; break; case 4: value="REPEATtok"; break; case 5: value="UNTILtok"; break; case 6: value="READtok"; break; case 7: value="WRITEtok"; break; case 9: break; // number is set already in getToken case 10: break; // id value is set already in getToken case 11: value="LPAREN: ("; break; case 12: value="RPAREN: )"; break; case 13: value="SEMI: ;"; break; case 14: value="EQ: ="; break; case 15: value="LT: <"; break; case 16: value="ASSIGN: :="; break; case 17: value="PLUS: +"; break; case 18: value="MINUS: -"; break; case 19: value="MUL: *"; break; case 20: value="DIV: /"; break; case 21: value="ERRORtok: " + value; break; } String temp=""; if ( number== 9) temp = number + " : NUMtok value: " + value ; else if (number==10) temp = number + " : IDtok name: " + value; else temp = number + " : " + value; return temp; } } // end of Token class } // end of Scanner class