結局なにをどう変更したのか(まとめ)
結局、どこをいじったのかだけ見たい忙しい人向け。
これだけ読めばどこを変えたのかがわかる。
文の意味変わらないし、句読点ってなんなん?(3)
最終日を残して(実際の最終日は投稿日ではないのだがトップで断っている)だいたい実装を終えてしまった僕達であったが、";"落としたらいけない反例が見つかってしまった…
それは変数宣言後の";"である。つまり、
int main(){
int i
i=1
printf("%d\n",i)
}
はコンパイラーを通らないのだ。中間報告の際に友人や先生方から、「int ihoge」となっている可能性が";"によって否定されるからではないか、というアドバイスを頂いていたので(つまり変数宣言時は";"は単なる句読点としての役割以外にも役割があるのだ!)早速その構造の解明にとりかかった。
…のだが、結論から言うとわからなかった。一体どこで宣言の処理をしているのか皆目見当がつかない。
make_treeのような関数があり、そのなかで構文解析をしているように考えられるが再起の回数が多く追い切ることができなかった。もし次にまたgccを手探ることがあったならばここに再チャレンジしてみたい。
文の意味変わらないし、句読点ってなんなん?(2)
さて、前回アセンブリの領域に入ってしまい詰んでしまったように思われたがエラーを吐いている関数obj->func->exec_child()の引数に実行可能ファイルcc1が入っていることがわかった。
ここで/home/denjo/gcc_install/libexec/…/cc1をデバッグすることにした。与える引数は、"$ ./gcc -v wrong.c"で確認したところ
/home/denjo/repo/lecture_doss/gcc_install/libexec/gcc/x86_64-pc-linux-gnu/6.2.0/cc1 -quiet -v -imultiarch x86_64-linux-gnu test.c -quiet -dumpbase test.c -mtune=generic -march=x86-64 -auxbase test -version -o /tmp/ccrITzFM.s
であることがわかった。
cc1をデバッグしていくとdo_compileなどという関数に入り、デバッグを続けていくとc_parser_skip_until_found()という関数で文法の正当性を評価していることがわかった。
この関数のc_parser_requireに分け入ってみると、
このような関数になっており、ここがtrueになることがコンパイラを通過するための必要条件になっていることがわかった。
ここで各引数の値をチェックしてみる。trueを返している時の画像が
上であり、この時parser[0]->tokens[0]->typeとtypeを比較して、合致している時にtrueを返していることがわかった。
ちなみに落ちた時には parser[0]->tokens[0]->type=CPP_KEYBOARDS(?) みたいな感じだった。
というわけで文末の";"がないときにもあることにしちゃうためには
if(type=CPP_SEMICOLON){return ture;}
の一文を加えてやればいいのでは?という淡い期待を乗せて変更、makeしたところ…
$ ./gcc wrong.c
$ ./wrong.out
Hello World!
できた〜!
文の意味変わらないし、句読点ってなんなん?(1)
さて、前回で"hoge.c"をコンパイルしたときコマンド無しで"hode.out"となるような改造を実装できた。そこで次の目標を立てることにした。
みなさん、こんにちわ
と
みなさん、こんにちわ。
とで相手に伝わる意味が変わるのだろうか。変わらない。
あくまで句読点は文法上のルールであって意味が通じればいいじゃん!って場面では必要ないのではないか?
これって、C言語でも同じじゃないか??
printf("Hello World");
と
printf("Hello World")
とで意味変わらないだろ!理解しろよ、gcc!
と御託を並べたが、僕はたまに打ち漏らす";"によってコンパイラーに弾かれるとき「許してくれよ〜」ってなり書きなおすのが億劫だなって。
ここで次の目標を
test.c: In function ‘main’:
test.c:5:5: error: expected ‘;’ before ‘}’ token
}
^
このエラーを吐かないようにすること、とした。