Parsing Antlr4:如何更改语法以允许解析链式元素?
我需要一个语法来解析双点分隔的标记,如:Parsing Antlr4:如何更改语法以允许解析链式元素?,parsing,antlr4,Parsing,Antlr4,我需要一个语法来解析双点分隔的标记,如: 1..5,v[1]…v[2]或1+f(1)…2+v[f(2)]…3+f(3) 基本上,这些标记表示整数范围,例如,1..5表示范围为1到5的整数。标记文字应仅表示为“整型..整型” 我还必须解析一些整数文本和实文本。 所以目前,我有一个自下而上的语法,比如: unary_expr : range_expr # ToRangeExpr | PLUS rhs=unary_expr # UnaryPlusE
1..5
,v[1]…v[2]
或1+f(1)…2+v[f(2)]…3+f(3)
基本上,这些标记表示整数范围,例如,1..5
表示范围为1到5的整数。标记文字应仅表示为“整型..整型”
我还必须解析一些整数文本和实文本。
所以目前,我有一个自下而上的语法,比如:
unary_expr
: range_expr # ToRangeExpr
| PLUS rhs=unary_expr # UnaryPlusExpr
| MINUS rhs=unary_expr # UnaryMinusExpr
| NOT rhs=unary_expr # UnaryNotExpr
;
range_expr
: index_expr # ToIndexExpr
| lhs=index_expr RANGEDOT rhs=index_expr # RangeExpr
| lhs=range_literal rhs=index_expr # RangeLiteralExpr
;
index_expr
: atom # ToAtom
| atom LBRACK expression RBRACK # IndexExpr
;
atom
: vector_atom # ToVectorAtom
| matrix_atom # ToMatrixAtom
| boolean_literal # ToBooleanLiteral
| int_literal # ToIntegerLiteral
| real_literal # ToRealLiteral
| char_literal # ToCharLiteral
| string_literal # ToStringLiteral
| tuple_literal # ToTupleLiteral
| range_literal # ToRangeLiteral
| tuple_element # ToTupleElement
| type_cast # ToTypeCast
| stream_state # ToStreamState
| function_call # ToFunctionCall
| ID # IDAtom
| IDENTITY # IdentityLiteral
| NULL # NullLiteral
| LPAREN expression RPAREN # ToSubExpr
range_literal: RANGE_LITERAL;
RANGE_LITERAL
: INT_LITERAL RANGEDOT INT_LITERAL
;
REAL_LITERAL
: DOT US+ INT_LITERAL REAL_EXP?
| INT_LITERAL DOT US* INT_LITERAL? REAL_EXP?
| INT_LITERAL REAL_EXP
| DOT INT_LITERAL REAL_EXP
;
REAL_EXP
: 'e' US* (PLUS | MINUS |)? US* INT_LITERAL
;
INT_LITERAL: NUM (NUM | US)*;
所以目前,我的语法可以解析多个整数链式范围标记。但是,我无法解析任何多表达式链接的范围标记。我试图将我的范围\u expr
更改为(使其更加模糊):
但是,这并没有改变我的解析敏感性。那么,为了让语法分析多个index\u expr
chained range标记,我还应该做哪些更改?解释
我无法重用您的语法(因为缺少lexer/parser规则),但如果我正确理解了这个问题:您希望有一个简单的两个数字范围,或者将任意数量的expr
链接在一起。这样做的想法是在index_expr
中有一个子规则,它将匹配数字范围(一个专门版本的exprChain
),并有一个由链接表达式(exprChain
)组成的expr
的递归定义
解决方案
作为一个例子,我介绍了小语法
语法测试;
内部:[0-9]+;
实数:[0-9]*'.[0-9]+;
名称:[a-zA-Z]+;
数字的
:INT | REAL
;
参考
:NAME#变量
|名称“['expr']”数组
|名称“('expr')”#函数调用
;
指数表达式
:数字“..”数字#数字范围
|expr#classicExpr
;
expr
:expr'+'expr#exprAdd
|参考#exprRef
|数字#exprNumber
|expr'..'expr#exprChain
;
此示例语法能够匹配您提到的所有范围表达式:
1..5
或1…3
(asrangeOfNumbers
)、v[1]…v[2]
或1+f(1)…2+v[f(2)]…3+f(3)
(两者都作为exprChain
).问题是我不能在语法中将range\u expr
视为uniary\u expr
,因为它会将antlr4与real\u literal
选项混淆,并强制antlr4匹配logic\u expr
标记(即xor
,或
,我在问题中没有显示它们)。在我的微修复之后,部分语法将如下所示:
unary_expr
: index_expr # ToIndexExpr
| PLUS rhs=unary_expr # UnaryPlusExpr
| MINUS rhs=unary_expr # UnaryMinusExpr
| NOT rhs=unary_expr # UnaryNotExpr
;
index_expr
: atom # ToAtom
| atom LBRACK expression RBRACK # IndexExpr
| lhs=index_expr RANGEDOT rhs=index_expr # RangeExpr
| lhs=range_literal rhs=index_expr # RangeLiteralExpr
;
atom
: vector_atom # ToVectorAtom
| matrix_atom # ToMatrixAtom
| boolean_literal # ToBooleanLiteral
| int_literal # ToIntegerLiteral
| real_literal # ToRealLiteral
| char_literal # ToCharLiteral
| string_literal # ToStringLiteral
| tuple_literal # ToTupleLiteral
| range_literal # ToRangeLiteral
| tuple_element # ToTupleElement
| type_cast # ToTypeCast
| stream_state # ToStreamState
| function_call # ToFunctionCall
| ID # IDAtom
| IDENTITY # IdentityLiteral
| NULL # NullLiteral
| LPAREN expression RPAREN # ToSubExpr
;
real_literal: REAL_LITERAL # RealLiteral
| DOT INT_LITERAL # EdgeCaseRealLiteral;
range_literal: RANGE_LITERAL;
RANGE_LITERAL
: INT_LITERAL RANGEDOT
;
REAL_LITERAL
: DOT US+ INT_LITERAL REAL_EXP?
| INT_LITERAL DOT US* INT_LITERAL? REAL_EXP?
| INT_LITERAL REAL_EXP
| DOT INT_LITERAL REAL_EXP
;
REAL_EXP
: 'e' US* (PLUS | MINUS |)? US* INT_LITERAL
;
INT_LITERAL: NUM (NUM | US)*;
我也应该添加我的lexer规则,因为我还必须将
.3
或1.
解析为实文本,将23_1
解析为int文本(可以在第一位数字后添加下划线)。您的答案将无法将.3
或1.
解析为实际文本。我通过重新排列递归定义解决了我的问题。我会在我的答案中告诉你。@Lingbotag:为了解析实数,你需要用lexem/token来表示实数(比如real:[0-9]*'.[0-9]+;
)。我修改了答案。是的,但是,[0-9]*'.[0-9]+
将不会解析2.
,因为[0-9]+
将捕获至少一个数字而不是0个数字。这就是为什么我让我的语法具有攻击性。我当前的语法可以解析这些大小写,因为我在索引\u expr
中递归定义了range\u literal
,这要感谢你的灵感。@lingbotag:OK:)
unary_expr
: index_expr # ToIndexExpr
| PLUS rhs=unary_expr # UnaryPlusExpr
| MINUS rhs=unary_expr # UnaryMinusExpr
| NOT rhs=unary_expr # UnaryNotExpr
;
index_expr
: atom # ToAtom
| atom LBRACK expression RBRACK # IndexExpr
| lhs=index_expr RANGEDOT rhs=index_expr # RangeExpr
| lhs=range_literal rhs=index_expr # RangeLiteralExpr
;
atom
: vector_atom # ToVectorAtom
| matrix_atom # ToMatrixAtom
| boolean_literal # ToBooleanLiteral
| int_literal # ToIntegerLiteral
| real_literal # ToRealLiteral
| char_literal # ToCharLiteral
| string_literal # ToStringLiteral
| tuple_literal # ToTupleLiteral
| range_literal # ToRangeLiteral
| tuple_element # ToTupleElement
| type_cast # ToTypeCast
| stream_state # ToStreamState
| function_call # ToFunctionCall
| ID # IDAtom
| IDENTITY # IdentityLiteral
| NULL # NullLiteral
| LPAREN expression RPAREN # ToSubExpr
;
real_literal: REAL_LITERAL # RealLiteral
| DOT INT_LITERAL # EdgeCaseRealLiteral;
range_literal: RANGE_LITERAL;
RANGE_LITERAL
: INT_LITERAL RANGEDOT
;
REAL_LITERAL
: DOT US+ INT_LITERAL REAL_EXP?
| INT_LITERAL DOT US* INT_LITERAL? REAL_EXP?
| INT_LITERAL REAL_EXP
| DOT INT_LITERAL REAL_EXP
;
REAL_EXP
: 'e' US* (PLUS | MINUS |)? US* INT_LITERAL
;
INT_LITERAL: NUM (NUM | US)*;