smw*_*dia 5 compiler-construction antlr compiler-errors antlr4
我正在尝试创建一种语法以匹配如下内容:
(有关此问题的简单语法,请参见添加1)
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = WebServer
FILE_GUID = 99E87DCF-6162-40c5-9FA1-32111F5197F7
MODULE_TYPE = SEC
UEFI_SPECIFICATION_VERSION = 0x00010005
Run Code Online (Sandbox Code Playgroud)
该UEFI_SPECIFICATION_VERSION = 0x00010005部分是可选的。
(为简洁起见,我省略了一些语法)。
我的语法1看起来像这样:
defines : '[Defines]'
define_statement+
;
define_statement : 'INF_VERSION' EQ SpecVersion_VersionVal
| 'BASE_NAME' EQ BaseName
| 'FILE_GUID' EQ RegistryFormatGUID
| 'MODULE_TYPE' EQ Edk2ModuleType
| ('UEFI_SPECIFICATION_VERSION' EQ SpecVersion_VersionVal)?
;
Run Code Online (Sandbox Code Playgroud)
ANTLR 4.7报告此错误:
消息:“规则定义包含一个闭包,该闭包至少具有一个可以匹配空字符串的选项”
但是如果我这样改变语法:
defines : '[Defines]'
define_statement+
| ('UEFI_SPECIFICATION_VERSION' EQ SpecVersion_VersionVal)? // <<< HERE
;
define_statement : 'INF_VERSION' EQ SpecVersion_VersionVal
| 'BASE_NAME' EQ BaseName
| 'FILE_GUID' EQ RegistryFormatGUID
| 'MODULE_TYPE' EQ Edk2ModuleType
Run Code Online (Sandbox Code Playgroud)
错误消失了。
我的问题是什么closure意思?是哪一部分closure?的define_statement?
移动可能为空的替代项后,defines规则可以在'[Defines]' define_statement+和之间交替('UEFI_SPECIFICATION_VERSION' EQ SpecVersion_VersionVal)?,这意味着仍defines可以匹配空字符串。错误如何消失?
为了使事情更清楚,我使用简化的语法来再现此错误:
grammar test;
rule : alternate+; // <<<<< HERE
alternate : '1'?;
Run Code Online (Sandbox Code Playgroud)
如果我使用+或*在HERE,ANTLR会报告错误:
“规则包含一个至少包含一个可以匹配空字符串的替代项的闭包”
如果?在上使用HERE,ANTLR将报告警告:
“规则包含一个可选块,其中至少有一个可以匹配空字符串的可选块”
我仍然不确定为什么。
每个alternateWILL都是的子节点rule,因此如果alternate可以为空字符串,则在逻辑上有可能导致的子节点无穷rule。因此,我想这可以解释为什么ANTLR禁止我使用alternate+或这样做alternate*。但是如果使用alternate?,最多将只有一个子节点。这只是性能问题。因此,ANTLR只会生成警告。
让我们从警告开始。该应用程序只是提醒您空字符串可以匹配某些内容。这是一个警告,因为大多数时候,您不希望标记与空字符串匹配。
defines : '[Defines]'
define_statement+
;
define_statement : 'INF_VERSION' EQ SpecVersion_VersionVal
| 'BASE_NAME' EQ BaseName
| 'FILE_GUID' EQ RegistryFormatGUID
| 'MODULE_TYPE' EQ Edk2ModuleType
| ('UEFI_SPECIFICATION_VERSION' EQ SpecVersion_VersionVal)?
;
Run Code Online (Sandbox Code Playgroud)
由于 ('UEFI_SPECIFICATION_VERSION' EQ SpecVersion_VersionVal) 是可选的(它后面跟着?,所以它可以不替换,如下所示:
define_statement : 'INF_VERSION' EQ SpecVersion_VersionVal
| 'BASE_NAME' EQ BaseName
| 'FILE_GUID' EQ RegistryFormatGUID
| 'MODULE_TYPE' EQ Edk2ModuleType
|
;
Run Code Online (Sandbox Code Playgroud)
最后一个|本身意味着规则不能匹配任何内容或空字符串。这样,关于警告的谜团就解开了。他们称之为闭包,但您可以将其视为“令牌绑定”或“匹配”。我认为术语在实际意义上并不那么重要。
如果删除替代方案,错误就会消失,因为为了清楚起见,再次重写,我们有:
define_statement : 'INF_VERSION' EQ SpecVersion_VersionVal
| 'BASE_NAME' EQ BaseName
| 'FILE_GUID' EQ RegistryFormatGUID
| 'MODULE_TYPE' EQ Edk2ModuleType
;
Run Code Online (Sandbox Code Playgroud)
那里没有什么可选的。其中之一必须匹配。
您已经在评论中提到,您明白为什么将规则移动到它自己的规则(可能会匹配无限数量的空字符串)是一个坏主意,所以我不会在这里详细说明。
但为什么当你这样做时错误就消失了呢?因为
defines : '[Defines]'
define_statement+
| ('UEFI_SPECIFICATION_VERSION' EQ SpecVersion_VersionVal)? // <<< HERE
;
Run Code Online (Sandbox Code Playgroud)
保证匹配某些东西,即使它只是标记[Defines],这是一个隐式词法分析器标记。因此,即使 UEFI 是空字符串,仍然有一些东西需要解析。在我们检查的第一个版本中情况并非如此;事实上,整个define_statement规则可能是一个空字符串。从解析的角度来看,这是一个很大的区别。
现在的大问题是:该[Defines]部分真的是可选的吗?只有你能回答这个问题。但如果是的话,也许你应该将其重新编码为:
defines : ('[Defines]' define_statement+)?
define_statement : 'INF_VERSION' EQ SpecVersion_VersionVal
| 'BASE_NAME' EQ BaseName
| 'FILE_GUID' EQ RegistryFormatGUID
| 'MODULE_TYPE' EQ Edk2ModuleType
| 'UEFI_SPECIFICATION_VERSION' EQ SpecVersion_VersionVal
Run Code Online (Sandbox Code Playgroud)
这使得它完全是可选的。同样,只有您可以决定这对于您的语法和预期输入是否有效。
合理?我希望我对你有帮助!
要缓解错误,请尝试以下语法(我为测试值创建了显式标记以使其运行):
grammar Uefi;
defines : '[Defines]' statement+ ;
statement : define_statement | uefi_statement ;
uefi_statement : 'UEFI_SPECIFICATION_VERSION' EQ SpecVersion_VersionVal ;
define_statement : 'INF_VERSION' EQ SpecVersion_VersionVal
| 'BASE_NAME' EQ BaseName
| 'FILE_GUID' EQ RegistryFormatGUID
| 'MODULE_TYPE' EQ Edk2ModuleType
;
// DUMMY VALUES
SpecVersion_VersionVal : '0x00010005';
BaseName : 'WebServer';
RegistryFormatGUID : '99E87DCF-6162-40c5-9FA1-32111F5197F7';
Edk2ModuleType : 'SEC';
EQ : '=';
WS : [ \t\r\n]+ -> skip;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1220 次 |
| 最近记录: |