Составление списка строк в Прологе - PullRequest
6 голосов
/ 17 января 2011

Я пишу переводчик Lisp to C, и у меня проблема с обработкой строк.Это код, который преобразует унарную функцию Лиспа в эквивалент C:

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), !.

Теперь я хочу прочитать любое количество функций и вернуть их в виде одной строки.Вышеприведенное funs - лучшее, что я могу придумать, но оно работает так:

?- 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)); }"].

Хотя я хочу что-то вроде этого:

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)); }".

, чтобы я мог красивоswritef входит в полную программу, между #include s и main ().Альтернативное решение - модифицировать переводчик самого высокого уровня для обработки списка.В настоящий момент это выглядит так:

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

Как бы я справился с любым из этих двух?Я использую SWI Prolog.

Ответы [ 3 ]

4 голосов
/ 19 января 2011

Оставив в стороне цель, для которой это необходимо, давайте напишем предикат Prolog, который объединяет список строк в одну строку, помещая двойной символ новой строки между каждой последовательной парой строк (но не в конце выходной строки,судя по примеру, опубликованному Джерри).

Руководство по SWI-Prolog: Обычно я бы публиковал "глубокие" ссылки на документацию , но SWI-PrologСайт использует стиль URL, который вызывает предупреждения межсайтового скриптинга (XSS) со многими комбинациями браузер / плагин.Поэтому вместо этого я буду ссылаться, чем ссылка на соответствующий раздел.

Раздел 4.22. Представление текста в строках говорит (частично), что «Строковые объекты по умолчанию не имеют лексического представления и, следовательно, могут быть созданы только с использованием предикатов нижеили через интерфейс на иностранном языке. "Это может немного сбивать с толку, поскольку SWI-Prolog записывает строки в виде текста в двойных кавычках, но читает текст в двойных кавычках (по умолчанию) как списки кодов символов.

Вот код для предиката, который объединяет строкив списке, вставляя еще один разделитель строк между последовательными парами строк:

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).

Обратите внимание, что мы определили два предиката, strSepCat / 3 и strSepCat / 4 .Первый определяется в терминах второго, типичного шаблона проектирования в Прологе, который вводит дополнительный аргумент в виде аккумулятора , который связывается с выводом после завершения рекурсии.Такая техника часто полезна для получения хвостовой рекурсивной определения.

Чтобы использовать предикат strSepCat / 3 , нам обычно нужно создать строку-разделитель с помощью(escape-последовательность для) двух новых строк:

?- funs(Fs,Lisp,[ ]), string_to_list(Sep,"\n\n"), strSepCat(Fs,Sep,CProg).
2 голосов
/ 17 января 2011

Как насчет использования записи DCG для добавления строк?

concat([]) --> [].
concat([List|Lists]) --> List, "\n\n", concat(Lists).
1 голос
/ 17 января 2011

Поскольку строки в Прологе на самом деле представляют собой списки кодов символов, вы можете использовать append в пользовательском предикате, который также вставляет символы новой строки:

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

Использование:

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