如何使用类似的词法分析器

时间:2013-02-03 05:51:20

标签: antlr

我有以下语法:

cmds
    : cmd+
    ;

cmd
    : include_cmd  |  other_cmd
    ;

include_cmd
    : INCLUDE  DOUBLE_QUOTE  FILE_NAME  DOUBLE_QUOTE
    ;

other_cmd
    : CMD_NAME  ARG+
    ;


INCLUDE
    : '#include'
    ;

DOUBLE_QUOTE
    : '"'
    ;

CMD_NAME
    : ('a'..'z')*
    ;

ARG
    : ('a'..'z' | 'A'..'Z' | '0'..'9' | '_')+
    ;

FILE_NAME
    : ('a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '.')+
    ;

因此,CMD_NAME,ARG和FILE_NAME之间的区别不大,CMD_NAME必须是小写字母,ARG可以是大写字母,“_”和FILE_NAME可以有“。”。

但这有一个问题,当我用 - #include“abc”测试规则时,'abc'被解释为CMD_NAME而不是FILE_NAME,我认为这是因为CMD_NAME在语法文件中位于FILE_NAME之前,这导致解析错误。

我是否必须依靠预测来处理这种技术?除了依赖主机编程语言之外,还有纯粹的EBNF解决方案吗?

感谢。

1 个答案:

答案 0 :(得分:1)

  

但这有一个问题,当我用 - #include“abc”测试规则时,'abc'被解释为CMD_NAME而不是FILE_NAME,我认为这是因为CMD_NAME在语法文件中位于FILE_NAME之前,这导致解析错误。

所有有效CMD_NAME的集合与所有有效FILE_NAME的集合相交。输入abc符合两者的条件。词法分析器将输入与列出的第一个规则(如您所怀疑的)匹配,因为它是第一个匹配的规则。

  

我是否必须依靠[谓词]等技术来处理这个问题?除了依赖主机编程语言之外,还有纯粹的EBNF解决方案吗?

这取决于你在语法中愿意接受的内容。考虑将include_cmd规则更改为更常规的规则,例如:

include_cmd : INCLUDE STRING;

STRING 
    : '"' ~('"'|'\r'|'\n')* '"' {String text = getText(); setText(text.substring(1, text.length() - 1));}
    ;

现在输入#include "abc"变成了令牌[INCLUDE : #include] [STRING : abc]

我认为语法不应该负责确定文件名是否有效:有效的文件名称并不意味着有效的文件,并且语法必须理解可能与语法本身无关的OS文件命名约定(有效字符,路径等)。我认为如果你愿意放弃FILE_NAME规则来处理上述规则,你会没事的。

另外值得注意的是,您的CMD_NAME规则与零长度输入相匹配。考虑将('a'..'z')*更改为('a'..'z')+,除非CMD_NAME确实为空。


请注意,ARG使用FILE_NAME时会遇到与CMD_NAME相同的问题。它列在abc之后,因此任何符合这两项规则的输入(例如CMD_NAME)都会点击other_cmd : ID (ID | NUMBER)+ SEMI; //instead of CMD_NAME ARG+ ID : ('a'..'z'|'A'..'Z'|'_')+; //instead of CMD_NAME, "id" part of ARG NUMBER : ('0'..'9')+; //"number" part of ARG SEMI : ';'; 。考虑将这些规则分解为更常规的规则,如下:

SEMI

我添加了规则a b c d来标记命令的结束。否则,解析器将不知道输入a(b,c,d)是否应该是具有三个参数(a(b), c(d))的一个命令,或者两个命令是否具有一个参数({{1}})。