[antlr-interest] Help with circular reference in parser?
Christopher Schultz
christopher.d.schultz at comcast.net
Thu Mar 2 08:22:32 PST 2006
Sorry, forgot the attachment.
Here is the grammar in all it's glory.
Thanks,
-chris
header {
package net.christopherschultz.evaluator.parser;
import net.christopherschultz.evaluator.*;
}
class ExpressionParserImpl extends Parser;
options {
buildAST = false;
k=2; // 2-token lookahead: can differentiate between
// ( MINUS INT ) and ( MINUS FLOAT )
defaultErrorHandler = false;
}
/* We have expr and mexpr separate, with the addition and subtraction
separate from multiplication in order to enforce order-of-operations. */
expr returns [Expression exp = null] throws EvaluationException
{
Expression right;
}
:
exp=relexpr (
( AND^ right=relexpr) { exp = new MathExpression(exp, "&&",
right); }
| (OR^ right=relexpr) { exp = new MathExpression(exp, "||",
right); }
)*
// This (EOF)? seem totally sketchy, but it works!
(EOF!)?
;
// Relational Expression
relexpr returns [Expression exp = null] throws EvaluationException
{
Expression right;
}
:
exp=addexpr (
(EQUALS^ right=addexpr) { exp = new MathExpression(exp, "=",
right); }
| (NOT_EQUALS^ right=addexpr) { exp = new
MathExpression(exp, "!=", right); }
| (GREATERTHAN^ right=addexpr) { exp = new
MathExpression(exp, ">", right); }
| (LESSTHAN^ right=addexpr) { exp = new MathExpression(exp,
"<", right); }
| (GREATERTHANEQUALTO^ right=addexpr) { exp = new
MathExpression(exp, ">=", right); }
| (LESSTHANEQUALTO^ right=addexpr) { exp = new
MathExpression(exp, "<=", right); }
)*
;
// Arithmetic Expression
addexpr returns [Expression exp = null] throws EvaluationException
{
Expression right;
}
:
exp=multexpr (( PLUS^ right=multexpr { exp = new
MathExpression(exp, "+", right); }
| MINUS^ right=multexpr { exp = new
MathExpression(exp, "-", right); } ))*
;
// Multiplicative (or divisive) expression
multexpr returns [Expression exp = null] throws EvaluationException
{
Expression right;
}
:
exp=unaryExpr (
( STAR^ right=unaryExpr { exp = new MathExpression(exp, "*",
right); } )
|
( SLASH right=unaryExpr { exp = new MathExpression(exp, "/",
right); } )
|
( PERCENT right=unaryExpr { exp = new MathExpression(exp,
"%", right); } )
)*
;
// (Logically) negated expression
unaryExpr returns [ Expression exp = null ] throws EvaluationException
:
(
(BANG^ exp=atom { exp = new NegatedExpression(exp); })
|
(MINUS^ exp=atom { exp = new UnaryMinusExpression(exp); })
|
(PLUS!)? exp=atom
)
;
// Function call expression
functioncall returns [ Expression exp = null ] throws EvaluationException
{
java.util.List args = null;
}
:
func:IDENTIFIER^ LPAREN! (args=argumentlist)? RPAREN!
{
exp = new FunctionCallExpression(func.getText(), args);
}
;
// Array reference (i.e. a[3])
arrayref returns [ Expression exp = null ] throws EvaluationException
{
Expression index; // dynamic index ;)
}
:
array:IDENTIFIER^ LBRACKET! (index=expr) RBRACKET!
{
exp = new ArrayReferenceExpression(array.getText(), index);
}
;
// arrayref returns [ Expression exp = null ] throws EvaluationException
// {
// Expression array; // dynamic reference ;)
// Expression index; // dynamic index ;)
// }
// :
// (array=expr)
// |
// (array=expr) LBRACKET! (index=expr) RBRACKET!
// {
// exp = new ArrayReferenceExpression(array.getText(), index);
// }
// ;
// Argument List
argumentlist returns [java.util.List list = new java.util.ArrayList()]
throws EvaluationException
{
Expression arg;
}
:
arg=argument { list.add(arg); }
(COMMA! arg=argument { list.add(arg); })*
;
// Argument (i.e. anything)
argument returns [Expression exp = null] throws EvaluationException
:
exp=expr
;
// Indentifiers (i.e. symbols)
identifier returns [ Expression exp = null ] throws EvaluationException
:
id:IDENTIFIER
{
exp = new IdentifierExpression(id.getText());
}
;
// Atoms
atom returns [Expression exp = null] throws EvaluationException
:
exp=functioncall
|
exp=arrayref
|
exp=identifier
|
hex:HEX_LITERAL { Object value;
String hexStr = hex.getText();
int length = hexStr.length();
if(length > 10) // 8 hex + leading "0x"
value = Long.decode(hexStr);
else if(length > 6)
value = Integer.decode(hexStr);
else if(length > 4)
value = Short.decode(hexStr);
else
value = Byte.decode(hexStr);
exp = new ConstantExpression(value);
}
|
oct:OCTAL_LITERAL { Object value;
String octalStr = oct.getText();
int length = octalStr.length();
if(length > 11) // 10 octal + leading "0"
value = Long.decode(octalStr);
else if(length > 6)
value = Integer.decode(octalStr);
else if(length > 3)
value = Short.decode(octalStr);
else
value = Byte.decode(octalStr);
exp = new ConstantExpression(value);
}
|
/* TODO: allow larger precision than simply 32-bit integer. Long?
BigInteger? */
/* TODO: How can we use a BigInteger to determine if the value fits into
a certain type of primitive? Just make BigInteger objects out of
Integer.MAX_VALUE, etc? */
i:INT_LITERAL { exp = new ConstantExpression(new
Integer(i.getText())); }
|
f:DECIMAL_LITERAL { exp = new ConstantExpression(new
Double(f.getText())); }
|
s:STRING { exp = new ConstantExpression(s.getText()); }
|
LPAREN! exp=expr RPAREN!
;
class ExpressionLexerImpl extends Lexer;
options {
k=2; // (2)needed for newline junk, (5) needed for booleans
charVocabulary = '\3'..'\377';
}
IDENTIFIER: WORDCHAR (WORDCHAR | DIGIT)*;
STRING
:
DOUBLEQUOTE!
(CHAR_ESC | ~('\"' | '\\') )*
DOUBLEQUOTE!
;
protected CHAR_ESC
:
'\\'
( 'n' { $setText("\n"); }
| 'r' { $setText("\r"); }
| 't' { $setText("\t"); }
| 'b' { $setText("\b"); }
| 'f' { $setText("\f"); }
| '\"' { $setText("\""); }
| '\'' { $setText("\'"); }
| '\\' { $setText("\\"); }
)
;
NUMERIC_LITERAL:
(ZERO (OCTAL_DIGIT)+) => OCTAL_LITERAL { $setType(OCTAL_LITERAL); }
|
(ZERO Xx) => HEX_LITERAL { $setType(HEX_LITERAL); }
|
(DOT DIGITS) => DECIMAL_LITERAL { $setType(DECIMAL_LITERAL); }
|
(DIGITS DOT) => DECIMAL_LITERAL { $setType(DECIMAL_LITERAL); }
|
(DIGITS) { $setType(INT_LITERAL); }
;
/*
NUMERIC_LITERAL:
(ZERO (OCTAL_DIGIT)+) => OCTAL_LITERAL { $setType(OCTAL_LITERAL); }
|
(ZERO Xx) => HEX_LITERAL { $setType(HEX_LITERAL); }
|
((
( PLUS { $setType(PLUS); } )
|
( MINUS { $setType(MINUS); } )
)?
( ( DIGITS { $setType(INT_LITERAL); } )
( DOT (DIGITS)? { $setType(DECIMAL_LITERAL); } )?
|
( ( DOT DIGITS ) => DECIMAL_LITERAL {
$setType(DECIMAL_LITERAL); } )
)
)
|
(DIGITS) { $setType(INT_LITERAL); }
((DOT) => DECIMAL_LITERAL { $setType(DECIMAL_LITERAL); } )?
;
*/
protected OCTAL_LITERAL: (ZERO (OCTAL_DIGIT)+) ;
protected OCTAL_DIGIT: '0'..'7' ;
protected HEX_LITERAL : (ZERO Xx (HEX_DIGIT)+) ;
protected ZERO: '0' ;
protected Xx: ('x' | 'X') ;
protected HEX_DIGIT: ( 'a'..'z' | 'A'..'Z' | DIGIT ) ;
protected INT_LITERAL: DIGITS ;
protected DECIMAL_LITERAL: ( ( DIGITS )? DOT ( DIGITS )? ) ;
protected DIGITS : ( DIGIT )+ ;
protected SIGN: ( PLUS | MINUS ) ;
protected
WORDCHAR: 'a'..'z' | 'A'..'Z' | '_' ;
protected
DIGIT: '0'..'9';
protected
DOT: '.' ;
BANG: '!' ;
COMMA: ','
;
LBRACKET: '['
;
RBRACKET: ']'
;
LPAREN: '('
;
RPAREN: ')'
;
PLUS: '+'
;
MINUS: '-'
;
STAR: '*'
;
PERCENT: '%'
;
SLASH: '/'
;
AND: '&''&'
;
OR: '|''|'
;
EQUALS: '='
;
NOT_EQUALS
:
BANG EQUALS
;
GREATERTHAN: '>' ;
LESSTHAN: '<' ;
GREATERTHANEQUALTO: '>' '=' ;
LESSTHANEQUALTO: '<' '=' ;
SINGLEQUOTE: '\'' ;
DOUBLEQUOTE: '\"' ;
/*
protected
TRUE: 't''r''u''e'
;
protected
FALSE: 'f''a''l''s''e'
;
*/
WS:
( ' '
| '\t'
| '\r' '\n' { newline(); }
| '\n' { newline(); }
)
{$setType(Token.SKIP);} //ignore this token
;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 250 bytes
Desc: OpenPGP digital signature
Url : http://www.antlr.org/pipermail/antlr-interest/attachments/20060302/3ec687ba/signature.bin
More information about the antlr-interest
mailing list