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))
}
}