数式の評価を便利な道具で #3
実際、デバグプリント付きで見てみると、
calc.l
%{ #include <gmp.h> #include "calc.tab.h" #define YY_USER_INIT init_yylval() void init_yylval(void); int yylex(void); #define CHECK_MPZ(s,p) gmp_printf("[lexer] "s"(%p)\n",(p)->_mp_d); void init_yylval(void) { mpz_init(yylval.val); CHECK_MPZ("init", yylval.val); } %} %option nounput %option noyywrap %% [ \t] {} [0-9]+ { mpz_set_str(yylval.val, yytext, 10); CHECK_MPZ("set", yylval.val); return UINT; } .|\n { return yytext[0]; } <<EOF>> { CHECK_MPZ("clear", yylval.val); mpz_clear(yylval.val); return -1; } %%
calc.y
%{ #include <stdio.h> #include <gmp.h> int yylex(void); void yyerror(char *s); #define CHECK_MPZ(s,p) gmp_printf("[parser] "s"(%p)\n",(p)->_mp_d); %} %union { mpz_t val; } %token <val> UINT %left '+' %left '*' %type <val> expr %% stmt: /* empty */ | stmt '\n' | stmt expr '\n' { gmp_printf("%Zd\n", $2); CHECK_MPZ("clear", $2); mpz_clear($2); } | error '\n' { yyerrok; } ; expr: UINT { mpz_init($$); CHECK_MPZ("init", $$); mpz_set($$, $1); CHECK_MPZ("set", $$); } | expr '+' expr { mpz_init($$); CHECK_MPZ("init", $$); mpz_add($$, $1, $3); CHECK_MPZ("add", $$); CHECK_MPZ("clear", $1); CHECK_MPZ("clear", $3); mpz_clears($1, $3, NULL); } | expr '*' expr { mpz_init($$); CHECK_MPZ("init", $$); mpz_mul($$, $1, $3); CHECK_MPZ("mul", $$); CHECK_MPZ("clear", $1); CHECK_MPZ("clear", $3); mpz_clears($1, $3, NULL); } ; %% int main(void) { yyparse(); return 0; } void yyerror(char *s) { gmp_printf("%s\n", s); }
$ ./calc [lexer] init(003E24D0) 1+2*3 [lexer] set(003E24D0) [parser] init(003E2540) [parser] set(003E2540) [lexer] set(003E24D0) [parser] init(003E2550) [parser] set(003E2550) [lexer] set(003E24D0) [parser] init(003E2560) [parser] set(003E2560) [parser] init(003E2570) [parser] mul(003E2570) [parser] clear(003E2550) [parser] clear(003E2560) [parser] init(003E2560) [parser] add(003E2560) [parser] clear(003E2540) [parser] clear(003E2570) 7 [parser] clear(003E2560) 1+2* [lexer] set(003E24D0) [parser] init(003E2560) [parser] set(003E2560) [lexer] set(003E24D0) [parser] init(003E2570) [parser] set(003E2570) syntax error 1+2 [lexer] set(003E24D0) [parser] init(003E2540) [parser] set(003E2540) [lexer] set(003E24D0) [parser] init(003E2550) [parser] set(003E2550) [parser] init(003E2580) [parser] add(003E2580) [parser] clear(003E2540) [parser] clear(003E2550) 3 [parser] clear(003E2580) [lexer] clear(003E24D0) $
同一アドレスに対するinitとclearの組を見れば分かるように、
「1+2*」という文法に合わない入力に対して、
割り付けられた2つの領域がclearされず、
メモリリークを引き起こしていることが分かる。