/* zweic -- a compiler for zwei * * Stephane Micheloud & LAMP * * $Id$ */ package zweic; /** * This class implements the parser of the zwei compiler. */ class Parser(in: java.io.InputStream) extends Scanner(in) { import Tokens._; var pushedBack: Option[Triple[Int,String,Token]] = None; var pos: Int = 0; /** * Reports an error that a specific token was expected but * a different token found. */ private def error(expected: Token): Unit = error("token of class " + expected); /** * Reports an error that a specific token was expected but * a different token found. */ private def error(expected: String): Unit = { val message = "syntax error\n" + "expected: " + expected + "\n" + "found : " + representation; Report.fail(start, message); } /** * If the current token corresponds to the token class 'expected' * then skip it, otherwise signal an error. */ private def accept(expected: Token): Unit = if (token == expected) nextToken; else error(expected); /** * If the current token corresponds to the token class 'expected' * then skip it and return success. */ private def check(expected: Token): Boolean = if (token == expected) { nextToken; true } else false; override def nextToken: Unit = { pushedBack match { case Some(Triple(p, c, t)) => token = t; chars = c; pos = p; pushedBack = None; case _ => return super.nextToken; } } def peekAhead: Token = pushedBack match { case Some(Triple(p, c, t)) => return t; case _ => val savedToken = token; val savedChars = chars; val savedPos = pos; nextToken; val rval = token; pushedBack = Some(Triple(pos, chars, token)); token = savedToken; chars = savedChars; pos = savedPos; return rval; } /** * Parse the input and return an abstract syntax tree. */ def parse: Program = { val result = program(); accept(EOF); //return result; return null; } /* --------------------------------------------------*/ /** * Program = { ClassDecl } Expression */ private def program(): Program = { while (token == CLASS) { classDecl(); } expression(); return null; } /** * ClassDecl = "class" ident ["extends" ident] "{" {Member} "}" */ private def classDecl(): Tree = { accept(CLASS); accept(IDENT); if (check (EXTENDS)) { accept(IDENT); } accept (LACCOLADE); while ( !check(RACCOLADE) ) { member(); } return null; } /** * Member = Formal * (";" | * "(" [Formal {"," Formal}] ")" Block) */ private def member(): Tree = { formal(); if (check (SEMICOLON)) { return null; } else { accept (LPAREN); //TODO: is this neccessary? if (token == IDENT || token == INT || token == NULLTYPE) { formal(); while (token != RPAREN) { accept (PERIOD); formal(); } } accept (RPAREN); block(); return null; } } /** * Formal = Type ident */ private def formal(): Tree = { type1(); accept(IDENT); return null; } /** * Block = "{" {Statements} ["return" Expression] "}" */ private def block(): Tree = { accept (LACCOLADE); while (token != RETURN && token != RACCOLADE) { statement(); } if (check (RETURN)) { expression(); } accept(RACCOLADE); return null; } /** * Type1 = "Int" | "Null" | ident */ private def type1(): Tree = token match { case INT => nextToken; return null; case NULLTYPE => nextToken; return null; case ident => nextToken; return null; case _ => error("'Int', 'Null' or identifier token"); return null; } /** * Statement = "while" "(" Expression ")" "{" {Statement} "}" * | Formal "=" Expression ";" * | ident "=" Expression ";" * | Expression ";" * | "printInt" "(" Expression ")" ";" * | "printChar" "(" Expression ")" ";" */ private def statement(): Tree = { if (token == IDENT) { peekAhead match { case IDENT => //type definition and affection formal(); accept(EQUALS); expression(); accept(SEMICOLON); case EQUALS => //affection accept(IDENT); accept(EQUALS); expression(); accept(SEMICOLON); case _ => //expression expression(); accept(SEMICOLON); } } else { if (check(WHILE)) { //while accept(LPAREN); expression(); accept(RPAREN); accept(LACCOLADE); while ( !check(RACCOLADE) ) { statement(); } } else if (token == NULLTYPE || token == INT) { //type definition and affection formal(); accept(EQUALS); expression(); accept(SEMICOLON); } else if (check(PRINTINT)) { //printInt accept(LPAREN); expression(); accept(RPAREN); accept(SEMICOLON); } else if (check(PRINTCHAR)) { //printChar accept(LPAREN); expression(); accept(RPAREN); accept(SEMICOLON); } else { //expression expression(); accept(SEMICOLON); } } return null; } /** * Expression = "if" "(" Expression ")" Expression [ "else" Expression ] | CmpExpression */ private def expression(): Tree = { if ( check(IF) ) { accept(LPAREN); expression(); accept(RPAREN); expression(); if ( check(ELSE) ) { expression(); } return null; } else { cmpExpression(); return null; } } /** * CmpExpression = [ SumExpression CompOp ] SumExpression * MyCmpExpression = SumExpression [ CompOp SumExpression ] */ private def cmpExpression(): Tree = { sumExpression(); if ( token == EQ || token == NE || token == LT || token == GT || token == LE || token == GE ) { compOp(); sumExpression(); } return null; } /** * SumExpression = Term | SumExpression SumOp Term * MySumExpression = Term [ SumOp SumExpression ] */ private def sumExpression(): Tree = { term(); if ( token == ADD || token == SUB || token == OR ) { sumOp(); sumExpression(); } return null; } /** * Term = [ Term ProdOp ] [ NegateOp ] Factor * MyTerm = [ NegateOp ] Factor [ ProdOp Term ] */ private def term(): Tree = { if ( token == SUB || token == NOT ) { nextToken; } factor(); if ( token == MUL || token == DIV || token == MOD || token == AND ) { prodOp(); term(); } return null; } /** * Factor = look it up yourself! */ private def factor(): Tree = { token match { case IDENT => nextToken; case NUMBER => nextToken; case STRING => nextToken; case TRUE => nextToken; case FALSE => nextToken; case THIS => nextToken; case NULLFACTOR => nextToken; case READINT => nextToken; case READCHAR => nextToken; case LPAREN => nextToken; expression(); accept(RPAREN); case LACCOLADE => block(); case NEW => nextToken; accept(IDENT); params(); case _ => error("Identifier, Number, String, 'true', 'false', 'this', 'null', 'readInt', 'readChar', '(Expression)', '{Block}' or 'new'"); } while ( check(DOT) ) { accept(IDENT); if ( token == LPAREN ) { params(); } } return null; } /** * Expressions = [ Expression { "," Expression } ] */ private def expressions(): Tree = { if ( token == IF || token == SUB || token == NOT || token == IDENT || token == NUMBER || token == STRING || token == TRUE || token == FALSE || token == THIS || token == NULLFACTOR || token == READINT || token == READCHAR || token == LPAREN || token == NEW || token == LACCOLADE ) { expression(); while ( check(PERIOD) ) { expression(); } } return null; } /** * Params = "(" Expressions ")" */ private def params(): Tree = { accept(LPAREN); expressions(); accept(RPAREN); return null; } /** * ProdOp = "*" | "/" | "%" | "&&" */ private def prodOp(): Tree = token match { case MUL => nextToken; return null; case DIV => nextToken; return null; case MOD => nextToken; return null; case AND => nextToken; return null; case _ => error("'*', '/', '%' or '&&' token"); return null; } /** * NegateOp = "-" | "!" */ private def negateOp(): Tree = token match { case SUB => nextToken; return null; case NOT => nextToken; return null; case _ => error("'-' or '!' token"); return null; } /** * SumOp = "+" | "-" | "||" */ private def sumOp(): Tree = token match { case ADD => nextToken; return null; case SUB => nextToken; return null; case OR => nextToken; return null; case _ => error("'+', '-' or '||' token"); return null; } /** * CompOp = "==" | "!" | "<" | ">" | "<=" | ">=" */ private def compOp(): Tree = token match { case EQ => nextToken; return null; case NE => nextToken; return null; case LT => nextToken; return null; case GT => nextToken; return null; case LE => nextToken; return null; case GE => nextToken; return null; case _ => error("comparison operator ('==', '!', '<', '>', '<=', '>=')"); return null; } }