上周末嘗試使用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)*;fragmentLETTER:'A'..'Z'|'a'..'z'|'_';DECIMAL_LITERAL: (INTEGER_LITERAL)? '.' Digit* Exponent? ;fragmentExponent : ('e'|'E') INTEGER_LITERAL;INTEGER_LITERAL : Digit+ ;fragmentDigit:'0'..'9';/* Ignore white spaces */WS: (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;};
歡迎轉載,轉載請註明:轉載自周金根 [ http://zhoujg.cnblogs.com/ ]