2017-09-14 81 views
0

我有一个语法:如何解决歧义

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的新手。

+0

什么是'两个变种op'应该代表,语义? – TomServo

回答

0

如x/0.123的表达式可以被解析为(S X/123),或作为(S X/0.123)

我不知道。在ReplaceAll页面(*)可能出现的问题段落中,表示“句点与数字的结合强于斜线”,因此/.123将始终被解释为除数.123的除法操作。接下来据说为了避免这个问题,如果你想把它理解为替代品,那么必须在/.运营商和号码之间的输入中插入一个空格。

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

ANTLR4词法分析器和解析器很贪婪。这意味着词法分析器(解析器)尝试读取尽可能多的输入字符(标记),以便在匹配规则时进行。根据您的OP规则OP : '/.' | '/' ;,词法分析器将始终将输入/./.替代(即使规则为OP : '/' | '/.' ;)相匹配。这意味着没有歧义,你没有机会将输入解释为OP = /和NUMBER = .123。由于我在ANTLR方面经验不足,除了将ReplaceAll运算符分成两个令牌之外,我没有找到任何其他解决方案。

语法Question.g4:

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