如何使用antlr4编写一个更好的解析器,可以区分属性访问表达式,方法调用表达式,数组访问表达式?

时间:2017-05-03 09:18:15

标签: antlr antlr4

我想用antlr4编写表达式引擎。

以下是语法。

expression
:   primary
|   expression '.' Identifier
|   expression '(' expressionList? ')'
|   expression '[' expression ']'
|   expression ('++' | '--')
|   ('+'|'-'|'++'|'--') expression
|   ('~'|'!') expression
|   expression ('*'|'/'|'%') expression
|   expression ('+'|'-') expression
|   expression ('<' '<' | '>' '>' '>' | '>' '>') expression
|   expression ('<=' | '>=' | '>' | '<') expression
|   expression ('==' | '!=') expression
|   expression '&' expression
|   expression '^' expression
|   expression '|' expression
|   expression '&&' expression
|   expression '||' expression
|   expression '?' expression ':' expression
|   <assoc=right> expression
    (   '='
    |   '+='
    |   '-='
    |   '*='
    |   '/='
    |   '&='
    |   '|='
    |   '^='
    |   '>>='
    |   '>>>='
    |   '<<='
    |   '%='
    )
    expression
;

这个语法是正确的,但无法区分属性访问expr,调用方法expr,数组访问expr。所以我把语法改为

   attributeAccessMethod:    
        expression '.' Identifier;

    expression
        :   primary
        |   attributeAccessMethod
        |   expression '(' expressionList? ')'
        |   expression '[' expression ']'
        |   expression ('++' | '--')
        |   ('+'|'-'|'++'|'--') expression
        |   ('~'|'!') expression

但是这个语法是左递归[expression,attributeAccessMethod] ,那么如何编写更好的语法可以删除左递归并区分这些条件?

2 个答案:

答案 0 :(得分:1)

为不同的规则替代添加标签,例如:

expression
:   primary                                 # RulePrimary
|   expression '.' Identifier               # RuleAttribute
|   expression '(' expressionList? ')'      # RuleExpression
|   expression '[' expression ']'           # RuleArray
... etc.

当您在此规则中对所有您的替代方案执行此操作时,将针对这些特殊情况生成BaseVisitor或BaseListener以及公共覆盖,您可以根据需要处理每个特殊情况。

答案 1 :(得分:0)

我建议你不要这样定义你的语法。除了@ JLH的回答之外,你的语法还有可能弄乱这些表达的相关性。

我建议的是你应该&#34;自上而下&#34;你的语法与关联顺序。

例如,您可以将语法中的所有文字,方法调用等视为原子(因为它们将始终以文字或标识符开头),并且您将这些原子与关联运算符相关联。

然后你可以写下你的语法:

expression: binary_expr;

// Binary_Expr

// Logic_Expr

// Add_expr

// Mult_expr

// Pow_expr

// Unary_expr

associate_expr
: index_expr                            # ToIndexExpr
| lhs=index_expr '.' rhs=associate_expr # AssociateExpr
;

index_expr
: index_expr '[' (expression (COMMA expression)*) ']' # IndexExpr
| atom #ToAtom
;

atom
: literals_1 #wwLiteral
| ...        #xxLiteral
| ...        #yyLiteral
| literals_n #zzLiteral
| function_call # FunctionCall
;


function_call
: ID '(' (expression (',' expression)*)? ')';

// Define Literals
// Literals Block

您的算术表达式的一部分可能如下所示:

add_expr
: mul_expr                   # ToMulExpr
| lhs=add_expr PLUS rhs=mul_expr  #AddExpr
| lhs=add_expr MINUS rhs=mul_expr #SubtractExpr
;

mul_expr
: pow_expr                         # ToPowExpr
| lhs=mul_expr '+' rhs=pow_expr   # MultiplyExpr
| lhs=mul_expr '/' rhs=pow_expr # DivideExpr
| lhs=mul_expr '%' rhs=pow_expr    # ModExpr
;

您将左侧视为当前expr,将右侧视为与其他级别关联的expr,以便在保留递归时保持关联顺序。