2013-12-20 3 views
5

У меня возникла проблема с использованием (реентерабельной) Flex + Lemon для синтаксического анализа. Я использую простую грамматику и лексер here. Когда я запустил его, я поставлю число, за которым следует токен EOF (Ctrl-D). Распечатка будет читать:синтаксический анализатор лимона 0 token

89 

found int of . 
AST=0. 

Если первая строка является число, которое я поставил в Теоретически значение АСТ должна быть сумма всего, что я положил в

EDIT:.., Когда я звоню Разбор () вручную выполняется правильно.

Кроме того, лимон, как представляется, запускает правило atom ::= INT, даже если токен равен 0 (токен остановки). Почему это? Я очень смущен этим поведением, и я не могу найти хорошую документацию.

ответ

5

Хорошо, я понял. Причина в том, что между гибким и лимоном происходит особенно неприятное (и плохо документированное) взаимодействие.

В попытке сохранить память лимон будет удерживаться на токене без копирования и надавить на внутренний стек токенов. Однако flex также пытается сэкономить память, изменив значение, которое указывает yyget_text, поскольку оно лексирует вход. Нарушитель линия в моем примере:

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

Это должно быть:

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

, который будет гарантировать, что значение, что лимонные указывает, когда он уменьшает маркер стека позже то же самое, что вы изначально

(Примечание: не забывайте, что strdup означает, что вам нужно будет освободить эту память в какой-то момент позже. Лимон позволит вам писать токены «деструкторы», которые могут это сделать, или если вы строите дерево АСТ, вы должны подождать до конца срока службы АСТ.)

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 заявление там? Я использую строку и длину, чтобы распечатать мой токен.

Смежные вопросы