您的位置:首页 > 其它

使用Antlr实现表达式引擎

2007-04-17 23:42 363 查看
上周末尝试使用Antlr生成C#语言的表达式引擎,目前已经可以支持基本运算.主要思路是把表达式解析成操作数和函数(操作符也作为函数看待)两种类型节点,主要部分类图如下:



GrandExpr.g文件内容如下:

grammar GrandExpr;

options {
output=AST;
ASTLabelType=CommonTree;
// language=CSharp;
}

tokens
{
INDEX;
MEMBERACCESS;
CALL;
}

expr
:	logicalOrExpr
;

logicalOrExpr
:	logicalAndExpr (OR logicalAndExpr)*
;

logicalAndExpr
:	equalityExpr (AND equalityExpr)*
;

equalityExpr
:	relationalExpr ((EQUALS|NOTEQUALS)^ relationalExpr)*
;

relationalExpr
:	additiveExpr ((LT|LTEQ|GT|GTEQ)^ additiveExpr)?
;

additiveExpr
:	multiplyExpr ((PLUS|MINUS)^ multiplyExpr)*
;

multiplyExpr
:	powExpr ((a=MUL| a=DIV | a=MOD) powExpr)*
;

powExpr
:	unaryExpr (POWER unaryExpr)?
;

unaryExpr
:  	(PLUS | MINUS | NOT) unaryExpr
|  	memberExpr
;

memberExpr
:	basicExpr (memberAccessExpr)*  (indexerExpr)?
;

basicExpr
:	 parenExpr | literal |  memberFunctionExpr;

parenExpr
:	LPAREN! expr  RPAREN!
;

literal
: 	numbericLiteral
| 	stringLiteral
;

numbericLiteral
:  	INTEGER_LITERAL
| 	DECIMAL_LITERAL
| 	DATETIME_LITERAL
;

stringLiteral
: 	STRING_LITERAL
;

memberAccessExpr
:	'.' memberFunctionExpr -> ^(MEMBERACCESS memberFunctionExpr)
;

memberFunctionExpr
:	fieldPropertyExpr | methodExpr
;

fieldPropertyExpr
:	IDENTIFIER
;

methodExpr
:	IDENTIFIER LPAREN (argument (COMMA argument)*)? RPAREN -> ^(CALL IDENTIFIER argument*)
;

indexerExpr
:	LBRACKET argument (COMMA argument)* RBRACKET -> ^(INDEX argument+)
;

argument
: 	expr
;

AND
:	'and'
;

OR
: 	'or'
;

NOT
: 	'not'
;

COMMA
: 	','
;

PLUS
: 	'+'
;

MINUS
: 	'-'
;

MUL
: 	'*'
;

DIV
: 	'/'
;

MOD
: 	'%'
;

POWER
: 	'^'
;

EQUALS	:	'=';

NOTEQUALS
:	'!=' | '<>';

LT	:	'<';
LTEQ	:	'<=';
GT	:	'>';
GTEQ	:	'>=';

LPAREN
:	'('
;

RPAREN	:	')'
;

LBRACKET
:	'['
;

RBRACKET
:	']'
;

DATETIME_LITERAL
: 	'\'' STRING_LITERAL '\''
;

STRING_LITERAL
:	'"' (~'"')* '"'
;

IDENTIFIER
:	LETTER (LETTER|Digit)*
;

fragment
LETTER
:	'A'..'Z'|'a'..'z'|'_'
;

DECIMAL_LITERAL
:   	(INTEGER_LITERAL)? '.' Digit* Exponent?
;

fragment
Exponent
: 	('e'|'E') INTEGER_LITERAL
;

INTEGER_LITERAL
: 	Digit+
;

fragment
Digit
:	'0'..'9'
;

/* Ignore white spaces */
WS
:  (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
;


欢迎转载,转载请注明:转载自周金根 [ http://zhoujg.cnblogs.com/ ]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: