有没有办法在不使用谓词的情况下解决这种歧义?

时间:2016-08-05 17:29:10

标签: antlr4

语法:

grammar Test;

file: (procDef | statement)* EOF;

procDef: 'procedure' ID NL statement+ ;

statement: 'statement'? NL;

WS: (' ' | '\t') -> skip;

NL: ('\r\n' | '\r' | '\n');

ID: [a-zA-Z0-9]+;

测试数据:

statement

procedure Proc1
    statement
    statement

解析器执行我想要的操作(即语句+贪婪),但它报告了歧义,因为它不知道最后一个语句是属于procDef还是文件(据我理解)。 由于谓词是语言依赖的,我不想使用谓词。 当一个不属于它的语句(例如“程序”)发生时,该程序应该结束。 我也希望将语句绑定到过程以避免以后重新排列结构。

修改

似乎我应该稍微扩展我的测试数据(但是我会留下原件,因为它很小并显示我想要解决的模糊性)。 我希望能够处理这样的情况:

statement

procedure Proc1
    statement
    statement

procedure Proc2
    statement
    statement

procedure Proc2a
    statement
    statement

global
statement

procedure Proc3
    statement
    statement

(缩进重要。)我可以在没有类似

之类的谓词的情况下做到这一点。
file: (
        commonStatement
        | globalStatement
    )* EOF;

procDef: 'procedure' ID NL commonStatement+ ;

commonStatement: 'statement'? NL;

globalStatement: 'global' NL | procDef (globalStatement | EOF);

但是随着每个连续的procDef,树变得更深,这感觉非常不合需要。 那么带谓词的解决方案实际上更可取。

@parser::members { boolean inProc; }

file: (
        {!inProc}? commonStatement
        | globalStatement
    )* EOF;

procDef: 'procedure' ID {inProc = true;} NL commonStatement+ ;

commonStatement: 'statement'? NL;

globalStatement: ('global' NL {inProc = false;} | procDef) ;

情况实际上比这更糟糕,因为全局可访问的commonStatements可以在没有干预的globalStatement(可通过gotos访问)的情况下发生,但是解析器无法区分它和属于该过程的语句,所以我的计划是只是不鼓励这样的使用(我不认为它很常见)。事实上,将转换为程序代码也是完全合法的...... 可能结果是,最后我将不得不检查运行时路径(范围在运行时非常确定),并且语法可能最终会像

file: (
        commonStatement
        | globalStatement
        | procDef 
    )* EOF;

procDef: 'procedure' ID NL procStatement*;

commonStatement: 'statement'? NL;

procStatement: 'proc' NL;

globalStatement: 'global' NL;

我们会看到......

1 个答案:

答案 0 :(得分:0)

根据您的标准,声明不可能遵循procDef。你完全有权使用这种方式设计一种语言,但我希望你能为常见问题解答做好准备“如何编写一个在程序定义之后的语句。”

编写语法很容易:

file: statement* procDef* EOF;