このプログラムは16bit RISC である SN/X の演習のために
作成した。
言語仕様とYACC/LEXファイルは
ePaper Press の
Thomas Niemann, "A Compact Guide To Lex & Yacc" に基づき
演習用に拡張している。コンパイラ演習を目的としていない
のでコンパイラとしての機能は最低限に抑えている。
アセンブラと
併せて利用されると便利である。
同テキストの例題はスタックマシン向けになっていたことと SN/Xには無い命令が多いことからコードジェネレータ部分を 大幅に書換えた。また、関数、メモリ、入出力などを拡張した。 アーカイブにはコンパイラ(snxc)とインタプリタ(snxi)が生成 できるように両ファイルを入れている。アーカイブを展開し、 make all とするとコンパイラとインタプリタを生成する。 コンパイラとインタプリタは標準入力から文を 読み込み対応するSN/Xアセンブリ言語もしくは 実行結果を出力する。 ソース言語はC言語風の記述を行なう。ただし、変数は"a"から"z"の26変数で 扱う数値はすべて整数型である。また、メモリmem[]と入出力ポートio[]を 扱うことができるように拡張した。 また、メモリの1番地から26番地は"a"から"z"までの変数と 重なるので、mem[x]を用いて変数をアクセスすることもできる。 例えば、mem[1]は変数aと同じメモリアドレスを指す。 演習専用のため、関数定義は関数名foo、引数名argのみ 許される。関数の型はvoidかintであり、引数は1または0個を指定する。 局所変数は用意していない。 print文はインタプリタはコンソールに出力するが コンパイラではmem[0]に値を書き出すだけである。 実行例1: $ ./snxc mem[20]=a-c; lda $3, 50($0) lda $1, 20($0) ld $2, 1($0) lda $3, -1($3) st $1, 0($3) ld $1, 3($0) not $1, $1 lda $1, 1($1) add $2, $2, $1 ld $1, 0($3) lda $3, 1($3) st $2, 0($1) 実行例2: $ cat tt.c a=10; while (a > 0) { a = a - 1; } $ snxc < tt.c lda $3, 50($0) lda $1, 10($0) st $1, 1($0) L000: ld $1, 1($0) slt $1, $2, $1 bz $1, L001 ld $1, 1($0) lda $2, 1($0) not $2, $2 lda $2, 1($2) add $1, $1, $2 st $1, 1($0) bal $0, L000 L001: 実行例3: $ ./snxc int foo(arg) { if(arg<1) return(0); return(foo(arg-1)); } foo: lda $3, -2($3) st $2, 0($3) st $1, 1($3) ld $1, 1($3) lda $2, 1($0) slt $1, $1, $2 bz $1, L000 lda $1, 0($0) bal $0, fooexit L000: ld $1, 1($3) lda $2, 1($0) not $2, $2 lda $2, 1($2) add $1, $1, $2 bal $2, foo bal $0, fooexit fooexit: ld $2, 0($3) lda $3, 2($3) bal $0, 0($2)
言語仕様 予約語: while, if, else, print, mem, io, int, void, arg, foo 演算子: +, -, *, /, <, >, >=, <=, == 文法: program: function ; function: function stmt | /* NULL */ ; stmt: ; | expr ; | DEF foo ( arg ) stmt | DEF foo ( ) stmt | print expr ; | io [ expr ] = expr ; | mem [ expr ] = expr ; | VARIABLE = expr ; | while ( expr ) stmt | return ( expr ) ; | return ; | if ( expr ) stmt | if ( expr ) stmt else stmt | { stmt_list } ; stmt_list: stmt | stmt_list stmt ; expr: INTEGER | VARIABLE | - expr | io [ expr ] | mem [ expr ] | foo ( expr ) | expr + expr | expr - expr | expr * expr | expr / expr | expr < expr | expr > expr | expr >= expr | expr <= expr | expr != expr | expr == expr | ( expr ) ; ただし、*,/の演算子はmul,divというSN/Xにない演算命令を 生成するので利用は注意を要する。