2

私は、Unixシステムコールのような高水準な機能の助けを借りずに非常に単純な言い回し(brainfuck)をコンパイル/作成する方法を知りたいと考えています。私は、単純な言語でソースコードを提供し、バイナリで終わることができるように、いくつかのCPU依存の低レベルアセンブリに言語用のコンパイラを書きたいと思います。これがはっきりしているかどうかは分かりませんが、基本的な質問は、ハードウェアにまだ存在していないものを使わずにソースをバイナリに変換する方法です。ハードウェアから低レベルの言語を書く

編集:より簡潔な問題声明...

は、与えられた:

- ハードウェア(マザーボード/ CPUなど)を与えられていない

- UNIX/DOS

-C/FORTRAN /他の言語

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

実際にコンパイルする方法がはるかにあることを知っていますが、私は教育目的でこれに興味があります。

申し訳ありませんが、この質問が重複または明白な場合 - 私はコンピュータ科学者ではないので、おそらく私はちょうど問題をオンラインで解決する適切な語彙を知っていません。誰でもリンクやテキストを提供することができれば感謝します。

+1

もう少し実用的なことは、ベアメタルの上から最初からForthを実装することです。そして、あなたはそれを使って、より複雑なシステムをブートストラップすることができます。 –

+0

Ok ...これは私が興味を持っているように思えます。「ベアメタル」とはハードウェアだけを意味します。これを行うための良いチュートリアルはありますか? Forthはうまくいきます...私は教育目的にのみ興味があると言ったので、私がForthでそれをする方法を理解すれば、私は幸せになれます。 –

+0

はい、このようなチュートリアルがたくさんあります:http://lambda-the-ultimate.org/node/2452またはこれ:http://hbrobotics.org/wiki/index.php?title=Forth_for_Robotics_and_Programming_at_the_Bare_Metal –

答えて

0

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

しかし、実際にはもっと指摘されています...独創的な言語。あなたは文脈自由構文解析などについて話をしたくないかもしれません(私ははその本をお勧めしませんものの、それはダブルプラス硬いが素晴らしいです。)を念頭に置いて

、あなたは見つけることによって起動する場合があります本当に単純な言語のためのインタープリタやコンパイラ、おそらくBrainfuck自身、おそらくSchemeの実装のようにもう少し便利なものかもしれません。それを読んで、分析し、学びなさい。コンパイラが使用する下位レベルのライブラリ関数を実装し、ターゲットとするマシンコードのブランドを出力するようにコードジェネレータを調整します。

1

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

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

それをアセンブリに変換します。 ptrを保持する1つのレジスタ、配列/ RAMを初期化するための数行のasm、レジスタ/ ptrを先頭に設定するだけです。ソースコードを参照する別のレジスタ。あなたは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のような呼び出しを使用することに本当に反対するならば、このコードの出力は、文字a、d、d、スペース、r、0、コンマ、#、1、cr、lfなどがあります。 asmやいくつかの高水準言語で実装するのは簡単です。あなたがバイナリにまっすぐに行きたい場合は、単純にマシンコードを出力します。

このコンパイラにソース文字列を取得し、後で実行することができ、いくつかのファイルへの出力が可能性の高いシステムコールを取るために起こっています。同じプラットフォーム上で実行していて、あるアドレスでマシンコードを構築するという意味で自己修正コードを実行し、解析が完了すると、そのアドレスにジャンプして実行することができます。

それはCまたはASMでソリューションを実装することであったであろうよりも、それはこの答えを書くために何度も時間がかかりました。あなたが抱える正確な問題は何ですか?

+0

ああ、実際には、プログラムが生成する入出力(ドット)とカンマ(、)は、相当な量のコードになる可能性があるため、問題があります。あなたの出力はどこかのRAMに配列されているか、埋め込まれていれば、uartを使用し、そのバイトをuartから吐き出します。通常、コードの最小量、uartのputchar関数の数行です。 uartの入力も最小限に抑えられます。 –

+0

入力してくれてありがとう...私の問題がファイルI/Oともっと関係しているかのように聞こえます。私はC /アセンブリでコンパイラを書く方法を知っていますが、そのような利便性がないときにどのように言語を実装するのかが不思議です。基本的には、与えられたすべてがハードウェア(恐らくBIOSを含む)であれば、どのようにして言語を実装できますか?私は私の編集が質問を明確にしたことを願っています。 –

+0

@AJMedford:あなたのI/Oとファイルシステムドライバも書いてあります。 –

1

あなたは非常に簡単にDOS .COMのアプリにbrainfuckのソースコードをコンパイルすることができます(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; 
} 

あなたはそれをハローワールドプログラム養う場合:

; 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.よりもはるかに簡単です。脳卒中よりも硬く、組み立てに多少匹敵します。

UPDATE 2:ここでは任意のDOSやBIOSの機能を使用していない小さな(〜サイズは1キロバイト)brainfuckインタプリタです:

; 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  "[email protected]#$%^&*()_+" 
    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を取りたい場合は上記のアセンブリコードを手作業でエンコードし、起動可能なフロッピーを作成してブートすることを歓迎します。

+0

システムコールをしていますが、これはシステムコールなしで行います。場合によっては、ビデオとキーボードはかなり基本的です(数百から数千行の高水準コード)が、ファイルシステムとシステムコールなしでハードディスクを制御する(int命令)ことはそれほど簡単ではありません。編集後でさえ、ポスターは質問を明確にする必要があります。おそらく、受け入れ可能なものと何かがないもののいくつかの例があります。 –

+0

彼は明らかにいくつかのCPU依存の低レベルアセンブリで述べています。これは同じ言語でコンパイルするコンパイラではありません。私は、高レベルのシステムコールの定義を望んでいます。私は、この文脈で定義を議論するのはあいまいで簡単だと考えます。 int21の呼び出しがうまくいけば、putcharを呼び出すだけで、asmやCなどをライブラリにリンクするだけです。この定義が5分のプログラミングタスクであるのか、それともあなたのライフタスクの残りのタスクであるのか、途中のどこかにあるのかどうかが決まります。 –

+0

@dwelch:追加されたインタプリタが要件を満たすことを望みます。 –

0

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

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

多くの無料のオープンソースのブートローダーがあります(それらのためのGoogle)。あなたのニーズに合ったものを選択するか、私が好きなように好奇心が強い/好奇心が強い場合は、自分で書くこともできます。

ブートローダを選択する(または書き込む)には、ターゲットシステムがBIOS(古いもの)またはUEFI(新しいもの、BIOSに置き換わるもの)を介してブートする方法が分かっている必要があります。プログラミング言語が成熟するにつれ、独自のブートローダを新しいプログラミング言語で記述することができます。

希望します。

関連する問題