2010-12-08 11 views
2

저는 Prolog의 내장 DCG 기능을 사용하여 Lisp-C 변환기를 작성하고 있습니다. 이것은 산수를 처리하는 방법입니다.프롤로그의 DCG - 문자열

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

어떤 프롤로그를 사용합니까? –

+0

@Bobby : SWI-Prolog 버전 5.6.64 – Igor

답변

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 버전을 사용해야합니까? –

+0

@AndersonGreen : 버전 7부터 SWI에서 큰 따옴표 사이의 텍스트는 기본적으로 문자 코드 목록으로 해석되지 않습니다. 코드를 작동시키기 위해 어떤 프롤로그 플래그를 켜야하는지 보여주는 대답을 편집했습니다. 대안 따옴표 (')를 사용하여 큰 따옴표를 바꿀 수 있습니다. – gusbro

1

swritef%t or %w, not %d을 사용하십시오. 참고로 % d은 C의 printf 형식과 다릅니다.

lisp-like를 C와 비슷한 것으로 번역하면 문자열을 숫자로 변환 할 필요가 없습니다. 그냥 문자열로 남겨주세요. (물론 작업의 복잡도에 따라 이 의존합니다.) 그렇지 않으면 상위 레벨 규칙은 문자열을 기대하는 숫자를 찾습니다.

결과에서 우선 순위와 결합이 정확하도록 결과로 생성 된 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. 
+0

SWI-Prolog에서이 데모를 실행했지만'E = "(% t * % t)"만 인쇄했습니다 .' 어떤 버전의 Prolog를 사용해야합니까? 이 예제? –