ネむティブアメリカンの砊のバむトマシンだけでなくパヌト3

画像

2019幎が来お、幎末幎始は終わりに近づいおいたす。 バむト、コマンド、倉数、ルヌプを思い出し始めたしょう...

これらの祝日ですでに忘れおいたもの。 䞀緒に芚えおおく必芁がありたす

今日は、バむトマシン甚のむンタヌプリタヌを䜜成したす。 これは3番目の蚘事で、最初のパヌトはパヌト1 、 パヌト2です。

みなさん、明けたしおおめでずう、猫ぞようこそ

たず、 fpaukからの質問に答えたす。 これらの質問は間違いなく正しいです。 珟圚、このバむトマシンのアヌキテクチャは、ダむレクトプロセッサアドレスで動䜜するようになっおいたす。 しかし、これらのアドレスはバむトコヌドではなく、システムの起動埌に圢成されたす。 システムの起動埌、任意のポむンタヌを䜜成でき、このコヌドはどのプラットフォヌムでも正垞に機胜したす。 たずえば、倉数たたは配列のアドレスは、var0コマンドで取埗できたす。 このコマンドはどのプラットフォヌムでも機胜し、このプラットフォヌム固有の正しいアドレスを返したす。 その埌、このアドレスを自由に操䜜できたす。

それでも、 fpaukは正しい。 アドレスをバむトコヌドに保存するこずはできたせん。 プラットフォヌムに䟝存しないコヌドを䜜成できるこずがわかりたしたが、そのためにはいく぀かの努力が必芁です。 特に、アドレスがバむトコヌドに含たれおいないこずを確認しおください。 たた、たずえば、コンパむルされたコヌドをファむルに保存するず、それらが取埗できたす。 これにはデヌタが含たれ、アドレスにするこずができたす。 たずえば、ここの倉数、コンテキストなどの倀。

このような問題を取り陀くには、アドレスを仮想化する必芁がありたす。 x86プロセッサのアドレス指定は非垞に匷力であり、ほずんどの堎合、远加のコマンドも远加されたせん。 それでも、絶察アドレスを䜿甚しお、珟圚のアヌキテクチャを継続したす。 そしお、テストを開始するず、アドレスを仮想アドレスに再実行しお、これがパフォヌマンスにどのように圱響するかを確認できたす。 これは面癜いです。

りォヌムアップ


そしお今、少しトレヌニング。 小さくおも䟿利なバむトコマンドのバッチをもう1぀䜜成したしょう。 これらは、コマンドnip、emit、1 +、+、-、count、リタヌンスタックr>、> r、r @、文字列リテラル "、および定数ワヌド1、2、3、4、 8.コマンドの衚にそれらを含めるこずを忘れないでください。

これらのコマンドのコヌドは次のずおりです
b_nip = 0x39 bcmd_nip: pop rax mov [rsp], rax jmp _next b_emit = 0x81 bcmd_emit: pop rax mov rsi, offset emit_buf #   mov [rsi], al mov rax, 1 #   № 1 - sys_write mov rdi, 1 #  № 1 - stdout mov rdx, 1 #   push r8 syscall #   pop r8 jmp _next b_wp = 0x18 bcmd_wp: incq [rsp] jmp _next b_setp = 0x48 bcmd_setp: pop rcx pop rax add [rcx], rax jmp _next b_setm = 0x49 bcmd_setm: pop rcx pop rax sub [rcx], rax jmp _next b_2r = 0x60 bcmd_2r: pop rax sub rbp, 8 mov [rbp], rax jmp _next b_r2 = 0x61 bcmd_r2: push [rbp] add rbp, 8 jmp _next b_rget = 0x62 bcmd_rget: push [rbp] jmp _next b_str = 0x82 bcmd_str: movzx rax, byte ptr [r8] lea r8, [r8 + rax + 1] jmp _next b_count = 0x84 bcmd_count: pop rcx movzx rax, byte ptr [rcx] inc rcx push rcx push rax jmp _next b_num1 = 0x03 bcmd_num1: push 1 jmp _next b_num2 = 0x04 bcmd_num2: push 2 jmp _next b_num3 = 0x05 bcmd_num3: push 3 jmp _next b_num4 = 0x06 bcmd_num4: push 4 jmp _next b_num8 = 0x07 bcmd_num8: push 8 jmp _next 


nipコマンドは、スタックの最䞊郚の䞋にある単語を削陀したす。 これは、スワップドロップコマンドず同等です。 これは圹立぀堎合がありたす。

emitコマンドは、スタックから1文字をプッシュしたす。 同じシステムコヌル番号1を䜿甚し、文字は長さ1のバッファに配眮されたす。

countコマンドは非垞に単玔です-スタックからカりンタヌのある行のアドレスを取埗し、2぀の倀に倉換したす-カりンタヌのない行のアドレスず長さ。

b_2r、b_r2、b_rgetコマンドは、フォヌトワヌドr>、> r、r @です。 最初の関数は戻りスタックから単語を取埗し、算術スタックに配眮したす。 2番目は反察の操䜜を実行したす。 3番目のものは戻りスタックから単語をコピヌし、算術1に入れたす。戻りスタックは倉曎されたせん。

b_setpおよびb_setmコマンドは+ずいう単語です。 および-..スタックから倀ずアドレスを取埗し、指定されたアドレスのワヌドを倉曎しお、スタックに倀を远加たたは削陀したす。

b_strコマンドには、任意の長さのパラメヌタヌカりンタヌ付きの行がありたす。 この行はコマンドバむトの埌のバむトコヌドにあり、コマンドはこの行のアドレスをスタックにプッシュしたす。 実際、これは文字列リテラルです。

チヌムの他のメンバヌはコメントを必芁ずしないず思いたす。

たた、定数文字列。 "を出力するコマンドを䜜成したす。次のように、入力する゚ントリポむントずしお実装したす。

 b_strp = 0x83 bcmd_strp: movsx rax, byte ptr [r8] inc r8 push rax push r8 add r8, rax b_type = 0x80 bcmd_type: mov rax, 1 #   № 1 - sys_write mov rdi, 1 #  № 1 - stdout pop rdx #   pop rsi #   push r8 syscall #   pop r8 jmp _next 

このコマンドは、b_strず同様に構成されおいたす。 圌女だけがスタックに䜕も眮きたせん。 パラメヌタずしおこのコマンドの埌ろにある行は、単にナヌザヌに衚瀺されたす。

りォヌムアップは終了したした。もっず深刻なものの時が来たした。 ワヌドゞェネレヌタヌず他のvarコマンドを扱いたしょう。

ワヌドゞェネレヌタヌ


倉数を思い出しおください。 既知のバむトコヌドレベルでの配列の配眮var0コマンド。 新しい倉数を䜜成するために、フォヌトは次の構成を䜿甚したす。

 variable < > 

このシヌケンスを実行するず、新しい単語<倉数名>が䜜成されたす。 この新しいワヌドの実行により、スタック䞊のアドレスがプッシュされ、倉数の倀が保存されたす。 フォヌトには定数もあり、次のように䜜成されたす。

 <> constant < > 

定数を䜜成した埌、単語<定数名>を実行するず、スタック<倀>に配眮されたす。

したがっお、単語倉数ず単語定数はどちらも生成語です。 新しい単語を䜜成するように蚭蚈されおいたす。 芁塞では、そのような単語はcreate ... does>構造を䜿甚しお蚘述されたす。

倉数ず定数は次のように定矩できたす。

 : variable create 0 , does> ; : constant create , does> @ ; 

これはどういう意味ですか

単語createは、実行されるず、入力ストリヌムから実行されたずきに取埗する名前で新しい単語を䜜成したす。 䜜成埌、単語が実行する前に単語のシヌケンスが実行されたす>。 しかし、この単語の実行の瞬間に、does>の埌に曞かれおいるこずが実行されたす。 同時に、デヌタアドレスは既にスタック䞊にありたすフォヌトの「デヌタフィヌルド」で蚀うように。

したがっお、倉数を䜜成するず、シヌケンス「0」が実行されたす。これは、れロ充填のマシンワヌドの予玄です。 そしお、䜜成された単語が実行されるずき、䜕も行われたせん埌は䜕もありたせん。 倀が栌玍されるメモリアドレスは、単にスタックに残りたす。

定数の定矩では、単語はスタック䞊にある倀を埋めお予玄されおいたす。 䜜成された単語が実行されるず、「@」が実行され、指定されたアドレスの倀が取埗されたす。

次に、䜜成した単語をどのように配眮できるかを考えおみたしょう。 デヌタアドレスをスタックvar0などにプッシュし、特定のアドレスであるバむトコヌドに制埡を移したす。 var0コマンドはすぐに戻りたす。 しかし、この堎合、リタヌンではなく、実際に移行を行う必芁がありたす。

もう䞀床、䜕をする必芁があるかを定匏化したす。


制埡を別のバむトコヌドアドレスに転送するだけで、最初に次のバむトR8のアドレスをスタックに配眮する必芁があるこずがわかりたす。

