在 C 中标记 s-表达式

Tokenizing an s-expression in C

我正在尝试创建自己的 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] == '[=10=]') {
        *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 之前的数据?

简单的错字。

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

应该是

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

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

无论如何,返回的token都是从start开始,长度是end - start,这就是为什么printf的长度参数需要是p - token.