クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

パーサーが見逃す誤りを見つける(意味解析)

このレッスンのあとで: パーサーには見つけられない誤りを見つけられる。

50分のレッスンコマンド13件コンパイラとアーキテクチャのラボ:gcc、flex、bison、RISC-V を1台の VM で

文法どおりなのに動かない

売上を集計するスクリプトに、show total + step という行があります。文法には合っていて、トークンもどれも正しいものです。

でも step は、もう終わったループの中にしかありませんでした。パーサーが調べるのは文の形で、意味が通るかではありません。意味を調べるのは、コンパイラの次の部分です。

このレッスンのゴール

メモ

パーサーには見つけられない誤りを見つけられる。

重要な言葉

ことばいみれい
意味解析プログラムの意味が通るかを調べること
宣言名前を使えるようにする行int step
スコープある名前が使える、プログラムの範囲
記号表スコープにある名前を、コンパイラが記録する表
型値がどんな種類かint
警告ビルドを止めないメッセージ

学生が入力するセルは、このプレビューでは空白です。

コンパイラは名前の表を持つ

コンパイラは構文木をたどりながら、記号表を持ちます。{ で新しいスコープが表の上に積まれ、宣言は一番上のスコープに名前を足します。} で一番上のスコープが捨てられます。

名前を調べるときは、一番上のスコープから下へ順に探します。どこにもなければ、宣言されていない名前です。Run で、scope.c の step がどこにあるかを見ます。

コンパイラのフォルダに入る

コマンド
cd ~/compiler

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

step が出てくる行

コマンド
grep -n "step" scope.c

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

例: scope.c の記号表

行起きることスコープにある名前
4と5main が unused と total を宣言するunused, total
6ループがスコープを開き、i を宣言するunused, total | i
7ループの中身が step を宣言するunused, total | i | step
9ループが終わり、そのスコープが捨てられるunused, total
10printf が step を使う。見つからないunused, total

学生が入力するセルは、このプレビューでは空白です。

追加の検査なしでコンパイル

コマンド
gcc -c scope.c

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

よくある警告も頼む

コマンド
gcc -Wall -c scope.c

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

オブジェクトファイルはできたか

コマンド
ls scope.o

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

関数の宣言と呼び出しを比べる

コンパイラは、式ごとの型も求め、使う場所に合うかを調べます。square は int を1つ受け取ると宣言されています。

最初の Run は、square(7, 8) と呼ぶコピー args.c を作ります。もとの hello.c は変わりません。呼び出しの形は文法に合っていますが、宣言とは合いません。次の Run でコンパイルします。

引数が多すぎるコピー

コマンド
sed "s/square(7)/square(7, 8)/" hello.c > args.c

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

コピーをコンパイルする

コマンド
gcc -Wall -c args.c

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

エラーは止め、警告は止めない

次のコピー kata.c は、printf に数を出す %d を頼み、文字列を渡します。gcc は printf の書式の読み方を知っているので、型を比べられます。

今度は警告です。ビルドは進み、ls で kata.o ができたと分かります。エラーのあとでは、オブジェクトファイルはできません。

書式の型が違うコピー

コマンド
sed "s/%s: 7/%d: 7/" hello.c > kata.c

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

コンパイルする

コマンド
gcc -Wall -c kata.c

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

今度はできたか

コマンド
ls kata.o

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

よくある間違い

注意

ビルドが通るのだから、警告は無視してよいと思いがちです。警告は、文法の上では正しいが、おそらく誤りだ、というコンパイラの知らせです。kata.c は通りますが、動かすと文字列のアドレスを数として出します。警告は、安全な理由が分かるまで不具合として扱います。

Python は動かしながら調べる

C は、名前と型を実行の前に調べます。これを静的な検査と言います。Python は、その行を実行するときに初めて調べ、そのときエラーになります。

下の3つの Run は、どれもプログラムを起動します。どの誤りも、Python がその行に来るまで見つかりません。

Python が知らない名前

コマンド
python3 -c "print(price)"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

足せない2つの型

コマンド
python3 -c "print('500' + 1)"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

長さのない値

コマンド
python3 -c "print(len(500))"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

さらに挑戦: 使われない名前

課題のチェッカーに、3つ目の種類 "unused" を足しましょう。宣言されたのに一度も使われない名前を、宣言した行の番号で報告します。スコープが閉じるとき、またはプログラムの終わりに調べます。

PROGRAM の最初に var spare = 1 を足して確かめましょう。そして、gcc が unused は -Wall のときだけ報告し、step はいつも報告する理由を説明しましょう。

このラボとソースについて: コンパイラとアーキテクチャのラボ:gcc、flex、bison、RISC-V を1台の VM で

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。