這裡有一個使用bison建立一個簡單的計算機的例子:
http://www.cs.berkeley.edu/~maratb/cs164/bison.html
使用bison和flex工具學習編譯原理,遠比單獨看書然後自己編寫一些程式生動的多。這樣你就不會在那些複雜的字元處理,Regex的處理上浪費精力,最後費盡心力,卻沒有結果,失去了學習的興趣。
我
這裡有一個簡單的計算機的程式,可以實現加、減、乘、除運算,並支援括弧的處理和26個字母作為變數。以前自己使用尾碼運算式方式寫過一個這樣的程式,單
單中綴運算式改為尾碼運算式就是幾百行的代碼,反正自己現在還是不知道怎麼處理裡面複雜的堆棧的(我用了STL的List實現)。
詞法處理檔案calc.lex內容如下:
%{
/*
* 一個簡單計算機的Lex詞法檔案
*/
#include <stdlib.h>
void yyerror(char*);
#include "calc.tab.h"
%}
%%
/* a-z為變數 */
[a-z] {
yylval = *yytext - 'a';
return VARIABLE;
}
/* 整數 */
[0-9]+ {
yylval = atoi(yytext);
return INTEGER;
}
/* 運算子 */
[-+()=\*\n] {return *yytext;}
/* 空白被忽略 */
[ /t] ;
/* 其他字元都是非法的 */
. yyerror("無效的輸入字元");
%%
int yywrap(void)
{
return 1;
}
詞法處理的目標就是區分出來每個成員到底是什麼,這裡有兩種 INTEGER和VARIABLE。只要區分出來各個成分詞法分析的任務就完成了。
文法處理檔案calc.y內容如下:
%token INTEGER VARIABLE
%left '+' '-'
%left '*' '/'
%{
#include <stdio.h>
void yyerror(char*);
int yylex(void);
int sym[26];
%}
%%
program:
program statement '\n'
|
;
statement:
expr {printf("%d\n", $1);}
|VARIABLE '=' expr {sym[$1] = $3;}
;
expr:
INTEGER
|VARIABLE{$$ = sym[$1];}
|expr '+' expr {$$ = $1 + $3;}
|expr '-' expr {$$ = $1 - $3;}
|expr '*' expr {$$ = $1 * $3;}
|expr '/' expr {$$ = $1 / $3;}
|'('expr')' {$$ = $2;}
;
%%
void yyerror(char* s)
{
fprintf(stderr, "%s\n", s);
}
int main(void)
{
printf("A simple calculator.\n");
yyparse();
return 0;
}
文法分析檔案的寫法就是將BNF運算式描述一下即可,規則隨著條目逐漸細化,變成了可以理解的內容。這裡不用管如何?這些文法的分析,只是需要告知如何構建這些文法。
編譯命令如下:
>bison -d calc.y
>flex calc.lex
>gcc calc.tab.c lex.yy.c -o calc
------------------------------------------------
yyparse 是bison產生的函數,用於解析文法,同時yylex是flex產生的函數,用於解析詞法,bison產生的函數調用yylex不斷處理,處理出來適合的運算式,之後計算.