在 antlr4 中解析带有可选后缀的字符串时出现意外行为
Unexpected behaviour when parsing a string with optional Suffix in antlr4
我想匹配多个函数以接受以逗号分隔的占位符列表,然后是单元的定义,它与其余参数再次以逗号分隔。要解析的文本类似于示例 1:"produkt([F1],[F2],EURO_CENT)"
或示例 2:"produkt([F1],[F2],EURO)"
我希望它能正常工作的语法是这样的:
[...]
term: [...]
| 'produkt(' placeholder ',' placeholder ',' UNIT ')' #MultUnit
[...]
| placeholder #PlaceholderTwo
;
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
LBRACK: '[';
RBRACK: ']';
PLACE: TEXT+ NUMBER?;
placeholder: LBRACK PLACE+ RBRACK;
[..]
UNIT: TEXT (('_' TEXT)*)?;
TEXT: ('a' .. 'z' | 'A' .. 'Z')+;//[a-zA-Z]+;
[...]
使用此语法示例 1 按预期工作,但示例 2 给出了错误 "line 1:18 mismatched input 'EURO' expecting UNIT"。据我了解,这意味着 "EURO" 本身与 UNIT 的模式不匹配,但 "EURO_CENT" 匹配。我不明白为什么会这样,因为 UNIT 的模式表明“_CENT”部分是可选的,只有第一部分是强制性的。
我还尝试通过将 Unit 的模式更改为 UNIT: 'Unit.' TEXT ('_' TEXT)*;
来为 UNIT 提供一些前缀(在本例中为 "Unit.")
我相应地将输入字符串更改为 "produkt([F1],[F2],Unit.EURO)"
,这非常匹配。
然而,第二种方法对用户来说不是很友好,因为我们必须在输入中添加一些(在我们看来)不必要的东西。所以问题是:当 UNIT-String 是单个单词时,为什么第一个选项与预期不匹配,是否有解决方法?
简短的回答是 PLACE
和 UNIT
对于只匹配 TEXT
的内容是相互不明确的。如果样本输入是规范的,则更改 PLACE
规则以消除歧义:
PLACE : TEXT+ NUMBER ;
其他可能性包括将 PLACE
重新定义为
PLACE : LBRACK TEXT+ NUMBER? RBRACK; // adjust other rules accordingly
向规则添加谓词:
PLACE : {followsLBRACK()}? TEXT+ NUMBER ;
并重新定义 UNIT
:
UNIT: TEXT ( 'S' | ( '_' TEXT )+ ) ; // EUROS or EURO_CENT; similar for other units.
顺便说一句,Antlr 通常自上而下地评估其语法,因此混合您的规则实际上会混淆逻辑。
我想匹配多个函数以接受以逗号分隔的占位符列表,然后是单元的定义,它与其余参数再次以逗号分隔。要解析的文本类似于示例 1:"produkt([F1],[F2],EURO_CENT)"
或示例 2:"produkt([F1],[F2],EURO)"
我希望它能正常工作的语法是这样的:
[...]
term: [...]
| 'produkt(' placeholder ',' placeholder ',' UNIT ')' #MultUnit
[...]
| placeholder #PlaceholderTwo
;
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
LBRACK: '[';
RBRACK: ']';
PLACE: TEXT+ NUMBER?;
placeholder: LBRACK PLACE+ RBRACK;
[..]
UNIT: TEXT (('_' TEXT)*)?;
TEXT: ('a' .. 'z' | 'A' .. 'Z')+;//[a-zA-Z]+;
[...]
使用此语法示例 1 按预期工作,但示例 2 给出了错误 "line 1:18 mismatched input 'EURO' expecting UNIT"。据我了解,这意味着 "EURO" 本身与 UNIT 的模式不匹配,但 "EURO_CENT" 匹配。我不明白为什么会这样,因为 UNIT 的模式表明“_CENT”部分是可选的,只有第一部分是强制性的。
我还尝试通过将 Unit 的模式更改为 UNIT: 'Unit.' TEXT ('_' TEXT)*;
来为 UNIT 提供一些前缀(在本例中为 "Unit.")
我相应地将输入字符串更改为 "produkt([F1],[F2],Unit.EURO)"
,这非常匹配。
然而,第二种方法对用户来说不是很友好,因为我们必须在输入中添加一些(在我们看来)不必要的东西。所以问题是:当 UNIT-String 是单个单词时,为什么第一个选项与预期不匹配,是否有解决方法?
简短的回答是 PLACE
和 UNIT
对于只匹配 TEXT
的内容是相互不明确的。如果样本输入是规范的,则更改 PLACE
规则以消除歧义:
PLACE : TEXT+ NUMBER ;
其他可能性包括将 PLACE
重新定义为
PLACE : LBRACK TEXT+ NUMBER? RBRACK; // adjust other rules accordingly
向规则添加谓词:
PLACE : {followsLBRACK()}? TEXT+ NUMBER ;
并重新定义 UNIT
:
UNIT: TEXT ( 'S' | ( '_' TEXT )+ ) ; // EUROS or EURO_CENT; similar for other units.
顺便说一句,Antlr 通常自上而下地评估其语法,因此混合您的规则实际上会混淆逻辑。