为模板文件定义 ANTLR 解析器的问题

Problems defining an ANTLR parser for template file

我已经开始使用 ANTLR4 为自定义模板文件格式创建语法分析器。

该格式基本上由称为“#settings”的强制性部分和至少一个称为“#region”的部分组成。零件 body 被大括号包围。

我创建了一个示例文件,还 copy-pasted-modified 一个 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
   : [ \t\n\r] + -> skip
   ;

这按预期工作。现在我想增加文件格式和解析器的复杂性,并通过#region NAME(属性)扩展#region header。 所以我在示例和 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
   : [ \t\n\r] + -> skip
   ;

现在解析器出现以下错误: 解析器错误 (7, 1): 不匹配的输入 '#region name (attributes, moreAttributes)' 期待 '#region'

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

谢谢。

这里有几个问题:

  1. 任何 NOSPACE 匹配,也被 TEXT
  2. 匹配
  3. TEXT 太贪心了

第 1 期

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

当 2 个(或更多)词法分析器规则匹配相同数量的字符时,第一个定义的规则 "wins"。

所以,如果输入是 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 匹配太多。这就是错误

Parser error (7, 1): mismatched input '#region name (attributes, moreAttributes)' expecting '#region'

告诉您:#region name (attributes, moreAttributes) 是单个 TEXT 标记,其中 #region 试图被解析器匹配。

解决方案?

删除 NOSPACE 并使 TEXT 令牌不那么贪婪(或相反)。

巴特

非常感谢您向我澄清这一点。关键词是词法分析器将匹配尽可能多的字符。这是我仍然需要习惯的行为。我重新设计了 Lexer 和 Parser 规则,它现在似乎适用于我的测试用例。

为了完整起见,现在这是我的 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
   : [ \t\n\r] + -> skip
   ;