2010-12-08 35 views
2

我正在使用Prolog的內置DCG功能編寫一個Lisp-to-C轉換程序。這是我如何處理算術:DCG in Prolog - 字符串

expr(Z) --> "(", "+", spaces, expr(M), spaces, expr(N), ")", {swritef(Z, "%d + %d", [M, N])}. 
expr(Z) --> "(", "-", spaces, expr(M), spaces, expr(N), ")", {swritef(Z, "%d - %d", [M, N])}. 
expr(Z) --> "(", "*", spaces, expr(M), spaces, expr(N), ")", {swritef(Z, "%d * %d", [M, N])}. 
expr(Z) --> "(", "/", spaces, expr(M), spaces, expr(N), ")", {swritef(Z, "%d/%d", [M, N])}. 
expr(E) --> number(E). 

number(C) --> "-", digits(X), {C is -X}. 
number(C) --> digits(C). 
digits(D) --> digit(D);digit(A),digits(B), {number_codes(B,Cs),length(Cs,L), D is A*(10^L)+B}. 
digit(D) --> [C], {"0"=<C, C=<"9", D is C - "0"}. 

現在,它不處理嵌套的表達式。以下是我認爲會的工作:

expr(Z) --> "(", "+", spaces, expr(M), spaces, expr(N), ")", {swritef(Z, "%s + %s", [M, N])}. 
expr(E) --> number(N), {swritef(E, "%d", [N])}. 

但我發現了這一點:

?- expr(E, "42", []). 
E = "42" %all OK 

?- expr(E, "(+ 3 (* 2 2))", []). 
E = "%s + %s" %not OK 

我如何工作的呢?

+0

你使用什麼Prolog? – 2010-12-08 16:29:43

+0

@Bobby:SWI-Prolog version 5.6.64 – Igor 2010-12-12 15:44:39

回答

2

問題是%s格式說明符需要參數爲字符列表。 所以你可以像這樣做:

:-set_prolog_flag(double_quotes, codes). % This is for SWI 7+ to revert to the prior interpretation of quoted strings. 

expr(Z) --> "(", "+", spaces, lexpr(M), spaces, lexpr(N), ")", {swritef(Z, "%s + %s", [M, N])}. 
expr(Z) --> "(", "-", spaces, lexpr(M), spaces, lexpr(N), ")", {swritef(Z, "%s - %s", [M, N])}. 
expr(Z) --> "(", "*", spaces, lexpr(M), spaces, lexpr(N), ")", {swritef(Z, "%s * %s", [M, N])}. 
expr(Z) --> "(", "/", spaces, lexpr(M), spaces, lexpr(N), ")", {swritef(Z, "%s/%s", [M, N])}. 
expr(N) --> number(N). 

lexpr(Z) --> expr(M), {atom_chars(M, Z)}. 

number(C) --> "-", digits(X), {C is -X}. 
number(C) --> digits(C). 

digits(D) --> digit(D);digit(A),digits(B), {number_codes(B,Cs),length(Cs,L), D is A*(10^L)+B}. 
digit(D) --> [C], {"0"=<C, C=<"9", D is C - "0"}. 

spaces --> " ", spaces. 
spaces --> []. 

謂詞lexpr只是解析表達式轉換爲字符的列表。

編輯:03/07/2016:從SWI 7.0版開始,用雙引號括起來的文本不再被解釋爲字符代碼列表。 您可以使用後引號(`)更改雙引號或添加指令;

:-set_prolog_flag(double_quotes, codes).

在代碼的開頭。

+0

這個演示似乎與SWI-Prolog不兼容。我應該使用哪個版本的Prolog來運行它? – 2016-03-06 06:28:51

1

在您的swritef中使用%t or %w, not %d。請注意,%d與C的printf格式不同。

如果您只是將lisp-like翻譯爲C-like,則不需要將字符串 的表示形式轉換爲數字。只要把它作爲字符串。 (當然它依賴於你的任務的複雜性 )。否則,上層規則會在期望字符串的地方出現一個數字。

將生成的C代碼放入括號中,以便結果中的優先級和關聯性正確。

expr(Z) --> "(", "-", spaces, expr(M), spaces, expr(N), ")", {swritef(Z, "(%t - %t)", [M, N])}. 
expr(Z) --> "(", "*", spaces, expr(M), spaces, expr(N), ")", {swritef(Z, "(%t * %t)", [M, N])}. 
expr(Z) --> "(", "/", spaces, expr(M), spaces, expr(N), ")", {swritef(Z, "(%t/%t)", [M, N])}. 
expr(Z) --> "(", "+", spaces, expr(M), spaces, expr(N), ")", {swritef(Z, "(%t + %t)", [M, N])}. 
expr(E) --> number(N), {swritef(E, "%s", [N])}. 

spaces --> " ". 

number([C|Cs]) --> "-", {C = "-"}, digits(Cs). 
number(C) --> digits(C). 

digits([D|[]]) --> digit(D). 

digits([D|Ds]) --> digit(D), digits(Ds). 
digit(D) --> [D], {code_type(D, digit)}. 

這是它是如何工作的。

?- expr(E, "(* 1342 (/ 44 -17))", []). 
E = "(1342 * (44/-17))" ; 
false.