2013-03-25 2 views
0

Я пытаюсь написать парсер с использованием flex и bison. Однако независимо от того, как я изменяю файлы, всегда появляется ошибка «синтаксическая ошибка в строке 1». Это test.vm файл yyinput:Как исправить «строка: 1: ошибка: синтаксическая ошибка!»

$asfdfsdf 
sdfsdfs 
sdfsdfsd 
sdfsdfsd 
sfsdfd 

это файл vtl4.l:

%{ 
#include<stdio.h> 
#include<string.h> 
#include "context.h" 
#include "bool.h" 
#include "vtl4.tab.h" 
%} 
%% 
(.|\n)* {yylval.string = yytext;return CONTENT;} 
<<EOF>> {return FINAL;} 
%% 

Это файл vtl4.y:

%{ 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include "bool.h" 
#include "parser.h" 
#include "context.h" 
#include "vtl4.tab.h" 

extern FILE * yyin; 
extern FILE * yyout; 
extern int yylex(); 
extern int yywrap(); 
%} 

%union { 
struct simpleNode *ast; 
double d; 
int i; 
bool b; 
char* string; 
struct symbol *sym; 
} 

%type <ast> root stmts stmt 

%token <string> CONTENT 

%token FINAL 

%% 

root:stmts FINAL {printf("root\n");$$ = process($1);traverse($$);} 
; 

stmts: {printf("stmts:stmt\n");$$ = 0;} 
|stmts stmt {printf("stmts:stmts stmt\n");$$ = add_ybrother($1,$2);} 
; 

stmt:CONTENT {printf("stmt\n");$$ = text($1);} 
; 

%% 
int main(){ 
FILE *src; 
src = fopen("test.vm","r"); 
yyin = src; 
yyparse(); 
fclose(src); 
return 1; 
} 

int yywrap(){ 
return 1; 
} 

Makefile:

CC=cc 

FLEX=vtl4.l 

BISON=vtl4.y 

parse:vtl4.tab.c lex.yy.c 
     $(CC) -o out *.c -ll 


vtl4.tab.c:$(BISON) 
     bison -d $(BISON) --report=all 

lex.yy.c:$(FLEX) 
     flex $(FLEX) 

когда я r un ./out, он напечатает правильный результат, но всегда говорит «строка: 1: ошибка: синтаксическая ошибка» наконец! Я не знаю почему?

Это хорошо работает, когда я редактирую ЛЕКС правило

<<EOF>> {return FINAL;} 

в

<<EOF>> {yyterminate();} 

и изменить правило YACC

root:stmts FINAL {printf("root\n");$$ = process($1);traverse($$);} 

в

root:stmts {printf("root\n");$$ = process($1);traverse($$);} 

но я не знаю почему?

ответ

2

Используя return FINAL в правиле <<EOF>>, токенизатор будет продолжать возвращать FINAL в конец файла. Когда flex используется в сочетании с bison, вам не нужно (и не должно) использовать явный токен конца файла. Просто положитесь на 0, которые будут возвращены yylex в конце файла, если yywrap возвращает 1. Это именно то, что yyterminate делает для вас тоже, и именно поэтому это прекрасно работает.

В этом случае грамматика сталкивается с бесконечным потоком токенов FINAL, с которыми он не может справиться. Конечно, вы не должны приспосабливать этот бесконечный поток в своей грамматике, потому что грамматика будет тогда «правильной», но никогда не закончится.

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

P.S: Я нашел эту проблему с помощью опции -t в bison, который добавляет отладочную трассировку к анализаторам, и он показал, что он задохнулся от второго появления FINAL.

P.S2: В Makefile вы использовали *.c в вызове компилятора для parse. Это довольно опасно, так как некоторые случайные файлы .c могут находиться в вашем каталоге. Лучше использовать $^ для просмотра всех файлов, от которых зависит правило.

P.S3: Как вы определили свои собственные yywrap и main, вы можете потерять -ll.

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