flex/bison テスト

構文解析って、手書きかnotavaCCでしかやったこと無い。なので一度lex/yaccなものをいじるべきだと思った。
とりあえず電卓づくり。
flexドキュメントの例ほぼそのまま。 http://www.asahi-net.or.jp/~wg5k-ickw/html/online/flex-2.5.4/flex_6.html#SEC32
整数だけの計算のときは整数演算するようにしてみた。そんだけ。

% flex -I expr.l
% bison -d -y expr.y
% gcc y.tab.c lex.yy.c -lfl
% ./a.out
3.
3.000000
% ./a.out
3+3*2-1
8
3+3*2-0.1
8.900000
1+2+(3.0+4.0)-5
5.000000
/**
* expr.l
**/
%{
#include "y.tab.h"
%}

%%

[0-9]+     {
             yylval.ival = atof(yytext);
             return(INTEGER);
           }
[0-9]+\.[0-9]* {
             sscanf(yytext,"%f",&yylval.fval);
             return(FLOAT);
           }
"+"        return(PLUS);
"-"        return(MINUS);
"*"        return(MULT);
"/"        return(DIV);
"("        return(LB);
")"        return(RB);
\n         return(EOL);
.          {
             yyerror("Illegal character");
             return(EOL);
           }
%%
/**
* expr.y
**/
%{
#include <stdio.h>
%}

%union {
   int ival;
   float fval;
}

%token INTEGER FLOAT
%token PLUS MINUS MULT DIV
%token EOL
%token LB RB

%left  MINUS PLUS
%left  MULT DIV

%type  <ival> ival INTEGER
%type  <fval> fval FLOAT

%%
input   :
        | input line
        ;

line    : EOL
        | ival EOL { printf("%d\n",$1);}
        | fval EOL { printf("%f\n",$1);}
        ;

fval    : FLOAT { $$ = $1;}
        | fval PLUS fval { $$ = $1 + $3;}
        | fval PLUS ival { $$ = $1 + $3;}
        | ival PLUS fval { $$ = $1 + $3;}
        | fval MINUS fval { $$ = $1 - $3;}
        | fval MINUS ival { $$ = $1 - $3;}
        | ival MINUS fval { $$ = $1 - $3;}
        | fval MULT fval { $$ = $1 * $3;}
        | fval MULT ival { $$ = $1 * $3;}
        | ival MULT fval { $$ = $1 * $3;}
        | fval DIV fval { $$ = $1 / $3;}
        | fval DIV ival { $$ = $1 / $3;}
        | ival DIV fval { $$ = $1 / $3;}
        | MINUS fval %prec MINUS { $$ = -$2;}
        | LB fval RB              { $$ = $2;}
        ;
ival    : INTEGER { $$ = $1;}
        | ival PLUS ival { $$ = $1 + $3;}
        | ival MINUS ival { $$ = $1 - $3;}
        | ival MULT ival { $$ = $1 * $3;}
        | ival DIV ival { $$ = $1 / $3;}
        | MINUS ival %prec MINUS { $$ = -$2;}
        | LB ival RB              { $$ = $2;}
        ;
%%

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

int main()
{
  yyparse();
}

test