2011-01-16 15 views
6

Piszę tłumacz Lisp to C i mam problem z obsługą napisów. Jest to kod, który przekształca jednoargumentowy funkcji Lisp do równowartości C:Sprawdzanie listy napisów w Prologu

define(F) --> fun_unary(F), !. 

fun_unary(F) --> "(define (", label(Fun), spaces, label(Arg1), ")", spaces, expr(Body), ")", 
    {swritef(F, "data *%t(data *%t) { return(%t); }", [Fun, Arg1, Body])}, !. 


funs([F]) --> define(F), !. 
funs([F|Fs]) --> define(F), spaces, funs(Fs), !. 

Teraz chcę przeczytać dowolną liczbę funkcji i zwraca je w postaci pojedynczego łańcucha. Powyższy funs jest najlepszym mogę wymyślić, ale to działa tak:

?- funs(F, "(define (carzero l) (= (car l) 0)) (define (zero n) (= 0 n))", []). 
F = ["data *carzero(data *l) { return(eq(car(l), make_atom_int(0))); }", "data *zero(data *n) { return(eq(make_atom_int(0), n)); }"]. 

Gdy chcę coś takiego:

F = "data *carzero(data *l) { return(eq(car(l), make_atom_int(0))); }\n\ndata *zero(data *n) { return(eq(make_atom_int(0), n)); }". 

tak, że można ładnie swritef jest do kompletnego programu , pomiędzy #include s i main(). Alternatywnym rozwiązaniem jest zmodyfikowanie translatora najwyższego poziomu do obsługi listy. Obecnie wygląda to tak:

program(P) --> define(F), {swritef(P, "#include \"lisp2c.h\" \n\n%t \nint main() { return 0; }", [F])}, !. 

Jak mógłbym wykonać którekolwiek z tych dwóch? Używam SWI Prolog.

+0

Przedmiotem wymienia Prolog, a ciało pytanie dotyczy tłumaczenia "Lisp to C". Pomóż mi uporządkować to, co jest tutaj. Fragmenty kodu wyglądają trochę jak Prolog, być może dlatego, że specjalna składnia DCG jest pomieszana z bardziej podstawową składnią reguł Prologu. Podczas gdy wiersz tematu pyta o "listę ciągów w Prologu", wydaje się, że analizowane są ciągi zawierające kod Lisp. Konkatenacja listy łańcuchów jest stosunkowo prostym zadaniem w Prologu. Twój przykładowy predykat ** funs/2 ** sugeruje, że chcesz rzucić kilka znaków nowej linii między ... – hardmath

+0

... kolejne ciągi są łączone. Jeśli to jest zakres pytania, mogę na nie odpowiedzieć i możemy rozwiązać problem składni składni (w razie potrzeby). – hardmath

+0

Lisp to C tłumaczenie jest tym, co robi program. Program napisany jest w Prologu, przy użyciu składni DCG do tłumaczenia pojedynczych przypadków. Większość z predykowanych parse kodu Lisp, z ich argumentem będącym wynikowym kodem C. Chcę dwa nowe linie między połączonymi łańcuchami. Mam nadzieję, że to wszystko. – Igor

Odpowiedz

4

Pomijając na razie celów, dla których jest to potrzebne, niech napisać predykat Prolog że skleja listę ciągów w jeden ciąg, umieszczając podwójne nowej linii pomiędzy każdą kolejną parę sznurków (ale nie na końcu ciąg wyjściowy, sądząc po przykładzie, który opublikował Jerry).

SWI-Prolog Manual: Normalnie bym Post "głębokie" linki do the documentation, ale strona SWI-Prolog wykorzystuje styl adresu URL, który wyzwala cross-site scripting (XSS) ostrzeżenia z wielu przeglądarek/kombinacji wtyczki . Zamiast tego odniosę się do linku do odpowiedniej sekcji.

Sekcja 4.22 Reprezentacja tekstu w łańcuchach mówi (częściowo), "Obiekty typu String domyślnie nie mają reprezentacji leksykalnych, a zatem można je tworzyć tylko za pomocą predykatów poniżej lub za pośrednictwem interfejsu obcego języka." Może to być trochę mylące, ponieważ SWI-Prolog zapisuje ciągi jako tekst z podwójnym cudzysłowem, ale odczytuje tekst z podwójnym cudzysłowem (domyślnie) jako listę kodów znaków.

Oto kod dla predykatu, który skleja sznurki na liście, wkładając inną Separator ciągu w między kolejnymi parami wyrażenie:

strSepCat([ ],_,Empty) :- 
    string_to_list(Empty,[ ]). 
strSepCat([H|T],Separator,StrCat) :- 
    strSepCat(T,Separator,H,StrCat). 

strSepCat([ ],_,StrCat,StrCat). 
strSepCat([H|T],Sep,Str,Cat) :- 
    string_concat(Sep,H,SepH), 
    string_concat(Str,SepH,StrSepH), 
    strSepCat(T,Sep,StrSepH,Cat). 

Należy pamiętać, że mamy zdefiniowane dwa predykaty, strSepCat/3 i strSepCat/4. Pierwszy z nich jest zdefiniowany pod względem tego ostatniego, typowy wzorzec projektowy w Prologu, który wprowadza dodatkowy argument jako , który łączy się z wyjściem po zakończeniu rekurencji. Taka technika często pomaga uzyskać definicję tail recursive.

Aby użyć orzeczenie strSepCat/3, to na ogół konieczne skonstruowanie łańcucha separatora (sekwencja ewakuacji) dwa znakami nowej linii: linia

?- funs(Fs,Lisp,[ ]), string_to_list(Sep,"\n\n"), strSepCat(Fs,Sep,CProg). 
1

Ponieważ ciągi znaków w Prologu są naprawdę Wykazy kodów znaków, można użyć append w niestandardowym orzecznika że również wstawia nowe linie:

concat_program([], ""). 
concat_program([L|Ls], Str) :- 
    concat_program(Ls, Str0), 
    append("\n\n", Str0, Str1), 
    append(L, Str1, Str). 

Zastosowanie:

funs(Fs, Lisp, []), 
concat_program(Fs, P), 
write("#include ...\n"), 
writef(P). 
+0

funs (F, "(define (zero x) 0) (zdefiniuj (jeden n) 1)", []), concat_program (F, X). to fałsz. – Igor

+0

'F = [" dane * carzero (dane * l) {return (eq (car (l), make_atom_int (0)));} "," dane * zero (dane * n) {return (eq (make_atom_int (0), n));} "], concat_program (F, X)." Działa. Nie widzę, co jest nie tak w pozostałej części kodu, ponieważ nie podałeś pełnej gramatyki. –

+0

Ogólny pomysł jest poprawny, ale podejrzewam, że przesłanie "ciągi w Prologu są naprawdę listami kodów znaków" może być błędne w zastosowaniu Prologu. Zobacz tę dyskusję dla ciągów SWI-Prolog i konkatenacji: http://www.sci.hkbu.edu.hk/scilab/doc/prolog/sec-3.20.html – hardmath

2

Co za pomocą notacji DCG do dołączania strun?

concat([]) --> []. 
concat([List|Lists]) --> List, "\n\n", concat(Lists).