解析星号分隔输入的 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 : ~[*]+
匹配 aEND
而 END
仅匹配 END
(ANTLR 也不会向前看标记匹配)。因此,相当折磨的语义谓词是禁止以 END
.
结尾的字符流的标记的唯一方法。
(注意:语义谓词特定于目标语言,此谓词用于 Java。其他目标将需要该目标语言的等效 int。)
另一种方法是检查您的输入是否以 (“END”) 结尾,然后在使用此语法进行解析之前将其删除:
grammar asterisks;
parseIt: 'START' dataItem* 'END' EOF;
dataItem: Delim Data?;
Delim : '*' ;
Data : ~[*]+;
这避免了 END
令牌问题,只需将其从输入流中删除即可。鉴于它是流的最后,这可能更简单。
我正在尝试使用 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 : ~[*]+
匹配 aEND
而 END
仅匹配 END
(ANTLR 也不会向前看标记匹配)。因此,相当折磨的语义谓词是禁止以 END
.
(注意:语义谓词特定于目标语言,此谓词用于 Java。其他目标将需要该目标语言的等效 int。)
另一种方法是检查您的输入是否以 (“END”) 结尾,然后在使用此语法进行解析之前将其删除:
grammar asterisks;
parseIt: 'START' dataItem* 'END' EOF;
dataItem: Delim Data?;
Delim : '*' ;
Data : ~[*]+;
这避免了 END
令牌问题,只需将其从输入流中删除即可。鉴于它是流的最后,这可能更简单。