2010-12-08 3 views
2

Я пишу переводчик Lisp-to-C, используя встроенные возможности DCG от Prolog. Вот как я обрабатываю арифметику: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

Какой пролог вы используете? – 2010-12-08 16:29:43

+0

@Bobby: версия SWI-Prolog 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

Используйте %t or %w, not %d в своем swritef. Обратите внимание, что% d не то, что есть в форматах printf C.

Если вы просто переводите 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. 
Смежные вопросы