2

UNIXシステムコールのような高レベル関数の助けを借りずに、非常に単純な言語(つまりbrainfuck)をコンパイル/作成する方法を見つけることに興味があります. 単純な言語でソースコードを提供し、最終的にバイナリを作成できるように、CPU 依存の低レベルアセンブリで言語のコンパイラを作成したいと考えています。これが明確かどうかはわかりませんが、基本的な問題は、ハードウェアにまだ存在していないものの助けを借りずにソースをバイナリに変換する方法です。

編集:より簡潔な問題文...

与えられた:

・ハードウェア(マザーボード・CPU等)

与えられていません:

-UNIX/DOS

-C/FORTRAN/その他の言語

Brainfuck のような単純な言語を実装するにはどうすればよいでしょうか?

もっと実用的なコンパイル方法があることは承知していますが、教育目的でこれに興味があります。

この質問が冗長または明白である場合は申し訳ありません-私はコンピューター科学者ではないため、オンラインで問題の解決策を見つけるための適切な語彙を知らないだけかもしれません. 誰かが主題に関するリンクまたはテキストを提供できる場合は、それをいただければ幸いです。

4

4 に答える 4

1

ウィキペディアの説明を見ると、これは難しい作業ではありません。私はおそらく、あなたが知っている、おそらく好きな、あるいはそうでない言語で始めるでしょう. Cは良い選択です。ファイル I/O は、プラットフォームなどに応じて小規模または巨大なプロジェクトです。後で心配して、言語の「ソース」でコンパイルします。そのソースの各キャラクターに対して、タスクを実行します

> ++ptr;
< --ptr;
+ ++*ptr;
etc

それをアセンブリに変換します。ptr を保持するために必要なレジスタは 1 つだけです。配列/ram を初期化し、レジスタ/ptr を先頭に設定するには、数行の asm が必要です。ソースコードをウォークスルーするための別のレジスタ。探しているのは 8 文字だけです。処理を容易にするビット パターンがない限り、if-then-else でそれらを処理できます。必要に応じて、256 バイトのルックアップ テーブルを作成し、それをその命令のハンドラーへのアドレスとして使用するか、それらを 0 ~ 7 の整数に変換し、それをジャンプ テーブルで使用します。

それはパーサーであり、必ずしもコンパイラーではありません。私はコンパイラをCまたはいくつかの高水準言語で記述します。それはプログラムであるバイト配列を取り、その命令を実装するasmソースコードを出力する命令ごとに、入力、出力でバイト未満を取得します( ARM asm を使用)

add r0,#1

マイナス記号

ldr r1,[r0]
sub r1,#1
str r1,[r0]

r0 は ptr レジスターであり、r1 はその手助けをしています。

本当に printf のような呼び出しを使用することに反対している場合は、このコードの出力を asm ソース出力の ascii であるバイトの配列にし、各文字 a、d、d、スペース、r、0、コンマ、#、 1、cr、lf など。asm や一部の高水準言語での実装はかなり簡単です。バイナリに直接行きたい場合は、マシンコードを出力するだけで、さらに簡単になります。

ソース文字列をこのコンパイラに取得し、出力を後で実行できるファイルに取得するには、システムコールが必要になる可能性があります。同じプラットフォームで実行している場合は、出力がファイルになるのを避けることができ、あるアドレスでマシンコードを構築し、解析が終了したらそのアドレスにジャンプして実行するという意味で自己変更コードを実行できます。

この回答を書くには、C や asm でソリューションを実装するよりも何倍も時間がかかりました。あなたが抱えている正確な困難は何ですか?

于 2012-05-08T04:02:11.760 に答える
1

Brainfuck ソース コードを DOS .COM アプリにコンパイルするのは非常に簡単です (命令オペコードを発行してジャンプを計算するには、NASM または追加のコードも必要です)。以下は少し変更された bf インタープリターで、ある種のコンパイラーに変わりました:

// file: bfcompil.c

#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_CODE_SIZE 30000

char code[MAX_CODE_SIZE];
char* pc = &code[0];
char* pcEnd = &code[0];

#define MAX_DATA_SIZE 30000

char data[MAX_DATA_SIZE] = { 0 };
char* pd = &data[0];

// Structures for quick bracket matching
unsigned brStack[MAX_CODE_SIZE];
unsigned brSptr = 0;
unsigned brMatch[MAX_CODE_SIZE];

