我正在尝试创建自己的Lisp解释器,并且在解析s表达式时遇到了一些问题。我最初的想法是将表达式标记化并一次处理一个位。 I came across some code to do this在我自己的尝试失败之后,但我对它的输出感到困惑。
int lex(const char *str, const char **start, const char **end)
{
const char *ws = " \t\r\n";
const char *delim = "() \t\r\n";
const char *prefix = "()'`";
str += strspn(str, ws);
if (str[0] == '\0') {
*start = *end = NULL;
return 1;
}
*start = str;
if (strchr(prefix, str[0]) != NULL)
*end = *start + 1;
else
*end = *start + strcspn(str, delim);
return 0;
}
用法:
const char *input = "(foo bar 17 '(a b c) 2)";
char *token;
char *p = input;
lex(p, &token, &p);
while(token != NULL)
{
printf("%.*s\n", (int)(p - input), token);
lex(p, &token, &p);
}
(
foo
bar 17 '
17 '(a b c)
'(a b c) 2)
(a b c) 2)
a b c) 2)
b c) 2)
c) 2)
) 2)
2)
)
查看代码,我曾预料到它会输出17
而不是17 '(a b c)
或输出2
而不是2)
。造成这种情况的原因是什么?如何解决?如果在这种情况下令牌化不是最佳解决方案,我也愿意接受建议。
在第二个注释中,像str
这样的参数绝对必要吗? start
和end
参数不足以满足start
之前的数据吗?
答案 0 :(得分:3)
简单的拼写错误。
printf("%.*s\n", (int)(p - input), token);
应该是
printf("%.*s\n", (int)(p - token), token);
str
是输入参数,start
和end
是输出参数。你可以让start
成为一个inout参数,但不是每个人都喜欢这些。
在任何情况下,返回的令牌都从start
开始,其长度为end - start
,这就是printf length参数需要为p - token
的原因。