Newer
Older
zweic / sources / zweic / Parser.scala
/*  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;
    //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);
	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("illegal start of expression");
	}

	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("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;
  }

}