Antlr4:如何更改我的语法以让链式元素被解析?
Antlr4: How to change my grammar to let chained elements being parsed?
我需要一个语法来解析双点分隔的标记,例如:
1..5
、v[1]..v[2]
或 1+f(1)..2+v[f(2)]..3+f(3)
.
基本上,这些标记表示整数范围,例如,1..5
表示范围为 1 到 5 的整数。标记文字应仅表示为 "Integer..Integer"
我还必须解析一些整数文字和实数文字。
所以目前,我有一个自下而上的语法,如:
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)*;
所以目前,我的语法可以解析多个整数链接的范围标记。但是,我无法解析任何多表达式链接的范围标记。我试图将我的 range_expr
更改为(使其更加模糊):
range_expr
: range_literal
| index_expr (RANGEDOT index_expr*)
;
但是,它并没有改变我的解析敏感度。那么我还应该做些什么改变让我的语法解析多个 index_expr
链式范围标记?
说明
我无法重用你的语法(因为缺少 lexer/parser 规则)但如果我正确理解问题:你想要一个简单的两个数字范围或将任意数量的数字链接在一起expr
。这样做的想法是在 index_expr
中有一个匹配数字范围的子规则(exprChain
的特殊版本),并有一个 expr
的递归定义,它将包含一个链接表达式 (exprChain
).
解决方案
作为思路的一个例子我介绍一下小语法。
grammar test;
INT : [0-9]+;
REAL : [0-9]* '.' [0-9]+;
NAME : [a-zA-Z]+;
numeric
: INT | REAL
;
reference
: NAME # variable
| NAME '[' expr ']' # array
| NAME '(' expr ')' # functionCall
;
index_expr
: numeric '..' numeric # rangeOfNumbers
| expr # classicExpr
;
expr
: expr '+' expr # exprAdd
| reference # exprRef
| numeric # exprNumber
| expr '..' expr # exprChain
;
此示例语法能够匹配您提到的所有范围表达式:1..5
或 .1...3
(如 rangeOfNumbers
)、v[1]..v[2]
或 1+f(1)..2+v[f(2)]..3+f(3)
(均为 exprChain
)。
问题是我无法在我的语法中将 range_expr
视为 unary_expr
,因为它会混淆 antlr4 与 real_literal
选项,并强制 antlr4 匹配 logic_expr
标记(即 xor
、or
,我没有在我的问题中显示它们)。在我的微修复之后,部分语法将是这样的:
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)*;
我需要一个语法来解析双点分隔的标记,例如:
1..5
、v[1]..v[2]
或 1+f(1)..2+v[f(2)]..3+f(3)
.
基本上,这些标记表示整数范围,例如,1..5
表示范围为 1 到 5 的整数。标记文字应仅表示为 "Integer..Integer"
我还必须解析一些整数文字和实数文字。 所以目前,我有一个自下而上的语法,如:
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)*;
所以目前,我的语法可以解析多个整数链接的范围标记。但是,我无法解析任何多表达式链接的范围标记。我试图将我的 range_expr
更改为(使其更加模糊):
range_expr
: range_literal
| index_expr (RANGEDOT index_expr*)
;
但是,它并没有改变我的解析敏感度。那么我还应该做些什么改变让我的语法解析多个 index_expr
链式范围标记?
说明
我无法重用你的语法(因为缺少 lexer/parser 规则)但如果我正确理解问题:你想要一个简单的两个数字范围或将任意数量的数字链接在一起expr
。这样做的想法是在 index_expr
中有一个匹配数字范围的子规则(exprChain
的特殊版本),并有一个 expr
的递归定义,它将包含一个链接表达式 (exprChain
).
解决方案
作为思路的一个例子我介绍一下小语法。
grammar test;
INT : [0-9]+;
REAL : [0-9]* '.' [0-9]+;
NAME : [a-zA-Z]+;
numeric
: INT | REAL
;
reference
: NAME # variable
| NAME '[' expr ']' # array
| NAME '(' expr ')' # functionCall
;
index_expr
: numeric '..' numeric # rangeOfNumbers
| expr # classicExpr
;
expr
: expr '+' expr # exprAdd
| reference # exprRef
| numeric # exprNumber
| expr '..' expr # exprChain
;
此示例语法能够匹配您提到的所有范围表达式:1..5
或 .1...3
(如 rangeOfNumbers
)、v[1]..v[2]
或 1+f(1)..2+v[f(2)]..3+f(3)
(均为 exprChain
)。
问题是我无法在我的语法中将 range_expr
视为 unary_expr
,因为它会混淆 antlr4 与 real_literal
选项,并强制 antlr4 匹配 logic_expr
标记(即 xor
、or
,我没有在我的问题中显示它们)。在我的微修复之后,部分语法将是这样的:
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)*;