为模板文件定义 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'
而且我不明白为什么它会这样。我希望解析器在比较时不会连接整行。我做错了什么?
谢谢。
这里有几个问题:
- 任何
NOSPACE
匹配,也被 TEXT
匹配
TEXT
太贪心了
第 1 期
ANTLR 的词法分析器独立于解析器工作,词法分析器将匹配尽可能多的字符。
当 2 个(或更多)词法分析器规则匹配相同数量的字符时,第一个定义的规则 "wins"。
所以,如果输入是 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
匹配太多。这就是错误
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
;
我已经开始使用 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'
而且我不明白为什么它会这样。我希望解析器在比较时不会连接整行。我做错了什么?
谢谢。
这里有几个问题:
- 任何
NOSPACE
匹配,也被TEXT
匹配
TEXT
太贪心了
第 1 期
ANTLR 的词法分析器独立于解析器工作,词法分析器将匹配尽可能多的字符。
当 2 个(或更多)词法分析器规则匹配相同数量的字符时,第一个定义的规则 "wins"。
所以,如果输入是 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
匹配太多。这就是错误
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
;