簡単な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)
標準入力から、セミコロンで区切られた自然数の加算と乗算の式を読み込み、
標準出力に 結果を出力します。
続く。