I-Compiler and MI-Interpreter"I" is the pretty minimalistic imperative language used by Prof. Dr. F. Bry in his lecture about compiler design, "MI" the corresponding machine language. I implemented a simple compiler for "I" and an interpreter for "MI", which are both available here. News
Download and Build instructionsThis is version 0.3 of the "I" compiler. It should be a fully functional "I" compiler with some simple tree-based optimization. I provide the complete source code here.
The archive contains 2 directories, mii which contains the
MI interpreter and ic for the I compiler.
In order to compile the code, you need flex, bison and gcc.
(I am using flex-2.5.31, bison-1.875a, gcc-3.4.1pre.)
Note that you must build mii first before compiling ic
because the latter depends on the former. DescriptionThe original design proposal by F. Bry was modified slightly: This implementation features:
The current implementation does the following optimizations, most of them need to be enabled using option -Ot:
This compiler is effectively three/four-step:
ExampleAs an example, let us consider the following code (some similar code is part of the source code archive above). /* test.i: Small I test program. */ program prog; var x,y,product,n,fac; procedure Mul; var a; begin product:=0; a:=y; while not a<1 do begin product:=product+x; a:=a-1 end end; procedure Faculty; begin if n>1 then begin //fac:=fac*n; x:=fac; y:=n; CALL Mul; fac:=product; n:=n-1; call Faculty end end; procedure Bar2; const a=33,g=99; var a,b; begin x:=1+a; b:=a; read g end; begin read x; read y; call Mul; write product; read n; fac:=1; call Faculty; write fac end. Compiling this code will yield a waning and errors: bash# ./icomp --help USAGE: icomp [options...] input_file options: --help print this help --version print version information -va emit verbose assembler code -nw switch off warnings -Ot perform tree-based optimizations -o file.mi set output file input_file: I-file to compile (max one) I compiler version 0.3 (c) 2004 by Wolfgang Wieser Compiler for pretty minimalistic imperative PASCAL-like programming language called "I" (based on design by F. Bry). bash# ./icomp test.i Compiling: test.i -> test.mi: test.i:32:[20..21]: error: variable "a" already declared test.i:31:[22..23]: error: this is the location of the previous declaration test.i:36:[24..28]: error: assignment to constant value "g" test.i:30:[8..17]: warning: unused procedure "Bar2" So, let's correct that (by removing the "a" in the var decl and remove the read operation). Furthermore, I use -va to enable verbose assembler output and -nw do disable all warnings. bash# ./icomp -va -nw test.i
Compiling: test.i -> test.mi:
The compiled assembler code will look like this: # Program "prog" compiled by icomp-0.2 (56 insns) # 000000 RST INC 5 JMP 41 # to prog (used=0) INC 1 LIT 0 STO 1 5 # product (0) LOD 1 4 # y (0) STO 0 3 # a (1) JMP 17 # while @11:30 (jump to condition) LOD 1 5 # product (0) # 000010 LOD 1 3 # x (0) OPR + # @12:48 STO 1 5 # product (0) LOD 0 3 # a (1) LIT 1 OPR - # @13:36 STO 0 3 # a (1) LOD 0 3 # a (1) LIT 1 OPR < # @11:35 # 000020 OPR ! # @11:30 JOT 9 # while @11:30 (loop jump) RET # from Mul INC 0 LOD 1 6 # n (0) LIT 1 OPR> # @19:28 JOF 40 # if @19:27 LOD 1 7 # fac (0) STO 1 3 # x (0) # 000030 LOD 1 6 # n (0) STO 1 4 # y (0) CAL 1 3 # Mul (0) LOD 1 5 # product (0) STO 1 7 # fac (0) LOD 1 6 # n (0) LIT 1 OPR - # @25:36 STO 1 6 # n (0) CAL 1 23 # Faculty (0) # 000040 RET # from Faculty REA # from x STO 0 3 # x (0) REA # from y STO 0 4 # y (0) CAL 0 3 # Mul (0) LOD 0 5 # product (0) WRI REA # from n STO 0 6 # n (0) # 000050 LIT 1 STO 0 7 # fac (0) CAL 0 23 # Faculty (0) LOD 0 7 # fac (0) WRI HLT This code can now be execured using the MI interpreter: bash# ../mii/miinterp test.mi
MI Abstract Machine version 0.4 (c) Wolfgang Wieser. Stack size 4096
miinterp: Read 56 instructions from "test.mi".
Read=10
Read=12
Write=120
Read=10
Write=3628800
miinterp: Normal termination after executing 1163 instructions.
miinterp: State: T=7, B=0, P=55
The MI interpreter can also dump the executed commands and the stack if desired: bash# ../mii/miinterp -it -st test.mi MI Abstract Machine version 0.4 (c) Wolfgang Wieser. Stack size 4096 miinterp: Read 56 instructions from "test.mi". Executing: 000000: RST Stack content: 000000: 0 B DL 000001: 0 RA 000002: --> 0 T SL Executing: 000001: INC 5 Stack content: 000000: 0 B DL 000001: 0 RA 000002: 0 SL 000003: -1 000004: -1 000005: -1 000006: -1 000007: --> -1 T Executing: 000002: JMP 41 Stack content: 000000: 0 B DL 000001: 0 RA 000002: 0 SL 000003: -1 000004: -1 000005: -1 000006: -1 000007: --> -1 T Executing: 000041: REA Read=1 Stack content: 000000: 0 B DL 000001: 0 RA 000002: 0 SL 000003: -1 000004: -1 000005: -1 000006: -1 000007: -1 000008: --> 1 T (...and so on...)
|