Concatting список строк в прологе

Я пишу Lisp для переводчика C, и у меня проблема с обработкой строк. Это код, который преобразует унарную функцию Lisp в эквивалент 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))); }nndata *zero(data *n) { return(eq(make_atom_int(0), n)); }".

так что я могу красиво swritef входит в полную программу, между #includes и main (). Альтернативным решением является изменение переводчика самого высокого уровня для обработки списка. Это выглядит так:

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

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

3 ответов


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

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

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

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. Первый определяется в терминах последнего, типичного шаблона проектирования в Prolog, который вводит дополнительный аргумент как аккумулятор который привязывается к выходу, когда рекурсия полный. Такая техника часто помогает получить хвост рекурсивной определение.

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

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

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

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

поскольку строки в прологе действительно являются списками кодов символов, вы можете использовать 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).