昨日に引き続き、bisonを学習。
http://www.mi.s.osakafu-u.ac.jp/~kada/course-kitami/j3_03/bison.pdf
の「2.5 練習問題」をやってみました。
(1),(2)は解けたのですが、
(3)初期化されていない変数について、値を書き込むのではなく、値を使おうとするとエラーを報告するようにプログラムを改良しなさい。
という問題でつまずいています。
(1),(2)までの解答は以下です。
mfcalc2.y
%{ #include <math.h> #include "calc.h" %} %union { double val; symrec *tptr; } %token <val> NUM %token <tptr> VAR FNCT %type <val> exp %right '=' %left '-' '+' %left '*' '/' %left NEG %right '^' %% input: /* 空 */ | input line ; line: '\n' | exp '\n' { printf ("\t%.10g\n", $1); } | error '\n' { yyerrok; } ; exp: NUM { $$ = $1; } | VAR { $$ = $1->value.var; } | VAR '=' exp { $$ = $3; $1->value.var = $3; } | FNCT '(' exp ')' { $$ = (*($1->value.fnctptr))($3); } | exp '+' exp { $$ = $1 + $3; } | exp '-' exp { $$ = $1 - $3; } | exp '*' exp { $$ = $1 * $3; } | exp '/' exp { $$ = $1 / $3; } | '-' exp %prec NEG { $$ = -$2; } | exp '^' exp { $$ = pow($1, $3); } | '(' exp ')' { $$ = $2; } ; %% #include <stdio.h> int main() { init_table(); yyparse(); return 0; } void yyerror(char *s) { printf("%s\n", s); } /* (2) init => init_f */ struct init_f { char *fname; double (*fnct)(); }; /* (2) */ struct init_v { char *vname; double var; }; struct init_f arith_fncts[] = { "sin", sin, "cos", cos, "atan", atan, "ln", log, "exp", exp, "sqrt", sqrt, "fabs", fabs, /* (1) */ 0, 0 }; struct init_v const_vars[] = { /* (2) */ "PI", 3.14159, "E", 2.71828, 0, 0 }; symrec *sym_table = (symrec *)0; void init_table() { int i; symrec *ptr; for (i = 0; arith_fncts[i].fname != 0; i++) { ptr = putsym(arith_fncts[i].fname, FNCT); ptr->value.fnctptr = arith_fncts[i].fnct; } for (i = 0; const_vars[i].vname != 0; i++) { /* (2) */ ptr = putsym(const_vars[i].vname, VAR); ptr->value.var = const_vars[i].var; } } symrec *putsym(char *sym_name, int sym_type) { symrec *ptr; ptr = (symrec *)malloc(sizeof(symrec)); ptr->name = (char *)malloc(strlen(sym_name) + 1); strcpy(ptr->name, sym_name); ptr->type = sym_type; ptr->value.var = 0; ptr->next = (struct symrec *)sym_table; sym_table = ptr; return ptr; } symrec *getsym(char *sym_name) { symrec *ptr; for (ptr = sym_table; ptr != (symrec *)0; ptr = (symrec *)ptr->next) if (strcmp(ptr->name,sym_name) == 0) return ptr; return 0; } #include <ctype.h> int yylex() { int c; while ((c = getchar ()) == ' ' || c == '\t'); if (c == EOF) return 0; if (c == '.' || isdigit (c)) { ungetc(c, stdin); scanf("%lf", &yylval.val); return NUM; } if (isalpha (c)) { symrec *s; static char *symbuf = 0; static int length = 0; int i; if (length == 0) length = 40, symbuf = (char *)malloc (length + 1); i = 0; do { if (i == length) { length *= 2; symbuf = (char *)realloc(symbuf, length + 1); } symbuf[i++] = c; c = getchar(); } while (c != EOF && isalnum(c)); ungetc(c, stdin); symbuf[i] = '\0'; s = getsym(symbuf); if (s == 0) s = putsym(symbuf, VAR); yylval.tptr = s; return s->type; } return c; }
calc.h
struct symrec { char *name; int type; union { double var; double (*fnctptr)(); } value; struct symrec *next; }; typedef struct symrec symrec; extern symrec *sym_table; symrec *putsym (); symrec *getsym ();