如何解决歧义

时间:2017-09-14 13:28:24

标签: antlr antlr4

我有一个语法:

grammar Test;

s      : ID OP (NUMBER | ID);

ID     : [a-z]+ ;
NUMBER : '.'? [0-9]+ ;

OP     : '/.' | '/' ;
WS     : [ \t\r\n]+ -> skip ;

x/.123之类的表达式可以解析为(s x /. 123),也可以解析为(s x / .123)。通过上面的语法,我得到了第一个变体。

有没有办法同时获得两个解析树?有没有办法控制它的解析方式?比如,如果在/.之后有一个数字,那么我会发出/,否则我会在树中发出/.

我是ANTLR的新手。

1 个答案:

答案 0 :(得分:0)

  

像x / .123这样的表达式既可以解析为(s x / .123),也可以解析为(s x / .123)

我不确定。在ReplaceAll页面(*),可能的问题段落中,据说“句点绑定到数字比强制更强”,因此/.123将始终被解释为除.123的除法运算}。接下来要说的是,为了避免这个问题,如果你想让它被理解为替代,那么必须在/.运算符和数字之间的输入中插入一个空格。

所以只有一个可能的解析树(否则Wolfram解析器如何决定如何解释该语句?)。

ANTLR4词法分析器和解析器都很贪心。这意味着词法分析器(解析器)尝试在匹配规则时读取尽可能多的输入字符(标记)。使用您的OP规则OP : '/.' | '/' ;,词法分析器将始终将输入/./.替代匹配(即使规则为OP : '/' | '/.' ;)。这意味着没有歧义,您无法将输入解释为OP = /和NUMBER = .123。

鉴于我对ANTLR的经验不足,我发现除了将ReplaceAll运算符拆分为两个标记之外没有其他解决方案。

语法问题.4:

grammar Question;

/* Parse Wolfram ReplaceAll. */

question
@init {System.out.println("Question last update 0851");}
    :   s+ EOF
    ;

s   :   division
    |   replace_all
    ;

division
    :   expr '/' NUMBER
        {System.out.println("found division " + $expr.text + " by " + $NUMBER.text);}
    ;

replace_all
    :   expr '/' '.' replacement
        {System.out.println("found ReplaceAll " + $expr.text + " with " + $replacement.text);}
    ;

expr
    :   ID
    |   '"' ID '"'
    |   NUMBER
    |   '{' expr ( ',' expr )* '}'
    ;

replacement
    :   expr '->' expr    
    |   '{' replacement ( ',' replacement )* '}'
    ;

ID     : [a-z]+ ;
NUMBER : '.'? [0-9]+ ;
WS     : [ \t\r\n]+ -> skip ;

输入文件t.text:

x/.123
x/.x -> 1
{x, y}/.{x -> 1, y -> 2}
{0, 1}/.0 -> "zero"
{0, 1}/. 0 -> "zero"

执行:

$ export CLASSPATH=".:/usr/local/lib/antlr-4.6-complete.jar"
$ alias a4='java -jar /usr/local/lib/antlr-4.6-complete.jar'
$ alias grun='java org.antlr.v4.gui.TestRig'
$ a4 Question.g4 
$ javac Q*.java
$ grun Question question -tokens -diagnostics t.text 
[@0,0:0='x',<ID>,1:0]
[@1,1:1='/',<'/'>,1:1]
[@2,2:5='.123',<NUMBER>,1:2]
[@3,7:7='x',<ID>,2:0]
[@4,8:8='/',<'/'>,2:1]
[@5,9:9='.',<'.'>,2:2]
[@6,10:10='x',<ID>,2:3]
[@7,12:13='->',<'->'>,2:5]
[@8,15:15='1',<NUMBER>,2:8]
[@9,17:17='{',<'{'>,3:0]
...
[@29,47:47='}',<'}'>,4:5]
[@30,48:48='/',<'/'>,4:6]
[@31,49:50='.0',<NUMBER>,4:7]
...
[@40,67:67='}',<'}'>,5:5]
[@41,68:68='/',<'/'>,5:6]
[@42,69:69='.',<'.'>,5:7]
[@43,71:71='0',<NUMBER>,5:9]
...
[@48,83:82='<EOF>',<EOF>,6:0]
Question last update 0851
found division x by .123
found ReplaceAll x with x->1
found ReplaceAll {x,y} with {x->1,y->2}
found division {0,1} by .0
line 4:10 extraneous input '->' expecting {<EOF>, '"', '{', ID, NUMBER}
found ReplaceAll {0,1} with 0->"zero"

输入x/.123在斜杠之前是不明确的。然后解析器有两个选择:除法规则中的/ NUMBER或replace_all规则中的/ . expr。我认为NUMBER吸收了输入,所以没有更多的模糊性。

(*)该链接是昨天发表的评论已消失,即Wolfram Language & System, ReplaceAll