5

解析に (再入可能) Flex + Lemon を使用すると問題が発生します。ここでは単純な文法とレクサーを使用しています。これを実行するときは、数字の後に EOF トークン (Ctrl-D) を入力します。プリントアウトには次のように表示されます。

89

found int of .
AST=0.

最初の行は入力した数値です。理論的には、AST 値は入力したすべての値の合計になるはずです。

編集: Parse() を手動で呼び出すと、正しく実行されます。

atom ::= INTまた、トークンが 0 (停止トークン) の場合でも、lemon はルールを実行しているように見えます。どうしてこれなの?この動作について非常に混乱しており、適切なドキュメントが見つかりません。

4

2 に答える 2

5

Okay, I figured it out. The reason is that there is a particularly nasty (and poorly documented) interaction going on between flex and lemon.

In an attempt to save memory, lemon will hold onto a token without copying, and push it on to an internal token stack. However, flex also tries to save memory by changing the value that yyget_text points to as it lexes the input. The offending line in my example is:

// in the do loop of main.c...
Parse(parser, token, yyget_text(lexer));

This should be:

Parse(parser, token, strdup(yyget_text(lexer)));

which will ensure that the value that lemon points to when it reduces the token stack later is the same as what you originally passed in.

(Note: Don't forget, strdup means you'll have to free that memory at some point later. Lemon will let you write token "destructors" that can do this, or if you're building an AST tree you should wait until the end of the AST lifetime.)

于 2013-12-21T00:07:39.547 に答える
0

文字列へのポインターと文字列の長さを含むトークン型を作成することもできます。私はこれで成功しました。

token.h

#ifndef Token_h
#define Token_h

typedef struct Token {
  int code;
  char * string;
  int string_length;
} Token;

#endif // Token_h

main.c

int main(int argc, char** argv) {
    // Set up the scanner
    yyscan_t scanner;
    yylex_init(&scanner);
    yyset_in(stdin, scanner);

    // Set up the parser
    void* parser = ParseAlloc(malloc);

    // Do it!
    Token t;
    do {
        t.code = yylex(scanner);
        t.string = yyget_text(scanner);
        t.string_length = yyget_leng(scanner);
        Parse(parser, t.code, t);
    } while (t.code > 0);

    if (-1 == t.code) {
        fprintf(stderr, "The scanner encountered an error.\n");
    }

    // Cleanup the scanner and parser
    yylex_destroy(scanner);
    ParseFree(parser, free);
    return 0;
}

language.y (抜粋)

class_interface   ::= INTERFACE IDENTIFIER(A) class_inheritance END.
{
    printf("defined class %.*s\n", A.string_length, A.string);
}

そこに私のprintfステートメントがありますか?文字列と長さを使用してトークンを出力しています。

于 2014-10-17T02:34:31.117 に答える