int main(int argc, char** argv)
{
  FILE* f = NULL;
  int ch;

  if (argc != 2)
  {
    fprintf(stderr, "usage:\n  bfcompil <brainfuck-source-code-file>\n"
                    "bfcompil will output NASM-compilable source code for"
                    "a DOS program\n");
    return EXIT_FAILURE;
  }

  if ((f = fopen(argv[1], "rb")) == NULL)
  {
    fprintf(stderr, "can't open file \"%s\" for reading\n", argv[1]);
    return EXIT_FAILURE;
  }

  while ((ch = getc(f)) != EOF)
  {
    if (strchr(" \t\r\n", ch) != NULL) // skip white space
    {
      continue;
    }
    else if (strchr("><+-.,[]", ch) != NULL) // store valid commands
    {
      if (pcEnd >= &code[sizeof(code)])
      {
        fprintf(stderr, "too many commands in file \"%s\", expected at most "
                        "%u commands\n", argv[1], (unsigned)sizeof(code));
        fclose(f);
        return EXIT_FAILURE;
      }

      if (ch == '[')
      {
        brStack[brSptr++] = (unsigned)(pcEnd - &code[0]);
      }
      else if (ch == ']')
      {
        if (brSptr == 0)
        {
          fprintf(stderr, "unmatched ']' in file \"%s\"\n", argv[1]);
          fclose(f);
          return EXIT_FAILURE;
        }

        brSptr--;
        brMatch[brStack[brSptr]] = (unsigned)(pcEnd - &code[0]);
        brMatch[pcEnd - &code[0]] = brStack[brSptr];
      }

      *pcEnd++ = ch;
    }
    else // fail on invalid commands
    {
      fprintf(stderr, "unexpected character '%c' in file \"%s\", valid command "
                      "set is: \"><+-.,[]\"\n", ch, argv[1]);
      fclose(f);
      return EXIT_FAILURE;
    }
  }

  fclose(f);

  if (brSptr != 0)
  {
    fprintf(stderr, "unmatched '[' in file \"%s\"\n", argv[1]);
    return EXIT_FAILURE;
  }

  if (pcEnd == &code[0])
  {
    fprintf(stderr, "no commands found in file \"%s\"\n", argv[1]);
    return EXIT_FAILURE;
  }

  printf("; how to compile: nasm -f bin <input file with this code.asm> -o "
         "<output executable.com>\n\n"
         "org 0x100\n"
         "bits 16\n\n"
         "    mov     bx, data\n"
         "    mov     di, bx\n"
         "    mov     cx, 30000\n"
         "    xor     al, al\n"
         "    cld\n"
         "    rep     stosb\n\n"
         "    jmp     code\n\n"
         "print:\n"
         "    mov     ah, 2\n"
         "    cmp     byte [bx], 10\n"
         "    jne     lprint1\n"
         "    mov     dl, 13\n"
         "    int     0x21\n"
         "lprint1:\n"
         "    mov     dl, [bx]\n"
         "    int     0x21\n"
         "    ret\n\n"
#if 01
         // buffered input
         "input:\n"
         "    cmp     byte [kbdbuf+1], 0\n"
         "    jne     linput1\n"
         "    mov     ah, 0xa\n"
         "    mov     dx, kbdbuf\n"
         "    int     0x21\n"
         "    inc     byte [kbdbuf+1]\n"
         "linput1:\n"
         "    mov     al, [kbdbuf+2]\n"
         "    cmp     al, 13\n"
         "    jne     linput4\n"
         "    mov     al, 10\n"
         "linput4:\n"
         "    mov     [bx], al\n"
         "    mov     si, kbdbuf+3\n"
         "    mov     di, kbdbuf+2\n"
         "    xor     cx, cx\n"
         "    dec     byte [kbdbuf+1]\n"
         "    mov     cl, [kbdbuf+1]\n"
         "    jz      linput3\n"
         "linput2:\n"
         "    lodsb\n"
         "    stosb\n"
         "    loop    linput2\n"
         "linput3:\n"
         "    ret\n\n"
#else
         // unbuffered input
         "input:\n"
         "    mov     ah, 1\n"
         "    int     0x21\n"
         "    cmp     al, 13\n"
         "    jne     linput\n"
         "    mov     al, 10\n"
         "linput:\n"
         "    mov     [bx], al\n"
         "    ret\n\n"
#endif
         "code:\n\n");

  for (pc = &code[0]; pc < pcEnd; pc++)
  {
    switch (*pc)
    {
    case '>':
      printf("    inc     bx\n");
      break;
    case '<':
      printf("    dec     bx\n");
      break;
    case '+':
      printf("    inc     byte [bx]\n");
      break;
    case '-':
      printf("    dec     byte [bx]\n");
      break;
    case '.':
      printf("    call    print\n");
      break;
    case ',':
      printf("    call    input\n");
      break;
    case '[':
      printf("label%u:\n", (unsigned)(pc - &code[0]));
      printf("    cmp     byte [bx], 0\n");
      printf("    je      label%u\n", (unsigned)brMatch[pc - &code[0]]);
      break;
    case ']':
      printf("    jmp     label%u\n", brMatch[pc - &code[0]]);
      printf("label%u:\n", (unsigned)(pc - &code[0]));
      break;
    }
  }

  printf("\n    ret\n\n");
  printf("kbdbuf:\n"
         "    db      254\n"
         "    db      0\n"
         "    times   256 db 0\n\n");
  printf("data:\n");

  return EXIT_SUCCESS;
}

