コンパイラ作成(98) 配列の宣言
今回の目標
いきなりだけど配列に手を出してみるよ。
// 配列 int main() { int a[10], b; }
まずは配列変数の宣言から。
Lexer
gettokenの修正。
# symbolの切り出し elsif m = @line[@idx,@line.length] .match(/^(==|!=|<=|>=|=|<|>|\+|\-|\*|\/|\%|&|:|,|;|\(|\)|\{|\}|\[|\])/) then str = m.to_s @idx += str.length return TK::SYMBOL, str end
括弧[]をを追加しただけ。
変数宣言
# 変数宣言の処理 def var_decl(kind, str) basetype = str loop do type = basetype ary = "" ary_size = nil kind, str = @lex.gettoken loop do if kind != TK::SYMBOL || str != "*" then break end type += str kind, str = @lex.gettoken end if kind != TK::ID then perror end var_name = str skind, sstr = @lex.gettoken if skind == TK::SYMBOL && sstr == "[" then ary += sstr skind, sstr = @lex.gettoken if skind != TK::NUMBER then perror end ary += sstr ary_size = sstr.to_i skind, sstr = @lex.gettoken if skind != TK::SYMBOL || sstr != "]" then perror end ary += sstr skind, sstr = @lex.gettoken end print "var #{var_name}:#{type}#{ary}\n" if $opt_d if ary_size then @lvarsize += (sizeof(type) * ary_size) else @lvarsize += sizeof(type) end if check_var str then perror "redefinition variable \"" + var_name +"\"" end if type == "void" then perror "invalid type 'void'" end set_var var_name, [type+ary,@lvarsize] if skind == TK::SYMBOL && sstr == "=" then kind, str = expr2 kind, str, skind, sstr; else kind, str = skind, sstr; end if kind != TK::SYMBOL || str != "," then break end end return kind, str end
変数の型をどう表現するか悩んだけどint[10]と表わすことにしたよ。扱いやすい形式じゃないから将来見直すかも。配列のサイズ情報は別に持った方が良いかもなあ。悩ましいけどとりあえずこれで実装してみるよ。あと配列の初期化については今のとこ考慮してないよ。多次元配列とかもね。まずは一番シンプルなとこから行くよ。
動作テスト
~/myc$ myc -dc q.myc var a:int[10] var b:int {"a"=>["int[10]", 40], "b"=>["int", 44]} {"main"=>["int", []]} ~/myc$
ちゃんと40byteの領域が確保されてる。大丈夫そうだね。えーと、次はポインターへの代入とかやってみるかな。割と簡単そうだしね。配列への代入や参照は難しそうだもんなあ。頑張ってちょっとずつ実装してこう。