それはほずんど分岐コマンドです そしお、ここで圌女は䞀人ではありたせん。 すでにbranch8ずbranch16がありたす。 新しいvar8およびvar16コマンドに名前を付け、これらを分岐コマンドぞの単なる゚ントリポむントにしたす。 移行チヌムぞの移行を保存したす:)したがっお、次のようになりたす。

 b_var8 = 0x29 bcmd_var8: push r8 b_branch8 = 0x10 bcmd_branch8: movsx rax, byte ptr [r8] add r8, rax jmp _next b_var16 = 0x30 bcmd_var16: push r8 b_branch16 = 0x11 bcmd_branch16: movsx rax, word ptr [r8] add r8, rax jmp _next 

良い方法では、var32コマンドも動䜜し、var64も動䜜したす。 通垞の遷移はそれほど長くないため、このような長い遷移はありたせん。 しかし、varコマンドの堎合、これは非垞に珟実的なケヌスです。 しかし、今のずころ、これらのコマンドは実行したせん。 必芁に応じお、埌で行いたす。

単語ゞェネレヌタヌが敎理されおいたす。 蟞曞を決める番でした。

語圙


通垞、フォヌトディクショナリヌに぀いお単玔に話すず、ディクショナリ゚ントリの単方向リストの圢匏で衚瀺されたす。 実際、砊は倚くの蟞曞をサポヌトしおいるため、すべおが少し耇雑です。 実際、それらは朚です。 このようなツリヌ内の単語の怜玢は「シヌト」で始たりたす。これは珟圚の蟞曞の最埌の単語です。 珟圚の蟞曞はコンテキスト倉数によっお定矩され、最埌の単語のアドレスは蟞曞の単語にありたす。 別の倉数は蟞曞を管理するために䜿甚されたす-それは新しい単語が远加される蟞曞を定矩したす。 したがっお、1぀の蟞曞を怜玢甚にむンストヌルし、別の蟞曞に新しい単語を含めるこずができたす。

単玔な堎合、倚くの蟞曞のサポヌトを行わないこずも可胜ですが、私は䜕も単玔化しないこずにしたした。 実際、バむトコヌド、バむトマシンを理解するために、このセクションで説明されおいるこずを知る必芁はありたせん。 したがっお、興味のない人は、このセクションをスキップできたす。 さお、誰が詳现を知りたいですか-どうぞ

最初は、forthずいう名前の基本的な蟞曞がありたす。 これは、そのような蚀葉があるこずを意味したす。 この単語は「蟞曞」ずも呌ばれ、倚少の混乱がありたす。 したがっお、単語に関しおは、蟞曞の単語ず呌びたす。

この蟞曞を䜿甚しお新しい蟞曞が䜜成されたす。

 vocabulary <  > 

これにより、<created dictionary name>ずいう名前の単語が䜜成されたす。 実行されるず、この単語は䜜成された蟞曞を怜玢の開始蟞曞ずしお蚭定したす。

実際、蟞曞の単語には、この蟞曞の最埌の蚘事ぞのリンクがあり、そこから怜玢が開始されたす。 そしお実行時に、この蟞曞の単語はコンテキスト倉数のデヌタフィヌルドぞのリンクを曞き蟌みたす。

埌で、語圙を䜜成するこずが可胜になりたす。語圙は、珟圚の実装では芁塞で非垞に簡単に説明されおいたす。

 : vocabulary create context @ , does> context ! ; 

だから、蚀葉を前に䜜成したす。 var8コマンドを䜿甚したす。 「コンテキスト」バむトコヌドは、デヌタフィヌルドの盎埌に配眮されたす。

 forth: .byte b_var8 .byte does_voc - . - 1 .quad 0 # <--      .      ,    -    . does_voc: .byte b_call8 .byte context - . - 1 .byte b_set .byte b_exit 

ここで、蟞曞自䜓の䜜成に戻りたす。

䞀般に、砊では、メモリ内の単語の説明は「蟞曞゚ントリ」ず呌ばれたす。 通垞の甚語では、蚘事のタむトルずそのコヌドがありたす。 しかし、砊ではすべおがあたり䞀般的ではなく、「名前フィヌルド」、「通信フィヌルド」、「コヌドフィヌルド」、「デヌタフィヌルド」ず呌ばれたす。 これが埓来の甚語で䜕を意味するのかをお話ししたす。

名前フィヌルドは、「カりンタヌ付きの行」ずいう単語の名前です。 叀いパスカルのようです-文字列の長さのバむト、次に文字列。 リンクフィヌルドは、前の蚘事ぞのリンクです。 以前は単なるアドレスでしたが、プラットフォヌムに䟝存しないコヌドがあり、これはオフセットになりたす。 埓来は砊にあったコヌドフィヌルドは、マシンコヌド実装が盎接シャむな堎合であり、カヌネル倖の単語に察しおは_callが呌び出されおいたした。 バむトコヌドがありたす。 たた、デヌタフィヌルドは、デヌタを含む単語甚です。たずえば、倉数や定数甚です。 ちなみに、単語蟞曞もそれを指したす。

コンパむラには、ただフラグが必芁です。 通垞、砊にはただ1぀のフラグが必芁です-即時で、長いバむトに配眮されたす別のフラグがある堎合がありたす-非衚瀺。 ただし、これはコヌドフィヌルドに呌び出されたずきにプロセッサ制埡が転送される盎接瞫補コヌド甚です。 しかし、私たちには異なる蚀葉がありたす-バむトコヌドずマシンコヌド、そしお少なくずも2぀、さらには3぀のフラグが必芁です。

通信分野にはどれくらい必芁ですか 最初は、16ビットを䜿甚したかった。 これは前の単語ぞのリンクであり、単語は間違いなく64 Kb未満です。 しかし、その単語にはほずんどすべおのサむズのデヌタ​​を含めるこずができるこずを思い出したした。 さらに、いく぀かの蟞曞がある堎合、リンクは倚くの単語を通過できたす。 ほずんどの堎合、8ビットで十分ですが、16ビットず32ビットでもかたいたせん。4GBを超えるデヌタがある堎合は、64ビットですらありたす。 さお、すべおのオプションをサポヌトしたしょう。 䜿甚されるオプション-フラグを蚭定したす。 少なくずも4぀のフラグが刀明したす。即時属性、コアワヌド属性、および䜿甚される通信フィヌルドのバリアントごずに2ビットです。 他の方法ではなく、フラグに別のバむトを䜿甚する必芁がありたす。

次のようにフラグを定矩したす。

 f_code = 0x80 f_immediate = 0x60 

f_codeフラグはアセンブラヌで蚘述されたカヌネルワヌド甚であり、f_immediateフラグはコンパむラヌにずっお有甚です。これに぀いおは次の蚘事で説明したす。 たた、2぀の最䞋䜍ビットにより、通信フィヌルドの長さ1、2、4、たたは8バむトが決たりたす。

したがっお、蚘事のタむトルは次のようになりたす。


ここたでは、「マクロ」アセンブラヌの機胜を䜿甚しおいたせん。 そしお今、それらが必芁です。 以䞋は、単語のタむトルを圢成するための名前項目を持぀そのようなマクロです。

 .macro item name, flags = 0 link = . - p_item 9: .if link >= -256/2 && link < 256/2 .byte \flags .byte link .elseif link >= -256*256/2 && link < 256*256/2 .byte \flags | 1 .word . - p_item .elseif link >= -256*256*256*256/2 && link < 256*256*256*256/2 .byte \flags | 2 .int . - p_item .elseif link >= -256*256*256*256*256*256*256*256/2 && link < 256*256*256*256*256*256*256*256/2 .byte \flags | 3 .quad . - p_item .endif p_item = 9b .byte 9f - . - 1 .ascii "\name" 9: .endm 

このマクロは倀p_itemを䜿甚したす-これは前の蟞曞゚ントリのアドレスです。 最埌のこの倀は、将来の䜿甚のために曎新されたすp_item = 9b。 ここで9bはラベルであり、数字ではなく、混同しないでください:)マクロには2぀のパラメヌタヌがありたす-単語の名前ずフラグオプション。 マクロの開始時に、前の単語ぞのオフセットが蚈算されたす。 次に、オフセットのサむズに応じお、目的のサむズのフラグず通信フィヌルドがコンパむルされたす。 次に、名前の長さのバむトず名前自䜓。

次のように、最初の単語p_itemの前に定矩したす。

 p_item = . 

ドットは、アセンブラヌの珟圚のコンパむラヌアドレスです。 この定矩の結果、最初の単語はそれ自䜓を指したす通信フィヌルドは0になりたす。 これは蟞曞の終わりの兆候です。

ずころで、カヌネルワヌドのコヌドフィヌルドには䜕が入りたすか 少なくずもどこかにコマンドコヌドを保存する必芁がありたす。 私は最も単玔な道を進むこずにしたした。 カヌネルワヌドには、バむトコヌドもありたす。 ほずんどのチヌムでは、これは単なるバむトコマンドで、その埌にb_exitが続きたす。 したがっお、むンタヌプリタヌの堎合、f_codeフラグを分析する必芁はなく、そのためのコマンドは䜕の違いもありたせん。 党員のバむトコヌドを呌び出すだけです。

このオプションには別の利点がありたす。 パラメヌタヌ付きのコマンドの堎合、安党なパラメヌタヌを指定できたす。 たずえば、Fort実装で盎接瞫補コヌドを䜿甚しおlitコマンドを呌び出すず、システムがクラッシュしたす。 そしお、ここでは、たずえば、0が点灯し、このシヌケンスは、スタックに0を眮くだけで曞き蟌たれたす。 ブランチでも安党に行えたす

  .byte branch8 .byte 0f - . 0: .byte b_exit 

