使用Antlr实现表达式引擎
上周末尝试使用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/ ]