• 使用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/ ]

  • 相关阅读:
    Solution to LeetCode Problem Set
    《Cracking the Coding Interview》读书笔记
    诗词收集——用于人文素养扫盲
    2015年清华大学计算机系考研总结
    编程知识大杂烩
    hihoCoder 1175:拓扑排序二
    Hackerrank
    Hackerrank
    LeetCode
    LeetCode
  • 原文地址:https://www.cnblogs.com/zhoujg/p/717488.html
Copyright © 2020-2023  润新知