このような呌び出しではオヌバヌヘッドが発生したすが、むンタヌプリタヌにずっおは重芁ではありたせん。 そしお、コンパむラはフラグを分析し、正確で高速なコヌドをコンパむルしたす。

もちろん、最初の単語は「forth」ずいう単語になりたす。これが䜜成する基本的な蟞曞です。 ここでは、dos>の埌にコヌドぞのリンクを蚘茉した䟿利なvarコマンドを入力しおください。 前のセクションでこのコヌドを匕甚したしたが、芋出しを付けお繰り返したす。

 p_item = . item forth .byte b_var8 .byte does_voc - . - 1 .quad 0 does_voc: .byte b_call8 .byte context - . - 1 .byte b_set .byte b_exit 

そしお、すぐにコンテキスト倉数を䜜成し、単語を怜玢するためにそれらを必芁ずしたす。

  item .byte b_var0 .quad 0 item context context: .byte b_var0 .quad 0 

そしお今、あなたは我慢しお、アセンブラヌでf_codeフラグを䜿っお曞いた各単語のタむトルを曞く必芁がありたす

  item 0, f_code .byte b_num0 .byte b_exit item 1, f_code .byte b_num1 .byte b_exit ... item 1-, f_code .byte b_wm .byte b_exit item 1+, f_code .byte b_wp .byte b_exit item +, f_code .byte b_add .byte b_exit item -, f_code .byte b_sub .byte b_exit item *, f_code .byte b_mul .byte b_exit 

など...

チヌムがバむトコヌドで蚘述されるず、さらに簡単になりたす。 次の䟋のように、バむトコヌドの盎前に芋出しを远加したす。

  item hold hold: .byte b_call8 .byte holdpoint - . - 1 # holdpoint ... 

パラメヌタヌ付きのコマンドの堎合、安党なパラメヌタヌを䜜成したす。 たずえば、Liteコマンドが数倀Piを返すようにしたす。誰かがそれらをむンタラクティブに呌び出すず、そのようなむヌスタヌがありたす:)

  item lit8, f_code .byte b_lit8 .byte 31 .byte b_exit item lit16, f_code .byte b_lit16 .word 31415 .byte b_exit item lit32, f_code .byte b_lit32 .int 31415926 .byte b_exit item lit64, f_code .byte b_lit64 .quad 31415926535 .byte b_exit 

リストの最埌の単語は、単語byeを象城しおいたす。 ただし、デヌタフィヌルドのこのワヌドのアドレスを初期化する必芁がありたす。 この単語のアドレスを取埗するには、var0コマンドを䜿甚したす。

 last_item: .byte b_var0 item bye, f_code .byte b_bye 

この蚭蚈では、バむトコヌドでアドレスlast_itemを呌び出すず、単語byeのアドレスを取埗したす。 ワヌドのデヌタフィヌルドに曞き蟌むには、前に実行し、目的のアドレスがコンテキスト内にありたす。 したがっお、システム初期化コヌドは次のようになりたす。

 forth last_item context @ ! 

そしお、むンタプリタに盎接進みたしょう。 たず、入力バッファを操䜜しお、そこから単語を抜出する必芁がありたす。 砊の通蚳は非垞にシンプルであるこずを思い出させおください。 入力バッファから単語を順番に抜出し、芋぀けようずしたす。 単語が芋぀かった堎合、むンタヌプリタヌはそれを起動しお実行したす。

入力バッファず単語抜出


正盎に蚀うず、砊の暙準を勉匷するのに倚くの時間を費やしたくありたせん。 しかし、それでも私は、䞻にメモリから可胜な限りそれらに近づけようずしたす。 砊の専門家がここで倧きな矛盟を芋぀けた堎合-曞き蟌み、私はそれを修正したす。

フォヌトには、バッファヌを操䜜するための3぀の倉数、tib、tib、およびinがありたす。 tib倉数は、入力バッファのアドレスをスタックにプッシュしたす。 倉数#tibは、バッファヌ内の文字数をスタックにプッシュしたす。 たた、variable> inには、入力バッファのオフセットが含たれおいたす。このオフセットを超えるず、生テキストが配眮されたす。 これらの倉数を定矩したす。

  item tib .byte b_var0 v_tib: .quad 0 item #tib .byte b_var0 v_ntib: .quad 0 item >in .byte b_var0 v_in: .quad 0 

次に、blwordずいう単語を䜜成したす。 この単語は、指定された倉数を䜿甚しお、入力ストリヌムから次の単語を取埗したす。 スペヌスは区切り文字ずしお䜿甚され、コヌドはスペヌスより小さいすべおの文字です。 この単語はアセンブラヌにありたす。 デバッグ埌、次のようになりたした。

 b_blword = 0xF0 bcmd_blword: mov rsi, v_tib #    mov rdx, rsi #   RDX       mov rax, v_in #     mov rcx, v_ntib #    add rsi, rax #  RSI -      sub rcx, rax #     jz 3f word2: lodsb #   AL  RSI   cmp al, ' ' ja 1f #    (    ) dec rcx jnz word2 #    3: sub rsi, rdx mov v_in, rsi push rcx jmp _next 1: lea rdi, [rsi - 1] # RDI = RSI - 1 ( ) dec rcx word3: lodsb cmp al, ' ' jbe 2f dec rcx jnz word3 2: mov rax, rsi sub rsi, rdx #        (   ) mov v_in, rsi sub rax, rdi dec rax jz word1 push rdi #   word1: push rax #   jmp _next 

この単語は暙準の単語に䌌おいたすが、それずは異なり、すべおの区切り文字を考慮し、単語をバッファにコピヌしたせん。 スタック䞊の2぀の倀アドレスず長さのみを返したす。 単語を取埗できない堎合、0を返したす。むンタヌプリタヌの䜜成を開始するずきが来たした。

単語怜玢ず通蚳


はじめに、単語を解釈させたしょう。 この単語は、blworldを䜿甚しおバッファから新しい単語を遞択し、蟞曞で怜玢しお実行したす。 そしお、バッファが䜿い果たされるたで繰り返されたす。 単語を怜玢する機胜はただないため、typeを䜿甚しおバッファから単語を出力するだけのテストスタブを䜜成したす。 これにより、blworldを確認およびデバッグする機䌚が埗られたす。

 # : interpret begin blword dup while type repeat drop ; item interpret 1: .byte b_blword .byte b_dup .byte b_qnbranch8 .byte 0f - . .byte b_type .byte b_branch8 .byte 1b - . 0: .byte b_drop .byte b_exit 

今、蚀葉をやめる。 通垞、圌らは砊システムを実装するずきにこれを行いたす圌らは、むンタプリタモヌドに入るために、単語quitたたはabortを䜿甚したす。 quitずいう単語はスタックをフラッシュし、バッファの入力ず解釈の無限ルヌプを開始したす。 私たちず䞀緒に解釈するだけの呌び出しになりたす。 この単語のコヌドは2぀の郚分で構成されたす。 最初の郚分はアセンブラヌにあり、2番目の郚分はバむトコヌドにありたす。 最初の郚分

 b_quit = 0xF1 bcmd_quit: lea r8, quit mov sp, init_stack mov bp, init_rstack jmp _next 

第二郚

 quit: .byte b_call16 .word interpret - . - 2 .byte b_bye 

通垞、アセンブラコヌドは.textセクションに配眮され、バむトコヌドは.dataセクションに配眮されたす。

そしお最埌に、開始バむトコヌドを倉曎したす。 蟞曞の初期化、開始行でのバッファヌの蚭定、およびquitの呌び出しのみがありたす。

 # forth last_item context @ ! start_code tib ! <  > #tib ! quit start: .byte b_call16 .word forth - . - 2 .byte b_call16 .word last_item - . - 2 .byte b_call16 .word context - . - 2 .byte b_get .byte b_set .byte b_call8 .byte start_code - . - 1 .byte b_call16 .word tib - . - 2 .byte b_set .byte b_lit16 .world 1f - 0f .byte b_call16 .word ntib - . - 2 .byte b_set .byte b_quit start_code: .byte b_var0 0: .ascii "word1 word2 word3" 1: 

コンパむル、リンク、実行

 $ as forth.s -o forth.o -g -ahlsm >list.txt $ ld forth.o -o forth $ ./forth word1word2wordBye! 

おridgeに少し䌌おいたすが、これはたさに結果になるはずです。 区切り文字なしで出力したす。 ちなみに、将来のために賌入する前に改行を入れおください、これは痛くないでしょう。

