编写获取下一个令牌函数

时间:2012-10-24 23:07:28

标签: c parsing static

给定一个C字符串:我如何编写一个能够获取字符串中下一个标记的函数,以及一个将查看下一个标记并在不使用全局变量的情况下返回该标记的函数?

我要做的是拥有一个静态变量来保存字符串,并且在调用时,它只会增加一个指针,它将重置该静态变量,抛出已检索的标记。问题是:当我刚刚检索它时,我怎么能区分第一个调用(当它实际存储字符串时)和其他调用?

对此有何想法?

修改 这就是我现在所做的“工作”但我想确保它实际上应该工作,而不仅仅是指针为空的巧合:

char next_token(char *line) {
    static char *p;
    if (p == NULL)
        p = line;
    else {
        char next_token = p[0];
        p++;
        return next_token;
    }
}

4 个答案:

答案 0 :(得分:0)

typedef struct {
   char* raw;
   // whatever you need to keep track
} parser_t


void parser_init(parser_t* p, char* s)
{
   // init your parser
}

bool parser_get_token(parser_t* p, char* token)
{
   // return the token in "token"  or return a bool error ( or an enum of various errors)
}

bool parser_peek_token(parser_t* p, char* token)
{
  // same deal, but don't update where you are...
}

答案 1 :(得分:0)

你有几个选择。一种是使用大致类似strtok的接口,其中传递非空指针初始化静态变量,并且传递空指针检索令牌。然而,这在多线程存在时相当丑陋,笨拙,容易出错并且存在问题。

另一种可能性是使用具有单独函数的文件级静态变量(在该文件中)以初始化静态变量,并从字符串中检索下一个标记。这稍微清洁一点,但仍然存在大部分相同的问题。

第三种方法是让它像文件一样行动(例如) - 用户调用parse_open(例如),传入字符串进行解析。你返回一个不透明的句柄。然后,每当他们想要另一个令牌时,他们就会将其传回(比方说)get_token。

答案 2 :(得分:0)

编辑中的代码错误。您正在错误地处理NULL情况。

我最初的回答是模仿strtok这似乎是你想要的,但你澄清了你想要单个字符。

if条件应为:

if (line != NULL) p = line;

你可能会删除else以便每次都执行代码...除非你不想在第一次调用时得到结果(你至少应该返回一个值)。

你这样打电话:

char token = next_token(line);

while( 0 != (token = next_token(NULL)) ) {
    // etc
}

答案 3 :(得分:0)

基本上,函数有三种方法可以将信息传递回调用者:

  • 通过全局变量
  • 通过返回值
  • 通过指针参数

同样,有一些方法可以使函数在调用之间保持状态:

  • 通过全局或(函数)静态变量
  • 将其作为函数参数提供,并在每次调用后返回
  • 通过指针参数。

词法分析器/标记器的一个不错的编码约定是使用返回值来传达消耗的字符数。 (并且可能使用额外的指针变量来传递解析器状态来回调用)

这是wakkerbot的解析器:

STATIC size_t tokenize(char *string, int *sp);

用法:

STATIC void make_words(char * src, struct sentence * target)
{
    size_t len, pos, chunk;
    STRING word ;
    int state = 0; /* FIXME: this could be made static to allow for multi-line strings */

    target->size = 0;

    len = strlen(src);
    if (!len) return;

    for(pos=0; pos < len ; ) {

    chunk = tokenize(src+pos, &state);
        if (!chunk) { /* maybe we should reset state here ... */ pos++; }
        if (chunk > STRLEN_MAX) {
            warn( "Make_words", "Truncated too long string(%u) at %s\n", (unsigned) chunk, src+pos);
            chunk = STRLEN_MAX;
            }
        word.length = chunk;
        word.word = src+pos;

        if (word_is_usable(word)) add_word_to_sentence(target, word);

        if (pos+chunk >= len) break;
        pos += chunk;
    }
...
}