yacc學習筆記(三)變量和有類型的標記

變量和有類型的標記

yacc不僅可以用%token定義標記,而且可以用

%type  <type>  token

爲標記指定類型,其中<type>需要是在%union中聲明的類型,token爲已由%token定義的標記名。

下面用帶類型的變記擴展之前的計算器來處理具有單個字母名字的變量。因爲只有26個字母(目前只關心小寫字母),所以我們能在26個條目的數組中(稱它爲vbltable)存儲變量。爲了使計算器更有用,也可以擴展它來處理多個表達式(每行一個)和使用浮點值。

具有變量和實值的yacc程序ch3-3.y
注:示例來源於《lex與yacc》第二版,書中此示例代碼有缺失,需要補充部分內容。

%{
#include <stdio.h>
        double vbltable[26];
%}

%union  {
        double  dval;
        int     vblno;
}

%token <vblno>  NAME
%token <dval>   NUMBER
%left  '-' '+'
%left  '*' '/'
%nonassoc UMINUS

%type <dval> expression

%%
statement_list: statement '\n'
        |       statement_list statement '\n'
statement:      NAME '=' expression     { vbltable[$1]=$3; }
        |       expression              { printf("=%g\n",$1); }
        ;

expression:     expression '+' expression  { $$=$1+$3; }
        |       expression '-' expression  { $$=$1-$3; }
        |       expression '*' expression  { $$=$1*$3; }
        |       expression '/' expression
                        {       if($3==0.0)
                                        yyerror("divided by zero.");
                                else
                                        $$ = $1 / $3;
                        }
        |       '-' expression %prec UMINUS     { $$=-$2; }
        |       '(' NUMBER ')'  { $$=$2; }
        |       NUMBER          { $$=$1; }              
        |       NAME            { $$=vbltable[$1]; }
        ;
%%

int main(){
        yyparse();
        return 0;
}

void yyerror(char *s){
        fprintf(stderr,"%s\n",s);
}

具有變量和實值的計算器詞法分析程序ch3-3.l:


%{
#include "y.tab.h"
#include <math.h>
extern double vbltable[26];
#undef yywrap
%}

%%
([0-9]+|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?)     {
                yylval.dval = atof(yytext);
                return NUMBER;
        }
[ \t] ;
[a-z]           { yylval.vblno=yytext[0]-'a'; printf("lex name=%d\n",yytext[0]-'a');  return NAME; }
"$"             { return 0; }
\n |            
.               return yytext[0];
%%

int yywrap()
{
        return 1;
}

編譯運行結果:

[postgre@host132 ch3]$ ls
3.y.bak  ch3-1.l  ch3-1.y  ch3-2.y  ch3-3.l  ch3-3.y  ch3-4.y  ch3hdr.h  lex.yy.c  test  test.l  test.y  y.tab.c  y.tab.h
[postgre@host132 ch3]$ yacc -d ch3-3.y
[postgre@host132 ch3]$ lex ch3-3.l
[postgre@host132 ch3]$ cc -o test  lex.yy.c y.tab.c
[postgre@host132 ch3]$ ./test
2/3
=0.666667
4/7
=0.571429
a=1/3
lex name=0
b=3/4
lex name=1
a+b
lex name=0
lex name=1
=1.08333
$
[postgre@host132 ch3]$
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章