yacc学习笔记(四)带符号表的计算器程序

符号表

上一篇的计算器程序中的变量名只支持单个字符(a-z), 很少有用户满意单字符变量名,所以现在要增加使用较长变量名的能力。这意味着需要一个符号表——一种用来跟踪使用中的名字的结构。每次记法分析程序读取输入中的名字时,它都在符号表中查找这个名字,并且得到一个对应符号表条目的指针。在程序的其它地方,使用符号表指针而不是名字串,因为每次需要时指针比查找名字更快速更容易。

因为符号表要求语法分析程序和词法分析程序共享的数据结构,所以我们创建一个头文件ch3hdr.h:

$ vi ch3hdr.h 

#define NSYMS 20        /* maximum number of symbols */

struct symtab {
        char *name;
        double value;
}symtab[NSYMS];

struct symtab *symlook(char *s);

这个符号表是一个结构体数组,每个结构都包含变量的名字和它的数值。我们还声明一个符号表查找程序symlook(),它以文本字符串形式的名字为参数,顺序地搜索字符表来寻找与传入参数名字对应的条目。如果某条目的name与symlook正在搜索的字符串匹配,就返回该条目的指针,因为名字已进被放进了表中。如果name字段为空,并且已经寻找了符号表中的所有条目且所有找到匹配的条目,那么我们就把名字输入至今为止还是空的符号表条目中。

具有符号表的语法分析程序ch3-4.y

%{
#include "stdio.h"
#include "ch3hdr.h"
#include <string.h>
%}

%union {
        double  dval;
        struct symtab *symp;
}

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

%type <dval> expression

%%
statement_list: statement '\n'
        |       statement_list statement '\n'

statement:      NAME '=' expression     { $1->value=$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.\n");
          else
                $$=$1 / $3;
        }
        |       '-' expression %prec UMINUS     { $$ = -$2; }
        |       '(' expression ')'              { $$ = $2; }
        |       NUMBER                          { $$ = $1; }
        |       NAME                            { $$ = $1->value; }

%%

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

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

具有符号表的词法分析程序ch3-4.l

%{
#include "y.tab.h"
#include "ch3hdr.h"
#include <math.h>
#undef yywrap
%}

%%
([0-9]+|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?)     {
                yylval.dval = atof(yytext);
                return NUMBER;
        }
[ \t] ;
[A-Za-z][A-Za-z0-9]*    {
                yylval.symp=symlook(yytext);
                return NAME;
        }
"$"     { return 0; }
\n      |
.       return yytext[0];
%%

int yywrap()
{
        return 1;
}

struct symtab *
symlook(char *s){
        char *p;
        struct symtab *sp;
        for(sp=symtab;sp<&symtab[NSYMS];sp++){
                if(sp->name && !strcmp(sp->name,s))
                        return sp;
        if(!sp->name){
                sp->name=strdup(s);
                return sp;
                }
        }
        yyerror("Too many symbols.");
        exit(1);
}

编译和运行:

[postgre@host132 ch3]$ yacc -d ch3-4.y
[postgre@host132 ch3]$ lex ch3-4.l
[postgre@host132 ch3]$ cc -o test lex.yy.c y.tab.c
[postgre@host132 ch3]$ ./test 
foo=23
foo/5
=4.6
abc=34
3*abc
=102
$
[postgre@host132 ch3]$
发布了8 篇原创文章 · 获赞 2 · 访问量 210

猜你喜欢

转载自blog.csdn.net/sxqinjh/article/details/104660169