Bison适合上下文无关文法(Context-free grammar),并采用LALR(1)算法的文法。当bison读入一个终结符(token),它会将该终结符及其语意值一起压入堆栈。这个堆栈叫做分析器堆栈(parser stack)。把一个token压入堆栈通常叫做移进(shifting);当已经移进的后n个终结符和组(groupings)与一个文法规则相匹配时,会被根据那个规则结合起来叫做归约(reduction)。
Bison布局:
%{ C/C++引入头文件和声明 %} Bison 声明 %% 语法规则(BNF) %% C/C++代码
一个计算器例子:
Calculator.l:
- %{
- #include"Calculator.tab.h"
- intyywrap();
- %}
- %%
- [\n]{yylloc.first_line++;yylloc.first_column=0;return*yytext;}
- [\t]{yylloc.first_column+=(*yytext=='\t'?3:1);}
- [0-9]+{yylloc.first_column+=yyleng;yylval=atoi(yytext);returnNUM;}
- [+\-*/\^\(\)]{yylloc.first_column+=yyleng;return*yytext;}
- .{return*yytext;}
- %%
- intyywrap()
- {return1;}
%{
#include"Calculator.tab.h"
int yywrap();
%}
%%
[\n] { yylloc.first_line++; yylloc.first_column = 0; return *yytext; }
[ \t] { yylloc.first_column += (*yytext == '\t' ? 3 : 1); }
[0-9]+ { yylloc.first_column += yyleng; yylval = atoi( yytext ); return NUM; }
[+\-*/\^\(\)] { yylloc.first_column += yyleng; return *yytext; }
. { return *yytext; }
%%
int yywrap()
{ return 1; }
Calculator.y:
- %{
- #defineYYSTYPEint
- #include<stdio.h>
- #include<math.h>
- voidyyerror(charconst*);
- intyylex(void);
- %}
- %tokenNUM
- %left'-''+'
- %left'*''/'
- %leftNEG
- %right'^'
- %%
- input:/*empty*/
- |inputline
- ;
- line:'\n'
- |exp'\n'{printf("%d\n",$1);}
- ;
- exp:NUM{$$=$1;}
- |exp'+'exp{$$=$1+$3;}
- |exp'-'exp{$$=$1-$3;}
- |exp'*'exp{$$=$1*$3;}
- |exp'/'exp{
- if($3){$$=$1/$3;}
- else{
- $$=1;
- fprintf(stderr,"%d:%d:DIVISIONBYZERO\n",@3.first_line,@3.first_column);
- }
- }
- |'-'exp%precNEG{$$=-$2;}
- |exp'^'exp{$$=pow($1,$3);}
- |'('exp')'{$$=$2;}
- ;
- %%
- voidyyerror(charconst*s)
- {printf("%s",s);}
- intmain()
- {returnyyparse();}
%{
#define YYSTYPE int
#include <stdio.h>
#include <math.h>
void yyerror (char const *);
int yylex( void );
%}
%token NUM
%left '-' '+'
%left '*' '/'
%left NEG
%right '^'
%%
input : /* empty */
| input line
;
line : '\n'
| exp '\n' { printf ( "%d\n" , $1 ); }
;
exp : NUM { $$ = $1; }
| exp '+' exp { $$ = $1 + $3; }
| exp '-' exp { $$ = $1 - $3; }
| exp '*' exp { $$ = $1 * $3; }
| exp '/' exp {
if ( $3 ) { $$ = $1 / $3; }
else {
$$ = 1;
fprintf (stderr, "%d:%d: DIVISION BY ZERO\n",@3.first_line, @3.first_column );
}
}
| '-' exp %prec NEG { $$ = -$2; }
| exp '^' exp { $$ = pow ($1, $3); }
| '(' exp ')' { $$ = $2; }
;
%%
void yyerror (char const *s )
{ printf( "%s" , s ); }
int main()
{ return yyparse(); }