用C标记s表达式

时间:2015-08-03 23:23:23

标签: c parsing lisp tokenize s-expression

我正在尝试创建自己的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);
}

Output:

(
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这样的参数绝对必要吗? startend参数不足以满足start之前的数据吗?

1 个答案:

答案 0 :(得分:3)

简单的拼写错误。

 printf("%.*s\n", (int)(p - input), token);

应该是

 printf("%.*s\n", (int)(p - token), token);

str是输入参数,startend是输出参数。你可以让start成为一个inout参数,但不是每个人都喜欢这些。

在任何情况下,返回的令牌都从start开始,其长度为end - start,这就是printf length参数需要为p - token的原因。