久々にBison/Flex

簡単なDSLのスレッドセーフな構文解析エンジンを作る必要ができたので、いろいろ調べつつメモ。
構文解析器はBison、字句解析はFlexに作ってもらいます。
かなり昔に、”ぼくのかんがえたさいきょうのぷろぐらみんぐげんご”のソースを標準入力から読み込み、”ぼくのかんがえたさいきょうのぶいえむ”用のバイトコードを出力するプログラムを作ったことがあったので、Bison/Flex についてはなんとなく覚えています。

今回作るのは、

  • ポートをLISTEN
  • 接続を確立したらスレッド分岐
  • 設計したDSLで書かれたプログラムを受信し、結果を送信する。

というものです。

ですので、構文解析エンジンは最低限次のことを満たす必要があります。

  • 入力はファイルからではなく、文字列、文字バッファ、またはストリームから
  • 出力はストリームに
  • スレッドセーフ(再入可能)


とりあえず、練習用に簡単な電卓プログラムを作成。

main.y

%{
#include "stdio.h"
extern void yyerror(char *s);
%}

%union {
    int int_val;
}

%token <int_val> CONST_N
%token DELIM

%type <int_val> expr

%left OP_PLUS
%left OP_MUL

%%

program: expr { printf("%dn", $1); }

expr
    : CONST_N { $$ = $1; }
    | expr OP_PLUS expr { $$ = $1 + $3; }
    | expr OP_MUL expr { $$ = $1 * $3; }

%%

void yyerror(char *s) {
    printf("aaa%sn", s);
}

main.l

%{
#include "main.tab.h"
%}

%%

"+" { return OP_PLUS; }

"*" { return OP_MUL; }

";" { return DELIM; }

([[:digit:]]{-}[0])[[:digit:]]* { yylval.int_val = atoi(yytext); return CONST_N; }

([[:blank:]]|n)+ {}
. return yytext[0];

calc.c


#include "main.tab.h"

main() {
    yyparse();
}

Makefile

BISON = bison
FLEX = flex
BISON_Y = main.y
BISON_H = main.tab.h
BISON_C = main.tab.c
BISON_OUT = $(BISON_C) $(BISON_H)
BISON_O = main.tab.o
FLEX_L = main.l
FLEX_H = lex.yy.h
FLEX_C = lex.yy.c
FLEX_OUT = $(FLEX_C) $(FLEX_H)
FLEX_O = lex.yy.o
CALC_C = calc.c
CALC_O = calc.o
OBJS = $(BISON_O) $(FLEX_O) $(CALC_O)
TARGET = calc.exe

LDFLAGS = -lfl

all: $(TARGET)

$(BISON_OUT): $(BISON_Y)
	$(BISON) --defines=$(BISON_H) -o $(BISON_C) $(BISON_Y)

$(FLEX_L): $(BISON_H)

$(FLEX_OUT): $(FLEX_Y)
	$(FLEX) --header-file=$(FLEX_H) $(FLEX_L)

$(OBJS): $(BISON_OUT) $(FLEX_OUT) $(CALC_C)

$(TARGET): $(OBJS)
	$(CC) -o $@ $(OBJS) $(LDFLAGS)

clean:
	rm -f $(FLEX_OUT) $(BISON_OUT) $(OBJS) $(TARGET)
	

標準入力から、セミコロンで区切られた自然数の加算と乗算の式を読み込み、
標準出力に 結果を出力します。

続く。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です