Posted on 2010-09-20 15:29
Prayer 閱讀(791)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
C/C++
這里有一個(gè)使用bison建立一個(gè)簡(jiǎn)單的計(jì)算器的例子:
http://www.cs.berkeley.edu/~maratb/cs164/bison.html
使用bison和flex工具學(xué)習(xí)編譯原理,遠(yuǎn)比單獨(dú)看書然后自己編寫一些程序生動(dòng)的多。這樣你就不會(huì)在那些復(fù)雜的字符處理,正則表達(dá)式的處理上浪費(fèi)精力,最后費(fèi)盡心力,卻沒(méi)有結(jié)果,失去了學(xué)習(xí)的興趣。
我
這里有一個(gè)簡(jiǎn)單的計(jì)算器的程序,可以實(shí)現(xiàn)加、減、乘、除運(yùn)算,并支持括號(hào)的處理和26個(gè)字母作為變量。以前自己使用后綴表達(dá)式方式寫過(guò)一個(gè)這樣的程序,單
單中綴表達(dá)式改為后綴表達(dá)式就是幾百行的代碼,反正自己現(xiàn)在還是不知道怎么處理里面復(fù)雜的堆棧的(我用了STL的List實(shí)現(xiàn))。
詞法處理文件calc.lex內(nèi)容如下:
%{
/*
* 一個(gè)簡(jiǎn)單計(jì)算器的Lex詞法文件
*/
#include <stdlib.h>
void yyerror(char*);
#include "calc.tab.h"
%}
%%
/* a-z為變量 */
[a-z] {
yylval = *yytext - 'a';
return VARIABLE;
}
/* 整數(shù) */
[0-9]+ {
yylval = atoi(yytext);
return INTEGER;
}
/* 運(yùn)算符 */
[-+()=/*\n] {return *yytext;}
/* 空白被忽略 */
[ \t] ;
/* 其他字符都是非法的 */
. yyerror("無(wú)效的輸入字符");
%%
int yywrap(void)
{
return 1;
}
詞法處理的目標(biāo)就是區(qū)分出來(lái)每個(gè)成員到底是什么,這里有兩種 INTEGER和VARIABLE。只要區(qū)分出來(lái)各個(gè)成分詞法分析的任務(wù)就完成了。
語(yǔ)法處理文件calc.y內(nèi)容如下:
%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;
}
語(yǔ)法分析文件的寫法就是將BNF表達(dá)式描述一下即可,規(guī)則隨著條目逐漸細(xì)化,變成了可以理解的內(nèi)容。這里不用管如何實(shí)現(xiàn)這些語(yǔ)法的分析,只是需要告知如何構(gòu)建這些語(yǔ)法。
編譯命令如下:
>bison -d calc.y
>flex calc.lex
>gcc calc.tab.c lex.yy.c -o calc