我正在写一个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))); }\n\ndata *zero(data *n) { return(eq(make_atom_int(0), n)); }".
这样我就可以很好地swritef
进入#include
和main()之间的完整程序。另一种解决方案是修改最高级别的翻译器来处理列表。它看起来像这样:
program(P) --> define(F), {swritef(P, "#include \"lisp2c.h\" \n\n%t \nint main() { return 0; }", [F])}, !.
我如何做这两个中的任何一个?我正在使用SWI Prolog。
答案 0 :(得分:4)
暂时搁置它需要的目的,让我们编写一个Prolog谓词,将一个字符串列表连接成一个字符串,在每个连续的字符串对之间放置一个双换行符(但不在输出字符串的末尾,以Jerry发布的例子来判断。
SWI-Prolog手册:通常我会发布 the documentation的“深层”链接,但SWI-Prolog网站使用一种触发跨站点脚本的URL样式(XSS )许多浏览器/插件组合的警告。所以相反,我会引用链接到相应的部分。
第4.22节用字符串表示文本说(部分),“默认情况下,字符串对象没有词法表示,因此只能使用下面的谓词或通过外语界面创建。”这可能有点令人困惑,因为SWI-Prolog将字符串写为双引号文本,但读取双引号文本(默认情况下)作为字符代码列表。
这是一个谓词的代码,它连接列表中的字符串,在连续的字符串对之间插入另一个字符串Separator:
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中的典型设计模式引入了额外的参数,作为累加器,在递归完成时绑定到输出。这种技术通常有助于获得 tail recursive定义。
要使用谓词 strSepCat / 3 ,我们通常需要构造带有(转义序列)两个换行符的分隔符字符串:
?- funs(Fs,Lisp,[ ]), string_to_list(Sep,"\n\n"), strSepCat(Fs,Sep,CProg).
答案 1 :(得分:2)
如何使用DCG表示法附加字符串?
concat([]) --> [].
concat([List|Lists]) --> List, "\n\n", concat(Lists).
答案 2 :(得分:1)
由于Prolog中的字符串实际上是字符代码列表,因此您可以在也插入换行符的自定义谓词中使用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).
答案 3 :(得分:0)
比接受的答案更简单(更通用)的解决方案是将reduce与现有的string_concat一起用作参数:
reduce3(_, [], Default, Default).
reduce3(_, [A], _, A).
reduce3(P3, [A,B|T], _, D):-
call(P3, A, B, C),
reduce3(P3, [C|T], _, D).
?- reduce3(string_concat, ["123", "456", "789"], "", R).
R = "123456789"
?- reduce3(string_concat, ["123"], "", R).
R = "123"
?- reduce3(string_concat, [], "", R).
R = ""
strings_concat(Strings, String):-
reduce3(string_concat, Strings, "", String).