;mode800,value4095 ;;;;;;;;;; ;;;NScLisper ;;;Copyright 2007 λ組 All rights reserved. ;;; 1.ソース・コード形式であれバイナリ形式であれ、変更の有無にかかわらず、以下の条件を満たす限りにおいて、再配布および使用を許可します。 ;;; 1-1.ソース・コード形式で再配布する場合、上記著作権表示、本条件書および第2項の責任限定規定を必ず含めてください。 ;;; 1-2.バイナリ形式で再配布する場合、上記著作権表示、本条件書および下記責任限定規定を、配布物とともに提供される文書および/または他の資料に必ず含めてください。 ;;; 2.本ソフトウェアは無保証です。自己責任で使用してください。 ;;; 3.著作権者の名前を、広告や宣伝に勝手に使用しないでください。 ;;;;;;;;;; ;;;;;;;;;; ;;;基本 ;;; データは GC用のフラグ(1bit)+タグ(5bit)+データ(26bit) で構成される ;;; set_gc/get_gc/set_tag/get_tag/set_data/get_dataは引数を保存する ;;; (ただし、tmp系は保存しないことに注意) ;;; ;;;データ構造 ;;; 基本:GC Mark(1bit), TAG(5bit), DATA(26bit) ;;; ×コンス:CAR(10bit), CDR(10bit) (変更の可能性高) ;;; ○コンス:CAR(13bit), CDR(13bit) ;;; EXPR/FEXPR:(env arg . body) ;;; ;;;禁止事項 ;;; forの中でセルを消費すること ;;; ;;;備考 ;;; ";value"は1行目に書く必要がある(確認済み) ;;; グローバル変数とやらは、globalonをしなければ、起動時は0らしい ;;; ロード後にmem_initを呼ぶ必要がある? ;;;;;;;;;; *define nsa rmenu "文字を消す", windowerase, "回想", lookback, "セーブする", save, "ロードする", load humanz 800 ;スプライト番号800以下は立ち絵より上に表示 windowback ;ウインドウもそれに従う usewheel ;定数 numalias MEM, 100 numalias MEM_END, 2999 numalias MEM_OVER, 3000 numalias STACK, 3000 numalias STACK_OVER, 4000 numalias SYMBOL_SET, 100 numalias SYMBOL_SET_END, 899 numalias SYMBOL_SET_OVER, 900 numalias SSTACK, 900 numalias SSTACK_OVER, 1000 numalias TAG_CONS, 0 numalias TAG_SYMBOL, 1 numalias TAG_NUM, 2 numalias TAG_SUBR, 3 numalias TAG_FSUBR, 4 numalias TAG_EXPR, 5 numalias TAG_FEXPR, 6 numalias TAG_FREE, 7 ;数値変数用エリアス ;;汎用変数 numalias tmp, 50 numalias ret, 51 numalias arg0, 52 numalias arg1, 53 numalias arg2, 54 numalias arg3, 55 numalias tmp1, 56 numalias tmp2, 57 numalias tmp3, 58 ;;特殊変数 numalias sp, 59 numalias free_lst, 60 numalias i, 61 numalias gc_tmp ,62 numalias test_val, 63 numalias symbol_used, 64 numalias ssp, 65 ;;オブジェクト numalias nil, 66 numalias quote, 67 numalias global_env, 68 numalias sharp_t, 69 numalias sharp_f, 70 numalias dummy, 71 numalias gc_count, 72 numalias sfree_lst, 73 numalias sfree_lst_tail, 74 numalias gc_run, 75 numalias gc_limit, 76 numalias tmp_env, 99 ;文字列変数用エリアス numalias sarg0, 10 numalias sarg1, 11 numalias sarg2, 12 numalias sarg3, 13 numalias stmp, 14 numalias stmp1, 15 numalias stmp2, 16 numalias stmp3, 17 numalias sret, 18 ;SUBR numalias lf_car, 0 numalias lf_cdr, 1 numalias lf_cons, 2 numalias lf_eq, 3 numalias lf_atom, 4 numalias lf_add, 5 numalias lf_sub, 6 numalias lf_mul, 7 numalias lf_div, 8 numalias lf_mod, 9 numalias lf_gt, 10 numalias lf_ge, 11 numalias lf_ls, 12 numalias lf_le, 13 numalias lf_set_car, 14 numalias lf_set_cdr, 15 numalias lf_eval, 16 numalias lf_apply_primitive, 17 numalias lf_booleanp, 18 numalias lf_pairp, 19 numalias lf_symbolp, 20 numalias lf_numberp, 21 numalias lf_procedurep, 22 numalias lf_null, 23 numalias lf_read, 24 numalias lf_write, 25 ;FSUBR numalias lf_quote, 0 numalias lf_begin, 1 numalias lf_cond, 2 numalias lf_lambda, 3 numalias lf_nlambda, 4 numalias lf_define, 5 numalias lf_let, 6 numalias lf_if, 7 numalias lf_and, 8 numalias lf_or, 9 numalias lf_set, 10 numalias lf_letrec, 11 numalias lf_letstar, 12 defaultspeed 50,15,5 caption "NScLisper" versionstr "NScLisper ver1.0", "λ組" resetmenu insertmenu "終了", END insertmenu "バージョン情報", VERSION insertmenu "選択肢まで進む", SKIP insertmenu "文字速度", SUB insertmenu "低速", TEXTSLOW, 1 insertmenu "普通", TEXTMIDDLE, 1 insertmenu "高速", TEXTFAST, 1 insertmenu "フォント", FONT insertmenu "画面", SUB insertmenu "フルスクリーン", FULL, 1 insertmenu "ウインドウ", WINDOW, 1 game ;;;;;;;;;; ;;;*push(val) ;;;;;;;;;; *push if %sp >= STACK_OVER mesbox "スタックオーバフロー", "Error" : end mov %%sp, %arg0 inc %sp return ;;;;;;;;;; ;;;*pop() ;;;;;;;;;; *pop if %sp <= STACK mesbox "Popできません", "Error" : end dec %sp mov %ret, %%sp return ;;;;;;;;;; ;;;*spush(val) ;;;;;;;;;; *spush if %ssp >= STACK_OVER mesbox "スタックオーバフロー", "Error" : end mov $%ssp, $sarg0 inc %ssp return ;;;;;;;;;; ;;;*spop() ;;;;;;;;;; *spop if %ssp <= SSTACK mesbox "Popできません" "Error" : end dec %ssp mov $sret, $%ssp return ;;;;;;;;;; ;;;*get_gc(*obj) ;;;;;;;;;; *get_gc mov %ret, %%arg0 mod 2 return ;;;;;;;;;; ;;;*set_gc(*obj, flag) ;;;;;;;;;; *set_gc mov %tmp, %%arg0 div %tmp, 2 mul %tmp, 2 mov %%arg0, %tmp + %arg1 return ;;;;;;;;;; ;;;*get_tag(*obj) ;;;;;;;;;; *get_tag mov %tmp, %%arg0 mod %tmp, 64 mov %ret, %tmp div %ret, 2 return ;;;;;;;;;; ;;;*set_tag(*obj, tag) ;;;;;;;;;; *set_tag mov %tmp, %%arg0 mov %tmp1, %tmp div %tmp1, 64 mul %tmp1, 64 ;DATA mov %tmp2, %tmp mod 2 ;GC mov %tmp3, %arg1 * 2 ;TAG mov %%arg0, %tmp1 + %tmp2 + %tmp3 return ;;;;;;;;;; ;;;*get_data(*obj) ;;;;;;;;;; *get_data mov %ret, %%arg0 div %ret, 64 return ;;;;;;;;;; ;;;*set_data(*obj, data) ;;;;;;;;;; *set_data mov %tmp, %%arg0 mov %tmp1, %tmp mod 64 mov %tmp2, %arg1 * 64 mov %%arg0, %tmp1 + %tmp2 return ;;;;;;;;;; ;;;*car(*obj) ;;;;;;;;;; *car if %arg0 == %nil mov %ret, %nil : return gosub *get_data mov %ret, %ret mod 8192 ;2^13 return ;;;;;;;;;; ;;;*cdr(*obj) ;;;;;;;;;; *cdr if %arg0 == %nil mov %ret, %nil : return gosub *get_data div %ret, 8192 ;2^13 return ;;;;;;;;;; ;;;*set_car(*obj0, *obj1) ;;;;;;;;;; *set_car gosub *push ;S(obj0) mov %tmp, %arg0 mov %arg0, %arg1 gosub *push ;S(obj1, obj0) mov %arg0, %tmp gosub *get_data mov %tmp1, %ret div %tmp1, 8192 mul %tmp1, 8192 ;tmp1 = cdr gosub *pop ;obj1 %ret は保存しなくてよい ;;; forの中でコンシングは起こらない => %i は保存しなくてよい ;;;;;;;;;; *gc if %gc_limit == 0 goto *gc_l1 inc %gc_run if %gc_run >= %gc_limit goto *gclimit *gc_l1 gosub *push ;S(arg0) mov %arg0, %arg1 gosub *push ;S(arg1, arg0) mov %arg0, %arg2 gosub *push ;S(arg2, arg1, arg0) mov %arg0, %arg3 gosub *push ;S(arg3, arg2, arg1, arg0) mov %arg0, %tmp gosub *push ;S(tmp, arg3, arg2, arg1, arg0) mov %arg0, %tmp1 gosub *push ;S(tmp1, tmp, arg3, arg2, arg1, arg0) mov %arg0, %tmp2 gosub *push ;S(tmp2, tmp1, tmp, arg3, arg2, arg1, arg0) mov %arg0, %tmp3 gosub *push ;S(tmp3, tmp2, tmp1, tmp, arg3, arg2, arg1, arg0) mov %gc_count, 0 textclear GCing・・・ gosub *gc_mark gosub *gc_sweep Used:%gc_count mov %gc_count, MEM_OVER - %gc_count mov %gc_count, %gc_count - MEM Available:%gc_count gosub *pop ;tmp3 MEM_END goto *gc_mark_l1 mov %arg0, %%i gosub *gc_mark_lobject *gc_mark_l1 next return ;;;;;;;;;; ;;;*gc_sweep() ;;;;;;;;;; *gc_sweep mov %free_lst, MEM_OVER for %i=MEM to MEM_END ;一つ目の未使用セルを見つける mov %arg0, %i gosub *get_gc if %ret == 0 mov %free_lst, %i : break mov %arg1, 0 gosub *set_gc next if %free_lst == MEM_OVER return ;未使用セルは無し mov %gc_tmp, %free_lst ;一つ前の空きセルを保持 for %i=%i+1 to MEM_END mov %arg0, %i gosub *get_gc ;;一つ前の未使用セルに新しい未使用セルをつなぎ、マークを消す if %ret == 0 mov %arg0, %gc_tmp : mov %arg1, %i : gosub *reuse_cell : mov %gc_tmp, %i mov %arg0, %i mov %arg1, 0 gosub *set_gc next mov %arg0, %gc_tmp mov %arg1, MEM_OVER ;フリーリストの終端はこの値 gosub *reuse_cell return ;;;;;;;;;; ;;;*create_cons() ;;;;;;;;;; *create_cons gosub *next_cell mov %arg0, %ret mov %arg1, TAG_CONS gosub *set_tag mov %ret, %arg0 return ;;;;;;;;;; ;;;*create_num(n) ;;;;;;;;;; *create_num gosub *push ;S(n) gosub *next_cell mov %arg0, %ret ;new cell mov %arg1, TAG_NUM gosub *set_tag gosub *pop ;n" mov $stmp, ">" if $stmp == "<" mov $stmp, "<" if $stmp == "=" mov $stmp, "=" if $stmp == "!" mov $stmp, "!" if $stmp == "_" mov $stmp, "_" mov $sret, $sret + $stmp mov %ret, %ret + 1 next return ;;;;;;;;;; ;;;*skip_sarg0(str) ;;sarg0 : 部分文字列 ;;;;;;;;;; *skip_sarg0 gosub *push ;%arg0 mov %arg0, %tmp gosub *push ;%tmp mov %arg0, %tmp1 gosub *push ;%tmp1 gosub *next_token len %arg0, $sarg0 mid $sarg0, $sarg0, %ret, %arg0-%ret gosub *pop ;%tmp1 mov %tmp1, %ret gosub *pop ;%tmp mov %tmp, %ret gosub *pop ;%arg0 mov %arg0, %ret return ;;;;;;;;;; ;;;*is_number(str) ;;ret : 数字=0, それ以外=1 ;;;;;;;;;; *is_number gosub *push len %arg0, $sarg0 mov %ret, 0 ;;if %arg0 > 8 gosub *pop : mov %arg0, %ret : mov $sarg0, "0" : mov %ret, 0 : return for %i=0 to %arg0-1 mid $stmp, $sarg0, %i, 1 if $stmp == "0" goto *is_number_l1 if $stmp == "1" goto *is_number_l1 if $stmp == "2" goto *is_number_l1 if $stmp == "3" goto *is_number_l1 if $stmp == "4" goto *is_number_l1 if $stmp == "5" goto *is_number_l1 if $stmp == "6" goto *is_number_l1 if $stmp == "7" goto *is_number_l1 if $stmp == "8" goto *is_number_l1 if $stmp == "9" goto *is_number_l1 gosub *pop : mov %arg0, %ret : mov %ret, 1 : break *is_number_l1 next if %ret == 0 goto *is_number_l2 return ;数字以外ならここで戻る *is_number_l2 ;全て数字 ;;8桁を超えるか確認 if %arg0 > 8 gosub *pop : mov %arg0, %ret : mov $sarg0, "0" : mov %ret, 0 : return atoi %arg0, $sarg0 if %arg0 > 67108863 gosub *pop : mov %arg0, %ret : mov $sarg0, "0" : mov %ret, 0 : return gosub *pop mov %arg0, %ret mov %ret, 0 return ;;;;;;;;;; ;;;*translate_quote(str) ;;ret : 変換したオブジェクト ;;;;;;;;;; *translate_quote gosub *create_cons mov %arg0, %ret gosub *push ;S(new cons1) mov %arg1, %quote gosub *set_car ;new cons1 = (quote ...) gosub *create_cons mov %tmp, %ret ;tmp = new cons2 gosub *pop ;new cons1 0 mov %ret, 1 if %ret < 0 mov %ret, 2 return ;;;;;;;;;; ;;;*input_to_lobject(str) ;;ret : 変換したオブジェクト ;;;;;;;;;; *input_to_lobject gosub *next_token len %tmp1, $sarg0 mid $sarg0, $sarg0, %ret, %tmp1-%ret if $sret == "(" gosub *input_to_list : return if $sret == "’" gosub *translate_quote : return if $sret == ")" mov %ret, %nil : return gosub *spush ;str mov $sarg0, $sret gosub *is_number if %ret == 0 atoi %arg0, $sarg0 : gosub *create_num : gosub *spop : mov $sarg0, $sret : return gosub *create_symbol gosub *spop ;str mov $sarg0, $sret return ;;;;;;;;;; ;;;*input_to_list(str) ;;ret : 変換したオブジェクト ;;$sarg0の値が常に変化することに注意 ;;;;;;;;;; *input_to_list gosub *create_cons mov %arg0, %ret mov %tmp, %ret gosub *push ;root(最初の地点を記憶) *input_to_list_l1 mov %arg0, %tmp gosub *push ;current gosub *next_token ;この%retは破棄する gosub *pop ;current mov %tmp, %ret if $sret == ")" goto *input_to_list_l2 if $sret == "." goto *input_to_list_l3 goto *input_to_list_l4 *input_to_list_l2 ; ')'における処理 gosub *skip_sarg0 ;')'の分を読み飛ばす mov %arg0, %tmp mov %arg1, %nil gosub *set_cdr ;current = (..., nil) gosub *pop ;root mov %arg0, %ret gosub *cdr return ;%ret = CDR(root) *input_to_list_l3 ; '.'における処理 gosub *skip_sarg0 ;'.'の分を読み飛ばす mov %arg0, %tmp gosub *push ;current gosub *input_to_lobject mov %arg1, %ret ;new object gosub *pop ;current mov %arg0, %ret gosub *set_cdr ;current = (..., new object) gosub *skip_sarg0 ;')'の分を読み飛ばす gosub *pop ;root mov %arg0, %ret gosub *cdr return ;%ret = CDR(root) *input_to_list_l4 ;通常の処理 ;;表記の上では省略しているが、スタックには常にrootがある ;;new object, new consの違いに注意 mov %arg0, %tmp gosub *push ;S(current) gosub *input_to_lobject mov $sarg0, $sarg0 mov %arg0, %ret gosub *push ;S(new object, current) gosub *create_cons mov %arg0, %ret ;%arg0 = new cons gosub *pop ;new object form mov %arg1, %ret gosub *pop ;new env form mov %arg1, %ret gosub *pop ;new env new object mov %arg0, %ret gosub *push ;S(new object, env, arg, current) gosub *create_cons mov %arg0, %ret ;new cons gosub *pop ;new object farg mov %arg0, %ret gosub *push ;S(farg, arg, fn) gosub *create_new_env mov %arg0, %ret ;arg0 = env gosub *pop ;farg cls_env mov %arg1, %ret gosub *pop ;env= 0 goto *subr_func_sub_l1 mov %arg0, 0 *subr_func_sub_l1 goto *create_num ;tail call return *subr_func_mul mov %arg0, 1 ;result gosub *push ;S(result) mov %arg0, %arg1 *subr_func_mul_l1 ;(arg0 = arg, S(result) if %arg0 == %nil goto *subr_func_mul_l2 gosub *push ;S(arg, result) gosub *car ;CAR(arg) mov %arg0, %ret gosub *get_data mov %tmp, %ret gosub *pop ;arg %tmp mov %ret, %sharp_t return *subr_func_ge mov %arg0, %arg1 gosub *push ;S(arg) gosub *car ;CAR(arg) mov %arg0, %ret gosub *get_data mov %arg0, %ret gosub *pop ;arg= %tmp mov %ret, %sharp_t return *subr_func_ls mov %arg0, %arg1 gosub *push ;S(arg) gosub *car ;CAR(arg) mov %arg0, %ret gosub *get_data mov %arg0, %ret gosub *pop ;arg expr mov %arg0, %ret mov %arg1, %global_env goto *eval ;tail call *subr_func_apply_primitive mov %arg0, %arg2 gosub *push ;S(env) mov %arg0, %arg1 gosub *push ;S(arg, env) gosub *car ;CAR(arg) => fn mov %arg0, %ret gosub *pop ;arg argument mov %arg1, %ret gosub *pop ;fn new object mov %arg0, %ret gosub *pop ;env argument mov %arg0, %ret gosub *pop ;argform mov %arg0, %ret ;arg0 = form gosub *pop ;argument sym mov %arg0, %ret gosub *get_tag if %ret == TAG_CONS goto *define_syntax_sugar ;(arg0 = sym, S(arg, env)) gosub *pop ;arg val mov %tmp, %ret gosub *pop ;sym argument mov %tmp, %ret gosub *pop ;sym body mov %arg0, %ret gosub *push ;S(body, argument, sym, env) gosub *create_cons mov %arg0, %ret gosub *pop ;body name mov %arg0, %ret gosub *pop ;val sym mov %arg0, %ret gosub *pop ;arg val mov %tmp, %ret gosub *pop ;sym object mov %tmp, %ret gosub *pop ;sym argument mov %arg0, %ret gosub *push ;S(argument, env, arg) gosub *let_arg_split1 ;namelist mov %tmp, %ret gosub *pop ;argument body mov %arg1, %ret gosub *pop ;new env argument mov %arg0, %ret gosub *push ;S(argument, env, arg) gosub *let_arg_split1 ;namelist mov %arg0, %ret gosub *push ;S(namelist, argument, env, arg) mov %tmp ,%sp - 2 ;=argument mov %arg0, %%tmp gosub *let_arg_split2 ;vallist mov %arg0, %ret gosub *push ;S(vallist, namelist, argument, env, arg) gosub *create_new_env mov %arg0, %ret gosub *push ;S(new env, vallist, namelist, argument, env, arg) mov %tmp, %sp - 5 ;=env mov %arg1, %%tmp gosub *nconc gosub *pop ;new env body mov %arg1, %ret gosub *pop ;new env argument mov %arg0, %ret gosub *push ;S(argument, env, arg) gosub *let_arg_split1 ;namelist mov %arg0, %ret gosub *push ;S(namelist, argument, env, arg) mov %tmp ,%sp - 2 ;=argument mov %arg0, %%tmp gosub *let_arg_split2 ;vallist mov %arg2, %ret gosub *pop ;namelist body mov %arg1, %ret gosub *pop ;new env cnd mov %tmp, %ret gosub *pop ;env expr mov %tmp, %ret gosub *pop ;env object if %ret == %sharp_f goto *fsubr_func_and_l2 mov %arg0, %ret gosub *pop ;env expr mov %tmp, %ret gosub *pop ;env object if %ret != %sharp_f goto *fsubr_func_or_l2 mov %arg0, %ret gosub *pop ;env name mov %tmp, %ret gosub *pop ;namelist val mov %arg2, %ret gosub *pop ;name val mov %arg0, %ret mov %tmp, %sp - 3;=env mov %arg1, %%tmp gosub *eval ;eval(val, env) mov %arg0, %ret gosub *push ;S(new object, vallist, namelist, env) mov %tmp, %sp - 3;=namelist mov %arg0, %%tmp gosub *car ;CAR(namelist) => name mov %arg1, %ret gosub *pop ;new object val mov %arg0, %ret mov %tmp, %sp - 1;=new env mov %arg1, %%tmp gosub *eval ;eval(val, env) mov %arg0, %ret gosub *push ;S(new object, new env, vallist, namelist) mov %tmp, %sp - 4;=namelist mov %arg0, %%tmp gosub *car ;CAR(namelist) => name mov %arg1, %ret gosub *pop ;new object