Blogged by Ujihisa. Standard methods of programming and thoughts including Clojure, Vim, LLVM, Haskell, Ruby and Mathematics written by a Japanese programmer. github/ujihisa

Sunday, July 4, 2010

Simple Mathematical Expression Converter with Jay

I wrote a simple mathematical expression converter with Jay: Yacc for Java for my study.

http://www.cs.rit.edu/~ats/lp-2002-2/html/skript-23.html

The sample code in this page is a mathematical expression interpreter. You can calculate four arithmetic operations and more like 1 + 2 * 3 to 7. My code which will be described in this post converts expressions into reverse Polish notation ones like 1 + 2 * 3 to 1 2 + 3 *.

%{
// vim: set ft=java :
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.Reader;
import java.io.ObjectOutputStream;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import jay.yydebug.yyAnim;
import jay.yydebug.yyDebugAdapter;
abstract class Node {
}
class Operator extends Node {
private Node left, right;
protected String op;
protected Operator(Node left, Node right) {
this.left = left;
this.right = right;
}
public String toString() {
return String.format("%s %s %s", left, right, op);
}
}
class Add extends Operator {
public Add(Node left, Node right) {
super(left, right);
this.op = "+";
}
}
class Sub extends Operator {
public Sub(Node left, Node right) {
super(left, right);
this.op = "-";
}
}
class Mul extends Operator {
public Mul(Node left, Node right) {
super(left, right);
this.op = "*";
}
}
class Div extends Operator {
public Div(Node left, Node right) {
super(left, right);
this.op = "/";
}
}
class Mod extends Operator {
public Mod(Node left, Node right) {
super(left, right);
this.op = "%";
}
}
class Value extends Node {
private Object value;
public Value(Object value) {
this.value = value;
}
public String toString() {
return value.toString();
}
}
/** recognizes, stores, and evaluates arithmetic expressions
using a parser generated with jay.
*/
public class Expr {
/** node factory.
*/
//protected static VM vm = new VM();
protected static Node root;
public static void main(String args []) throws Exception {
Object trace = null;
if (args.length > 0)
trace = new yyAnim("Expr", Integer.parseInt(args[0]));
Expr parser = new Expr();
Scanner scanner = new Scanner(new InputStreamReader(System.in));
while (scanner.ttype != scanner.TT_EOF)
try {
Node n = (Node)parser.yyparse(scanner, trace);
if (n != null)
System.out.println(n);
} catch (yyException ye) { System.err.println(scanner+": "+ye); }
}
%}
%token <String> Int, Real
%type <Node> line, sum, product, term
%%
line : sum // $$ = $1
| /* null */ { $$ = null; }
sum : product // $$ = $1
| sum '+' product { $$ = new Add($1, $3); }
| sum '-' product { $$ = new Sub($1, $3); }
product : term // $$ = $1
| product '*' term { $$ = new Mul($1, $3); }
| product '/' term { $$ = new Div($1, $3); }
| product '%' term { $$ = new Mod($1, $3); }
term : '+' term { $$ = $2; }
| '-' term { $$ = $2; } // FIXME
| '(' sum ')' { $$ = $2; }
| Int { $$ = new Value(Integer.parseInt($1)); }
| Real { $$ = new Value(Double.parseDouble($1)); }
%%
/** lexical analyzer for arithmetic expressions.
*/
public static class Scanner extends StreamTokenizer implements yyInput {
public Scanner (Reader r) {
super(r);
resetSyntax();
commentChar('#'); // comments from # to end-of-line
wordChars('0', '9'); // parse decimal numbers as words
wordChars('.', '.');
whitespaceChars(0, ' '); // ignore control-* and space
eolIsSignificant(true); // need '\n'
}
/** moves to next input token.
Consumes end of line and pretends (once) that it is end of file.
@return false at end of file and once at each end of line.
*/
public boolean advance () throws IOException {
if (ttype != TT_EOF) nextToken();
return ttype != TT_EOF && ttype != TT_EOL;
}
/** determines current input, sets value to String for Int and Real.
@return Int, Real or token's character value.
*/
public int token () {
switch (ttype) {
case TT_EOL:
case TT_EOF: assert false; // should not happen
case TT_WORD: value = sval;
return sval.indexOf(".") < 0 ? Int : Real;
default: value = null;
return ttype;
}
}
/** value associated with current input.
*/
protected Object value;
/** produces value associated with current input.
@return value.
*/
public Object value () {
return value;
}
}
}
view raw gistfile1.txt hosted with ❤ by GitHub

Followers