因为这次加入了字符变量名,所以不能再用默认的yylval(int),这次使用的是一个union,
%union{
double dval;//double val
int vblno;//varible number 讨厌缩写,实在是读着麻烦
}
dval代表原来的NUMBER,不过这次支持了double,
vlbno代表的是字符变量名,在符号表里面的地址
仍然在词法分析的时候给yylval赋值,只不过遇到数字付给dval,如果是变量名字,那就设置vblno
完整的程序代码
cal.y
%{
#include <stdio.h>
double vbltable[26];
%}
%union{
double dval;
int vblno;
}
%token PRINT
%token <vblno> NAME
%token <dval> NUMBER
%type <dval> expression
%left '+' '-'
%left '*' '/'
%%
paragraph:
paragraph statement '\n'
|statement '\n'
;
statement:
PRINT expression {
printf("\ntest yacc PRINT expression\n");
printf("result is %lf", $2);
}
|NAME '=' expression {
printf("\ntest yacc = expression\n");
vbltable[$1] = $3;
}
;
expression:
expression '*' expression {
printf("\ntest yacc expression + expression\n");
$$ = $1 * $3;
}
|expression '/' expression {
printf("\ntest yacc expression + expression\n");
$$ = $1 / $3;
}
|expression '+' expression {
printf("\ntest yacc expression + expression\n");
$$ = $1 + $3;
}
|expression '-' expression {
printf("\ntest yacc expression + expression\n");
$$ = $1 - $3;
}
|NUMBER {
printf("\ntest yacc NUMBER\n");
$$ = $1;
}
|NAME {
$$ = vbltable[$1];
}
;
%%
cal.l
%{
#include "y.tab.h"
#include <math.h>
extern double vbltable[26];
%}
%%
print {printf("\ntest lex print\n"); return PRINT;}
[0-9]+ |
[0-9]*\.[0-9]+ {printf("\ntest lex NUMBER\n");yylval.dval = atof(yytext); return NUMBER;}
[ \t] ;
[a-z] {yylval.vblno = yytext[0] - 'a'; return NAME;}
"$" {return 0;}
\n |
. {printf("\ntest lex %s", yytext); return yytext[0];}
%%
编译代码
nosourcesmatoMacBook-Pro:vtable nosources$ yacc -d cal.y && lex cal.l && cc -o calex.yy.c -ly -ll
nosourcesmatoMacBook-Pro:vtable nosources$ ./cal
a=1+2
test lex =
test lex NUMBER
test yacc NUMBER
test lex +
test lex NUMBER
test yacc NUMBER
test lex
test yacc expression + expression
test yacc = expression
print a
test lex print
test lex
test yacc PRINT expression
result is 3.000000
全部的输入语句,a=1+2,就在符号表里面的a对应的位置赋值为1+2,然后print a,语句输出符号表里面a的位置的值