スクリプト言語の仕様を策定しつつ構文解析します
本題に入る前に。identの扱いですが、crc16でハッシュ値にしてもちまわることにしました。
ここまで考えた。
enum e_expression { EXPR_TYPE_NOT , // 'not' <expr> EXPR_TYPE_LITERAL, // (<number>|<string>|<flag>) EXPR_TYPE_ARRAY , // '[' [<expr> ',']* <expr> ']' EXPR_TYPE_VAR , // <ident> EXPR_TYPE_LET , // 'let' <ident> <expr> EXPR_TYPE_IF , // 'if' <expr> 'then' <expr> ['else' <expr>] EXPR_TYPE_LOOP , // 'loop' <expr> ';' <expr> ';' <expr> <expr> EXPR_TYPE_CALC , // ('add'|'sub'|'mul'|'div'|'mod') <array> EXPR_TYPE_LOGIC , // ('and'|'or') <array> EXPR_TYPE_GUARD , // ('lt'|'gt'|'eq') <expr> <expr> EXPR_TYPE_MULTI , // '{' [<expr> ',']* <expr> '}' EXPR_TYPE_CALL // '#' <ident> <array> }; enum e_literal { LIT_FLAG, LIT_INTEGER, LIT_STRING, LIT_ARRAY };
まだexpressionだけだけど勘弁
んでもってこれをもとに構造体の定義(途中)をば
typedef struct _EXPR { enum e_expression type; union { int ident; /* EXPR_TYPE_VAR */ struct { /* EXPR_TYPE_LITERAL */ enum e_literal type; // () int num; char *str; } lit; struct { /* EXPR_TYPE_ARRAY */ int size; struct _EXPR **d; } ary; struct { /* EXPR_TYPE_GUARD */ enum e_operand type; struct _EXPR *left; struct _EXPR *right; } guard; . . . } d; } EXPR;
うんうん。
いまイメージしてるインタプリタの流れとしては
- tokenize関数でTOKEN*のストリーム(みたいなの)を生成
- syntax_analysis関数で複数の関数定義FUN*(未定義)の構文木をつくる
- 内部でexpression関数とかが呼ばれて、exprの式の構文解析をしてEXPR*の構文木をつくる
- 意味解析して無効な参照を見つける(余裕があったらここで末尾再帰の検出)
中間表現(まだ考えてない)を吐く
あ、で構文解析ですが
init_token_chain(chain); chain = tokenize(); cur = chain;
こんな感じでこの前の字句解析をさせてから始める
このcurをどんどん次に進めていきながら解析をするようにしようかなっておもう
void expression(EXPR *expr) { switch(cur->type) { case TOKEN_TYPE_SYMBOL : case TOKEN_TYPE_OPERAND: case TOKEN_TYPE_VARTYPE: case TOKEN_TYPE_RESVED : case TOKEN_TYPE_NUMBER : case TOKEN_TYPE_IDENT : case TOKEN_TYPE_STRING : case TOKEN_TYPE_EOF : default: fprintf(stderr, "SYNTAX ERROR: unknown syntax\n"); exit(EXIT_FAILURE); } }
このcase内でcur = cur->nextとかやっていろいろ動かす