アセンブラでも関数型プログラミング
16命令アセンブラで、C言語のような関数型プログラミングをする
callで関数を実行し、returnで帰還
引数やローカル変数を使える
スタック領域から動的にメモリ確保、開放する
変数が関数内に隔離される
変数をグローバルで静的にメモリ配置する必要がない
mugyuu の投影に成功main.m4include(`init.m4')
title_str: "mugyuu";
main: call(print, 1244, title_str); goto(main);
print: locals(`vram_pointer', `str_pointer'); arguments(`position', `str');
sread(position); swrite(vram_pointer); sread(str); swrite(str_pointer);
print_char_loop: sread(str_pointer); inread; write *autosp; eq 0; branch print_char_break; read *autosp; inread; inwrite(sread(vram_pointer); );
sread(str_pointer); add 1; swrite(str_pointer); sread(vram_pointer); add 1; swrite(vram_pointer); goto(print_char_loop); print_char_break: read *autosp; return;
もはやm4マクロ定義のほうがコード長い
マクロアセンブラは、ボトムアップで独自言語を作れるのが面白いところ
init.m4dnl m4マクロ定義 define(cat, $1$2$3$4$5$6$7$8$9)
dnl メモリマップ define(`pc', 0) define(`wreg', 1) define(`sp', 2) define(`autosp', 3) define(`fractional', 4)
define(`inwrite_data', 128) define(`inwrite_addr', 129)
dnl 拡張命令 define(`goto', `read $1; write pc') define(`mod', `div $1; read *fractional') define(`nop', `add 0')
define(`inread_label_count', 0) dnl 間接読み込み define(`inread', ` dnl 自己書き換えコード write cat(`inread_label_', inread_label_count); cat(`inread_label_', inread_label_count): 0;
define(`inread_label_count', eval(inread_label_count + 1)) ') dnl スタックからの相対読み込み define(`sread', `read *sp; add $1; inread') dnl 間接書き込み define(`inwrite', ` write inwrite_data; $1 write inwrite_addr; read *inwrite_data; write *inwrite_addr ') dnl スタックからの相対書き込み define(`swrite', `inwrite(read *sp; add $1; )')
define(`return_label_count', 0) define(`push_arguments', ` ifelse( $#, 0, , $#, 1, `read $1; write *autosp', `push_arguments(shift($@)); read $1; write *autosp' ) ') define(`call', ` push_arguments(shift($@), cat(`return_label_', return_label_count)); goto($1); cat(`return_label_', return_label_count):
define(`return_label_count', eval(return_label_count + 1)) ')
define(`define_locals', ` write *autosp;
ifelse( $#, 0, , $#, 1, ` define($1, local_count); define(`local_count', eval(local_count + 1)) ', ` define($1, local_count); define(`local_count', eval(local_count + 1)); define_locals(shift($@)) ' ) ') define(`locals', ` define(`local_count', 0) define_locals($@) ') define(`arguments', ` ifelse( $#, 0, , $#, 1, ` define($1, local_count); define(`local_count', eval(local_count + 1)) ', ` define($1, local_count); define(`local_count', eval(local_count + 1)); arguments(shift($@)) ' ) ') define(`return', ` read *sp; add eval(local_count + 1); write sp; sread(-1); write pc ')
dnl 電源投入時にCPUの安定を待ってプログラム開始 nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; goto(main);