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"
- 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; }
%{
#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:
- %{
- #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(); }
%{
#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(); }