编译器 - 显示解析错误的bison

时间:2014-04-19 20:09:27

标签: compiler-construction bison flex-lexer

我是编译器的新手,并为c语言的子集编写自己的编译器。

flex代码:

%{
#include "parser.tab.h"
%}

%option warn noyywrap noinput nounput yylineno

%%
"else"      {return ELSE;}
"if"        {return IF;}
"int"       {return INT;}
"return"    {return RETURN;}
"void"      {return VOID;}
"while"     {return WHILE;}
"+"         {return ADD;}
"-"         {return SUB;}
"*"         {return MUL;}
"/"         {return DIV;}
"<"         {return LT;}
"<="        {return LTE;}
">"         {return GT;}
">="        {return GTE;}
"=="        {return EQ;}
"!="        {return NEQ;}
"="         {return ASSIGN;}
";"         {return SEMI;}
","         {return COMMA;}
"("         {return ROUND_OPEN;}
")"         {return ROUND_CLOSE;}
"["         {return SQUARE_OPEN;}
"]"         {return SQUARE_CLOSE;}
"{"         {return CURLY_OPEN;}
"}"         {return CURLY_CLOSE;}
[a-zA-z]+   {return ID;}
[0-9]+      {yylval.intVal=atoi(yytext);return NUM;}
"//".*      /* discard comments */
[ \t\n\b]+  { if (yytext[0] == '\n') ++yylineno; } /* discard whitespace */
%%

野牛代码:

%{
extern int yylex();
void yyerror(char* err, ...);
%}
%union{
    int intVal;
};

%token ELSE, IF, RETURN, VOID, INT
%token WHILE
%token ADD, SUB, MUL, DIV
%token LT, LTE, GT, GTE, EQ, NEQ
%token ASSIGN
%token SEMI, COMMA
%token ROUND_OPEN, ROUND_CLOSE, SQUARE_OPEN, SQUARE_CLOSE, CURLY_OPEN, CURLY_CLOSE
%token ID, NUM

%type <int> S 
%type <int>expr
%type <int> term
%type <int> factor 


%%
S: expr'\n' {$<intVal>$=$<intVal>1;printf("%d",$<intVal>$);}
expr: expr ADD term {$<intVal>$=$<intVal>1+$<intVal>2;};
expr: term {$<intVal>$=$<intVal>1};
term: term MUL factor {$<intVal>$=$<intVal>1*$<intVal>2};
term: factor {$<intVal>$=$<intVal>1};
factor:NUM {$<intVal>$=yylval.intVal};

%%

void yyerror(char* err, ...)
{
    fprintf(stderr, "%s\n", err);
}

有一个用于调用yyparse的主文件。我只是编写一个算术计算器,但它给我解析错误请帮助。

1 个答案:

答案 0 :(得分:1)

我只列出我认为不正确的所有内容 - 一旦你修复它们,它可能会开始工作:

%type <int> S 
%type <int> expr
%type <int> term
%type <int> factor 

应该是:

%type <intVal> S 
%type <intVal> expr
%type <intVal> term
%type <intVal> factor 

您可以在此处定义每个[非]终端应使用哪个联合字段。那个:

S: expr'\n' {$<intVal>$=$<intVal>1;printf("%d",$<intVal>$);}

Bison绝不知道'\n' char - 它只接收来自Flex lexer的令牌。由于您没有向解析器发送新行令牌,因此它不知道它。它肯定不会'\n'

改为使用:

// in bison "header"
%token EOL // End of Line

// in flex definitions
"\n"          { ++yylineno; return EOL; }
[ \t\r\f\v]+  /* remove blanks */

// again in bison
S: expr EOL { $$ = $1; printf("%d",$$); }

您不需要手动选择联盟字段 - %type <intVal> S的用途是什么。

为什么要将制作分成不同的行?你可以这么做:

S: expr EOL { $$ = $1; printf("%d",$$); }
 ;

expr: expr ADD term { $$ = $1 + $2;}
    | term          { $$ = $1; }
    ;

term: term MUL factor { $$ = $1 * $2; }
    | factor          { $$ = $1; }
    ;

factor: NUM { $$ = $1; }
      ;

一旦以缩短的方式写作,你也犯了很多错误:

term: term MUL factor {$<intVal>$=$<intVal>1*$<intVal>2};

而不是:

term: term MUL factor {$<intVal>$=$<intVal>1*$<intVal>2;}

其中};是无效语法而不是;} - 这毕竟是普通的C代码,每次使用yylval.fieldName或{{时,bison只会插入$$ 1}}等 - 右侧字段由$1定义选择。

那些只是我立即看到的错误。删除它们然后我们将看它是否仍然无法正常工作。