解析星号分隔输入的 ANTLR 语法

ANTLR Grammar to parse a Asterisk-delimited input

我正在尝试使用 ANTLR (v4) 为由 START 和 END 标记封装的星号分隔列表创建解析器生成器。

START**na**na**aa*aa*a*asdfaaa*aaDDFdasa*aaaffdda*aa*aassda*ataaaaaaaaa*a*a*aEND

普通输入字符串应该是这样的:

START*na*na*aa*aa*a*asdfaaa*aaDDFdasa*aaaffdda*aa*aassda*ataaaaaaaaa*a*a*aEND

我仍然需要能够允许空格、制表符、null/empty 字段(基本上是星号之间除 START, END, * 之外的任何字符。

包括 ** * * *asdf fdsa* * asdf *

到目前为止,这是我的语法:

parseIt: ENTRY ;

ENTRY : 'START*' FIELD_SET 'END' ;

fragment Delim : '*' ;

fragment Data : (ANY | WS)* ;

fragment FIELD_SET : Data (Delim Data|Delim)* ;

我可以识别简单的输入(就像我给出的第一个例子),但我无法识别星号之间有空格或特殊字符的标记。

我很确定你可以使用 RegEx 和捕获组来处理这个问题,但是如果你真的想使用 ANTLR…

以下作品:

grammar asterisks;

parseIt: 'START' dataItem* 'END' EOF;

dataItem: Delim Data?;

Delim : '*' ;

Data : ~[*]+ {!(
       (getText().endsWith("E") && _input.LA(1) == (int) 'N' && _input.LA(2) == (int) 'D') || 
       (getText().endsWith("EN") && _input.LA(1) == (int) 'D') || 
       (getText().endsWith("END")))}?;

并给出以下解析树(供您首次输入)(点击查看全尺寸):

不幸的是,词法分析器的工作方式,像 Data : ~[*]+ 这样的简单词法分析器规则将优先匹配 aEND 而不是你的 END 隐含词法分析器规则,因为 ANTLR 词法分析器使用匹配最长序列离子输入字符的规则,并且 Data : ~[*]+ 匹配 aENDEND 仅匹配 END (ANTLR 也不会向前看标记匹配)。因此,相当折磨的语义谓词是禁止以 END.

结尾的字符流的标记的唯一方法。

(注意:语义谓词特定于目标语言,此谓词用于 Java。其他目标将需要该目标语言的等效 int。)

另一种方法是检查您的输入是否以 (“END”) 结尾,然后在使用此语法进行解析之前将其删除:

grammar asterisks;

parseIt: 'START' dataItem* 'END' EOF;

dataItem: Delim Data?;

Delim : '*' ;

Data : ~[*]+;

这避免了 END 令牌问题,只需将其从输入流中删除即可。鉴于它是流的最后,这可能更简单。