如何在ANTLR中为不明确的输入生成多个解析树



我面临着一个不明确的情况,输入字符串可以使用不同的规则进行解析,我需要考虑这两个选项,并为它们生成多个解析树。

为了简单起见,考虑到像"Alber Johanson"这样的人名,这个名字可以解析为

(fullName (firstName Alber) (lastName Johanson)) 

或解析为

(fullName (firstName Alber) (lastName Johan) (relation son)) 

首先,如何配置规则来处理第二种情况?因为它是第二个字符串的一部分,而不是一个单独的令牌。

其次,如何为输入字符串的所有可能选项生成解析树?

更新

这是我的语法示例,它只能用于解析第一种情况,而不能用于解析第二种情况

fullName: firstName lastName | firstName lastName relation;
firstName: NAME;
lastName: NAME;
relation: REL;
NAME: ('a'..'z'|'A'..'Z')+;
REL: 'son';
WHITESPACE : ('t' | ' ' | 'r' | 'n'| 'u0020' | 'u000C' )+ -> skip ;

ANTLR将不允许您按照自己想要的方式进行操作。然而,原因不是模棱两可,而是象征性的东西。

"Johanson"一词总是用NAME拼写,因为ANTLR的拼写策略是:

  • 返回匹配时间最长的Token
  • 在两个令牌匹配具有相同长度的情况下,首选第一个定义的令牌

令牌REL永远不会发生,因为

  • 任何后缀为"son"的单词都是NAME(最长匹配)
  • 任何前缀为"son"的单词都是NAME(最长匹配)
  • 然而,一个孤立的单词"son"是NAME(REL匹配但不是第一次定义的)

回答您的第一个问题:它不能由ANTLR解析器处理,因为它依赖于在解析之前进行标记化。你有两个选择:

  • 使用语法分析器生成器,允许您标记语法分析器定向(PEG语法分析器像parboiled,rats应该这样做)
  • 丢弃令牌REL,并在访问解析树时重新分析姓氏

回答第二个问题:

以上两种选择都很难解决打印同一字符序列的可能解释的问题。

PEG解析器被设计为通过设计更喜欢第一种替代方案,如果找到有效的解释,它将不会进一步探索。

ANTLR还没有被设计成驱动解析器引导的lexer。如果您决定重新分析姓氏,那么使用纯java查找解释可能比编写新的lexer/parser来查找姓氏更容易。

从一长串评论中切换:

只要你定义词素来提取整个单词,并且有一个策略来确定当识别出两个单词时哪个词素获胜,你就会遇到这个问题。

为了避免这种情况,你必须使用不竞争的词汇。您可以使用字符作为词法来运行GLR解析器;对于简短的输入(例如,人名),这不会有任何问题。然后,您可以在语法中定义您的名称规则,而不是作为词位识别器,GLR解析器将提供所有可能的解释。

不,我不知道有什么好的基于Java的GLR解析器。这里有一个大列表:http://en.wikipedia.org/wiki/Comparison_of_parser_generators

相关内容

  • 没有找到相关文章

最新更新