目前我试图将词法分析器和语法分析器分开,基于书籍《Prolog and Natural Language Analysis》的建议,该书对词法分析/标记化并没有详细说明。所以我正在尝试,并且发现几个小问题,这表明我可能遗漏了一些显而易见的东西。
所有我的小型标记解析器似乎都工作得很好;目前这是我的代码片段:
:- use_module(library(dcg/basics)).
operator('(') --> "(". operator(')') --> ")".
operator('[') --> "[". operator(']') --> "]".
% ... etc.
keyword(array) --> "array".
keyword(break) --> "break".
% ... etc.
虽然有点重复,但似乎还是有效的。然后我有一些自己不完全满意的东西,希望能得到建议,但它们似乎也起作用:
id(id(Id)) -->
[C],
{
char_type(C, alpha)
},
idRest(Rest),
{
atom_chars(Id, [C|Rest])
}.
idRest([C|Rest]) -->
[C],
{
char_type(C, alpha) ; char_type(C, digit) ; C = '_'
},
idRest(Rest).
idRest([]) --> [].
int(int(Int)) --> integer(Int).
string(str(String)) -->
"\"",
stringContent(Codes),
"\"",
{
string_chars(String, Codes)
}.
stringContent([C|Chars]) -->
stringChar(C), stringContent(Chars).
stringContent([]) --> [].
stringChar(0'\n) --> "\\n".
stringChar(0'\t) --> "\\t".
stringChar(0'\") --> "\\\"".
stringChar(0'\") --> "\\\\".
stringChar(C) --> [C].
我的标记器的主要规则是这样的:
token(X) --> whites, (keyword(X) ; operator(X) ; id(X) ; int(X) ; string(X)).
它并不完美;我会看到 int
解析成 in,id(t)
,因为 keyword(X)
在 id(X)
之前。所以我想这是第一个问题。
我更大的问题是我不知道如何将注释正确地集成到这种情况中。我尝试了以下方法:
skipAhead --> [].
skipAhead --> (comment ; whites), skipAhead.
comment --> "/*", anything, "*/".
anything --> [].
anything --> [_], anything.
token(X) --> skipAhead, (keyword(X) ; operator(X) ; id(X) ; int(X) ; string(X)).
这似乎不起作用;返回的解析结果(我得到了很多解析结果)似乎没有删除注释。我担心我的注释规则可能是不必要的低效率,并且可能会引起许多不必要的回溯。我还担心来自dcg/basics的whites//0
是确定性的;然而,方程的那部分似乎是有效的,只是将其与跳过注释集成起来似乎行不通。
最后,我不知道如何将解析错误传播回带有行/列信息的用户。感觉好像我必须追踪和线程一些当前的行/列信息,并将其写入令牌,然后尝试重新构建行,如果我想做类似于llvm的事情。这合理吗?还是有一个“推荐做法”?
整个代码可以在此处找到。
comment//0
感到紧张的好理由是:phrase(comment,"/**/*/")
是正确的,但应该失败。 - false