1

C 文字列が与えられた場合: 文字列内の次のトークンを取得する関数と、グローバル変数を使用せずに次のトークンをピークしてそれを返す関数を作成するにはどうすればよいでしょうか?

私がやろうとしているのは、文字列を保持する静的変数を持つことです。呼び出されると、ポインターがインクリメントされ、静的変数がリセットされ、取得されたトークンがスローされます。問題は、最初の呼び出し (実際に文字列を格納するとき) と、それを取得するときの他の呼び出しをどのように区別できるでしょうか?

これについて何か考えはありますか?

編集: これが私が今持っている「機能する」ものですが、実際に機能する必要があり、ポインターがnullであるという単なる偶然ではないことを確認したい:

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

4 に答える 4

0

編集中のコードが間違っています。NULL ケースを正しく処理していません。

strtok私は最初、あなたが望んでいるように見えるエミュレートに関して答えましたが、あなたは単一のキャラクターが欲しいと明言しました。

if 条件は次のようにする必要があります。

if (line != NULL) p = line;

elseそして、コードが毎回実行されるように、おそらくを削除します...最初の呼び出しで結果が必要でない場合を除きます(ただし、少なくとも値を返す必要があります)。

次のように呼び出します。

char token = next_token(line);

while( 0 != (token = next_token(NULL)) ) {
    // etc
}
于 2012-10-24T23:22:39.707 に答える
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...
}
于 2012-10-24T23:11:17.193 に答える
0

いくつかの選択肢があります。1 つは、大まかにインターフェイスを使用することstrtokです。null 以外のポインターを渡すと静的変数が初期化され、null ポインターを渡すとトークンが取得されます。ただし、これはかなり見苦しく、ぎこちなく、エラーが発生しやすく、マルチスレッドが存在する場合には問題があります。

もう 1 つの可能性は、静的変数を初期化し、文字列から次のトークンを取得するために、ファイル レベルの静的変数を別の関数 (そのファイル内の両方) と共に使用することです。これはわずかにきれいですが、ほとんど同じ問題があります。

3 つ目は、(一例として) ファイルのように動作させることです。ユーザーは parse_open を呼び出し (たとえば)、解析する文字列を渡します。それらに不透明なハンドルを返します。次に、別のトークンが必要になるたびに、それを (たとえば) get_token に渡します。

于 2012-10-24T23:11:29.353 に答える
0

基本的に、関数が呼び出し元に情報を返す方法は 3 つあります。

  • グローバル変数経由
  • 戻り値を介して
  • ポインタ引数を介して

同様に、関数が呼び出し間で状態を維持する方法があります。

  • グローバル変数または (関数) 静的変数を介して
  • それを関数パラメーターとして提供し、呼び出しのたびに返すことによって
  • ポインタ引数を介して。

lexer/tokeniser の適切なコーディング規則は、戻り値を使用して消費された文字数を伝えることです。(そして追加のポインター変数を使用して、パーサーの状態を呼び出しの前後に渡すことができます)

これは 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;
    }
...
}
于 2012-10-25T00:01:28.523 に答える