如何使用antlr4编写一个更好的解析器,可以区分属性访问表达式、方法调用表达式、数组访问表达式?
How to use antlr4 write a better parser that can distinguish attribute access expression, method invoke expression, array access expression?
我想用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
;
这个语法是对的,但是不能区分属性访问表达式、方法调用表达式和数组访问表达式。所以我把语法改成了
attributeAccessMethod:
expression '.' Identifier;
expression
: primary
| attributeAccessMethod
| expression '(' expressionList? ')'
| expression '[' expression ']'
| expression ('++' | '--')
| ('+'|'-'|'++'|'--') expression
| ('~'|'!') expression
但是这个语法是 左递归 [expression, attributeAccessMethod]。 我怎样才能写出更好的语法 - 我能以某种方式删除左递归 属性并区分这些条件?
为您的不同规则选项添加标签,例如:
expression
: primary # RulePrimary
| expression '.' Identifier # RuleAttribute
| expression '(' expressionList? ')' # RuleExpression
| expression '[' expression ']' # RuleArray
... etc.
当您针对此规则中的所有 选项执行此操作时,将为这些特殊情况生成您的 BaseVisitor 或 BaseListener public 覆盖,您可以在其中处理每一个你认为合适的。
我不建议你这样定义你的语法。除了@JLH 的回答之外,您的语法还有可能搞乱这些表达式的关联性。
我的建议是,您应该 "top-down" 您的语法具有关联顺序。
例如,您可以在语法中将所有文字、方法调用等视为原子(因为它们总是以文字或标识符开头),并将这些原子与关联运算符相关联。
然后你可以这样写你的语法:
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
;
您将左侧作为当前表达式,将右侧作为其他级别关联的表达式,这样您可以在对它们进行左递归的同时保持关联性的顺序。
我想用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
;
这个语法是对的,但是不能区分属性访问表达式、方法调用表达式和数组访问表达式。所以我把语法改成了
attributeAccessMethod:
expression '.' Identifier;
expression
: primary
| attributeAccessMethod
| expression '(' expressionList? ')'
| expression '[' expression ']'
| expression ('++' | '--')
| ('+'|'-'|'++'|'--') expression
| ('~'|'!') expression
但是这个语法是 左递归 [expression, attributeAccessMethod]。 我怎样才能写出更好的语法 - 我能以某种方式删除左递归 属性并区分这些条件?
为您的不同规则选项添加标签,例如:
expression
: primary # RulePrimary
| expression '.' Identifier # RuleAttribute
| expression '(' expressionList? ')' # RuleExpression
| expression '[' expression ']' # RuleArray
... etc.
当您针对此规则中的所有 选项执行此操作时,将为这些特殊情况生成您的 BaseVisitor 或 BaseListener public 覆盖,您可以在其中处理每一个你认为合适的。
我不建议你这样定义你的语法。除了@JLH 的回答之外,您的语法还有可能搞乱这些表达式的关联性。
我的建议是,您应该 "top-down" 您的语法具有关联顺序。
例如,您可以在语法中将所有文字、方法调用等视为原子(因为它们总是以文字或标识符开头),并将这些原子与关联运算符相关联。
然后你可以这样写你的语法:
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
;
您将左侧作为当前表达式,将右侧作为其他级别关联的表达式,这样您可以在对它们进行左递归的同时保持关联性的顺序。