/* zweic -- a compiler for zwei * * Stephane Micheloud & LAMP * */ 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 = 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; start = 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 = start; nextToken; val rval = token; pushedBack = Some(Triple(start, chars, token)); token = savedToken; chars = savedChars; start = 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 = { val pos = start; var classes:List[ClassDef] = Nil; while (token == CLASS) { classes = classDecl() :: classes; } val main = expression(); return Program(classes.reverse, main).setPos(pos); } /** * ClassDecl = "class" ident ["extends" ident] "{" {Member} "}" */ private def classDecl(): ClassDef = { val pos = start; 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).setPos(pos); } /** * Member = Formal * (";" | * "(" [Formal {"," Formal}] ")" Block) */ private def member(): Member = { val pos = start; val f:Formal = formal(); if (check(SEMICOLON)) { return FieldDecl(f).setPos(pos); } else { accept(LPAREN); 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).setPos(pos); } } /** * Formal = Type ident */ private def formal(): Formal = { val typ = type1(); val pos = start; val name = Name(chars); accept(IDENT); return Formal(name, typ).setPos(pos); } /** * Block = "{" {Statements} ["return" Expression] "}" */ private def block(): Block = { val pos = start; accept (LACCOLADE); var s:List[Stat] = Nil; var e:Expr = NullLit().setPos(pos); while (token != RETURN && token != RACCOLADE) { s = statement() :: s; } if (check (RETURN)) { e = expression(); } accept(RACCOLADE); return Block(s.reverse, e).setPos(pos); } /** * Type1 = "Int" | "Null" | ident */ private def type1(): TypeTree = { val pos = start; token match { case INT => nextToken; return IntType().setPos(pos); case NULLTYPE => nextToken; return NullType().setPos(pos); case IDENT => val name=Name(chars); nextToken; return ClassType(name).setPos(pos); 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 = { val pos = start; 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).setPos(pos); case EQUALS => //affection val name = Name(chars); accept(IDENT); accept(EQUALS); val e = expression(); accept(SEMICOLON); return Set(name, e).setPos(pos); case _ => //expression val e = expression(); accept(SEMICOLON); return Do(e).setPos(pos); } } 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).setPos(pos); } 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).setPos(pos); } else if (check(PRINTINT)) { //printInt accept(LPAREN); val e = expression(); accept(RPAREN); accept(SEMICOLON); return PrintInt(e).setPos(pos); } else if (check(PRINTCHAR)) { //printChar accept(LPAREN); val e = expression(); accept(RPAREN); accept(SEMICOLON); return PrintChar(e).setPos(pos); } else { //expression val e = expression(); accept(SEMICOLON); return Do(e).setPos(pos); } } } /** * Expression = "if" "(" Expression ")" Expression [ "else" Expression ] | CmpExpression */ private def expression(): Expr = { val pos = start; 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).setPos(pos); } else { return cmpExpression(); } } /** * MyCmpExpression = SumExpression { CompOp SumExpression } */ private def cmpExpression(): Expr = { val pos = start; var left = sumExpression(); while ( token == EQ || token == NE || token == LT || token == GT || token == LE || token == GE ) { var op = compOp(); var right = sumExpression(); left = Binop(op, left, right).setPos(pos); } return left; } /** * SumExpression = Term | SumExpression SumOp Term * MySumExpression = Term { SumOp Term } */ private def sumExpression(): Expr = { val pos = start; var left = term(); while ( token == ADD || token == SUB || token == OR ) { if ( check(OR) ) { var right = term(); left.brackets = true; right.brackets = true; var bo = Binop(Operators.AND, Unop(Operators.NOT, left).setPos(pos), Unop(Operators.NOT, right).setPos(pos)).setPos(pos); bo.brackets = true; left = Unop(Operators.NOT, bo).setPos(pos); } else { left = Binop(sumOp(), left, term()).setPos(pos); } } return left; } /** * Term = [ Term ProdOp ] [ NegateOp ] Factor * MyTerm = [ NegateOp ] Factor { ProdOp [ NegateOp ] Factor } */ private def term(): Expr = { val pos = start; var left:Expr = _negFactor(); while ( token == MUL || token == DIV || token == MOD || token == AND ) { var op = prodOp(); left = Binop(op, left, _negFactor()).setPos(pos); } return left; } private def _negFactor(): Expr = { val pos = start; if ( token == SUB || token == NOT ) { val op = Operators.token2op(token); nextToken; val e = factor(); e.brackets = true; return Unop(op, e).setPos(pos); } else { return factor(); } } private def _string(str: String): New = { val pos = start; /*if ( str.length() > 1 ) { return New(Name("Cons"), IntLit(str.charAt(0).asInstanceOf[Int]).setPos(pos)::_string(str.substring(1))::Nil).setPos(pos); } else { return New(Name("Cons"), New(Name("Nil"), Nil).setPos(pos)::Nil).setPos(pos); }*/ if ( str.length() > 0 ) { val il = IntLit(str.charAt(0).asInstanceOf[Int]); il.setPos(pos); val n = New(Name("Cons"), il::_string(str.substring(1))::Nil); n.setPos(pos); return n; } else { val nl = New(Name("Nil"), Nil); nl.setPos(pos); return nl; } } /** * Factor = look it up yourself! */ private def factor(): Expr = { val pos = start; var name = chars; var rval:Expr = null; rval = token match { case IDENT => nextToken; Ident(Name(name)).setPos(pos); case NUMBER => nextToken; IntLit(Integer.parseInt(name)).setPos(pos); case STRING => nextToken; _string(name); case TRUE => nextToken; IntLit(1).setPos(pos); case FALSE => nextToken; IntLit(0).setPos(pos); case THIS => nextToken; Ident(Name("this")).setPos(pos); case NULLFACTOR => nextToken; NullLit().setPos(pos); case READINT => nextToken; ReadInt().setPos(pos); case READCHAR => nextToken; ReadChar().setPos(pos); case LPAREN => nextToken; var t = expression(); t.brackets = true; accept(RPAREN); t; case LACCOLADE => block(); case NEW => nextToken; accept(IDENT); New(Name(chars), params()).setPos(pos); case _ => error("Identifier, Number, String, 'true', 'false', 'this', 'null', 'readInt', 'readChar', '(Expression)', '{Block}' or 'new'"); null; } while ( check(DOT) ) { accept(IDENT); if ( token == LPAREN ) { rval = Call(rval, Name(chars), params()).setPos(pos); } else { rval = Select(rval, Name(chars)).setPos(pos); } name = chars; } return rval; } /** * Expressions = [ Expression { "," Expression } ] */ private def expressions(): List[Expr] = return ( if ( IF::SUB::NOT::IDENT::NUMBER::STRING::TRUE::FALSE::THIS::NULLFACTOR ::READINT::READCHAR::LPAREN::NEW::LACCOLADE::Nil contains token) { var rval = expression() :: Nil; while ( check(PERIOD) ) { rval = expression() :: rval; } rval; } else Nil).reverse; /** * Params = "(" Expressions ")" */ private def params(): List[Expr] = { accept(LPAREN); val exprs = expressions(); accept(RPAREN); return exprs; } /** * ProdOp = "*" | "/" | "%" | "&&" */ private def prodOp(): Operators.Operator = token match { case MUL => nextToken; return Operators.MUL; case DIV => nextToken; return Operators.DIV; case MOD => nextToken; return Operators.MOD; case AND => nextToken; return Operators.AND; case _ => error("'*', '/', '%' or '&&' token"); return null; } /** * NegateOp = "-" | "!" */ private def negateOp(): Operators.Operator = token match { case SUB => nextToken; return Operators.NEG; case NOT => nextToken; return Operators.NOT; case _ => error("'-' or '!' token"); return null; } /** * SumOp = "+" | "-" | "||" */ private def sumOp(): Operators.Operator = token match { case ADD => nextToken; return Operators.ADD; case SUB => nextToken; return Operators.SUB; // case OR => nextToken; return null; // no longer needed case _ => error("'+', '-' or '||' token"); return null; } /** * CompOp = "==" | "!" | "<" | ">" | "<=" | ">=" */ private def compOp(): Operators.Operator = token match { case EQ => nextToken; return Operators.EQ; case NE => nextToken; return Operators.NE; case LT => nextToken; return Operators.LT; case GT => nextToken; return Operators.GT; case LE => nextToken; return Operators.LE; case GE => nextToken; return Operators.GE; case _ => error("comparison operator ('==', '!', '<', '>', '<=', '>=')"); return null; } }