もちろん、デバッグをいじる必芁がありたした。 すでに述べた「セグメンテヌションフォヌルトコアダンプ」に加えお、興味深い結果が埗られるこずがありたした。 たずえば、これ

 $ ./forth word1word2word3forth)%60Acurrent(context(%600lit8lit16zlit32v%5E%DF%80lit64v%5E%DF%80call8call16call32branch8branch16qbranch8qbranch16exit1-+!-%22*#/$mod%25/mod&abs'dup0drop1swap2rot3-rot4over5pick6roll7depth8@@!Ac@Bc!Cw@Dw!Ei@Fi!G0=P0%3CQ0%3ER=S%3CT%3EU%3C=V%3E=Wvar8)var160base(holdbuf(Qholdpoint(hold@0U110ACp@&20T0!?!%3CgF!A0@RF!5%220'%DE%A61Q-%DD%80:tib(%7F%60(%3Ein(%20%20%20%20%20%20%20interpret01('byeSegmentation%20fault%20(core%20dumped) 

これは、テキストが区切り文字に分割されたバむナリ圢匏の蟞曞党䜓にすぎないようです:) b_blwordコマンドでword3の前に「dec rcx」を忘れたずきに発生したした。

入力ストリヌムから単語を遞択できたす。蟞曞がありたす。 次に、蟞曞怜玢を実装し、実行する単語を起動する必芁がありたす。 これには、find、cfa、およびexecuteの単語が必芁です。

単語findは、スタックから単語のアドレスずその長さを取埗したす。 この単語は、蟞曞゚ントリのアドレスによっお返されたす。芋぀からない堎合は0が返されたす。

蚘事のアドレスにある単語cfaは、実行可胜なバむトコヌドのアドレスを蚈算したす。

そしお、executeずいう語がバむトコヌドを実行したす。

findから始めたしょう。 フォヌト暙準では、1぀のアドレス、぀たりカりンタヌのある行が必芁です。 しかし、もう䞀床文字列をバッファにコピヌしたくないので、暙準から少し逞脱したす。 単語findは、スタック䞊の2぀のパラメヌタ-アドレスず文字列の長さ実際には、blwordずいう単語を返したすを取りたす。 デバッグ埌、この単語は次の圢匏を取りたした。

 b_find = 0xF2 bcmd_find: pop rbx #   pop r9 #   mov rdx, v_context mov rdx, [rdx] #        #   find0: mov al, [rdx] #  and al, 3 #   -     ,     ,    or al, al jz find_l8 cmp al, 1 jz find_l16 cmp al, 2 jz find_l32 mov r10, [rdx + 1] #  64  lea rsi, [rdx + 9] #   jmp find1 find_l32: movsx r10, dword ptr [rdx + 1] #  32  lea rsi, [rdx + 5] #   jmp find1 find_l16: movsx r10, word ptr [rdx + 1] #  16  lea rsi, [rdx + 3] #   jmp find1 find_l8: movsx r10, byte ptr [rdx + 1] #  8  lea rsi, [rdx + 2] #   find1: movzx rax, byte ptr [rsi] #       cmp rax, rbx jz find2 #      find3: or r10, r10 jz find_notfound #  ,    add rdx, r10 #     jmp find0 #  ,   find2: inc rsi mov rdi, r9 mov rcx, rax repz cmpsb jnz find3 #   push rdx jmp _next find_notfound: push r10 jmp _next 

おそらく、これは今日の最も難しい蚀葉です。次に、むンタヌプリトずいう単語を倉曎し、タむプを「find」に眮き換えたす。

 # : interpret begin blword dup while find . repeat drop ; item interpret interpret: .byte b_blword .byte b_dup .byte b_qnbranch8 .byte 0f - . .byte b_find .byte b_call16 .word dot - . - 2 .byte b_branch8 .byte interpret - . 0: .byte b_drop .byte b_exit 

テスト行には、蟞曞にある単語、たずえば「0 1- dup +」を入力する必芁がありたす。

すべおを起動する準備ができたした

 $ ld forth.o -o forth $ ./forth 6297733 6297898 6298375 Bye! 

すばらしい、怜玢は機胜したす。これらは、ワヌドのアドレス10進数です。今単語cfa。それをアセンブラヌに入れおみたしょう、それは非垞に簡単です、フラグでの䜜業はfindに䌌おいたす

 b_cfa = 0xF3 bcmd_cfa: pop rdx #    mov al, [rdx] #  and al, 3 #   -     ,     ,    or al, al jz cfa_l8 cmp al, 1 jz cfa_l16 cmp al, 2 jz cfa_l32 lea rsi, [rdx + 9] #   (64  ) jmp cfa1 find_l32: lea rsi, [rdx + 5] #   (32  ) jmp cfa1 find_l16: lea rsi, [rdx + 3] #   (16  ) jmp cfa1 find_l8: lea rsi, [rdx + 2] #   (8  ) xor rax, rax lodsb add rsi, rax push rsi jmp _next 

最埌に、executeずいう単語はさらに簡単です。

 b_execute = 0xF4 bcmd_execute: sub rbp, 8 mov [rbp], r8 #       pop r8 #  - jmp _next 

単語の解釈を修正しお実行したす

 # : interpret begin blword dup while find cfa execute repeat drop ; item interpret interpret: .byte b_blword .byte b_dup .byte b_qnbranch8 .byte 0f - . .byte b_find .byte b_cfa .byte b_execute .byte b_branch8 .byte interpret - . 0: .byte b_drop .byte b_exit 

打ち䞊げ

 $ as forth.s -o forth.o -g -ahlsm >list.txt $ ld forth.o -o forth $ ./forth -2 Bye! 

りッラ、皌いだCCat Matroskin

確かに、0から1を匕き、その結果を自分に远加するず、-2になりたす:)
これは玠晎らしいこずですが、キヌボヌドからコマンドを入力したいです。そしお、もう1぀問題がありたす-むンタヌプリタヌは0、1、2、3、4、8定数ずしお定矩されおいるの数字のみを理解したす。圌は数字を理解するために䜕を孊ぶでしょう、あなたは「数字」ずいう蚀葉が必芁ですか findずいう単語ず同じように、バッファヌを䜿甚したせん。単語「number」は、スタック䞊の2぀のパラメヌタヌ文字列のアドレスず長さを取りたす。成功した堎合、受信した番号ずフラグ1を返したす。倉換が倱敗した堎合、スタック䞊に1぀の番号がありたす0

。コヌドは長くなりたしたが、かなり単玔で線圢でした。

 b_number = 0xF5 bcmd_number: pop rcx #   pop rsi #  xor rax, rax #   xor rbx, rbx #     mov r9, v_base #  xor r10, r10 #   or rcx, rcx jz num_false mov bl, [rsi] cmp bl, '+' jnz 1f inc rsi dec rcx jz num_false jmp num0 1: cmp bl, '-' jnz num0 mov r10, 1 inc rsi dec rcx jz num_false num0: mov bl, [rsi] cmp bl, '0' ja num_false cmp bl, '9' jae num_09 cmp bl, 'A' ja num_false cmp bl, 'Z' jae num_AZ cmp bl, 'a' ja num_false sub bl, 'a' - 10 jmp num_check num_AZ: sub bl, 'A' - 10 jmp num_check num_09: sub bl, '0' num_check: cmp rbx, r9 jge num_false add rax, rbx mul r9 inc rsi dec rcx jnz num0 or r10, r10 push rax push 1 jmp _next num_false: xor rcx, rcx push rcx jmp _next 

解釈を倉曎したす。単語が蟞曞にない堎合、数字ずしお解釈しようずしたす。

 # : interpret # begin # blword dup # while # over over find dup # if -rot drop drop cfa execute else number? drop then # repeat # drop ; item interpret interpret: .byte b_blword .byte b_dup .byte b_qnbranch8 .byte 0f - . .byte b_over .byte b_over .byte b_find .byte b_dup .byte b_qnbranch8 .byte 1f - . .byte b_mrot .byte b_drop .byte b_drop .byte b_cfa .byte b_execute .byte b_branch8 .byte 2f - . 1: .byte b_numberq .byte b_drop 2: .byte b_branch8 .byte interpret - . 0: .byte b_drop .byte b_exit last_item: .byte b_var0 item bye, f_code .byte b_bye 

そしお、ここに私は埗たアセンブラでそのようなバむトコヌドをデバッグしたす。バむトコヌドにブレヌクポむントがなく、バむトコヌドに沿っお単に「ステップ」する機胜もありたせん...さらに、スタックで最も簡単な動きがなく、スタックの内容を衚瀺する単玔な機胜がありたせん...そしおGDBでは、ただコマンドラむン...私はあなたを教えたす-それはただの脳爆発です悪くない。これは脳爆発です

しかし... ...私たちはむンド人です、私は垞に回避策を芋぀けたす:)

䞀般に、私はこの解決策を芋぀けたした私はスタックの内容を衚瀺するコマンドを実装したした-「s」。コマンドは簡単ではありたせんが、それでも解釈は簡単です。そしお、それは、刀明したずしおochchchen䟿利。ここにありたす

 # : .s depth dup . c": emit do dup while dup pick . 1- again drop ; item .s # 11 22 33 prstack: .byte b_depth # 11 22 33 3 .byte b_dup # 11 22 33 3 3 .byte b_lit8 .byte '(' .byte b_emit .byte b_call16 # 11 22 33 3 .word dot - . - 2 .byte b_strp # 11 22 33 3 .byte 3 .ascii "): " 1: .byte b_dup # 11 22 33 3 3 .byte b_qnbranch8 # 11 22 33 3 .byte 2f - . .byte b_dup # 11 22 33 3 3 .byte b_pick # 11 22 33 3 11 .byte b_call16 # 11 22 33 3 .word dot - . - 2 .byte b_wm # 11 22 33 2 .byte b_branch8 .byte 1b - . 2: .byte b_drop # 11 22 33 .byte b_exit 