hello world プログラムにフィードすると、次のようになります。

++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

コンパイル可能なアセンブリ コードが生成されます。

; how to compile: nasm -f bin <input file with this code.asm> -o <output executable.com>

org 0x100
bits 16

    mov     bx, data
    mov     di, bx
    mov     cx, 30000
    xor     al, al
    cld
    rep     stosb

    jmp     code

print:
    mov     ah, 2
    cmp     byte [bx], 10
    jne     lprint1
    mov     dl, 13
    int     0x21
lprint1:
    mov     dl, [bx]
    int     0x21
    ret

input:
    cmp     byte [kbdbuf+1], 0
    jne     linput1
    mov     ah, 0xa
    mov     dx, kbdbuf
    int     0x21
    inc     byte [kbdbuf+1]
linput1:
    mov     al, [kbdbuf+2]
    cmp     al, 13
    jne     linput4
    mov     al, 10
linput4:
    mov     [bx], al
    mov     si, kbdbuf+3
    mov     di, kbdbuf+2
    xor     cx, cx
    dec     byte [kbdbuf+1]
    mov     cl, [kbdbuf+1]
    jz      linput3
linput2:
    lodsb
    stosb
    loop    linput2
linput3:
    ret

code:

    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
label10:
    cmp     byte [bx], 0
    je      label41
    inc     bx
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     bx
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     bx
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     bx
    inc     byte [bx]
    dec     bx
    dec     bx
    dec     bx
    dec     bx
    dec     byte [bx]
    jmp     label10
label41:
    inc     bx
    inc     byte [bx]
    inc     byte [bx]
    call    print
    inc     bx
    inc     byte [bx]
    call    print
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    call    print
    call    print
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    call    print
    inc     bx
    inc     byte [bx]
    inc     byte [bx]
    call    print
    dec     bx
    dec     bx
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    call    print
    inc     bx
    call    print
    inc     byte [bx]
    inc     byte [bx]
    inc     byte [bx]
    call    print
    dec     byte [bx]
    dec     byte [bx]
    dec     byte [bx]
    dec     byte [bx]
    dec     byte [bx]
    dec     byte [bx]
    call    print
    dec     byte [bx]
    dec     byte [bx]
    dec     byte [bx]
    dec     byte [bx]
    dec     byte [bx]
    dec     byte [bx]
    dec     byte [bx]
    dec     byte [bx]
    call    print
    inc     bx
    inc     byte [bx]
    call    print
    inc     bx
    call    print

    ret

kbdbuf:
    db      254
    db      0
    times   256 db 0

data:

コンパイルすると、DOS、Windows 9x/XP (おそらく 32 ビット Vista/7)、および DosBox で実行できるようになります。

当然のことながら、出力は次のとおりです。

Hello World!

UPDATE : 上記のコードの DOS ベースの入出力ルーチンは、スクリーン バッファとキーボード ポートへの直接アクセスに置き換えることができます。キーボード コードは、キーボード割り込みも処理する必要があります。x86 PC で行うのはそれほど難しくありません。OSなしでベアハードウェアで実行する言語用のコンパイラを実際に実装できます。

Forthこれは、特定の環境に適した種類の言語であるため、も確認する必要があります。そして、それは簡単に実装できます。C よりもはるかに簡単。brainfuck よりも難しく、アセンブリに匹敵します。

