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
(as
rangeOfNumbers
)、
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)*;