Pascalでかんたんな自作言語のコンパイラを書いた

[かんたんな自作言語のコンパイラをいろんな言語で書いてみるシリーズ](https://memo88.hatenablog.com/entry/2020/08/30/132314) 17番目の言語は Pascal です。


Pascal 初めて書きました。処理系は Free Pascal です。いつもの通りでライフゲームのコンパイルが通ったのでヨシ、という程度の雑なものです。

https://github.com/sonota88/vm2gol-v2-pascal

# 移植元

https://memo88.hatenablog.com/entry/2020/05/04/155425

https://github.com/sonota88/vm2gol-v2

ライフゲームのプログラムだけコンパイルできればOKという簡単なコンパイラです。Ruby 版だとコンパイラ部分だけで 1000行くらい。

~~ベースになっているバージョンは [ステップ 58](https://github.com/sonota88/vm2gol-v2/tree/58) のあたり。~~
（2021-11-29 追記） [ステップ 62](https://memo88.hatenablog.com/entry/20210930_vm2gol_v2_62_case_when) の変更まで反映しました。



作り方はここに全部書いています（Ruby 版のものですが）: [vm2gol v2 製作メモ](https://memo88.hatenablog.com/entry/2019/05/04/234516)




# 動かし方の例

```sh
# ビルド ... bin/ 以下に実行ファイルが生成される
$ rake build-all

$ echo '
  func add(a, b) {
    return a + b;
  }

  func main() {
    call add(1, 2);
  }
' | bin/lexer | bin/parser | bin/codegen

# ↓アセンブリが出力される

  call main
  exit
label add
  push bp
  cp sp bp
  cp [bp:2] reg_a
  push reg_a
  cp [bp:3] reg_a
  push reg_a
  pop reg_b
  pop reg_a
  add_ab
  cp bp sp
  pop bp
  ret
label main
  push bp
  cp sp bp
  cp 2 reg_a
  push reg_a
  cp 1 reg_a
  push reg_a
  _cmt call~~add
  call add
  add_sp 2
  cp bp sp
  pop bp
  ret

# ... snip ...
```


# メモ


主な部分のサイズ（行数）はこんな感じ。

```
$ wc -l *.pas lib/{types,utils}.pas
  482 codegen.pas
  154 lexer.pas
  520 parser.pas
  222 lib/types.pas
  195 lib/utils.pas
 1573 合計
```



----


※ VB はほとんど書いたことがなく、一方 LibreOffice Basic の方は多少書いたことあるので、以下では LibreOffice Basic を挙げていますが、たぶん VB でも大体似た感じだと思います。

<!--
以下、 LibreOffice Basic と書いている箇所がありますが、 VB でも大体同じなんじゃないかと思います。

※ 以下、VB より LibreOffice Basic の方が触ったことあるので LibreOffice Basic と書いていますが、 VB でも大体似た感じだと思います。
-->

ちなみに少し前に LibreOffice Basic で書いたもの:

- [素朴な自作言語のコンパイラをLibreOffice Basicに移植した](https://qiita.com/sonota88/items/31c127c42a9722892aa8)
- [LibreOffice BasicでLispインタプリタ（mal）を書いた](https://qiita.com/sonota88/items/501f0efa437bc4d53cc7)


---

- 自分が知っているものの中では C と LibreOffice Basic の中間みたいな印象
    - Pascal + 動的型 → （VB） → LibreOffice Basic という流れ？
- string 型があって文字列の扱いは C より楽
- Emacs に pascal-mode をインストール……しなくてもすでに入っていた（インストールした記憶がないので最初から入ってた？）
    - デフォルト設定だとインデントがスペース3つ
- 今回は fpc をインストールした Docker イメージを使うようにしてみた
- 処理系に配慮された整理された文法になっていて、たとえば C コンパイラを作るより Pascal コンパイラを作る方がハードルが低そう（コンパイラというか主に構文解析部分？）
    - 教育的、というか元々教育目的として生まれた言語だそう
    - 言語処理系自作に興味がある人は触れておいて損はなさそう
    - 書籍『[コンパイラ 作りながら学ぶ](https://www.ohmsha.co.jp/book/9784274221163/)』の PL/0' も Pascal 系の言語
      - 参考: [書籍「コンパイラ 作りながら学ぶ」を読みながら JavaScript でコンパイラを実装してみた - Qiita](https://qiita.com/lambdataro/items/017d20d1024732332285)
      - 参考: [Delphi で PL/0 をコンパイルする - Qiita](https://qiita.com/ht_deko/items/a3080ec5a95e320eade1)

----

Pascal は今まで触れる機会がなくて全然知らない文化圏という意識でいたのですが、実際触ってみると完全に異文化ということもなくて、自分が書いたことのある言語でいえば LibreOffice Basic が近いです（とりあえず見た目は）。

<!--
後の言語に影響を与えているのが分かっておもしろいですね。

たとえば LibreOffice Basic
※ VB より LibreOffice Basic の方が触ったことあるので LibreOffice Basic としていますが、 VB でも大体似た感じだと思います。

- [LibreOffice BasicでLispインタプリタ（mal）を書いた](https://qiita.com/sonota88/items/501f0efa437bc4d53cc7)
- [素朴な自作言語のコンパイラをLibreOffice Basicに移植した](https://qiita.com/sonota88/items/31c127c42a9722892aa8)
-->

たとえば整数を2つ受け取って足した結果を返す関数は次のようになります。

```pascal
// Pascal

function add(a : integer; b : integer) : integer;
begin
  add := a + b;
end;
```

```vb
' LibreOffice Basic

function add(a, b)
  add = a + b
end function
```


- `return 返り値` ではなく `関数名 = 返り値` と書く
- 返り値の有無で `sub`（Pascal では `procedure`） と `function` を使い分ける
- 関数・プロシージャ呼び出し時に引数がない場合は括弧を省略可

といったあたりが Pascal 由来と思われます。構造体の扱いも似ているような？

書いているときの感触としては「LibreOffice Basic の変数に型が付いて、文法はなんとなく似ていて、低水準の操作ができる」みたいな感じでした。

<!--
----

```pascal
procedure foo();
var
  i : integer = 0;
begin
  i := i + 1;
  // ...
end;
```

変数への代入には `:=` を使う、ただし、var で宣言時に初期化する場合は `=` で OK。
これは Go に似ている……じゃなくて、 Go が Pascal から受け継いだんでしょうね。

Go が C に比べてパースしやすそうな文法になってる点にも Pascal 由来の文化を感じます。
-->

----

LibreOffice Basic 以外でも、JavaScript の `with` も Pascal 由来かな？ とか、Go の `:=` も Pascal 由来かな？ とか、 Scala や Rust、Zig など、コロンで区切って型を後置するのも Pascal 由来かな？ といった感じで、他の言語への影響と思われる（※確認はしていなくて、あくまで「思われる」という程度）要素がいろいろあって面白かったです。

（204-04-29 追記）[3. JavaScript 1.0 と JavaScript 1.1 - JavaScript: 最初の 20 年 (翻訳) - inzkyk.xyz](https://inzkyk.xyz/js_20_years/origins_of_javascript/javascript_1_0_and_1_1/) によれば、JavaScript の with は AWK 由来だそうです。

[Kuin](https://kuina.ch/kuin) の言語仕様の解説にも Pascal への言及がちらほら出てきますね。たとえば「[Kuin言語仕様3 演算子](https://kuina.ch/kuin/spec3)」など。


# 参考

- [Pascal入門 (全18回) - プログラミングならドットインストール](https://dotinstall.com/lessons/basic_pascal)
  - とりあえず最初にこれを見るのがおすすめ
- [変数の代入演算子と等価演算子について - Qiita](https://qiita.com/yaju/items/16d91d58ae65af1ecab9)
- (2019) [世界のプログラミング言語(22) 今も改良が続くPascal/Delphi言語の栄枯盛衰 | TECH+](https://news.mynavi.jp/article/programinglanguageoftheworld-22/)
- (2015) [Pascalは過小評価されている | スラド デベロッパー](https://developers.srad.jp/story/15/01/27/0543208/)





# 他の言語への移植

| 記事 | リポジトリ | 日付 |
| --- | --- | --- |
| [Haskell](https://memo88.hatenablog.com/entry/20210628_vm2gol_v2_haskell) | [github](https://github.com/sonota88/vm2gol-v2-haskell) | 2021-06-28 |
| [OCaml](https://memo88.hatenablog.com/entry/2021/06/26/054540) | [github](https://github.com/sonota88/vm2gol-v2-ocaml) | 2021-06-26 |
| [Julia](https://qiita.com/sonota88/items/b80696f23a08c3c2fc5d) | [github](https://github.com/sonota88/vm2gol-v2-julia) | 2021-05-03 |
| [Rust](https://memo88.hatenablog.com/entry/20210407_vm2gol_v2_rust) | [github](https://github.com/sonota88/vm2gol-v2-rust) | 2021-04-07 |
| [Crystal](https://qiita.com/sonota88/items/275c2b5407986b100cc8) | [github](https://github.com/sonota88/vm2gol-v2-crystal) | 2021-03-27 |
| [Kotlin](https://memo88.hatenablog.com/entry/2021/01/14/032813) | [github](https://github.com/sonota88/vm2gol-v2-kotlin) | 2021-01-14 |
| [Zig](https://memo88.hatenablog.com/entry/2021/01/07/235019) | [github](https://github.com/sonota88/vm2gol-v2-zig) | 2021-01-07 |
| [LibreOffice Basic](https://qiita.com/sonota88/items/31c127c42a9722892aa8) | [github](https://github.com/sonota88/vm2gol-v2-libreoffice-basic) | 2020-12-14 |
| [Go](https://memo88.hatenablog.com/entry/2020/09/25/073200) | [github](https://github.com/sonota88/vm2gol-v2-go) | 2020-09-25 |
| [PHP](https://memo88.hatenablog.com/entry/2020/09/18/193844) | [github](https://github.com/sonota88/vm2gol-v2-php) | 2020-09-18 |
| [C♭](https://memo88.hatenablog.com/entry/2020/09/13/133735) | [github](https://github.com/sonota88/vm2gol-v2-cflat) | 2020-09-13 |
| [Perl](https://memo88.hatenablog.com/entry/2020/09/08/053329) | [github](https://github.com/sonota88/vm2gol-v2-perl) | 2020-09-08 |
| [C](https://memo88.hatenablog.com/entry/2020/09/06/043607) | [github](https://github.com/sonota88/vm2gol-v2-c) | 2020-09-06 |
| [Java](https://memo88.hatenablog.com/entry/2020/08/30/121437) | [github](https://github.com/sonota88/vm2gol-v2-java) | 2020-08-30 |
| [Dart](https://memo88.hatenablog.com/entry/2020/08/22/162201) | [github](https://github.com/sonota88/vm2gol-v2-dart) | 2020-08-22 |
| [Python](https://qiita.com/sonota88/items/5267dcd4750235680c8f) | [github](https://github.com/sonota88/vm2gol-v2-python) | 2020-08-19 |
| [TypeScript (Deno)](https://memo88.hatenablog.com/entry/2020/08/15/114754) | [github](https://github.com/sonota88/vm2gol-v2-typescript/tree/20200815) | 2020-08-15 |