/* 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 = { if (debug == true) { Console.print (" " + token); } 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; } /* --------------------------------------------------*/ /** * Program = { ClassDecl } Expression */ private def program(): Program = { var classes:List[ClassDef] = Nil; while (token == CLASS) { classDecl() :: classes; } var main = expression(); return Program(classes.reverse, main); } /** * ClassDecl = "class" ident ["extends" ident] "{" {Member} "}" */ private def classDecl(): ClassDef = { accept(CLASS); val name = Name(chars); accept(IDENT); var extend:Option[Name] = None; if (check (EXTENDS)) { extend = Some(Name(chars)); accept(IDENT); } accept (LACCOLADE); var members:List[Member] = Nil; while ( !check(RACCOLADE) ) { members = member() :: members; } return ClassDef (name, extend, members.reverse); } /** * Member = Formal * (";" | * "(" [Formal {"," Formal}] ")" Block) */ private def member(): Member = { val f:Formal = formal(); if (check(SEMICOLON)) { return FieldDecl(f); } else { accept(LPAREN); //TODO: is this neccessary? var par:List[Formal] = Nil; if (token == IDENT || token == INT || token == NULLTYPE) { par = formal() :: par; while (token != RPAREN) { accept (PERIOD); par = formal() :: par; } } accept (RPAREN); val b:Block = block(); return MethodDef (f.name, par.reverse, f.typ, b); } } /** * Formal = Type ident */ private def formal(): Formal = { var typ = type1(); var name = Name(chars); accept(IDENT); return Formal(name, typ); } /** * Block = "{" {Statements} ["return" Expression] "}" */ private def block(): Block = { accept (LACCOLADE); var s:List[Stat] = Nil; var e:Expr = null; while (token != RETURN && token != RACCOLADE) { s = statement() :: s; } if (check (RETURN)) { e = expression(); } accept(RACCOLADE); return Block(s.reverse, e); } /** * Type1 = "Int" | "Null" | ident */ private def type1(): TypeTree = token match { case INT => nextToken; return IntType(); case NULLTYPE => nextToken; return NullType(); case IDENT => var name=Name(chars); nextToken; return ClassType(name); 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(): Stat = { if (token == IDENT) { peekAhead match { case IDENT => //type definition and affection val v = formal(); accept(EQUALS); val e = expression(); accept(SEMICOLON); return Var(v.name, v.typ, e); case EQUALS => //affection val name = Name(chars); accept(IDENT); accept(EQUALS); val e = expression(); accept(SEMICOLON); return Set(name, e); case _ => //expression val e = expression(); accept(SEMICOLON); return Do(e); } } else { if (check(WHILE)) { //while accept(LPAREN); val cond = expression(); accept(RPAREN); accept(LACCOLADE); var stats:List[Stat] = Nil; while ( !check(RACCOLADE) ) { stats = statement() :: stats; } return While(cond, stats.reverse); } else if (token == NULLTYPE || token == INT) { //type definition and affection val v = formal(); accept(EQUALS); val e = expression(); accept(SEMICOLON); return Var(v.name, v.typ, e); } else if (check(PRINTINT)) { //printInt accept(LPAREN); val e = expression(); accept(RPAREN); accept(SEMICOLON); return PrintInt(e); } else if (check(PRINTCHAR)) { //printChar accept(LPAREN); val e = expression(); accept(RPAREN); accept(SEMICOLON); return PrintChar(e); } else { //expression val e = expression(); accept(SEMICOLON); return Do(e); } } } /** * Expression = "if" "(" Expression ")" Expression [ "else" Expression ] | CmpExpression */ private def expression(): Expr = { if ( check(IF) ) { accept(LPAREN); val cond = expression(); accept(RPAREN); val stata = expression(); var statb:Expr = NullLit(); if ( check(ELSE) ) { statb = expression(); } return If(cond, stata, statb); } else { cmpExpression(); return null; } } /** * CmpExpression = [ SumExpression CompOp ] SumExpression * MyCmpExpression = SumExpression [ CompOp SumExpression ] */ private def cmpExpression(): Expr = { var left = sumExpression(); if ( token == EQ || token == NE || token == LT || token == GT || token == LE || token == GE ) { val op = compOp(); val right = sumExpression(); return Binop(op, left, right); } return left; } /** * SumExpression = Term | SumExpression SumOp Term * MySumExpression = Term [ SumOp SumExpression ] */ private def sumExpression(): Expr = { val left = term(); if ( token == ADD || token == SUB || token == OR ) { val op = sumOp(); val right = sumExpression(); return Binop(op, left, right); } return left; } /** * Term = [ Term ProdOp ] [ NegateOp ] Factor * MyTerm = [ NegateOp ] Factor [ ProdOp Term ] */ private def term(): Expr = { var left:Expr; if ( token == SUB || token == NOT ) { val op = token; nextToken; val e = factor(); left = Unop(op, e); } else { left = factor(); } if ( token == MUL || token == DIV || token == MOD || token == AND ) { val op = prodOp(); val right = term(); return Binop(op, left, right); } return left; } /** * Factor = look it up yourself! */ private def factor(): Expr = { 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(): List[Expr] = { 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(): Operators = 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(): Operators = token match { case SUB => nextToken; return null; case NOT => nextToken; return null; case _ => error("'-' or '!' token"); return null; } /** * SumOp = "+" | "-" | "||" */ private def sumOp(): Operators = 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(): Operators = 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; } }