[antlr-interest] Heterogeneous AST - simple calculator parser
koud0002
robertkoudelka at power-solutions.com.au
Thu Feb 7 16:03:07 PST 2002
I am building a parser and an interpreter for a tool to validate data
in a database.
I want to be able to specify validation rules for table columns (eg.
> TODAY AND < #7-FEB-2002#)
I would like to use ANTLR to help me build the parser so I have
started off with a simple grammar for a calculator.
I got (+, -, *, /) operators working. However, I have a difficulty
incorporating unary minus into the grammar.
I tried to use actions to build parts of the AST but my attempt were
unsuccessful.
Would you be able to point me in the right direction? Thank you.
I am using heterogeneous ASTs because I want to become familiar with
this concept as I feel that I will need to use them later in the
validator tool.
My grammar (calc.g), the AST node classes, a test program and a batch
file to build the parser, compile it and run the Calc test program
follow this message.
Sorry about bothering you with my problems but I would really
appreciate your help.
Robert Koudelka
// File: calc.g
class CalcParser extends Parser;
options {
k = 4; // four token lookahead
codeGenMakeSwitchThreshold = 2; // Some optimizations
codeGenBitsetTestThreshold = 3;
defaultErrorHandler = false; // Don't generate parser error
handlers
ASTLabelType = "CalcAST";
buildAST = true;
}
tokens {
UNARY_MINUS<AST=UnaryMinusNode>;
PLUS<AST=PlusNode>;
MINUS<AST=MinusNode>;
STAR<AST=MultNode>;
DIV<AST=DivNode>;
INT<AST=IntNode>;
}
expression
: logicalExpression SEMI!
;
logicalExpression
: relExpression ((AND^ | OR^) relExpression)*
;
relExpression
: simpleExpression ((LT^ | LE^ | EQ^ | GE^ | GT^ | NEQ^)
simpleExpression)*
;
simpleExpression
: MINUS t:term!
{
System.out.println("Got unary");
#simpleExpression = #([UNARY_MINUS, "-"], #t);
// #simpleExpression = antlr.ASTFactory.create(new
UnaryMinusNode(LT(1))), #t);
// #simpleExpression = new UnaryMinusNode(t);
}
| term ( (PLUS^ | MINUS^) term )*
;
term
: factor ( (STAR^ | DIV^) factor )*
;
factor
: INT
| LPAREN! logicalExpression RPAREN!
;
class CalcTreeWalker extends TreeParser;
expression returns [float r]
{
float a,b;
r=0;
}
: #(PLUS a=expression b=expression) { r = a+b; }
| #(MINUS a=expression b=expression) { r = a-b; }
| #(UNARY_MINUS a=expression)
{
r = (-1) * a;
}
| #(STAR a=expression b=expression) { r = a*b; }
| #(DIV a=expression b=expression) { r = a/b; }
| #(LT a=expression b=expression) { if (a < b) r =
1; else r = 0; }
| #(LE a=expression b=expression) { if (a <= b) r =
1; else r = 0; }
| #(EQ a=expression b=expression) { if (a == b) r =
1; else r = 0; }
| #(GE a=expression b=expression) { if (a >= b) r =
1; else r = 0; }
| #(GT a=expression b=expression) { if (a > b) r =
1; else r = 0; }
| #(NEQ a=expression b=expression) { if (a != b) r =
1; else r = 0; }
| #(AND a=expression b=expression) { if ((a > 0) &&
(b > 0)) r = 1; else r = 0; }
| #(OR a=expression b=expression) { if ((a > 0) ||
(b > 0)) r = 1; else r = 0; }
| i:INT { r = (float)
Integer.parseInt(i.getText()); }
;
class CalcLexer extends Lexer;
options {
charVocabulary = '\0'..'\377';
testLiterals = false; // don't automatically test for literals
k = 4; // four characters of lookahead
caseSensitive = true;
caseSensitiveLiterals = true;
}
WS
: (' '
| '\t'
| '\n'
| '\r')
{ _ttype = Token.SKIP; }
;
SEMI options {paraphrase = ";";} : ';' ;
STAR options {paraphrase = "*";} : '*' ;
PLUS options {paraphrase = "+";} : '+' ;
MINUS options {paraphrase = "-";} : '-' ;
DIV options {paraphrase = "/";} : '/' ;
AND options {paraphrase = "AND";} : "AND" ;
OR options {paraphrase = "OR";} : "OR" ;
EQ options {paraphrase = "=";} : '=' ;
NEQ options {paraphrase = "<>";} : "<>" ;
LT options {paraphrase = "<";} : '<' ;
LE options {paraphrase = "<=";} : "<=" ;
GE options {paraphrase = ">=";} : ">=" ;
GT options {paraphrase = ">";} : '>' ;
LPAREN options {paraphrase = "(";} : '(' ;
RPAREN options {paraphrase = ")";} : ')' ;
protected
DIGIT : '0'..'9';
INT : (DIGIT)+;
// File: Calc.java
import java.io.*;
import antlr.CommonAST;
import antlr.collections.AST;
import antlr.RecognitionException;
import antlr.TokenStreamException;
class Calc {
public static void main(String[] args) throws Exception {
boolean b = true;
try {
if (args.length > 0) {
String filename = args[0];
if (processEquationFile(filename)) {
return;
}
}
float value = 0;
BufferedReader reader = null;
while (true) {
System.out.print("Enter an expression: ");
reader = new BufferedReader(new InputStreamReader(System.in));
value = parseExpression(reader, "<stdin>");
System.out.println("value is " + value);
}
}
catch (TokenStreamException e) {
System.err.println("exception: " + e);
}
catch (RecognitionException e) {
System.err.println("exception: " + e);
}
}
private static float parseExpression(Reader reader, String
filename) {
float r = 0;
try {
CalcLexer lexer = new CalcLexer(reader);
lexer.setFilename(filename);
CalcParser parser = new CalcParser(lexer);
parser.setFilename(filename);
parser.setASTNodeType("CalcAST");
parser.setASTNodeClass("CalcAST");
parser.expression(); // Parse the input expression
// AST t = parser.getAST();
CalcAST t = (CalcAST)parser.getAST();
System.out.println("Tree in LIST notation: " + t.toStringTree
());
CalcTreeWalker walker = new CalcTreeWalker();
// Traverse the tree created by the parser
r = walker.expression(t);
} catch (TokenStreamException e) {
System.err.println("exception: " + e);
} catch (RecognitionException e) {
System.err.println("exception: " + e);
}
return r;
} // method parseExpression
private static boolean processEquationFile(String filename) throws
Exception {
File f = new File(filename);
if (f.exists() == false) {
System.out.println("File: " + f.getAbsoluteFile() + " does not
exist!");
return false;
}
BufferedReader fileReader = new BufferedReader(new FileReader(f));
StringReader reader = null;
String line = null;
float value = 0;
while ((line = fileReader.readLine()) != null) {
if (line.startsWith("//") || (line.length() == 0)) {
continue;
}
System.out.println("\nProcessing equation: " + line);
reader = new StringReader(line);
value = parseExpression(reader, "<stdin>");
System.out.println("value is " + value);
}
return true;
} // method processEquationFile
} // class Calc
// File: CalcAST.java
import antlr.*;
import antlr.collections.AST;
public class CalcAST extends BaseAST {
protected Token token;
public CalcAST() {
} // constructor
public CalcAST(Token token) {
this.token = token;
// System.out.println("CalcAST(" + token + ") constructor");
} // constructor
public String getText() {
if (this.token == null) {
System.out.println("null token in CalcAST.getText()");
return "";
}
return token.getText();
}
// satisfy abstract methods from BaseAST
public void initialize(int parm1, String parm2) { }
public void initialize(Token parm1) { }
public void initialize(AST parm1) { }
public int value() { return 0; }
} // class CalcAST
// File: BinaryOperatorAST.java
import antlr.*;
import antlr.collections.AST;
public abstract class BinaryOperatorAST extends CalcAST {
public BinaryOperatorAST(Token token) {
super(token);
}
public CalcAST left() {
return (CalcAST) getFirstChild();
}
public CalcAST right() {
CalcAST t = left();
if (t == null) {
return null;
}
return (CalcAST) t.getNextSibling();
}
} // class BinaryOperatorAST
// File: IntNode
import antlr.*;
import antlr.collections.AST;
public class IntNode extends CalcAST {
public IntNode(Token token) {
super(token);
}
public int getType() {
return CalcParserTokenTypes.INT;
}
public String toString() {
return " " + value();
}
public int value() {
return Integer.parseInt(token.getText());
}
} // class IntNode
// File: PlusNode.java
import antlr.*;
import antlr.collections.AST;
public class PlusNode extends BinaryOperatorAST {
public PlusNode(Token token) {
super(token);
}
public int getType() {
return CalcParserTokenTypes.PLUS;
}
public String toString() {
return " +";
}
public int value() {
if (left() == null) {
System.out.println("Error: PlusNode (no operands)!");
return 0;
}
int val = left().value();
if (right() != null) { // binary plus
val += right().value();
}
return val;
}
} // class PlusNode
// File: MinusNode.java
import antlr.*;
import antlr.collections.AST;
public class MinusNode extends BinaryOperatorAST {
public MinusNode(Token token) {
super(token);
}
public int getType() {
return CalcParserTokenTypes.MINUS;
}
public String toString() {
return " -";
}
public int value() {
if (left() == null) {
System.out.println("Error: MinusNode (no operands)!");
return 0;
}
int val = left().value();
if (right() != null) { // binary plus
val -= right().value();
} else { // unary minus
val = -val;
}
return val;
}
} // class MinusNode
// File: MultNode.java
import antlr.*;
import antlr.collections.AST;
public class MultNode extends BinaryOperatorAST {
public MultNode(Token token) {
super(token);
}
public int getType() {
return CalcParserTokenTypes.STAR;
}
public String toString() {
return " *";
}
public int value() {
return left().value() * right().value();
}
} // class MultNode
// File: DivNode.java
import antlr.*;
import antlr.collections.AST;
public class DivNode extends BinaryOperatorAST {
public DivNode(Token token) {
super(token);
}
public int getType() {
return CalcParserTokenTypes.DIV;
}
public String toString() {
return " /";
}
public int value() {
return left().value() / right().value();
}
} // class DivNode
// File: UnaryMinusNode.java
import antlr.*;
import antlr.collections.AST;
public class UnaryMinusNode extends CalcAST {
public UnaryMinusNode(Token token) {
super(token);
System.out.println("UnaryMinusNode(" + token + ") constructor");
}
public int getType() {
return CalcParserTokenTypes.UNARY_MINUS;
}
public String toString() {
return " - " + ((CalcAST) getFirstChild()).toString();
}
public int value() {
System.out.println("UnaryMinusNode.value()");
int val = ((CalcAST) getFirstChild()).value();
System.out.println("UnaryMinusNode.value(): " + -val);
return -val;
}
} // class UnaryMinusNode
// File: 1.expr
1;
3 + 2;
4 * 3 + 10 / 5;
4 * ( 3 + 10 ) / 5;
8 + 7 * 2;
-1;
// (- 8) + 7 * 2;
// - ( 8 + 7 * 2);
// File: run.bat
set CLASSPATH=.;f:\java\antlr\antlr-2.7.1
java antlr.Tool calc.g
javac *.java
rem 1.expr is a file containing expressions
java Calc 1.expr
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
More information about the antlr-interest
mailing list