优先匹配 ANTLR4 中较短的标记
Preferentially match shorter token in ANTLR4
我目前正在尝试使用 ANTLR4 编写 UCUM 解析器。我当前的方法涉及将每个有效单元和前缀定义为标记。
这是已定义标记的一小部分。我可以制作一个简化版的语法作为示例,但似乎没有必要解决这个问题(或者指出我正在以完全错误的方式解决这个问题)。
MILLI_OR_METRE: 'm' ;
OSMOLE: 'osm' ;
MONTH: 'mo' ;
SECOND: 's' ;
标准测试用例之一是 mosm
,词法分析器应从中生成令牌流 MILLI_OR_METRE OSMOLE
。不幸的是,因为 ANTLR 优先匹配较长的标记,它生成标记流 MONTH SECOND MILLI_OR_METRE
,然后导致解析器引发错误。
是否可以让 ANTLR4 词法分析器首先尝试使用较短的标记进行匹配?将先行类型规则添加到 MONTH
并不是一个很好的解决方案,因为我需要考虑各种潜在的词法冲突(例如 mol
被词法分析为 MONTH LITRE
而不是 MOLE
等等)。
编辑:
下面的StefanA当然是对的;这是一个能够回溯的解析器的工作(例如递归下降,packrat,PEG 和可能的其他各种...... Coco/R 是一个合理的包来做到这一点)。为了避免添加对另一个解析器生成器的依赖(或将项目的其他部分从 ANTLR 移动到这个新生成器),我已经解决了这个问题:
MONTH: 'mo' { _input.La(1) != 's' && _input.La(1) != 'l' && _input.La(1) != '_' }? ;
// (note: this is a C# project; java would use _input.LA instead)
但这并不是一个真正可扩展或可维护的解决方案,并且可能会引入其他我尚未遇到的微妙问题。
您的问题不要求优先使用较小的标记(在这种情况下,永远不会匹配 MONTH)。您需要依赖于匹配与否的文本的回溯行为。对吗?
ANTLR 将标记化和解析严格分开。因此,您的问题的每一个解决方案看起来都像是 hack。
然而,其他解析器生成器专门处理像您这样的问题。 Packrat 解析器 (PEG) 正在回溯并允许动态标记化。为此目的尝试 parboiled。
问题的框架似乎不正确。
I'm currently attempting to write a UCUM parser using ANTLR4. My current approach has involved defining every valid unit and prefix as a token.
但是,根据 UCUM:
The expression syntax of The Unified Code for Units of Measure generates an infinite number of codes with the consequence that it is impossible to compile a table of all valid units.
词法分析器最值得期待的是在不考虑其语义值的情况下明确识别测量字符串。类似地,单独的解析器将无法在 MONTH LITRE
和 MOLE
等单元序列之间有效地 select - 两者都可以合理地应用于泄漏率 - 除非问题 space 是静态的受解析器定义约束。
很可能需要启发式、结构化(明确识别问题 space)或上下文(考虑问题中其他单元的相对性质 space)select正确的单位解释。
最好的工具是让您处于最佳位置以实施消除单位字符串歧义所需的启发式方法的工具。 Antlr 可以 使用解析树遍历器来完成。这是否是合适的方法需要进一步分析。
我目前正在尝试使用 ANTLR4 编写 UCUM 解析器。我当前的方法涉及将每个有效单元和前缀定义为标记。
这是已定义标记的一小部分。我可以制作一个简化版的语法作为示例,但似乎没有必要解决这个问题(或者指出我正在以完全错误的方式解决这个问题)。
MILLI_OR_METRE: 'm' ;
OSMOLE: 'osm' ;
MONTH: 'mo' ;
SECOND: 's' ;
标准测试用例之一是 mosm
,词法分析器应从中生成令牌流 MILLI_OR_METRE OSMOLE
。不幸的是,因为 ANTLR 优先匹配较长的标记,它生成标记流 MONTH SECOND MILLI_OR_METRE
,然后导致解析器引发错误。
是否可以让 ANTLR4 词法分析器首先尝试使用较短的标记进行匹配?将先行类型规则添加到 MONTH
并不是一个很好的解决方案,因为我需要考虑各种潜在的词法冲突(例如 mol
被词法分析为 MONTH LITRE
而不是 MOLE
等等)。
编辑:
下面的StefanA当然是对的;这是一个能够回溯的解析器的工作(例如递归下降,packrat,PEG 和可能的其他各种...... Coco/R 是一个合理的包来做到这一点)。为了避免添加对另一个解析器生成器的依赖(或将项目的其他部分从 ANTLR 移动到这个新生成器),我已经解决了这个问题:
MONTH: 'mo' { _input.La(1) != 's' && _input.La(1) != 'l' && _input.La(1) != '_' }? ;
// (note: this is a C# project; java would use _input.LA instead)
但这并不是一个真正可扩展或可维护的解决方案,并且可能会引入其他我尚未遇到的微妙问题。
您的问题不要求优先使用较小的标记(在这种情况下,永远不会匹配 MONTH)。您需要依赖于匹配与否的文本的回溯行为。对吗?
ANTLR 将标记化和解析严格分开。因此,您的问题的每一个解决方案看起来都像是 hack。
然而,其他解析器生成器专门处理像您这样的问题。 Packrat 解析器 (PEG) 正在回溯并允许动态标记化。为此目的尝试 parboiled。
问题的框架似乎不正确。
I'm currently attempting to write a UCUM parser using ANTLR4. My current approach has involved defining every valid unit and prefix as a token.
但是,根据 UCUM:
The expression syntax of The Unified Code for Units of Measure generates an infinite number of codes with the consequence that it is impossible to compile a table of all valid units.
词法分析器最值得期待的是在不考虑其语义值的情况下明确识别测量字符串。类似地,单独的解析器将无法在 MONTH LITRE
和 MOLE
等单元序列之间有效地 select - 两者都可以合理地应用于泄漏率 - 除非问题 space 是静态的受解析器定义约束。
很可能需要启发式、结构化(明确识别问题 space)或上下文(考虑问题中其他单元的相对性质 space)select正确的单位解释。
最好的工具是让您处于最佳位置以实施消除单位字符串歧义所需的启发式方法的工具。 Antlr 可以 使用解析树遍历器来完成。这是否是合适的方法需要进一步分析。