更新 2 : これは、DOS または BIOS 機能を使用していない小さな (サイズが ~1KB) ブレインファック インタープリターです。

; file: bfint.asm
; compile: nasm.exe -f bin bfint.asm -o bfint.com
; run in: DOS, DosBox or equivalent

bits 16
org 0x100

section .text

SCREEN_WIDTH   equ 80
SCREEN_HEIGHT  equ 25
SCAN_BUF_SIZE  equ 256

MAX_CODE_SIZE  equ 20000
MAX_DATA_SIZE  equ 30000

    cld

    ; set new keyboard (IRQ1) ISR
    push    byte 0
    pop     es
    cli                         ; update ISR address w/ ints disabled
    mov     word [es:9*4], Irq1Isr
    mov     [es:9*4+2], cs
    sti

    push    cs
    pop     es

Restart:

    call    ClearScreen
    mov     si, MsgHello
    call    PrintStr

    mov     word [CodeSize], 0
    mov     byte [EnterCount], 0

WaitForKey:
    call    GetKey

    ; Escape erases code
    cmp     ah, 1      ; Escape
    je      Restart

    ; Non-characters are ignored
    cmp     al, 0      ; non-character key
    je      WaitForKey

    ; Enter is "printed" but not stored, use for formatting
    cmp     al, 10     ; Enter
    je      KeyEnter
    mov     byte [EnterCount], 0

    ; Backspace deletes last character
    cmp     al, 8      ; Backspace
    je      KeyBackspace

    ; Space is printed but not stored, use for formatting
    cmp     al, " "    ; Space
    je      PrintOnly

    ; 0 runs a test program
    cmp     al, "0"
    je      TestProgram

    ; Other chracters are stored as code
    mov     bx, [CodeSize]
    cmp     bx, MAX_CODE_SIZE
    jae     ErrCodeTooBig
    mov     [Code + bx], al
    inc     word [CodeSize]
PrintOnly:
    call    PrintChar
    jmp     WaitForKey

ErrCodeTooBig:
    mov     si, MsgCodeTooBig
    call    PrintStr
    mov     word [CodeSize], 0
    jmp     WaitForKey

KeyEnter:
    call    PrintChar
    inc     byte [EnterCount]
    cmp     byte [EnterCount], 1
    je      WaitForKey
    mov     byte [EnterCount], 0
    call    Execute
    jmp     WaitForKey

KeyBackspace:
    call    PrintChar
    cmp     word [CodeSize], 0
    je      WaitForKey
    dec     word [CodeSize]
    jmp     WaitForKey

TestProgram:
    mov     si, TestCode
    mov     di, Code
    mov     cx, TestCodeEnd - TestCode
    mov     [CodeSize], cx
    rep     movsb
    call    Execute
    jmp     WaitForKey

Execute:
    mov     si, Code ; code start
    xor     bp, bp ; instruction index

    mov     di, Data ; data start
    mov     cx, MAX_DATA_SIZE
    xor     al, al
    rep     stosb
    sub     di, MAX_DATA_SIZE
    xor     bx, bx ; data index

ExecuteLoop:
    cmp     bp, [CodeSize]
    jae     ExecuteDone

    mov     al, [bp+si]
    cmp     al, ">"
    je      IncPtr
    cmp     al, "<"
    je      DecPtr
    cmp     al, "+"
    je      IncData
    cmp     al, "-"
    je      DecData
    cmp     al, "."
    je      PrintData
    cmp     al, ","
    je      InputData
    cmp     al, "["
    je      While
    cmp     al, "]"
    je      EndWhile

    mov     si, MsgInvalidChar
    call    PrintStr
    call    PrintChar
    mov     al, 10
    call    PrintChar
    jmp     ExecuteDone

IncPtr:
    inc     bx
    jmp     ExecuteContinue

DecPtr:
    dec     bx
    jmp     ExecuteContinue

IncData:
    inc     byte [bx+di]
    jmp     ExecuteContinue

DecData:
    dec     byte [bx+di]
    jmp     ExecuteContinue

PrintData:
    mov     al, [bx+di]
    call    PrintChar
    jmp     ExecuteContinue

InputData:
    call    GetKey
    or      al, al
    jz      InputData
    mov     [bx+di], al
    jmp     ExecuteContinue

While:
    cmp     byte [bx+di], 0
    jne     ExecuteContinue
    mov     ax, 1
    mov     dx, "[]"
    call    FindMatchingBracket
