我已经开始使用 ANTLR4 为自定义模板文件格式创建语法解析器。
该格式基本上由称为"#settings"的强制性部分和至少一个名为"#region"的部分组成。零件主体被牙套包围。
我创建了一个示例文件,并且还复制粘贴修改了一个antlr g4文件来解析它。到目前为止工作正常:
文件:
#settings
{
setting1: value1
setting2: value2
}
#region
{
[Key1]=Value1(Comment1)
[Key2]=Value2(Comment2)
}
此示例的 G4 文件:
grammar Template;
start
: section EOF
;
section
: settings regions
;
settings
: '#settings' '{' (settingsText)* '}'
;
settingsText
: TEXT
;
regions
: (region)+
;
region
: '#region' '{' (regionText)* '}'
;
regionName
: NOSPACE
;
regionText
: TEXT
;
TEXT
: (~[u0000-u001F])+
;
NOSPACE
: (~[u0000-u0020])+
;
WS
: [ tnr] + -> skip
;
这按预期工作。现在我想增加文件格式和解析器的复杂性,并通过 #region NAME(属性(扩展 #region 标头。 所以我在示例和 G4 文件中更改的是:
示例更改为
...
#region name (attributes, moreAttributes)
{
...
和 G4 文件修改为
grammar Template;
start
: section EOF
;
section
: settings regions
;
settings
: '#settings' '{' (settingsText)* '}'
;
settingsText
: TEXT
;
regions
: (region)+
;
region
: '#region' regionName (regionAttributes)? '{' (regionText)* '}'
;
regionName
: NOSPACE
;
regionAttributes
: '(' regionAttribute (',' regionAttribute)* ')'
;
regionAttribute
: NOSPACE
;
regionText
: TEXT
;
TEXT
: (~[u0000-u001F])+
;
NOSPACE
: (~[u0000-u0020])+
;
WS
: [ tnr] + -> skip
;
现在解析器显示以下错误:解析器错误 (7, 1(:输入不匹配"#region 名称(属性,更多属性(",预期"#region">
我不明白为什么它会这样。我希望解析器在比较时不会连接整行。我做错了什么?
谢谢。
这里有几个问题:
- 无论
NOSPACE
匹配,也匹配TEXT
TEXT
是不是太贪婪了
问题 1
ANTLR的词法分析器独立于解析器工作,词法分析器将匹配尽可能多的字符。
当 2 个(或更多(词法分析器规则匹配相同数量的字符时,首先定义的规则"获胜"。
因此,如果输入是Foo
而解析器是。 尝试匹配NOSPACE
标记,您就不走运了:因为TEXT
和NOSPACE
都匹配文本Foo
并且首先定义TEXT
,因此词法分析器将生成TEXT
标记。对此你无能为力:这是ANTLR的工作方式。
问题 2
如问题 1 中所述,词法分析器尝试匹配尽可能多的字符。正因为如此,你的TEXT
规则太贪婪了。这就是您的输入被标记为的内容:
'{' `{`
TEXT `setting1: value1`
TEXT `setting2: value2`
'}' `}`
TEXT `#region name (attributes, moreAttributes)`
'{' `{`
TEXT `[Key1]=Value1(Comment1)`
TEXT `[Key2]=Value2(Comment2)`
'}' `}`
如您所见,TEXT
匹配太多。这就是错误所在
解析器错误 (7, 1(:输入不匹配"#region 名称(属性,更多属性(",预期"#region">
告诉您:#region name (attributes, moreAttributes)
是一个单一的TEXT
令牌,其中#region
正在尝试与解析器匹配。
溶液?
删除NOSPACE
并使TEXT
令牌不那么贪婪(或相反(。
巴特,
非常感谢您向我澄清这一点。关键短语是词法分析器将匹配尽可能多的字符。这是我仍然需要习惯的行为。我重新设计了我的词法分析和解析器规则,它现在似乎适用于我的测试用例。
为了完整起见,这是我现在的 g4 文件:
grammar Template;
start
: section EOF
;
section
: settings regions
;
settings
: '#settings' '{' (settingsText)* '}'
;
regions
: (region)+
;
region
: '#region' regionName (regionAttributes)? '{' (regionText)* '}'
;
regionName
: TEXT
;
settingsText
: TEXT
;
regionAttributes
: '(' regionAttribute (',' regionAttribute)* ')'
;
regionAttribute
: TEXT
;
regionText
: regionLine '('? (regionComment?) ')'?
;
regionLine
: TEXT
;
regionComment
: TEXT
;
TEXT
: ([A-z0-9:-|= ])+
;
WS
: [ tnr] + -> skip
;