我在ANTLRWorks 1.4中有以下语法。我正在讨论在文本冒险游戏创建者中实现解析器的想法,用户将为其游戏指定各种允许的命令。
grammar test;
parse : cmd EOF;
cmd : putSyn1 gameObject inSyn1 gameObject;
putSyn1 : Put | Place | Drop ;
inSyn1 : In | Into | Within;
gameObject : det obj;
det : The | A | An | ;
obj : Word obj | Word;
Space : (' ' | '\t' | '\r' | '\n'){$channel=HIDDEN;};
Put : 'put';
Place : 'place';
Drop : 'drop';
In : 'in';
Into : 'into';
Within : 'within';
The : 'the';
A : 'a';
An : 'an';
Word : ('a'..'z' | 'A'..'Z')+;
我只是感受到所涉及的各种微妙之处(就像我做过here)。
这一次,使用ANTLR,我想知道我是否可以解析输入,如:
put wood in fire place
也就是说,“木头”和“火场”是上面的游戏对象。但是,“地方”也是“put”的同义词。所以这同样有效:
place wood in fire place
在尝试解析最后一个“place”标记时,ANTLR给了我一个NoViableAltException。我想将“火场”识别为游戏对象。
在ANTLR中这种事情可能吗?语法是否可能?
另一方面,我正在开发一个手动实现,它使用奇怪的自定义数据结构,包括NFA,Dictionary和whatnot。但我仍然需要更多的时间,必须牺牲一些脑细胞来设计所需的搜索和插入算法。
但是如果在ANTLR中这是可能的,我可以使用生成的C#文件,是吗?
答案 0 :(得分:4)
不确定。 PL / 1因没有任何保留字而闻名,例如,您可以在任何不需要作为关键字的地方使用关键字(例如 IF )作为变量名称:
IF IF = 1 THEN ELSE=3; ELSE END=4;
构建执行此操作的解析器更难。你不能在词法分析器中“简单地”这样做,因为它不知道标识符可能是关键字的上下文。
有几种方法可以解决。找到像实体这样的标识符时:
1)让词法分析器询问解析器,“你现在想要一个关键词吗?”。在这种情况下,生成一个关键字。让解析器在这里合作可能很难。它也可能是解析器不知道,因为它必须看到更多输入来决定。考虑一下Fortran着名的格式声明:
FORMAT ( A1, I2, ... ) X
如果您是关键字或标识符,则无法确定何时看到“FORMAT”字样;你必须任意向前扫描以检查X.如果X不是语句的结尾,则FORMAT字是数组标识符的名称;如果X是end-of-statment,则为FORMAT关键字和语句。
2)发出一个关键字(如果标识符匹配一个)和标识符,并使解析器同时尝试。大多数解析器都不能很好地处理这个问题,但如果合理设计,GLR parsers可以解决这个问题。这通过推入解析器的前瞻功能来轻松处理FORMAT问题。 (ANTLR不是GLR。我们的DMS Software Reengineering Toolkit具有这样的GLR解析器,我们经常使用这个技巧。)
3)将所有类似标识符的东西放入哈希表中。使用递归下降解析器(ANTLR是一个);当该解析器想要一个关键字时,它只是检查它获得的标识符,以验证它是否是它需要的关键字。如果它不想要关键字,它只是使用标识符作为标识符。我不知道如何用ANTLR实现这个技巧,因为我不使用它。这不会处理“不能毫无前瞻”的情况。
答案 1 :(得分:1)
我用词法分析器而不是解析器来处理这样的事情 - 让词法分析器执行“最大限度的咀嚼”,因此它将“火场”识别为单个令牌,并且仅将“地点”识别为单独的令牌,如果它没有立即前面的“火”。
通过这种方式,解析器不必注意到输入中的相同字符序列碰巧形成了两个完全独立的标记的全部或部分。