为模板文件定义 ANTLR 解析器时出现问题



我已经开始使用 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">

我不明白为什么它会这样。我希望解析器在比较时不会连接整行。我做错了什么?

谢谢。

这里有几个问题:

  1. 无论NOSPACE匹配,也匹配TEXT
  2. TEXT是不是太贪婪了

问题 1

ANTLR的词法分析器独立于解析器工作,词法分析器将匹配尽可能多的字符。

当 2 个(或更多(词法分析器规则匹配相同数量的字符时,首先定义的规则"获胜"。

因此,如果输入是Foo而解析器是。 尝试匹配NOSPACE标记,您就不走运了:因为TEXTNOSPACE都匹配文本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
;

相关内容

  • 没有找到相关文章

最新更新