/*************************************************************************** * @author John Miller * @version 1.0 * @date Thu Mar 25 12:38:03 EDT 2010 */ import java.util.regex.Pattern._ /*************************************************************************** * This object provides a simple recursive descent parser for an LL(1) * Expression Grammar. It also produces a parse tree, which can be trimmed * to make a syntax tree. Finally, a postfix tree traveral of the syntax * tree is used to evaluate the arithmetic expressions. * Caveat: must use blanks to separate all input symbols. * Need a left-associative grammar, with no left-recursion so that 3 - 2 - 1 = 0. * E --> T { A T } * T --> F { M F } * F --> integer | ( E ) * A --> + | - * M --> * | / */ object ParseExpr { case class Node (value: String, var lf: Node, var md: Node = null, var rt: Node = null, terminal: Boolean = false) private var tok: Array [String] = null // array of tokens private var i = 0 // index of current token private val addOps = Set ("+", "-") // additive operators private val mulOps = Set ("*", "/") // multiplicative operators def expr (): Node = { var n = Node ("E", term ()) while (addOps contains tok(i)) n = Node ("T", n, operator (tok(i)), term ()) n } // expr def term (): Node = { var n = Node ("T", factor ()) while (mulOps contains tok(i)) n = Node ("F", n, operator (tok(i)), factor ()) n } // term def factor (): Node = { val n = Node ("F", null) if (tok(i) == "(") { paren ("("); n.lf = expr (); paren (")") } else n.lf = number () n } // factor def paren (p: String) { if (tok(i) != p) println ("paren: error - found " + tok(i) + " instead of " + p) i += 1 } // paren def operator (op: String): Node = { val n = Node (op, null, null, null, true) if (tok(i) != op) println ("plus: error - found " + tok(i) + " instead of " + op) i += 1 n } // operator def number (): Node = { val n = Node (tok(i), null, null, null, true) if ( ! tok(i).matches ("\\d+")) { println ("number: error - found " + tok(i) + " instead of integer") } // if i += 1 n } // number def show (n: Node, j: Int) { if (n != null) { show (n.lf, j + 1) for (k <- 1 to j) print ("\t") println (n.value + "(" + (if (n.md == null) " " else n.md.value) + ")") show (n.rt, j + 1) } // if } // show def trimTree (n: Node) { if (n != null) { while (n.lf != null && ! n.lf.terminal && n.lf.md == null) n.lf = n.lf.lf while (n.rt != null && ! n.rt.terminal && n.rt.md == null) n.rt = n.rt.lf trimTree (n.lf) trimTree (n.rt) } // if } // trimTree def eval (n: Node): Int = { if (n.terminal) n.value.toInt else n.md.value match { case "+" => eval (n.lf) + eval (n.rt) case "-" => eval (n.lf) - eval (n.rt) case "*" => eval (n.lf) * eval (n.rt) case "/" => eval (n.lf) / eval (n.rt) } // match } // eval def main (args: Array [String]) { if (args.length > 0) { println ("input: " + args(0)) tok = (args(0) + " _END_").split (" ") val root = expr () println ("Parse Tree"); show (root, 0) println ("Syntax Tree"); trimTree (root); show (root, 0) println ("Evaluate"); println ("eval = " + eval (root)) } else { println ("usage: scala ParseExpr \"\"") } // if } // main } // ParseExpr