ExecuteContinue:
    inc     bp
    jmp     ExecuteLoop

EndWhile:
    mov     ax, -1
    mov     dx, "]["
    call    FindMatchingBracket
    jmp     ExecuteLoop

ExecuteDone:
    mov     word [CodeSize], 0
    mov     si, MsgCompleted
    jmp     PrintStr

FindMatchingBracket:
    xor     cx, cx
FindMatchingBracket1:
    cmp     byte [bp+si], dl
    jne     FindMatchingBracket2
    inc     cx
    jmp     FindMatchingBracket3
FindMatchingBracket2:
    cmp     byte [bp+si], dh
    jne     FindMatchingBracket3
    dec     cx
    jnz     FindMatchingBracket3
    ret
FindMatchingBracket3:
    add     bp, ax
    jmp     FindMatchingBracket1

; Inputs:
; AL = ASCII character code
PrintChar:
    ; assuming it's a color text mode (not monochrome or graphics)
    pusha
    push    es

    push    word 0xb800
    pop     es
    mov     bx, [CursorPos]

    cmp     al, 8
    je      PrintCharBackSpace

    cmp     al, 10
    je      PrintCharBackLF

    cmp     al, 13
    je      PrintCharBackCR

    mov     [es:bx], al
    call    AdvanceCursorPosition

    jmp     PrintCharDone

PrintCharBackSpace:
    ; move the cursor back and erase the last character
    or      bx, bx
    jz      PrintCharDone
    dec     bx
    dec     bx
    mov     word [es:bx], 0x0720
    jmp     PrintCharSetCursorPos

PrintCharBackLF:
    ; move the cursor to the beginning of the next line - '\n' behavior
    add     bx, SCREEN_WIDTH * 2
    cmp     bx, SCREEN_WIDTH * SCREEN_HEIGHT * 2
    jc      PrintCharBackCR
    sub     bx, SCREEN_WIDTH * 2
    call    ScrollUp

PrintCharBackCR:
    ; move the cursor to the beginning of the current line - '\r' behavior
    mov     ax, SCREEN_WIDTH * 2
    xchg    ax, bx
    xor     dx, dx
    div     bx
    mul     bx
    mov     bx, ax

PrintCharSetCursorPos:
    mov     [CursorPos], bx
    shr     bx, 1
    call    SetCursorPosition

PrintCharDone:
PopEsAllRet:
    pop     es
    popa
    ret

ClearScreen:
    ; assuming it's a color text mode (not monochrome or graphics)
    pusha
    push    es

    push    word 0xb800
    pop     es
    xor     di, di
    mov     cx, SCREEN_WIDTH * SCREEN_HEIGHT
    mov     ax, 0x0720 ; character = space, color = lightgray on black
    rep     stosw

    xor     bx, bx
    mov     [CursorPos], bx
    call    SetCursorPosition

    jmp     PopEsAllRet

ScrollUp:
    ; assuming it's a color text mode (not monochrome or graphics)
    pusha
    push    es
    push    ds

    push    word 0xb800
    pop     es
    push    es
    pop     ds
    mov     si, SCREEN_WIDTH * 2
    xor     di, di
    mov     cx, SCREEN_WIDTH * (SCREEN_HEIGHT - 1)
    rep     movsw

    mov     cx, SCREEN_WIDTH
    mov     ax, 0x0720 ; character = space, color = lightgray on black
    rep     stosw

    pop     ds
    jmp     PopEsAllRet

; Inputs:
; DS:SI = address of NUL-terminated ASCII string
PrintStr:
    pusha
PrintStr1:
    lodsb
    or      al, al
    jz      PrintStrDone
    call    PrintChar
    jmp     PrintStr1
PrintStrDone:
    popa
    ret

; Inputs:
; BX = Y * SCREEN_WIDTH + X
SetCursorPosition:
    ; assuming it's a color text mode (not monochrome or graphics)
    pusha

%if 0
    mov     dx, 0x3d4
    mov     al, 0x0f
    out     dx, al
    inc     dx
    mov     al, bl
    out     dx, al

    dec     dx
    mov     al, 0x0e
    out     dx, al
    inc     dx
    mov     al, bh
    out     dx, al
%else
    mov     dx, 0x3d4
    mov     al, 0x0f
    mov     ah, bl
    out     dx, ax

    dec     al
    mov     ah, bh
    out     dx, ax
