2017-09-14 85 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