处理ANTLR4中的语法歧义

时间:2016-11-21 15:52:46

标签: parsing antlr4

我有一个语法应该解析下面的代码片段(例如):

vmthread programm_start
{
    CALL main
}

subcall main
{
    // Declarations
    DATAF i

    CALL i

    // Statements
    MOVEF_F 3 i
}

问题是CALL语句之间存在歧义。此操作代码在vmthread部分(仅限CALL!)中有效,但也在这些子部分中有效。如果我使用所有操作码和一个额外的OC_CALL令牌定义OP_CODES令牌,那么词法分析器就无法处理这种情况(显然)。

以下列表是我的语法片段(第一个词法分析器,第二个解析器):

VMTHREAD
    : 'vmthread'
    ;

SUBCALL
    : 'subcall'
    ;

CURLY_OPEN
    : '{'
    ;

CURLY_CLOSE
    : '}'
    ;

OP_CODES
    : 'DATA8'
    | 'DATAF'
    | 'MOVE8_8'
    | 'MOVEF_F'
    | 'CALL'
    ;

OC_CALL
    : 'CALL'
    ;

lms
    : vmthread subcalls+
    ;

vmthread
    : VMTHREAD name = ID CURLY_OPEN vmthreadCall CURLY_CLOSE
    ;

vmthreadCall
    : oc = OC_CALL name = ID
    ;

subcalls
    : SUBCALL name = ID CURLY_OPEN ins = instruction* CURLY_CLOSE
    ;

//instruction+
instruction
    : oc = OP_CODES args = argumentList
    ;

argumentList
    : arguments+
    ;

arguments
    : INTEGER
    | NUMBER
    | TEXT
    | ID
    ;

要继续工作,我已使用OP_CODES标记切换vmthreadCall解析器规则中的OC_CALL标记。这解决了现在的问题,因为代码是自动生成的。但是,用户可以输入此代码,这样可能会出错。

是否有解决方案,或者我应该将验证移到解析器中。在那里,我可以轻松确定vmthread部分中的语句是否仅包含调用语句。

澄清:在vmthread中只允许使用CALL。在子查询中(可能不止一个)允许每个操作码(CALL +定义的每个其他操作码)。我不想区分那些不同的CALL语句。我知道在上下文无关语法中是不可能的。我将在解析器中处理此问题。我只想将vmthread限制为一个CALL语句并允许子语句中的所有语句(所有操作代码)。希望这更清楚。

1 个答案:

答案 0 :(得分:1)

更改您的词法规则如下:

OP_CODES
    : 'DATA8'
    | 'DATAF'
    | 'MOVE8_8'
    | 'MOVEF_F'
    | OP_CALL
    ;

OC_CALL
    : 'CALL'
    ;

或者替代地:

OP_CODES
    : 'DATA8'
    | 'DATAF'
    | 'MOVE8_8'
    | 'MOVEF_F'
    | CALL
    ;

OC_CALL
    : CALL
    ;

fragment CALL: 'CALL';

顺便说一下,我建议您为文字创建明确的词法分析器规则(比如CALL片段),这将使以后的处理更容易。 ANTLR将通用名称分配给隐式创建的文字,这使得很难找出哪个标记属于哪个文字。