2015-05-06 2 views
1

Я пытаюсь построить очень простой язык, используя Лекса и Yacc Это может быть только одна переменная Int через присвоение как этотLex & Yacc разборе заявления

a = 1 

Он может печатать переменную, как это

print a 

он должен выводить значение только если имя переменной совпадает иначе он должен напечатать сообщение об ошибке
Мой закон файл

%{ 
    #include "y.tab.h" 
    #include <stdlib.h> 
    void yyerror(char *); 
%} 
letter  [A-z] 
digit  [0-9] 
%% 
"print"   {return PRINT;} 
{letter}+  { yylval.id = yytext;return IDENTIFIER;} 
{digit}+  { yylval.num = atoi(yytext);return NUMBER; } 

[=\n]  return *yytext; 

[ \t]  ; /* skip whitespace */ 

.   yyerror("invalid character"); 

%% 

int yywrap(void) { 
    return 1; 
} 

И мой файл Yacc является

%{ 
    #include <stdio.h> 
    #include <string.h> 
    int yylex(void); 
    void yyerror(char *); 
    int value; 
    char *key; 
    void print_var(char *s); 
%} 
%union {char *id;int num;} 
%start exp 
%token <id> IDENTIFIER 
%token <num> NUMBER 
%token PRINT 

%% 

exp: IDENTIFIER '=' NUMBER '\n' {key = $1;value = $3;} 
    |PRINT IDENTIFIER '\n'  {print_var($2);} 
    |exp IDENTIFIER '=' NUMBER '\n' {key = $2;value = $4;} 
    |exp PRINT IDENTIFIER '\n'  {print_var($3);} 
    ; 
%% 
void yyerror(char *s) { 
    fprintf(stderr, "%s\n", s); 
} 

void print_var(char *s){ 
    if(strcmp(s,key) == 0){ 
     printf("%s:%d\n",key,value); 
    }else{ 
     printf("%s not found\n",s); 
    } 
} 

int main(void) { 
    yyparse(); 
    return 0; 
} 

Но когда я типа что-то вроде этого

a = 1 
print a 

Я получаю следующую ошибку не найден

ответ

0

После того, как ваша Лекса программа возвращается yacc (или, в основном, выходит за пределы правила), значение yytext не обязательно не тронуто. Вместо того, чтобы сделать id указателем на yytext, вы должны использовать strdup или что-нибудь такое, чтобы сделать копию строки в yytext.

Это указано в руководстве пользователя flex в формате 21.3 A Note About yytext And Memory.

В вашей грамматике, это единственное правило, показано:

exp: IDENTIFIER '=' NUMBER '\n' {key = $1;value = $3;} 
    |PRINT IDENTIFIER '\n'  {print_var($2);} 
    |exp IDENTIFIER '=' NUMBER '\n' {key = $2;value = $4;} 
    |exp PRINT IDENTIFIER '\n'  {print_var($3);} 
    ; 

копирует указатель в глобальную переменную key (опять же, что сталкивается с проблемой коррупции памяти) и печатает $2 идентификатор. Если вы выделили копию программы yytext в программе lex, кажется, вы можете спокойно освободить ее в print_var. Два присвоений key должны быть заменены вызовами функции, которая устанавливает key, во время проверки, если он уже был установлен, например,

void set_key(const char *value) 
{ 
    if (key != 0) 
     free(key); 
    key = strdup(value); 
} 

Это было бы оставить не более одной копии yytext выделенной в то время — незначительный объем памяти.

+0

Как освободить память? –

+0

Это сложнее. Вы должны изучить грамматику yacc, чтобы узнать, где вам больше не понадобится значение, а затем освободите его. Вы можете только освободить строку один раз (без того, чтобы ваша программа умерла). –