LARA

Parser for While Language that Generates Trees

/* A very simple version of while language:
 
program ::= statements EOF
statements = statement*
statement ::= print | assign | while | block
write ::= "println" "(" var ")" ";"
assign ::= var "=" expr ";"
while ::= "while" "(" expr ")" statement
block ::= "{" statements "}"
expr ::= expr "+" expr | expr "-" expr | expr "*" expr | 
         "(" expr ")" | var | intconst 
*/
 
class Parser(lex : Lexer) {
  // program ::= statement* EOF
  def parseProgram : List[Statement] = {
    val list = parseStatements
    ensure(EOF)
    list
  }
 
  // statements = statement*
  def parseStatements : List[Statement] = {
    var list : List[Statement] = List()
    while (firstTokenOfStatement) {
      list = list ::: List(parseStatement)
    }
    list
  }
 
  def firstTokenOfStatement : Boolean = {
    lex.current match {
      case PRINTLN => true
      case ID(_) => true
      case WHILE => true
      case OBRACE => true
      case _ => false
    }
  }
 
  // statement ::= print | assign | if | while | block
  def parseStatement : Statement = {
    lex.current match {
      case PRINTLN => parseWrite
      case ID(_) => parseAssign
      case WHILE => parseWhile
      case OBRACE => parseBlock
      case _ => { error("statement expected"); Skip}
    }
  }
 
  // write ::= "println" "(" var ")" ";"
  def parseWrite : Statement = {
    eat(PRINTLN)
    eat(OPAREN)
    val id = parseID
    eat(CPAREN)
    eat(SEMICOL)
    Print("", id)
  }
 
  // assign ::= var "=" expr ";"
  def parseAssign : Statement = {
    val id = parseID
    eat(AssignEQ)
    val e = parseExpr
    eat(SEMICOL)
    Assign(id,e)
  }
 
  // while ::= "while" "(" expr ")" statement
  def parseWhile : Statement = {
    eat(WHILE)
    eat(OPAREN)
    val e = parseExpr
    eat(CPAREN)
    val s = parseStatement
    While(e,s)
  }
 
  // block ::= "{" statements "}"
  def parseBlock : Statement = {
    eat(OBRACE)
    val sts = parseStatements
    eat(CBRACE)
    Block(sts)
  }
 
  /* Original rule:
     expr ::= expr "+" expr | expr "-" expr | expr "*" expr | 
              "(" expr ")" | var | intconst 
 
     Modified rules:
       expr ::= term ("+" term)*
       term ::= factor ("*" factor)*
       factor ::= "(" expr ")" | var | intconst
  */
 
  // expr ::= term ("+" term)*
  def parseExpr : Expression = { 
    var e = parseTerm
    while ((lex.current==PLUS)|(lex.current==MINUS)) {
      if (lex.current==PLUS) {
        lex.next
  	e = Plus(e,parseTerm)
      } else {
	lex.next
        e = Minus(e,parseTerm)
      }
    }
    e
  }
 
  // term ::= factor ("*" factor)*
  def parseTerm : Expression = {
    var e = parseFactor
    while (lex.current==MUL) {
      lex.next
      e = Times(e,parseFactor)
    }
    e
  }
 
  // factor ::= "(" expr ")" | var | intconst
  def parseFactor : Expression = {
    lex.current match {
      case OPAREN => { lex.next; val e = parseExpr; eat(CPAREN); e }
      case ID(s) => { lex.next; Var(s) }
      case IntConst(c) => { lex.next; IntLiteral(c) }
      case _ => error("(, ID, or IntConst expected")
    }
  }
 
  def error(s : String) = { println(s); exit(-1); }
  def eat(t : Token) = {
    if (lex.current==t) lex.next
    else error("Expected token " + t + " found token " + lex.current)
  }
  def ensure(t : Token) = {
    if (lex.current==t) {}
    else error("Expected token " + t + " found token " + lex.current)
  }
  def parseID : String = {
    lex.current match {
      case ID(s) => { lex.next; s }
      case _ => { error("identifier expected"); ""}
    }
  }
}
 
object ParserTest {
  def main(args : Array[String]) = {
    val lex = new Lexer(new CharStream(args(0)))
    val p = new Parser(lex)
    val trees = p.parseProgram
    TreePrinter(Block(trees))
  }
}