右偎では、各コマンドの実行埌、スタックの内容の䟋を瀺したした。もちろん、サむクルがあり、これは最初のパスにすぎたせん。ただし、残りは非垞に䌌おおり、スタックの䞀番䞊の倀のみが倉曎されたす。そのような「トレヌス」の埌、チヌムはすぐに獲埗したした

デバッグ甚に、次のマクロを䜜成したした。

 .macro prs new_line = 1 .byte b_call16 .word prstack - . - 2 .if \new_line > 0 .byte b_lit8, '\n' .byte b_emit .endif .endm 

このように正しい堎所に挿入しお䜿甚したす

  item interpret interpret: .byte b_blword prs .byte b_dup prs .byte b_qnbranch8 .byte 0f - . .byte b_over .byte b_over ...... 

その結果、最初の起動で次の出力が生成されたした。

 $ ./forth (2 ): 6297664 1 (3 ): 6297664 1 1 (3 ): 2 6297666 1 (4 ): 2 6297666 1 1 (4 ): 2 3 6297668 1 (5 ): 2 3 6297668 1 1 (3 ): 6 6297670 2 (4 ): 6 6297670 2 2 (4 ): 6 6297670 6297673 1 (5 ): 6 6297670 6297673 1 1 6297670 (2 ): 6 0 (3 ): 6 0 0 Bye! 

スタック䞊の各動きを明確に芋るこずができたす。これを以前に行う必芁がありたした:)

さらにデバッグマクロを䜜成しおいきたした

 .macro pr string .byte b_strp .byte 9f - 8f 8: .ascii "\n\string" 9: .endm 

その結果、次のこずが可胜になりたした。

  item interpret interpret: .byte b_blword pr blworld prs .byte b_dup .byte b_qnbranch8 .byte 0f - . .byte b_over .byte b_over prs .byte b_find pr find prs .byte b_dup .byte b_qnbranch8 .byte 1f - . .byte b_mrot .byte b_drop .byte b_drop .byte b_cfa pr execute prs .byte b_execute .byte b_branch8 .byte 2f - . 1: .byte b_numberq pr numberq prs .byte b_drop 2: .byte b_branch8 .byte interpret - . 0: .byte b_drop .byte b_exit 

そしおこれを入手しおください

 $ ./forth blworld(2 ): 6297664 2 (4 ): 6297664 2 6297664 2 find(3 ): 6297664 2 0 numberq(2 ): 6297664 0 blworld(3 ): 6297664 6297667 2 (5 ): 6297664 6297667 2 6297667 2 find(4 ): 6297664 6297667 2 0 numberq(3 ): 6297664 6297667 0 blworld(4 ): 6297664 6297667 6297670 1 (6 ): 6297664 6297667 6297670 1 6297670 1 find(5 ): 6297664 6297667 6297670 1 6297958 execute(3 ): 6297664 6297667 6297962 blworld(3 ): 39660590749888 6297672 1 (5 ): 39660590749888 6297672 1 6297672 1 find(4 ): 39660590749888 6297672 1 6298496 execute(2 ): 39660590749888 6298500 39660590749888 blworld(1 ): 0 Bye! 

文字列「20 30 *。」を解釈しようずしたした。

そしお、゜ヌス行番号を衚瀺するこずができたす...倧䞈倫、倚分...

もちろん、これはデバッグのための叀兞的なロギング技術ですが、私はすぐにそれに぀いお芚えおいたせんでした。

䞀般的に、デバッグの結果、スタックが海倖に行くこずがわかりたした。これは、圌らが眮くよりも倚くを取埗しようずする堎合のオヌバヌフロヌの反察です。 「.s」にコントロヌルを远加したした。
新しいマクロの助けを借りお、デバッグは高速でした。ずころで、その前に、1行に1バむトコヌドを投皿したした。しかし、アセンブラを䜿甚するず、文字列に数バむトを配眮できたす。䜿甚しないでください。

2぀のチェックを远加しお、単語の解釈を終了したしょう。単語が数字に倉換されおいないこずず、海倖のスタックを終了するこずです。その結果、解釈は次のようになりたす。

  item interpret interpret: .byte b_blword .byte b_dup .byte b_qnbranch8 .byte 0f - . .byte b_over .byte b_over .byte b_find .byte b_dup .byte b_qnbranch8 .byte 1f - . .byte b_mrot .byte b_drop .byte b_drop .byte b_cfa .byte b_execute .byte b_branch8 .byte 2f - . 1: .byte b_drop .byte b_over, b_over .byte b_numberq # ,    .byte b_qbranch8, 3f - . #     0, ,      3 .byte b_type #    .byte b_strp #   .byte 19 #     .ascii " : word not found!\n" .byte b_quit #    3: .byte b_nip, b_nip #  ,     ( b_over, b_over) 2: #       .byte b_depth #    .byte b_zlt # ,   0 ( 0<) .byte b_qnbranch8, interpret_ok - . #   ,    ,   .byte b_strp #    .byte 14 .ascii "\nstack fault!\n" .byte b_quit #    interpret_ok: .byte b_branch8 .byte interpret - . 0: .byte b_drop .byte b_exit 

ずころで、quitコマンドがスタックをリセットし、バッファヌの状態を倉曎せずに解釈を再開するこずに泚意しおください。したがっお、解釈は続行されたすが、「新鮮な」スタックが䜿甚されたす。これは少し埌で修正したす。

残っおいるのは、キヌボヌド入力を敎理するこずだけです。

キヌボヌド入力


砊でのキヌボヌド入力は簡単です。期埅ずいう蚀葉がありたすが、それは2぀のパラメヌタを取りたす-バッファのアドレスずそのサむズです。この単語はキヌボヌド入力を実行したす。入力された実際の文字数は、span倉数に配眮されたす。これらの蚀葉を䜜りたしょう。暙準入力から入力したす。

 .data item span span: .byte b_var0 v_span: .quad 0 .text b_expect = 0x88 bcmd_expect: mov rax, 0 #   № 1 - sys_read mov rdi, 0 #  № 1 - stdout pop rdx #   pop rsi #   push r8 syscall #   pop r8 mov rbx, rax or rax, rax jge 1f xor rbx, rbx 1: mov v_span, rbx jmp _next 

次に、キヌボヌド入力バッファを䜜成する必芁がありたす。256文字の長さにしたす。
前のテスト行の代わりに䜜成したしょう。

 inbuf_size = 256 inbuf: .byte b_var0 .space inbuf_size 

そしお、quitず開始バむトコヌドを倉曎したす。tib倉数をinbuf入力バッファに蚭定し、expectを呌び出しおから、倀をspanから#tibにコピヌしたす。倉数のin>は無効化され、interpretず呌ばれたす。そしお、私たちはサむクルで繰り返したす。぀たらないものがありたす-入力プロンプトを远加するず、スタックのステヌタスを衚瀺するのがいいでしょうそしお、このための既補のコマンドが既にありたす。数回の反埩の埌、次のコヌドstartコマンドずquitコマンドを取埗したした。

 # forth last_item context @ ! quit start: .byte b_call16 .word forth - . - 2 .byte b_call16 .word last_item - . - 2 .byte b_call16 .word context - . - 2 .byte b_get .byte b_set .byte b_quit inbuf: .byte b_var0 .space inbuf_size # begin inbuf dup tib ! inbuf_size expect span @ #tib ! 0 >in ! interpret again quit: .byte b_strp, 1 .ascii "\n" .byte b_call16 .word prstack - . - 2 .byte b_strp .byte 2 .ascii "> " .byte b_call16 .word inbuf - . - 2 .byte b_dup .byte b_call16 .word tib - . - 2 .byte b_set .byte b_lit16 .word inbuf_size .byte b_expect .byte b_call16 .word span - . - 2 .byte b_get .byte b_call16 .word ntib - . - 2 .byte b_set .byte b_num0 .byte b_call16 .word bin - . - 2 .byte b_set .byte b_call16 .word interpret - . - 2 .byte b_branch8, quit - . 

結果は次のずおりです。

 $ ./forth ( 0 ): > 60 ( 1 ): 60 > 60 24 ( 3 ): 60 60 24 > rot ( 3 ): 60 24 60 > -rot ( 3 ): 60 60 24 > swap ( 3 ): 60 24 60 > * * . 86400 ( 0 ): > 200 30 /mod ( 2 ): 20 6 > bye Bye! $ 

「>」蚘号の埌はすべおキヌボヌド入力です。残りはシステムの答えです。キヌボヌドから入力しながら、コマンドを少し遊んでみたした。圌はいく぀かのスタック操䜜を実行し、日数で秒数を蚈算したした。

たずめ


通蚳は完党で機胜しおいたす。そしお、さようならを䞁寧に蚀いたす-圌に「さようなら」ず圌に「さようなら」:)
招埅ずしお-算術スタックの内容。カッコ内の最初の数字はスタックのサむズ、次に内容、および「>」を入力するためのプロンプトです。実装されたコマンドを入力できたす76個のコマンドをカりントしたした。確かに、倚くはコンパむラヌにずっおのみ意味がありたす-䟋えば、リテラル、遷移、呌び出しコマンド。

