N. Wirth の Compiler Construction
Wirth の Compiler Contruction という本が無料公開されていまして、Wirth の Oberon 言語のサブセットの Oberon-0 言語のコンパイラの作り方を開陳して Oberon 言語で実装しています。対象機械としては簡潔な RISC の模型を想定して、そのエミュレータ用の機械語を出力するようになっています。エミュレータも Oberon で書かれていますがとても短く簡潔なものになっています。
しかし Wirth が Oberon の仕様を何度も改定し、Compiler Construction も改訂を繰り返すので RISC の仕様が変動しネットに落ちている Oberon + Oberon-0 の組み合わせで中々エラーなしに動くものが見つかりません。
Oberon + Oberon-0 組み合わせ
ネットを検索していたところ、以下のレポジトリで Java code を吐く Oberon-07 上で、Oberon-0 を動くようにしてくれていることが分かりました。
How to build に従ってまず Oberon-07 で`Oberon-0 をコンパイルし java 用のバイナリをつくり、その後は java 上の Oberon-0 でコンパイル&RISC エミュレータ上での実行となります。
Fortran で Oberon-0 用 RISC エミュレータ
Oberon-0 の吐き出す仮想のモデル RISC 用のオブジェクトを実行するエミュレータを Fortran でも試みました。まだデバッグ中ですが、メモ帳代わりに張り付けておきますw
Oberon-0 ソースプログラム File unko.Mod
ファイル名と Module 名が一致していないと駄目なようです。
MODULE unko; PROCEDURE go; BEGIN WriteChar("F"); WriteChar("o"); WriteChar("r"); WriteChar("t"); WriteChar("r"); WriteChar("a"); WriteChar("n"); WriteLn; END go; BEGIN go END unko.
生成オブジェクト
Oberon-0 のソースファイルの一つ OSG.Mod 中の Execute プロシージャを書き換えて生成オブジェクトを画面に書き出し、コピペして fort.10 というファイルに保存し、これを Fortran から読み込むこととします。
PROCEDURE Execute*; VAR i: INTEGER; BEGIN i:=0; WHILE i < 100 DO Out.Int(code[i],8);Out.Ln; i:=i+1 END; RISC.Execute(code, pc) END Execute;
-419430372 1323892740 -1344274432 1073741894 1359020024 -1609564160 1073741935 1359020024 -1609564160 1073741938 1359020024 -1609564160 1073741940 1359020024 -1609564160 1073741938 1359020024 -1609564160 1073741921 1359020024 -1609564160 1073741934 1359020024 -1609564160 1342242804 -1610612736 -1881145344 1323827204 -956301297 -134217757 1073741824 -956301312 0 0 0 0 0 0 0 0 0
Oberon-0 Compiler OSP 30.10.2013 compiling unko code generated 32 0 Fortran
Fortran ソースプログラム
Fortran は符号なし整数が無く、元のままではうまくゆかないので、ビット演算を用いました。
(R2/9/15) bugfix
program risc implicit none integer, parameter :: & MOV = 0, Lsl = 1, Asr = 2, Ror = 3, AND = 4, ANN = 5, JOR = 6, XOR = 7, & ADD = 8, SUB = 9, MUL = 10, Div = 11 integer :: ir, pc, h = 0! instruction register, program counter, aux registere for division integer :: r(0:15) logical :: n, z ! condition flags integer :: m(0:1024) read(10, *, end = 99) m 99 call execute(m, pc) contains subroutine execute(m, pc) integer, intent(in out) :: m(0:), pc integer :: a, b, op, im integer :: adr, aa, bb, cc pc = 0 r(13) = pc * 4 r(14) = size(m) * 4 do ! interpretation cycle ir = m(pc) pc = pc + 1 a = iand(shiftr(ir, 24), z'F') ! modulo(ir / z'1000000', z'10') b = iand(shiftr(ir, 20), z'F') ! modulo(ir / z'100000' , z'10') op = iand(shiftr(ir, 16), z'F') ! modulo(ir / z'10000' , z'10') im = iand(ir, z'FFFF') ! modulo(ir , z'10000') if (.not. btest(ir, 31))then !modulo(ir / z'80000000', 2) == 0) then ! ~p register instruction bb = r(b) if (.not. btest(ir, 30)) then !modulo(ir / z'40000000', 2) == 0) then ! ~q cc = r(iand(ir, z'F')) !r(modulo(ir, z'10')) else if (.not. btest(ir, 28)) then !modulo(ir / z'10000000', 2) == 0) then ! q&~v cc = im else ! q & v cc = im + z'ffff0000' end if select case (op) case (MOV) if (.not. btest(ir, 29)) then !modulo(ir / z'20000000', 2) == 0) then aa = cc else aa = h end if case (Lsl); aa = shiftl(bb, cc) !LSL(bb, cc) case (Asr); aa = shifta(bb, cc) !ASR(bb, cc) case (Ror); aa = ishftc(bb,-cc) !ROR(bb, cc) case (AND); aa = iand(bb, cc) case (ANN); aa = iand(bb, not(cc)) case (JOR); aa = ior(bb, cc) case (XOR); aa = ieor(bb, cc) case (ADD); aa = bb + cc case (SUB); aa = bb - cc case (MUL); aa = bb * cc case (Div); aa = bb / cc; h = mod(bb, cc) end select r(a) = aa n = aa < 0 z = aa == 0 else if (.not. btest(ir, 30)) then !modulo(ir / z'40000000',2) == 0) then ! p & ~q adr = (r(b) + modulo(ir, z'100000')) / 4 if (.not. btest(ir, 29)) then !modulo(ir / z'20000000',2) == 0) then if (adr >= 0) then ! load r(a) = m(adr) n = a < 0 z = a == 0 else ! input if (adr == -1) then ! ReadInt read *, r(a) end if end if else if (adr >= 0) then ! store m(adr) = r(a) else ! output if (adr == -1) then write(*, '(g0, x)', advance = 'no') r(a) else if (adr == -2) then write(*, '(a1)', advance = 'no') char(modulo(r(a), z'80')) else if (adr == -3) then print * end if end if end if else ! p & q branch instruction if ( (a == 0 .and. n) .or. (a == 1 .and. z) .or. (a == 5 .and. n) & .or. (a == 6 .and. (n .or. z)) .or. (a == 7) .or. (a ==8 .and. .not. n) & .or. (a == 9 .and. .not. z) .or. (a == 13 .and. .not. n) & .or. (a == 14 .and. .not. (n .or. z)) ) then if (btest(ir, 28)) r(15) = pc * 4 !modulo(ir / z'10000000', 2) == 1) r(15) = pc * 4 if (btest(ir, 29)) then !modulo(ir / z'20000000', 2) == 1) then pc = iand(pc + iand(ir, z'FFFFFF'), z'3FFFF') !pc = modulo(pc + modulo(ir, z'1000000'), z'40000') else pc = r(iand(ir, z'F')) / 4 !pc = r(modulo(ir, z'10')) / 4 end if end if end if if (pc == 0) exit end do end subroutine execute end program risc
Fortran での実行結果
とりあえずうまく行きましたが、まだ命令の一部しか使っていないので何の保証にもなりませんw Bug ってたので修正。
Fortran
積計算
test.Mod
MODULE test; PROCEDURE Multiply; VAR x, y, z: INTEGER; BEGIN WriteChar("x");WriteChar("?"); ReadInt(x); WriteChar("y");WriteChar("?"); ReadInt(y); z := 0; WHILE x > 0 DO IF x MOD 2 = 1 THEN z := z + y END; y := 2 * y; x := x DIV 2 END; WriteInt(x); WriteInt(y); WriteInt(z); WriteLn END Multiply; BEGIN Multiply END test.
Oberon-0 Compiler OSP 30.10.2013 compiling test code generated 60 0 x?2 y?3 0 12 6
-419430344 1323892752 -1344274432 1073741944 1359020024 -1609564160 1073741887 1359020024 -1609564160 1088946180 1359020028 -2129657856 -1593835520 1073741945 1359020024 -1609564160 1073741887 1359020024 -1609564160 1088946184 1359020028 -2129657856 -1593835520 1073741824 -1595932660 -2132803580 1074331648 -436207601 -2132803580 1074003969 1074331649 -385875964 -2132803572 -2116026360 524289 -1595932660 -2132803576 1074397186 -1595932664 -2132803580 1073872897 -1595932668 -402653202 -2132803580 1359020028 -1609564160 -2132803576 1359020028 -1609564160 -2132803572 1359020028 -1609564160 1342242804 -1610612736 -1881145344 1323827216 -956301297 -134217785 1073741824 -956301312
Fortran にて
x?2 y?3 0 12 6
x?123 y?456 0 58368 56088
ヴィルトのコンパイラ構成法 (Higher Education Computer Series)
- 作者:ニクラウス ヴィルト
- 発売日: 1997/12/01
- メディア: 単行本
Compiler Construction (International Computer Science Series)
- 作者:Wirth, Niklaus,Wirth, Hiklaus
- 発売日: 1996/06/01
- メディア: ペーパーバック
Objektorientierte Programmierung in Oberon-2
- 作者:Moessenboeck, Hanspeter
- 発売日: 1998/09/08
- メディア: ペーパーバック
Programming in Oberon: Steps Beyond Pascal and Modula (ACM Press)
- 作者:Reiser, Martin,Wirth, Niklaus
- 発売日: 1992/06/01
- メディア: ペーパーバック