使用ANTLR3将换行符,EOF解析为语句结尾标记

chr*_*nhy 4 antlr antlrworks antlr3

我的问题是关于在ANTLRWorks中运行以下语法:

INT :('0'..'9')+;
SEMICOLON: ';';
NEWLINE: ('\r\n'|'\n'|'\r');
STMTEND: (SEMICOLON (NEWLINE)*|NEWLINE+);

statement
    : STMTEND
    | INT STMTEND
    ;

program: statement+;
Run Code Online (Sandbox Code Playgroud)

无论选择哪个换行NL(CR / LF / CRLF)或整数,我都可以通过以下输入(以程序作为开始规则)获得以下结果:

“; NL ”或“ 32; NL ”解析没有错误。“;” 或“ 45;” (不包含换行符)将导致EarlyExitException。“ NL ”本身解析没有错误。不带分号的“ 456 NL ”会导致MismatchedTokenException。

我想要的是一个语句以换行符,分号或分号后接换行符来终止,并且我希望解析器在终止符上尽可能多地吃掉连续的换行符,因此“; NL NL NL NL ”只是一个终端,而不是四个或五个。另外,我希望文件结尾的情况也可以是有效的终止,但是我还不知道该怎么做。

那么,这有什么问题,如何使它在EOF终止呢?我对解析,ANTLR和EBNF完全陌生,并且在简单的计算器示例和参考之间的某个水平上,我没有发现太多要阅读的资料(我有The Definitive ANTLR Reference,但它确实一个参考,前面有一个快速入门,我还没有在ANTLRWorks之外运行过,所以任何阅读建议(除了Wirth的1977 ACM论文)也将有所帮助。谢谢!

Bar*_*ers 5

在输入如";"或的情况下,将永远不会创建"45;"令牌STMTEND

";"将创建一个令牌:SEMICOLON"45;"并将产生:INT SEMICOLON

你(可能)想要的是SEMICOLONNEWLINE永远不会进入真正的标记本身,但他们将永远是一个STMTEND。您可以通过使它们成为所谓的“碎片”规则来做到这一点:

program: statement+;

statement
 : STMTEND
 | INT STMTEND
 ;

INT     : '0'..'9'+;
STMTEND : SEMICOLON NEWLINE* | NEWLINE+;

fragment SEMICOLON : ';';
fragment NEWLINE   : '\r' '\n' | '\n' | '\r';
Run Code Online (Sandbox Code Playgroud)

片段规则仅可用于其他词法分析器规则,因此它们永远不会以解析器(生产)规则结尾。要强调的是:上面的语法只会创建INTSTMTEND标记。