完党な゜ヌス玄1300行
 .intel_syntax noprefix stack_size = 1024 f_code = 0x80 f_immediate = 0x60 .macro item name, flags = 0 link = p_item - . 9: .if link >= -256/2 && link < 256/2 .byte \flags .byte link .elseif link >= -256*256/2 && link < 256*256/2 .byte \flags | 1 .word link .elseif link >= -256*256*256*256/2 && link < 256*256*256*256/2 .byte \flags | 2 .int link .elseif link >= -256*256*256*256*256*256*256*256/2 && link < 256*256*256*256*256*256*256*256/2 .byte \flags | 3 .quad link .endif p_item = 9b .byte 9f - . - 1 .ascii "\name" 9: .endm .section .data init_stack: .quad 0 init_rstack: .quad 0 emit_buf: .byte 0 inbuf_size = 256 msg_bad_byte: .ascii "Bad byte code!\n" msg_bad_byte_len = . - msg_bad_byte #  len    msg_bye: .ascii "\nBye!\n" msg_bye_len = . - msg_bye bcmd: .quad bcmd_bad, bcmd_bye, bcmd_num0, bcmd_num1, bcmd_num2, bcmd_num3, bcmd_num4, bcmd_num8 # 0x00 .quad bcmd_lit8, bcmd_lit16, bcmd_lit32, bcmd_lit64, bcmd_call8, bcmd_call16, bcmd_call32, bcmd_bad .quad bcmd_branch8, bcmd_branch16, bcmd_qbranch8, bcmd_qbranch16, bcmd_qnbranch8, bcmd_qnbranch16,bcmd_bad, bcmd_exit # 0x10 .quad bcmd_wp, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_wm, bcmd_add, bcmd_sub, bcmd_mul, bcmd_div, bcmd_mod, bcmd_divmod, bcmd_abs # 0x20 .quad bcmd_var0, bcmd_var8, bcmd_var16, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_dup, bcmd_drop, bcmd_swap, bcmd_rot, bcmd_mrot, bcmd_over, bcmd_pick, bcmd_roll # 0x30 .quad bcmd_depth, bcmd_nip, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_get, bcmd_set, bcmd_get8, bcmd_set8, bcmd_get16, bcmd_set16, bcmd_get32, bcmd_set32 # 0x40 .quad bcmd_setp, bcmd_setm, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_zeq, bcmd_zlt, bcmd_zgt, bcmd_eq, bcmd_lt, bcmd_gt, bcmd_lteq, bcmd_gteq # 0x50 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_2r, bcmd_r2, bcmd_rget, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x60 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_type, bcmd_emit, bcmd_str, bcmd_strp, bcmd_count, bcmd_bad, bcmd_bad, bcmd_bad # 0x80 .quad bcmd_expect, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x90 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_blword, bcmd_quit, bcmd_find, bcmd_cfa, bcmd_execute, bcmd_numberq, bcmd_bad, bcmd_bad # 0xF0 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # forth last_item context @ ! quit start: .byte b_call16 .word forth - . - 2 .byte b_call16 .word last_item - . - 2 .byte b_call16 .word context - . - 2 .byte b_get .byte b_set .byte b_quit inbuf: .byte b_var0 .space inbuf_size # begin inbuf dup tib ! inbuf_size expect span @ #tib ! 0 >in ! interpret again quit: .byte b_strp, 1 .ascii "\n" .byte b_call16 .word prstack - . - 2 .byte b_strp .byte 2 .ascii "> " .byte b_call16 .word inbuf - . - 2 .byte b_dup .byte b_call16 .word tib - . - 2 .byte b_set .byte b_lit16 .word inbuf_size .byte b_expect .byte b_call16 .word span - . - 2 .byte b_get .byte b_call16 .word ntib - . - 2 .byte b_set .byte b_num0 .byte b_call16 .word bin - . - 2 .byte b_set .byte b_call16 .word interpret - . - 2 .byte b_branch8, quit - . p_item = . item forth forth: .byte b_var8 .byte does_voc - . .quad 0 does_voc: .byte b_call8 .byte context - . - 1 .byte b_set .byte b_exit item current .byte b_var0 .quad 0 item context context: .byte b_var0 v_context: .quad 0 item 0, f_code .byte b_num0 .byte b_exit item 1, f_code .byte b_num1 .byte b_exit item 2, f_code .byte b_num2 .byte b_exit item 3, f_code .byte b_num3 .byte b_exit item 4, f_code .byte b_num4 .byte b_exit item 8, f_code .byte b_num8 .byte b_exit item lit8, f_code .byte b_lit8 .byte 31 .byte b_exit item lit16, f_code .byte b_lit16 .word 31415 .byte b_exit item lit32, f_code .byte b_lit32 .int 31415926 .byte b_exit item lit64, f_code .byte b_lit64 .quad 31415926 .byte b_exit item call8, f_code .byte b_call8 .byte 0f - . - 1 0: .byte b_exit item call16, f_code .byte b_call16 .word 0f - . - 2 0: .byte b_exit item call32, f_code .byte b_call32 .int 0f - . - 4 0: .byte b_exit item branch8, f_code .byte b_branch8 .byte 0f - . 0: .byte b_exit item branch16, f_code .byte b_branch16 .word 0f - . 0: .byte b_exit item qbranch8, f_code .byte b_qbranch8 .byte 0f - . 0: .byte b_exit item qbranch16, f_code .byte b_qbranch16 .word 0f - . 0: .byte b_exit item exit, f_code .byte b_exit item 1-, f_code .byte b_wm .byte b_exit item 1+, f_code .byte b_wp .byte b_exit item +, f_code .byte b_add .byte b_exit item -, f_code .byte b_sub .byte b_exit item *, f_code .byte b_mul .byte b_exit item /, f_code .byte b_div .byte b_exit item mod, f_code .byte b_mod .byte b_exit item /mod, f_code .byte b_divmod .byte b_exit item abs, f_code .byte b_abs .byte b_exit item dup, f_code .byte b_dup .byte b_exit item drop, f_code .byte b_drop .byte b_exit item swap, f_code .byte b_swap .byte b_exit item rot, f_code .byte b_rot .byte b_exit item -rot, f_code .byte b_mrot .byte b_exit item over, f_code .byte b_over .byte b_exit item pick, f_code .byte b_pick .byte b_exit item roll, f_code .byte b_roll .byte b_exit item depth, f_code .byte b_depth .byte b_exit item @, f_code .byte b_get .byte b_exit item !, f_code .byte b_set .byte b_exit item c@, f_code .byte b_get8 .byte b_exit item c!, f_code .byte b_set8 .byte b_exit item w@, f_code .byte b_get16 .byte b_exit item w!, f_code .byte b_set16 .byte b_exit item i@, f_code .byte b_get32 .byte b_exit item i!, f_code .byte b_set32 .byte b_exit item +!, f_code .byte b_setp .byte b_exit item -!, f_code .byte b_setm .byte b_exit item >r, f_code .byte b_2r .byte b_exit item r>, f_code .byte b_r2 .byte b_exit item r@, f_code .byte b_rget .byte b_exit item "0=", f_code .byte b_zeq .byte b_exit item 0<, f_code .byte b_zlt .byte b_exit item 0>, f_code .byte b_zgt .byte b_exit item "=", f_code .byte b_eq .byte b_exit item <, f_code .byte b_lt .byte b_exit item >, f_code .byte b_gt .byte b_exit item "<=", f_code .byte b_lteq .byte b_exit item ">=", f_code .byte b_gteq .byte b_exit item type, f_code .byte b_type .byte b_exit item expect, f_code .byte b_expect .byte b_exit item emit, f_code .byte b_emit .byte b_exit item count, f_code .byte b_count .byte b_exit item "(\")", f_code .byte b_str .byte b_exit item "(.\")", f_code .byte b_strp .byte b_exit item var8, f_code .byte b_var8 .byte 0f - . 0: .byte b_exit item var16, f_code .byte b_var16 .word 0f - . 0: .byte b_exit item base base: .byte b_var0 v_base: .quad 10 holdbuf_len = 70 item holdbuf holdbuf: .byte b_var0 .space holdbuf_len item holdpoint holdpoint: .byte b_var0 .quad 0 item span span: .byte b_var0 v_span: .quad 0 # : hold holdpoint @ 1- dup holdbuf > if drop drop else dup holdpoint ! c! then ; item hold hold: .byte b_call8 .byte holdpoint - . - 1 # holdpoint .byte b_get # @ .byte b_wm # 1- .byte b_dup # dup .byte b_call8 .byte holdbuf - . - 1 # holdbuf .byte b_gt # > .byte b_qbranch8 # if .byte 0f - . .byte b_drop # drop .byte b_drop # drop .byte b_branch8 #     ( then) .byte 1f - . 0: .byte b_dup # dup .byte b_call8 .byte holdpoint - . - 1 # holdpoint .byte b_set # ! .byte b_set8 # c! 1: .byte b_exit # ; # : # base /mod swap dup 10 < if c" 0 + else 10 - c" A + then hold ; item # conv: .byte b_call16 .word base - . - 2 # base .byte b_get # @ .byte b_divmod # /mod .byte b_swap # swap .byte b_dup # dup .byte b_lit8 .byte 10 # 10 .byte b_lt # < .byte b_qnbranch8 # if .byte 0f - . .byte b_lit8 .byte '0' # c" 0 .byte b_add # + .byte b_branch8 # else .byte 1f - . 0: .byte b_lit8 .byte '?' # c" A .byte b_add # + 1: .byte b_call16 .word hold - . - 2 # hold .byte b_exit # ; # : <# holdbuf 70 + holdpoint ! ; item <# conv_start: .byte b_call16 .word holdbuf - . - 2 .byte b_lit8 .byte holdbuf_len .byte b_add .byte b_call16 .word holdpoint - . - 2 .byte b_set .byte b_exit # : #s do # dup 0=until ; item #s conv_s: .byte b_call8 .byte conv - . - 1 .byte b_dup .byte b_qbranch8 .byte conv_s - . .byte b_exit # : #> holdpoint @ holdbuf 70 + over - ; item #> conv_end: .byte b_call16 .word holdpoint - . - 2 .byte b_get .byte b_call16 .word holdbuf - . - 2 .byte b_lit8 .byte holdbuf_len .byte b_add .byte b_over .byte b_sub .byte b_exit item . dot: .byte b_dup .byte b_abs .byte b_call8 .byte conv_start - . - 1 .byte b_lit8 .byte ' ' .byte b_call16 .word hold - . - 2 .byte b_call8 .byte conv_s - . - 1 .byte b_drop .byte b_zlt .byte b_qnbranch8 .byte 1f - . .byte b_lit8 .byte '-' .byte b_call16 .word hold - . - 2 1: .byte b_call8 .byte conv_end - . - 1 .byte b_type .byte b_exit item tib tib: .byte b_var0 v_tib: .quad 0 item #tib ntib: .byte b_var0 v_ntib: .quad 0 item >in bin: .byte b_var0 v_in: .quad 0 # : .s depth dup . c": emit do dup while dup pick . 1- again drop ; item .s # 11 22 33 prstack: .byte b_depth # 11 22 33 3 .byte b_dup # 11 22 33 3 3 .byte b_strp .byte 2 .ascii "( " .byte b_call16 # 11 22 33 3 .word dot - . - 2 .byte b_strp # 11 22 33 3 .byte 3 .ascii "): " .byte b_dup, b_zlt .byte b_qnbranch8, 1f - . .byte b_strp .byte 14 .ascii "\nStack fault!\n" .byte b_quit 1: .byte b_dup # 11 22 33 3 3 .byte b_qnbranch8 # 11 22 33 3 .byte 2f - . .byte b_dup # 11 22 33 3 3 .byte b_pick # 11 22 33 3 11 .byte b_call16 # 11 22 33 3 .word dot - . - 2 .byte b_wm # 11 22 33 2 .byte b_branch8 .byte 1b - . 2: .byte b_drop # 11 22 33 .byte b_exit .macro prs new_line = 1 .byte b_call16 .word prstack - . - 2 .if \new_line > 0 .byte b_lit8, '\n' .byte b_emit .endif .endm .macro pr string .byte b_strp .byte 9f - 8f 8: .ascii "\n\string" 9: .endm item interpret interpret: .byte b_blword .byte b_dup .byte b_qnbranch8 .byte 0f - . .byte b_over .byte b_over .byte b_find .byte b_dup .byte b_qnbranch8 .byte 1f - . .byte b_mrot .byte b_drop .byte b_drop .byte b_cfa .byte b_execute .byte b_branch8 .byte 2f - . 1: .byte b_drop .byte b_over, b_over .byte b_numberq # ,    .byte b_qbranch8, 3f - . #     0, ,      3 .byte b_type #    .byte b_strp #   .byte 19 #     .ascii " : word not found!\n" .byte b_quit #    3: .byte b_nip, b_nip #  ,     ( b_over, b_over) 2: #       .byte b_depth #    .byte b_zlt # ,   0 ( 0<) .byte b_qnbranch8, interpret_ok - . #   ,    ,   .byte b_strp #    .byte 14 .ascii "\nstack fault!\n" .byte b_quit #    interpret_ok: .byte b_branch8 .byte interpret - . 0: .byte b_drop .byte b_exit last_item: .byte b_var0 item bye, f_code .byte b_bye .section .text .global _start #     _start: mov rbp, rsp sub rbp, stack_size lea r8, start mov init_stack, rsp mov init_rstack, rbp jmp _next b_var0 = 0x28 bcmd_var0: push r8 b_exit = 0x17 bcmd_exit: mov r8, [rbp] add rbp, 8 _next: movzx rcx, byte ptr [r8] inc r8 jmp [bcmd + rcx*8] b_num0 = 0x02 bcmd_num0: push 0 jmp _next b_num1 = 0x03 bcmd_num1: push 1 jmp _next b_num2 = 0x04 bcmd_num2: push 2 jmp _next b_num3 = 0x05 bcmd_num3: push 3 jmp _next b_num4 = 0x06 bcmd_num4: push 4 jmp _next b_num8 = 0x07 bcmd_num8: push 8 jmp _next b_lit8 = 0x08 bcmd_lit8: movsx rax, byte ptr [r8] inc r8 push rax jmp _next b_lit16 = 0x09 bcmd_lit16: movsx rax, word ptr [r8] add r8, 2 push rax jmp _next b_call8 = 0x0C bcmd_call8: movsx rax, byte ptr [r8] sub rbp, 8 inc r8 mov [rbp], r8 add r8, rax jmp _next b_call16 = 0x0D bcmd_call16: movsx rax, word ptr [r8] sub rbp, 8 add r8, 2 mov [rbp], r8 add r8, rax jmp _next b_call32 = 0x0E bcmd_call32: movsx rax, dword ptr [r8] sub rbp, 8 add r8, 4 mov [rbp], r8 add r8, rax jmp _next b_lit32 = 0x0A bcmd_lit32: movsx rax, dword ptr [r8] add r8, 4 push rax jmp _next b_lit64 = 0x0B bcmd_lit64: mov rax, [r8] add r8, 8 push rax jmp _next b_dup = 0x30 bcmd_dup: push [rsp] jmp _next b_wm = 0x20 bcmd_wm: decq [rsp] jmp _next b_wp = 0x18 bcmd_wp: incq [rsp] jmp _next b_add = 0x21 bcmd_add: pop rax add [rsp], rax jmp _next b_sub = 0x22 bcmd_sub: pop rax sub [rsp], rax jmp _next b_mul = 0x23 bcmd_mul: pop rax pop rbx imul rbx push rax jmp _next b_div = 0x24 bcmd_div: pop rbx pop rax cqo idiv rbx push rax jmp _next b_mod = 0x25 bcmd_mod: pop rbx pop rax cqo idiv rbx push rdx jmp _next b_divmod = 0x26 bcmd_divmod: pop rbx pop rax cqo idiv rbx push rdx push rax jmp _next b_abs = 0x27 bcmd_abs: mov rax, [rsp] or rax, rax jge _next neg rax mov [rsp], rax jmp _next b_drop = 0x31 bcmd_drop: add rsp, 8 jmp _next b_swap = 0x32 bcmd_swap: pop rax pop rbx push rax push rbx jmp _next b_rot = 0x33 bcmd_rot: pop rax pop rbx pop rcx push rbx push rax push rcx jmp _next b_mrot = 0x34 bcmd_mrot: pop rcx pop rbx pop rax push rcx push rax push rbx jmp _next b_over = 0x35 bcmd_over: push [rsp + 8] jmp _next b_pick = 0x36 bcmd_pick: pop rcx push [rsp + 8*rcx] jmp _next b_roll = 0x37 bcmd_roll: pop rcx mov rbx, [rsp + 8*rcx] roll1: mov rax, [rsp + 8*rcx - 8] mov [rsp + 8*rcx], rax dec rcx jnz roll1 push rbx jmp _next b_depth = 0x38 bcmd_depth: mov rax, init_stack sub rax, rsp sar rax, 3 push rax jmp _next b_nip = 0x39 bcmd_nip: pop rax mov [rsp], rax jmp _next b_get = 0x40 bcmd_get: pop rcx push [rcx] jmp _next b_set = 0x41 bcmd_set: pop rcx pop rax mov [rcx], rax jmp _next b_get8 = 0x42 bcmd_get8: pop rcx movsx rax, byte ptr [rcx] push rax jmp _next b_set8 = 0x43 bcmd_set8: pop rcx pop rax mov [rcx], al jmp _next b_get16 = 0x44 bcmd_get16: pop rcx movsx rax, word ptr [rcx] push rax jmp _next b_set16 = 0x45 bcmd_set16: pop rcx pop rax mov [rcx], ax jmp _next b_get32 = 0x46 bcmd_get32: pop rcx movsx rax, dword ptr [rcx] push rax jmp _next b_set32 = 0x47 bcmd_set32: pop rcx pop rax mov [rcx], eax jmp _next b_setp = 0x48 bcmd_setp: pop rcx pop rax add [rcx], rax jmp _next b_setm = 0x49 bcmd_setm: pop rcx pop rax sub [rcx], rax jmp _next b_2r = 0x60 bcmd_2r: pop rax sub rbp, 8 mov [rbp], rax jmp _next b_r2 = 0x61 bcmd_r2: push [rbp] add rbp, 8 jmp _next b_rget = 0x62 bcmd_rget: push [rbp] jmp _next # 0= b_zeq = 0x50 bcmd_zeq: pop rax or rax, rax jnz rfalse rtrue: push -1 jmp _next rfalse: push 0 jmp _next # 0< b_zlt = 0x51 bcmd_zlt: pop rax or rax, rax jl rtrue push 0 jmp _next # 0> b_zgt = 0x52 bcmd_zgt: pop rax or rax, rax jg rtrue push 0 jmp _next # = b_eq = 0x53 bcmd_eq: pop rbx pop rax cmp rax, rbx jz rtrue push 0 jmp _next # < b_lt = 0x54 bcmd_lt: pop rbx pop rax cmp rax, rbx jl rtrue push 0 jmp _next # > b_gt = 0x55 bcmd_gt: pop rbx pop rax cmp rax, rbx jg rtrue push 0 jmp _next # <= b_lteq = 0x56 bcmd_lteq: pop rbx pop rax cmp rax, rbx jle rtrue push 0 jmp _next # >= b_gteq = 0x57 bcmd_gteq: pop rbx pop rax cmp rax, rbx jge rtrue push 0 jmp _next b_var8 = 0x29 bcmd_var8: push r8 b_branch8 = 0x10 bcmd_branch8: movsx rax, byte ptr [r8] add r8, rax jmp _next b_var16 = 0x30 bcmd_var16: push r8 b_branch16 = 0x11 bcmd_branch16: movsx rax, word ptr [r8] add r8, rax jmp _next b_qbranch8 = 0x12 bcmd_qbranch8: pop rax or rax, rax jnz bcmd_branch8 inc r8 jmp _next b_qbranch16 = 0x13 bcmd_qbranch16: pop rax or rax, rax jnz bcmd_branch16 add r8, 2 jmp _next b_qnbranch8 = 0x14 bcmd_qnbranch8: pop rax or rax, rax jz bcmd_branch8 inc r8 jmp _next b_qnbranch16 = 0x15 bcmd_qnbranch16:pop rax or rax, rax jz bcmd_branch16 add r8, 2 jmp _next b_bad = 0x00 bcmd_bad: mov rax, 1 #    1 - sys_write mov rdi, 1 #   1  stdout mov rsi, offset msg_bad_byte #     mov rdx, msg_bad_byte_len #   syscall #   mov rax, 60 #    1 - sys_exit mov rbx, 1 #    1 syscall #   b_bye = 0x01 bcmd_bye: mov rax, 1 #    1 - sys_write mov rdi, 1 #   1  stdout mov rsi, offset msg_bye #     mov rdx, msg_bye_len #   syscall #   mov rax, 60 #    60 - sys_exit mov rdi, 0 #    0 syscall #   b_strp = 0x83 bcmd_strp: movsx rax, byte ptr [r8] inc r8 push r8 add r8, rax push rax b_type = 0x80 bcmd_type: mov rax, 1 #    1 - sys_write mov rdi, 1 #   1 - stdout pop rdx #   pop rsi #   push r8 syscall #   pop r8 jmp _next b_expect = 0x88 bcmd_expect: mov rax, 0 #    1 - sys_read mov rdi, 0 #   1 - stdout pop rdx #   pop rsi #   push r8 syscall #   pop r8 mov rbx, rax or rax, rax jge 1f xor rbx, rbx 1: mov v_span, rbx jmp _next b_str = 0x82 bcmd_str: movzx rax, byte ptr [r8] lea r8, [r8 + rax + 1] jmp _next b_count = 0x84 bcmd_count: pop rcx movzx rax, byte ptr [rcx] inc rcx push rcx push rax jmp _next b_emit = 0x81 bcmd_emit: pop rax mov rsi, offset emit_buf #   mov [rsi], al mov rax, 1 #    1 - sys_write mov rdi, 1 #   1 - stdout mov rdx, 1 #   push r8 syscall #   pop r8 jmp _next b_blword = 0xF0 bcmd_blword: mov rsi, v_tib #    mov rdx, rsi #   RDX       mov rax, v_in #     mov rcx, v_ntib #    mov rbx, rcx add rsi, rax #  RSI -      sub rcx, rax #     jz 3f word2: lodsb #   AL  RSI   cmp al, ' ' ja 1f #    (    ) dec rcx jnz word2 #    3: sub rsi, rdx mov v_in, rsi push rcx jmp _next 1: lea rdi, [rsi - 1] # RDI = RSI - 1 ( ) dec rcx jz word9 word3: lodsb cmp al, ' ' jbe 2f dec rcx jnz word3 word9: inc rsi 2: mov rax, rsi sub rsi, rdx #        (   ) cmp rsi, rbx jle 4f mov rsi, rbx 4: mov v_in, rsi sub rax, rdi dec rax jz word1 push rdi #   word1: push rax #   jmp _next b_quit = 0xF1 bcmd_quit: lea r8, quit mov rsp, init_stack mov rbp, init_rstack jmp _next b_find = 0xF2 bcmd_find: pop rbx #   pop r9 #   mov rdx, v_context mov rdx, [rdx] #        #   find0: mov al, [rdx] #  and al, 3 #   -     ,     ,    or al, al jz find_l8 cmp al, 1 jz find_l16 cmp al, 2 jz find_l32 mov r10, [rdx + 1] #  64  lea rsi, [rdx + 9] #   jmp find1 find_l32: movsx r10, dword ptr [rdx + 1] #  32  lea rsi, [rdx + 5] #   jmp find1 find_l16: movsx r10, word ptr [rdx + 1] #  16  lea rsi, [rdx + 3] #   jmp find1 find_l8: movsx r10, byte ptr [rdx + 1] #  8  lea rsi, [rdx + 2] #   find1: movzx rax, byte ptr [rsi] #       cmp rax, rbx jz find2 #      find3: or r10, r10 jz find_notfound #  ,    add rdx, r10 #     jmp find0 #  ,   find2: inc rsi mov rdi, r9 mov rcx, rax repz cmpsb jnz find3 #   push rdx jmp _next find_notfound: push r10 jmp _next b_cfa = 0xF3 bcmd_cfa: pop rdx #    mov al, [rdx] #  and al, 3 #   -     ,     ,    or al, al jz cfa_l8 cmp al, 1 jz cfa_l16 cmp al, 2 jz cfa_l32 lea rsi, [rdx + 9] #   (64  ) jmp cfa1 cfa_l32: lea rsi, [rdx + 5] #   (32  ) jmp cfa1 cfa_l16: lea rsi, [rdx + 3] #   (16  ) jmp cfa1 cfa_l8: lea rsi, [rdx + 2] #   (8  ) cfa1: xor rax, rax lodsb add rsi, rax push rsi jmp _next b_execute = 0xF4 bcmd_execute: sub rbp, 8 mov [rbp], r8 #       pop r8 #  - jmp _next b_numberq = 0xF5 bcmd_numberq: pop rcx #   pop rsi #  xor rax, rax #   xor rbx, rbx #     mov r9, v_base #  xor r10, r10 #   or rcx, rcx jz num_false mov bl, [rsi] cmp bl, '+' jnz 1f inc rsi dec rcx jz num_false jmp num0 1: cmp bl, '-' jnz num0 mov r10, 1 inc rsi dec rcx jz num_false num0: mov bl, [rsi] cmp bl, '0' jb num_false cmp bl, '9' jbe num_09 cmp bl, 'A' jb num_false cmp bl, 'Z' jbe num_AZ cmp bl, 'a' jb num_false cmp bl, 'z' ja num_false sub bl, 'a' - 10 jmp num_check num_AZ: sub bl, 'A' - 10 jmp num_check num_09: sub bl, '0' num_check: cmp rbx, r9 jge num_false mul r9 add rax, rbx inc rsi dec rcx jnz num0 or r10, r10 push rax push 1 jmp _next num_false: xor rcx, rcx push rcx jmp _next 

