diff --git a/sources/zweic/Parser.scala b/sources/zweic/Parser.scala new file mode 100755 index 0000000..d0c1157 --- /dev/null +++ b/sources/zweic/Parser.scala @@ -0,0 +1,414 @@ +/* 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 None => return super.nextToken; + } + + def peekAhead: Token = pushedBack match { + case Some(Triple(p, c, t)) => return t; + case None => + val savedToken = token; + val savedChars = chars; + val savedPos = pos; + val rval = token; + nextToken; + 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 (token != 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; + //TODO: better error message + case _ => error("illegal start of expression"); 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); + statement(); + accept(RACCOLADE); + + } 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 ] + */ + private def expression(): Tree = { + accept(IF); + accept(LPAREN); + expression(); + accept(RPAREN); + expression(); + if ( check(ELSE) ) { + expression(); + } + 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("illegal start of expression"); + } + + if ( 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 ( token == 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("illegal start of expression"); return null; + } + + /** + * NegateOp = "-" | "!" + */ + private def negateOp(): Tree = token match { + case SUB => nextToken; return null; + case NOT => nextToken; return null; + case _ => error("illegal start of expression"); 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("illegal start of expression"); 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("illegal start of expression"); return null; + } + +}