Parser for While Language that Generates Trees
/* A very simple version of while language: program ::= statements EOF statements = statement* statement ::= print | assign | while | block write ::= "println" "(" var ")" ";" assign ::= var "=" expr ";" while ::= "while" "(" expr ")" statement block ::= "{" statements "}" expr ::= expr "+" expr | expr "-" expr | expr "*" expr | "(" expr ")" | var | intconst */ class Parser(lex : Lexer) { // program ::= statement* EOF def parseProgram : List[Statement] = { val list = parseStatements ensure(EOF) list } // statements = statement* def parseStatements : List[Statement] = { var list : List[Statement] = List() while (firstTokenOfStatement) { list = list ::: List(parseStatement) } list } def firstTokenOfStatement : Boolean = { lex.current match { case PRINTLN => true case ID(_) => true case WHILE => true case OBRACE => true case _ => false } } // statement ::= print | assign | if | while | block def parseStatement : Statement = { lex.current match { case PRINTLN => parseWrite case ID(_) => parseAssign case WHILE => parseWhile case OBRACE => parseBlock case _ => { error("statement expected"); Skip} } } // write ::= "println" "(" var ")" ";" def parseWrite : Statement = { eat(PRINTLN) eat(OPAREN) val id = parseID eat(CPAREN) eat(SEMICOL) Print("", id) } // assign ::= var "=" expr ";" def parseAssign : Statement = { val id = parseID eat(AssignEQ) val e = parseExpr eat(SEMICOL) Assign(id,e) } // while ::= "while" "(" expr ")" statement def parseWhile : Statement = { eat(WHILE) eat(OPAREN) val e = parseExpr eat(CPAREN) val s = parseStatement While(e,s) } // block ::= "{" statements "}" def parseBlock : Statement = { eat(OBRACE) val sts = parseStatements eat(CBRACE) Block(sts) } /* Original rule: expr ::= expr "+" expr | expr "-" expr | expr "*" expr | "(" expr ")" | var | intconst Modified rules: expr ::= term ("+" term)* term ::= factor ("*" factor)* factor ::= "(" expr ")" | var | intconst */ // expr ::= term ("+" term)* def parseExpr : Expression = { var e = parseTerm while ((lex.current==PLUS)|(lex.current==MINUS)) { if (lex.current==PLUS) { lex.next e = Plus(e,parseTerm) } else { lex.next e = Minus(e,parseTerm) } } e } // term ::= factor ("*" factor)* def parseTerm : Expression = { var e = parseFactor while (lex.current==MUL) { lex.next e = Times(e,parseFactor) } e } // factor ::= "(" expr ")" | var | intconst def parseFactor : Expression = { lex.current match { case OPAREN => { lex.next; val e = parseExpr; eat(CPAREN); e } case ID(s) => { lex.next; Var(s) } case IntConst(c) => { lex.next; IntLiteral(c) } case _ => error("(, ID, or IntConst expected") } } def error(s : String) = { println(s); exit(-1); } def eat(t : Token) = { if (lex.current==t) lex.next else error("Expected token " + t + " found token " + lex.current) } def ensure(t : Token) = { if (lex.current==t) {} else error("Expected token " + t + " found token " + lex.current) } def parseID : String = { lex.current match { case ID(s) => { lex.next; s } case _ => { error("identifier expected"); ""} } } } object ParserTest { def main(args : Array[String]) = { val lex = new Lexer(new CharStream(args(0))) val p = new Parser(lex) val trees = p.parseProgram TreePrinter(Block(trees)) } }