プログラミング言語の作り方

javascript/C言語/アセンブラを用い、 字句解析、構文解析、インタプリタ、コンパイラのプログラムをスクラッチから作りながら、 「プログラミング言語の作り方」を解説する。

関数呼び出し対応
javascript版プログラミング言語の作り方(コンパイラ開発)

print文専用の構文解析をやめ、汎用的な関数呼び出しの構文解析に対応する。

ページメニュー

インタプリタ作成時にparserの処理を変更しているが、 それをコンパイラ側でも使うだけだ。

genasm.jsの実装

変更なし

コンパイラの実行

parserの処理を汎用的に変えたが、結果は同じだ。

$ ./compiler.js
処理前tokens =[
  'print',          '(',
  '"hello world"',  ')',
  ';',              'print',
  '(',              '"hello world2"',
  ')',              ';',
  'print',          '(',
  '"hello world3"', ')',
  ';'
]
抽象構文木ast={
  left: {
    left: {
      left: { left: 'print', op: '()', right: '"hello world"' },
      op: ';',
      right: { left: 'print', op: '()', right: '"hello world2"' }
    },
    op: ';',
    right: { left: 'print', op: '()', right: '"hello world3"' }
  },
  op: ';',
  right: undefined
}

hello world
hello world2
hello world3

コンパイラが出力したアセンブラ

コンパイラが出力したアセンブラ(source.s)を載せておく。

$ cat source.s

#intel表記を使う
.intel_syntax noprefix

#エントリポイント
.global _start
_start:

#.s1で定義されたリテラル文字列取得
lea r10,[.s1]
push r10

#アライメント8バイト伸ばす
sub rsp,8

#アライメント8バイト戻し
add rsp,8
pop rdi

#文字列をprintfするときは、rax=0でないとエラー
mov rax,0

#文字列表示
call printf

#改行コード.newline表示
lea rdi,[.newline]
call printf

#.s2で定義されたリテラル文字列取得
lea r10,[.s2]
push r10

#アライメント8バイト伸ばす
sub rsp,8

#アライメント8バイト戻し
add rsp,8
pop rdi

#文字列をprintfするときは、rax=0でないとエラー
mov rax,0

#文字列表示
call printf

#改行コード.newline表示
lea rdi,[.newline]
call printf

#.s3で定義されたリテラル文字列取得
lea r10,[.s3]
push r10

#アライメント8バイト伸ばす
sub rsp,8

#アライメント8バイト戻し
add rsp,8
pop rdi

#文字列をprintfするときは、rax=0でないとエラー
mov rax,0

#文字列表示
call printf

#改行コード.newline表示
lea rdi,[.newline]
call printf

#exit(0)で終了
end:
mov rdi,0
call exit

#printfで使う文字列リテラルを定義
.newline: .string "\n"
.fmtg: .string "%g"

#文字列リテラル.s連番で定義
.s1: .string "hello world"
.s2: .string "hello world2"
.s3: .string "hello world3"

このページの目次へ戻るサイトの最上位へ戻る