1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

基本情報の擬似言語が読みにくいのは「動かせない」から ── ブラウザで1行ずつ実行できるようにした

1
Posted at

はじめに

基本情報技術者試験の科目 B で出てくる「擬似言語」は、文法だけ見ればとても小さい言語です。変数宣言、if、while、for、配列、関数。それだけ。C や Java を書ける人なら 10 分で覚えられます。

それなのに、科目 B の正答率は上がりにくい。理由ははっきりしていて、問われているのが文法ではなく「実行したときに何が起きるか」だからです。そして擬似言語には処理系がありません。紙の上で変数の値を書き写しながら追うしかない。

なので、擬似言語をブラウザで実行できるようにしました。1 行ずつ進めて、変数がどう変わるかを見られます。

基本情報 擬似言語 実行シミュレーター

この記事では、そもそも科目 B のどこでつまずくのかを 4 つの具体例で整理したあと、ツールの中身(手書きのレキサ・パーサ・インタプリタ)の話を少しします。


つまずくのは文法ではなく「状態の変化」

科目 B の設問は、突き詰めると次の 2 種類しかありません。

  • このプログラムを実行したとき、出力される値はどれか
  • 空欄に入れる正しい記述はどれか

どちらも「頭の中で実行する」必要があります。文法を知っているかどうかはスタートラインで、そこから先は変数の値をどれだけ正確に追えるかの勝負です。

そして、追い方を間違えやすい箇所は毎回だいたい同じところに集まっています。


つまずきポイント 1: 配列の添字は 1 始まり

整数型の配列: 得点 ← {40, 50, 60, 70}
print(得点[1])
print(得点[3])

出力は 4060 です。5070 ではありません。

C、Java、Python、JavaScript はいずれも 0 始まりなので、プログラミング経験があるほど間違えます。試験の擬似言語だけは 1 始まりだと切り替える必要があります。

この 1 個のズレは、ループと組み合わさると全部の要素がずれるので影響が大きい。「arr[1] が先頭」と口に出して確認する癖をつけるのが早いです。

つまずきポイント 2: for の「〜まで」は終了値を含む

整数型: 合計 ← 0
for (i を 2 から 6 まで 2 ずつ増やす)
  合計 ← 合計 + i
endfor
print(合計)

i は 2、4、6 と変化して、出力は 12 です。

ここで 6 を含まないと考えると 2 + 4 = 6 になります。Python の range(2, 6) が 6 を含まないので、Python に慣れているほど引っかかります。さらに「2 ずつ増やす」を読み飛ばすと 2+3+4+5+6 = 20 になる。開始・終了・増分の 3 つを毎回確認するしかありません。

つまずきポイント 3: while を抜けた時点のカウンタ

整数型: i ← 1
整数型: 合計 ← 0
while (i ≦ 4)
  合計 ← 合計 + i
  i ← i + 1
endwhile
print(合計)
print(i)

合計 が 10 なのは分かりやすい。問題は i です。答えは 5 で、4 ではありません。

while は「条件を判定してから中身を実行する」を繰り返すので、ループを抜けた時点の変数は条件を満たさなくなった値になっています。「最後に処理した値」と「抜けた時点の値」は別物です。

これは探索処理で必ず効いてきます。

整数型の配列: 数値 ← {4, 8, 15}
整数型: 目標 ← 16
整数型: i ← 1
while (i ≦ 3 and 数値[i] ≠ 目標)
  i ← i + 1
endwhile
print(i)

見つからなかったので i4(要素数 + 1)になります。「ループを抜けた後に i ≦ 3 かどうかで見つかったか判定する」という定石は、この性質の上に成り立っています。

ついでに、この条件式は順序も重要です。i が 4 のとき 数値[4] を読めば範囲外アクセスですが、and は左が偽なら右を評価しない(短絡評価)ので落ちません。(数値[i] ≠ 目標 and i ≦ 3) と逆に書くと落ちます。

つまずきポイント 4: elseif は最初に成立した分岐だけ

整数型: 点数 ← 85
if (点数 ≧ 60)
  print("合格")
elseif (点数 ≧ 80)
  print("優秀")
else
  print("不合格")
endif

出力は 合格 だけです。85 は 80 以上でもありますが、2 つ目の条件はそもそも評価されません。

条件が重なるとき、判定の順序そのものが仕様になります。「優秀」を出したいなら厳しい順に並べ替える必要がある、というのが読み取れるかどうか。


