如何在ANTLR中为模糊输入生成多个解析树

时间:2015-04-12 22:00:01

标签: java parsing antlr antlr4

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

为简单起见,考虑像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 ;

2 个答案:

答案 0 :(得分:2)

ANTLR不允许您按照自己的方式进行操作。然而,原因不是模糊,而是标记化。

由于ANTLR lexing政策,“Johanson”一词总是被称为NAME:

  • 使用最长匹配返回令牌
  • 如果两个令牌匹配具有相同的长度,则优先选择第一个定义的

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

  • 任何带后缀'son'的单词都是NAME(最长匹配)
  • 前缀为'son'的任何单词都是NAME(最长匹配)
  • 但是一个孤立的单词'son'是NAMEREL匹配,但未首先定义)

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

  • 使用解析器生成器,允许你对解析器进行标记(PEG-Parsers就像预先设定,老鼠应该这样做)
  • 丢弃令牌REL,并在访问解析树时重新分析姓氏

回答您的第二个问题:

上述两种替代方案都难以解决打印相同char序列的可能解释的问题。

PEG-Parsers旨在通过设计选择第一种替代方案,如果找到有效的解释,则不会进一步探索。

ANTLR尚未设计用于驱动解析器指示的词法分析器。如果您决定重新分析姓氏,那么使用纯java找到解释可能比编写新的词法分析器/解析器更容易找到它们。

答案 1 :(得分:2)

从长篇评论中切换:

只要你定义lexemes来获取整个单词,并且有一个关于当两个被识别时lexeme获胜的策略,你就会遇到这个问题。

要避免它,你必须有不竞争的词汇。你可以做的是运行一个带有字符的GLR解析器作为lexemes;对于短输入(例如,人名),这不会是任何类型的问题。然后,您可以在语法中定义您的名称规则,而不是作为词法识别器,GLR解析器将提供所有可能的解释。

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