%endif

    popa
    ret

AdvanceCursorPosition:
    ; assuming it's a color text mode (not monochrome or graphics)
    pusha

    mov     ax, [CursorPos]
    inc     ax
    inc     ax
    cmp     ax, SCREEN_WIDTH * SCREEN_HEIGHT * 2
    jc      AdvanceCursorPosition1

    sub     ax, SCREEN_WIDTH * 2
    call    ScrollUp

AdvanceCursorPosition1:
    mov     [CursorPos], ax
    shr     ax, 1
    xchg    ax, bx
    call    SetCursorPosition

    popa
    ret

; Outputs:
; AH = scan code
; AL = character
GetKey:
    push    bx
    push    si

GetKeyRepeat:
    mov     ax, [ScanWriteIdx]
    mov     si, [ScanReadIdx]
    sub     ax, si
    jz      GetKeyRepeat
    mov     bx, si
    mov     ax, [ScanBuf + bx + si]
    inc     si
    and     si, SCAN_BUF_SIZE - 1
    mov     [ScanReadIdx], si

    pop     si
    pop     bx
    ret

Irq1Isr:
    pusha
    push    ds

    push    cs
    pop     ds

    ; read keyboard scan code
    in      al, 0x60

    cmp     al, 0x2a ; Left Shift down
    jne     Irq1Isr1
    or      byte [Shift], 1
Irq1Isr1:
    cmp     al, 0x36 ; Right Shift down
    jne     Irq1Isr2
    or      byte [Shift], 2
Irq1Isr2:
    cmp     al, 0xaa ; Left Shift up
    jne     Irq1Isr3
    and     byte [Shift], ~1
Irq1Isr3:
    cmp     al, 0xb6 ; Right Shift up
    jne     Irq1Isr4
    and     byte [Shift], ~2
Irq1Isr4:

    test    al, 0x80
    jnz     Irq1IsrEois ; key released

    mov     ah, al
    cmp     al, 58
    jc      Irq1Isr5
    xor     al, al   ; don't translate non-character keys
    jmp     Irq1Isr7
Irq1Isr5:
    mov     bx, ScanToChar
    cmp     byte [Shift], 0
    je      Irq1Isr6
    add     bx, ScanToCharShift - ScanToChar
Irq1Isr6:
    xlatb

Irq1Isr7:
    mov     bx, [ScanWriteIdx]
    mov     di, bx
    mov     [ScanBuf + bx + di], ax
    inc     bx
    and     bx, SCAN_BUF_SIZE - 1
    mov     [ScanWriteIdx], bx

Irq1IsrEois:
%if 0
    ; send EOI to XT keyboard
    in      al, 0x61
    mov     ah, al
    or      al, 0x80
    out     0x61, al
    mov     al, ah
    out     0x61, al
%endif

    ; send EOI to master PIC
    mov     al, 0x20
    out     0x20, al

    pop     ds
    popa
    iret

ScanToChar:
    db      0 ; unused
    db      0 ; Escape
    db      "1234567890-="
    db      8 ; Backspace
    db      9 ; Tab
    db      "qwertyuiop[]"
    db      10 ; Enter
    db      0 ; Ctrl
    db      "asdfghjkl;'`"
    db      0 ; Left Shift
    db      "\zxcvbnm,./"
    db      0 ; Right Shift
    db      0 ; Print Screen
    db      0 ; Alt
    db      " " ; Space
ScanToCharShift:
    db      0 ; unused
    db      0 ; Escape
    db      "!@#$%^&*()_+"
    db      8 ; Backspace
    db      9 ; Tab
    db      "QWERTYUIOP{}"
    db      10 ; Enter
    db      0 ; Ctrl
    db      'ASDFGHJKL:"~'
    db      0 ; Left Shift
    db      "|ZXCVBNM<>?"
    db      0 ; Right Shift
    db      0 ; Print Screen
    db      0 ; Alt
    db      " " ; Space

MsgHello:
    db      "Brainfuck Interpreter", 10, 10
    db      "Press 0 to run test code OR", 10
    db      "Type your code.", 10
    db      "Use Esc to erase it all or Backspace to delete last character.", 10
    db      "Press Enter twice to run it.", 10, 10, 0

MsgCodeTooBig:
    db      10, "Code's too big", 10, 0

MsgCompleted:
    db      10, "Code's completed", 10, 0

MsgInvalidChar:
    db      10, "Invalid character: ", 0