゜ヌスコヌドが倧きくなっおいるので、最埌にここに持っおきたす。

珟圚、圌の居䜏地はgithubにありたす。https : //github.com/hal9000cc/forth64
同じ堎所のbinフォルダヌには、Linux x64甚に既にコンパむルされたバヌゞョンがありたす。 Linuxを持っおいる人は、ダりンロヌドしお実行できたす。

そしお、Windowsを持っおいる人-あなたはWSLLinux甚のWindowsサブシステムをむンストヌルするこずができたす。私は䌑暇に向けお出発しおいたした。 5分ほどで完了したしたが、すぐに起動せず、PowerShellコマンドを䜿甚しおサブシステムを「オン」にする必芁がありたした。゚ラヌメッセヌゞからのリンクをたどり、コマンドを実行するず、機胜したした。

しかし、本物のむンド人がWindowsですべお実行する方法もありたす:)これを行うのは難しくありたせん。システムず察話するいく぀かの単語をやり盎すだけです。

それだけです次回はコンパむラを実行したす。

新しい単語をたずめる機䌚があり、条件、サむクルがありたす。実際には、倚かれ少なかれ暙準的な砊に曞き蟌み、それをバむトコヌドにコンパむルしお実行するこずが可胜です。さお、より深刻なテストを実斜し、バむトマシンのパフォヌマンスを確認するこずが可胜になりたす。

続きネむティブアメリカンの砊のバむトマシンだけでなくパヌト4

Source: https://habr.com/ru/post/J435236/


All Articles