我是编译器的新手,并为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的主文件。我只是编写一个算术计算器,但它给我解析错误请帮助。
答案 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
定义选择。
那些只是我立即看到的错误。删除它们然后我们将看它是否仍然无法正常工作。