# 第8章: 簡易インタプリタ シェルの上で動く小さな言語処理系を作ります。 ## サンプルコード - ディレクトリ: `docs/os-on-arduino/code/08_interpreter` - ビルドと書き込み: ```bash uv run pio run -d 08_interpreter -t upload uv run pio device monitor -b 115200 ``` コードを見る: [docs/os-on-arduino/code/08_interpreter](https://github.com/iory/learning-os-from-arduino/tree/main/docs/os-on-arduino/code/08_interpreter) ## ソースコード この章のスケッチです。ファイル名をクリックすると開きます。コードは原稿リポジトリから自動で同期されているので、ここに出ているものが常に最新です。 :::{dropdown} `src/main.cpp` — 53 行 :icon: code [GitHub で開く](https://github.com/iory/learning-os-from-arduino/blob/main/docs/os-on-arduino/code/08_interpreter/src/main.cpp) ```{literalinclude} ../../../../code/08_interpreter/src/main.cpp :language: cpp :linenos: ``` ::: :::{dropdown} `include/interpreter.h` — 36 行 :icon: code [GitHub で開く](https://github.com/iory/learning-os-from-arduino/blob/main/docs/os-on-arduino/code/08_interpreter/include/interpreter.h) ```{literalinclude} ../../../../code/08_interpreter/include/interpreter.h :language: cpp :linenos: ``` ::: :::{dropdown} `include/os_display.h` — 18 行 :icon: code [GitHub で開く](https://github.com/iory/learning-os-from-arduino/blob/main/docs/os-on-arduino/code/08_interpreter/include/os_display.h) ```{literalinclude} ../../../../code/08_interpreter/include/os_display.h :language: cpp :linenos: ``` ::: :::{dropdown} `include/os_fault.h` — 46 行 :icon: code [GitHub で開く](https://github.com/iory/learning-os-from-arduino/blob/main/docs/os-on-arduino/code/08_interpreter/include/os_fault.h) ```{literalinclude} ../../../../code/08_interpreter/include/os_fault.h :language: cpp :linenos: ``` ::: :::{dropdown} `include/os_kernel.h` — 75 行 :icon: code [GitHub で開く](https://github.com/iory/learning-os-from-arduino/blob/main/docs/os-on-arduino/code/08_interpreter/include/os_kernel.h) ```{literalinclude} ../../../../code/08_interpreter/include/os_kernel.h :language: cpp :linenos: ``` ::: :::{dropdown} `include/servo_pwm.h` — 61 行 :icon: code [GitHub で開く](https://github.com/iory/learning-os-from-arduino/blob/main/docs/os-on-arduino/code/08_interpreter/include/servo_pwm.h) ```{literalinclude} ../../../../code/08_interpreter/include/servo_pwm.h :language: cpp :linenos: ``` ::: :::{dropdown} `include/shell.h` — 23 行 :icon: code [GitHub で開く](https://github.com/iory/learning-os-from-arduino/blob/main/docs/os-on-arduino/code/08_interpreter/include/shell.h) ```{literalinclude} ../../../../code/08_interpreter/include/shell.h :language: cpp :linenos: ``` ::: :::{dropdown} `src/interpreter.cpp` — 288 行 :icon: code [GitHub で開く](https://github.com/iory/learning-os-from-arduino/blob/main/docs/os-on-arduino/code/08_interpreter/src/interpreter.cpp) ```{literalinclude} ../../../../code/08_interpreter/src/interpreter.cpp :language: cpp :linenos: ``` ::: :::{dropdown} `src/os_display.cpp` — 162 行 :icon: code [GitHub で開く](https://github.com/iory/learning-os-from-arduino/blob/main/docs/os-on-arduino/code/08_interpreter/src/os_display.cpp) ```{literalinclude} ../../../../code/08_interpreter/src/os_display.cpp :language: cpp :linenos: ``` ::: :::{dropdown} `src/os_fault.cpp` — 170 行 :icon: code [GitHub で開く](https://github.com/iory/learning-os-from-arduino/blob/main/docs/os-on-arduino/code/08_interpreter/src/os_fault.cpp) ```{literalinclude} ../../../../code/08_interpreter/src/os_fault.cpp :language: cpp :linenos: ``` ::: :::{dropdown} `src/os_kernel.cpp` — 241 行 :icon: code [GitHub で開く](https://github.com/iory/learning-os-from-arduino/blob/main/docs/os-on-arduino/code/08_interpreter/src/os_kernel.cpp) ```{literalinclude} ../../../../code/08_interpreter/src/os_kernel.cpp :language: cpp :linenos: ``` ::: :::{dropdown} `src/shell.cpp` — 237 行 :icon: code [GitHub で開く](https://github.com/iory/learning-os-from-arduino/blob/main/docs/os-on-arduino/code/08_interpreter/src/shell.cpp) ```{literalinclude} ../../../../code/08_interpreter/src/shell.cpp :language: cpp :linenos: ``` ::: ## 実機での出力 Arduino UNO R4 WiFi の実機で実際に取得した出力です(macOS / Windows の 両方で同じ結果を確認しています)。手元の出力と見比べてください。 `run FORWARD 10` と `run PRINT hello` を送ったところです。 ```{figure} ../_static/ch08_interpreter.gif :name: fig-ch08-interpreter :width: 100% 自作インタプリタにコマンドを打ち込んでいるところ。`PRINT` は `[Print]`、`FORWARD` は `[Motor]` に届きます ``` ```text run FORWARD 10 [Interpreter] Loaded 1 lines [Interpreter] Starting script... [Motor] Forward 10 units [Interpreter] Script completed: 1 commands executed > run PRINT hello [Interpreter] Loaded 1 lines [Interpreter] Starting script... [Print] hello [Interpreter] Script completed: 1 commands executed > ``` ### シミュレータで見る 実機が無くても、同じファームウェアを {doc}`シミュレータ <../getting-started/simulator>` で動かすとこう見えます。 ```{figure} ../_static/sim_ch08_led.gif :name: fig-ch08-sim :width: 80% `LED` タスクが L を 500ms ごとに反転させ続けるので、先に `kill 1` で止めてから、インタプリタで `run LED 13 1`(点灯)、`run LED 13 0`(消灯)を実行しています。`LED` タスクを止めないと、次の反転で上書きされます。(シミュレータで撮影) ``` ## 改良版: `08_interpreter_v2`(書籍未掲載) 第8章の LED マトリクスの表示は第7章と同じもので、読み取りにくさも同じです ({doc}`ch07` の「改良版」を参照)。そこで第7章の [`07_led_matrix_v2`](https://github.com/iory/build-your-own-arduino-rtos/tree/main/code/07_led_matrix_v2) と同じ表示とシェルの `top` を入れた改良版を [`code/08_interpreter_v2`](https://github.com/iory/build-your-own-arduino-rtos/tree/main/code/08_interpreter_v2) に置きました。インタプリタとカーネルは本書と同じです。 書籍のリポジトリには入っていないので、このサイトのリポジトリから取ってきて 書き込みます(第7章の改良版で clone 済みなら、`build-your-own-arduino-rtos/code` で 書き込みの行だけで済みます)。 ```bash git clone https://github.com/iory/build-your-own-arduino-rtos.git cd build-your-own-arduino-rtos/code uv sync uv run pio run -d 08_interpreter_v2 -t upload uv run pio device monitor -b 115200 ``` | 行 | 中身(どれも 12 個で 100%、0.5 秒ごとに更新) | |---|---| | 0–1 | CPU 全体の負荷(idle 以外) | | 2 | 空き | | 3–7 | LED / Shell / Display / Light / Heavy の CPU 使用率 | 第8章のタスク(LED・Shell・Display)はどれもほとんど CPU を使いません。LED タスクの 反転も、インタプリタの `FORWARD` / `TURN` / `DELAY` も `os_sleep()` で眠って待つので、 眠っている間 CPU はほかのタスクに回ります。棒が動くように、第7章の改良版と同じ Light(CPU を 20 ms 使っては 60 ms 眠る)と Heavy(眠らずに計算し続ける)を、本書の 3 つのタスクの後ろに足しました。LED・Shell・Display のタスク番号は本書と同じなので、 `kill 1` → `run LED 13 1` の手順もそのまま使えます。 ```{raw} html ``` 実機(UNO R4 WiFi)の `top` の値は次のとおりです。 | 操作 | CPU 全体 | 目に見えること | |---|---|---| | 起動直後 | 約 60% | Light(16%)と Heavy(40%)の行に棒 | | `kill 5` | 約 24% | Heavy の棒が消え、全体の棒が縮む | | `kill 4` | 約 4% | 残るのは `top` を描いている Shell だけ | | `exec 4` / `exec 5` | 元に戻る | | ```{note} `run` でスクリプトを実行している間は、`top` の表示が止まります。描き直すのがシェルの 入力待ちの中なので、スクリプトが終わるまで更新されません。マトリクスは表示のタスクが 描くので、その間も動きます。 ``` ## つまずきやすいポイント (読者からの質問に応じて随時追記します。質問は [GitHub Issues](https://github.com/iory/build-your-own-arduino-rtos/issues) へどうぞ)