動かして確かめられるようにした

上の 4 つはどれも「言われれば分かる」話です。問題は、試験中に自力で気づけるかどうか。そのためには一度自分の手で動かして、値が変わる瞬間を見ておくのが一番速いと思っています。

作ったツールでできることは 3 つです。

できること 中身
1 行ずつ実行 実行中の行がハイライトされ、変数テーブルが毎ステップ更新される
Python / TypeScript へ変換 同じロジックを知っている言語で読み直せる
練習問題 オリジナル 20 問。解答するとその場で正誤と解説が出る

すべてブラウザ内で完結していて、書いたコードはサーバに送信されません。

擬似言語をブラウザで動かせる実行シミュレーター

Python と並べると「1 始まり」の意味が分かる

変換機能を作ったのは、添字の話を口で説明するより並べたほうが早いからです。

擬似言語:

整数型の配列: 得点 ← {40, 50, 60, 70}
for (i を 1 から 4 まで 1 ずつ増やす)
  print(得点[i])
endfor

これを Python に変換すると、添字に -1 が付き、その理由がコメントで入ります。for の範囲も range(1, 4 + 1) になって、「〜まで」が閉区間だったことが目で見えます。

擬似言語と Python / TypeScript を横並びで比較する

構文別の解説と練習問題

構文ごとの解説を 6 本(変数 / 条件分岐 / while / for / 配列 / 関数)、練習問題を 20 問用意しました。

練習問題は 2 層に分けています。

  • 基礎 10 問: 上に挙げたような「読めれば解ける」パターン
  • 本番相当 10 問: 配列で表した連結リストの走査、挿入ソートの空欄補充、リングバッファのキュー、整列の交換回数、再帰、在庫[注文[i]] のような間接参照

すべてオリジナル問題です(IPA 公式の過去問は転載していません)。解答キーは全問インタプリタに実行させて検証しているので、「解説と実際の出力が違う」ことは起きません。

構文別レッスン 6 本 / 擬似言語の練習問題 20 問


実装の話: 処理系がないなら書けばいい

ここからはエンジニア向けの余談です。

擬似言語には公式の処理系がないので、IPA が公表している「試験で使用する情報技術に関する用語・プログラム言語など Ver.5.1」の擬似言語仕様を読んで、レキサ・パーサ・インタプリタを手書きしました。フロントエンドだけで完結しています。

全角記号と日本語キーワード

擬似言語は といった全角記号と、i を 1 から n まで 1 ずつ増やす のような日本語の for 構文を使います。レキサでは全角・半角の両方を受け付けて、から まで ずつ 増やす をキーワードトークンとして切り出しています。

識別子に日本語(漢字・カタカナ)が使えるので、そこも判定に入れる必要があります。

ステップ実行はジェネレータで書くと素直

「1 行ずつ実行」の実装は、インタプリタをジェネレータ関数にするのが一番きれいでした。

function* runFromState(state: ExecutionState): Generator<StepEvent> {
  for (const stmt of program.body) {
    yield { type: "before-stmt", pos: stmt.pos };  // ここで停止できる
    yield* execStatement(stmt, state);
  }
}

文を実行する前に yield すれば、呼び出し側は「次へ」が押されるまで待てます。状態機械を自前で持つ必要がなく、再帰的な構造(if の中の while の中の関数呼び出し)もそのまま yield* で伝播します。

はまったのは forwhile の 2 周目以降で、条件行のハイライトが出ないバグでした。ループ本体の外側で before-stmt を出していたのが原因で、ループ内で自前に管理する形に直しています。この手の「教材としての正しさ」は普通のインタプリタでは要求されない部分で、作っていて面白いところでした。


参考書

ツールはトレースの練習にはなりますが、出題パターンの網羅は書籍のほうが早いです。擬似言語まわりで実際に読んで良かったものを挙げておきます。


おわりに

科目 B が難しいのは、アルゴリズムが難しいからというより、処理系のない言語を頭の中で実行させられるからだと思っています。だったら処理系を用意すればいい、というのが今回作ったものの動機です。

紙で追うトレースは本番で必要なスキルなので置き換えるつもりはありませんが、最初の 1 回だけは動かして見たほうが速く腹落ちするはずです。


本記事には Amazon アソシエイトのリンクが含まれます。リンク経由で購入いただくと運営者に紹介料が入りますが、価格は変わりません。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?