使用Antlr实现表达式引擎

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

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/ ]

posted on 2007-04-17 23:42  周 金根  阅读(3982)  评论(5编辑  收藏  举报

导航