数式の評価を便利な道具で #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されず、
メモリリークを引き起こしていることが分かる。