Shift           db      0

CursorPos       dw      0

ScanReadIdx     dw      0
ScanWriteIdx    dw      0

EnterCount      db      0

CodeSize        dw      0

TestCode:
    ; Hello World!
    db "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."
    ; Squares of 0 through 100
;    db "++++[>+++++<-]>[<+++++>-]+<+[>[>+>+<<-]++>>[<<+>>-]>>>[-]++>[-]+>>>+[[-]++++++>>>]<<<[[<++++++++<++>>-]+<.<[>----<-]<]<<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++>[-[<->-]+[<<<]]<[>+<-]>]<<-]<<-]"
    ; ROT13
;    db "+[,+[-[>+>+<<-]>[<+>-]+>>++++++++[<-------->-]<-[<[-]>>>+[<+<+>>-]<[>+<-]<[<++>>>+[<+<->>-]<[>+<-]]>[<]<]>>[-]<<<[[-]<[>>+>+<<<-]>>[<<+>>-]>>++++++++[<-------->-]<->>++++[<++++++++>-]<-<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<<<<+>>>>++++[<++++++++>-]>-]<<-<-]>[<<<<[-]>>>>[<<<<->>>>-]]<<++++[<<++++++++>>-]<<-[>>+>+<<<-]>>[<<+>>-]+>>+++++[<----->-]<-[<[-]>>>+[<+<->>-]<[>+<-]<[<++>>>+[<+<+>>-]<[>+<-]]>[<]<]>>[-]<<<[[-]<<[>>+>+<<<-]>>[<<+>>-]+>------------[<[-]>>>+[<+<->>-]<[>+<-]<[<++>>>+[<+<+>>-]<[>+<-]]>[<]<]>>[-]<<<<<------------->>[[-]+++++[<<+++++>>-]<<+>>]<[>++++[<<++++++++>>-]<-]>]<[-]++++++++[<++++++++>-]<+>]<.[-]+>>+<]>[[-]<]<]"
TestCodeEnd:

section .bss

ScanBuf:
    resw SCAN_BUF_SIZE

Code:
    resb MAX_CODE_SIZE

Data:
    resb MAX_DATA_SIZE

DOS (ホスティング環境として) と NASM を排除したい場合は、上記のアセンブリ コードを手作業でエンコードし、そこから起動可能なフロッピーを作成して起動してください。

于 2012-05-08T11:52:18.140 に答える
0

正規のコンパイラ学習本は Dragon Book ( http://dragonbook.stanford.edu/ ) です。

ただし、実際にはもっと... 洗練された言語を対象としています。文脈自由構文解析などについては話したくないかもしれません (私その本をお勧めしますが、それは 2 倍難しいですが素晴らしいです)。

それを念頭に置いて、非常に単純な言語のインタープリターまたはコンパイラーを見つけることから始めたいと思うかもしれません.Brainfuck自体かもしれませんし、Scheme実装のようなもう少し使いやすいものかもしれません. 読んで、分析して、それが何をするかを学びましょう。コンパイラが使用する低レベルのライブラリ関数を実装し、そのコード ジェネレータを調整して、ターゲットにしたいマシン コードのブランドを出力すれば完了です。

于 2012-05-08T03:26:06.473 に答える
0

実は、私も同様のプロジェクトを考えています。必要なのは、ベア ハードウェア (オペレーティング システムなし) で実行されるコンパイラを作成することです。コンパイラは、あなたの場合のように裸のハードウェアで実行されることを除いて、他のすべてのプログラムと同様のプログラムです。

コンパイラにブートローダーを使用することを検討してください (ブートローダーはオペレーティング システムではありません)。ブートローダーは、通常、オペレーティング システムではなくコンパイラをロードするときだけ、オペレーティング システムをディスクからメモリにロードして実行します。

無料でオープンソースのブートローダーがたくさんあります (Google で検索してください)。あなたのニーズに合ったものを選択してください。または、私と同じくらい好奇心旺盛/好奇心が強い場合は、独自のものを作成することもできます.

ブートローダーを選択する (または作成する) には、ターゲット システムがどのように起動するかを知っている必要があります。これは、BIOS (古い) または UEFI (新しい。これは BIOS の代わりです) のいずれかです。プログラミング言語が成熟するにつれて、新しいプログラミング言語で独自のブートローダーを作成できるようになります。

お役に立てれば

于 2014-12-31T04:11:00.547 に答える