2

Мне интересно узнать, как скомпилировать/создать очень простой язык (т. Е. Brainfuck) без помощи высокоуровневых функций, таких как системные вызовы unix. Я хотел бы написать компилятор для языка в некоторой низкоуровневой сборке, зависящей от процессора, так что я могу предоставить исходный код на простом языке и в итоге получить двоичный файл. Не уверен, что это ясно или нет, но основной вопрос заключается в том, как преобразовать источник в двоичный код без помощи чего-либо, что еще не присутствует в аппаратном обеспечении.Запись низкоуровневого языка с аппаратного обеспечения

Edit: более краткое изложение проблемы ...

ДАЛИ:

-Аппаратное (материнская плата/CPU и т.д.)

НЕ ДАЛИ:

- UNIX/DOS

-C/FORTRAN/любые другие языки

Как бы я начал реализовывать простой язык, например, мозг?

Я знаю, что есть гораздо более практичные способы компиляции, но я заинтересован в этом в образовательных целях.

Извините, если этот вопрос является излишним или очевидным - я не ученый-компьютер, поэтому, возможно, я просто не знаю правильный словарь, чтобы найти решение проблемы в Интернете. Если кто-то может предоставить ссылку или текст по этому вопросу, это будет оценено по достоинству.

+1

Немного более практичным было бы реализовать Forth с нуля на голом металле. И тогда вы сможете использовать его для загрузки более сложной системы поверх нее. –

+0

Хорошо ... это похоже на то, что меня интересует. Я предполагаю, что «голый металл» означает только аппаратное обеспечение? Есть ли хороший учебник для этого? 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

Канонический сборник-учебник - Книга Дракона, http://dragonbook.stanford.edu/.

Однако на самом деле это указано на более ... СОФИЛИРОВАННЫЕ языки. Вы не можете говорить о контекстно-свободной разборе и тому подобное (хотя я сделать рекомендую эту книгу, это двойной плюс жесткий, но УДИВИТЕЛЬНЫЙ.)

Имея это в виду, вы можете начать с поиска интерпретатор или компилятор для действительно простого языка - возможно, самого Brainfuck, возможно, что-то более удобное, как реализация схемы. Прочитайте, проанализируйте, узнайте, что он делает. Реализуйте те функции библиотеки нижнего уровня, которые использует компилятор, настройте генератор кода для вывода любой марки машинного кода, на который вы хотите настроить таргетинг, и все готово.

1

Глядя на описание на википедию, это непростая задача. Я все же, вероятно, начну с того, что вы знаете и, возможно, любите, возможно, нет. C - хороший выбор. Файловый ввод-вывод - это небольшой или огромный проект в зависимости от платформы и т. Д. Побеспокоитесь об этом позже, скомпилируйте в «источнике» для языка. для каждого символа в этом источнике выполните задачу

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

затем перевести это на сборку. вам нужен только один регистр, чтобы удерживать ptr, несколько строк asm для инициализации массива/ram и установить регистр/ptr в начало. Другой регистр, чтобы пройти через исходный код. вы ищете только 8 символов, вы можете, если-то-иначе, пройти через них, если не будет элемента бит-паттерна, из-за которого их легче справиться. если вы хотите, вы можете создать таблицу поиска в 256 байт и использовать ее либо для адреса для обработчика для этой команды, либо для преобразования их в целое число от 0 до 7 и использовать это в таблице перехода, что угодно.

Ну, это парсер, не обязательно компилятор.Я бы написал компилятор на языке C или на каком-то высоком уровне, он принимает массив байтов, который является программой, для каждой команды вы выводите исходный код asm, который реализует эту инструкцию, вы получаете меньше байта на входе, выходе (с помощью ARM ASM)

add r0,#1 

минус

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

r0 является регистром PTR и r1 только помогаю.

Если вы действительно против использования вызовов типа printf, то сделайте вывод этого кода массивом байтов, которые являются ascii для источника asm, помещают каждый символ a, d, d, пробел, r, 0, запятая, #, 1, cr, lf и т. д. Довольно легко реализовать в asm, а также некоторые языки высокого уровня. Если вы хотите перейти прямо в двоичный код, то просто выпустите машинный код, еще проще.

Получение исходной строки в этот компилятор и вывод в некоторый файл, который затем может быть выполнен позже, скорее всего, будет принимать системные вызовы. Вы можете избежать выхода, являющегося файлом, если вы работаете на той же платформе и можете делать самомодифицирующийся код в том смысле, что вы создаете машинный код на каком-то адресе, а затем, когда закончите синтаксический анализ, вы переходите на этот адрес для выполнения.

потребовалось много времени, чтобы написать этот ответ, чем это было бы для реализации решения в C или asm. Какова конкретная сложность, с которой вы сталкиваетесь?

+0

ahh, на самом деле ввод/вывод, который генерирует программа, точка (.) и запятая (,) являются проблематичными, так как вам нужно понять, что может быть значительным количеством кода. Пусть ваш вывод будет массивом в ram, или если встроенный использует uart и выплевывает байты из uart, обычно это минимальное количество кода, несколько строк для функции uart putchar. ввод на uart также минимален. –

+0

Спасибо за вход ... это звучит так, как будто моя проблема связана с файлами ввода/вывода. Я знаю, как писать компилятор в C/assembly, но мне любопытно, как можно реализовать язык в отсутствие таких удобств. В принципе, как вы можете реализовать язык, если все, что вам дано, является аппаратным обеспечением (предположительно, включая BIOS)? Надеюсь, мое редактирование разъяснило вопрос. –

+0

@AJMedford: Ну, вы тоже пишете драйверы ввода-вывода и файловой системы, если этого не хватает. –

1

Вы можете скомпилировать исходный код brainfuck в приложениях DOS .COM довольно легко (вам также понадобится NASM или какой-нибудь дополнительный код, чтобы испускать коды команд и вычислять переходы). Ниже слегка модифицированный интерпретатор бф, превратился в компилятор сортов:

// 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! 

ОБНОВЛЕНИЕ: в DOS на основе подпрограмм ввода и вывода в приведенном выше коде могут быть заменены прямыми доступов к экранного буфера и порты клавиатуры. Код клавиатуры также должен обрабатывать прерывания клавиатуры. Это не очень сложно сделать на ПК x86. Вы действительно можете реализовать компилятор для языка, который будет работать на голом оборудовании без ОС.

Вы также должны взглянуть на Forth, так как это именно тот вид языка для данной среды. И это легко реализовать. Гораздо проще, чем C. Сложнее мозгового укола, несколько сопоставимого с сборкой.

UPDATE 2: Вот небольшой (~ 1KB размера) Brainfuck интерпретатор, который не использует какой-либо DOS или BIOS функциональность:

; 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

он четко заявлял в некоторой сборке низкого уровня, зависящей от процессора. Это не компилятор, который компилируется на одном языке. Я хочу, чтобы определение системных вызовов высокого уровня, я считаю, что быть неопределенным и легко обсуждать определение в этом контексте. Если вызов int21 в порядке, значит, это вызов putchar и просто связать asm или C или что-то другое с библиотекой.определение определяет, является ли это 5-минутной задачей программирования или остальной частью вашей жизненной задачи или где-то посередине. –

+0

@ dwelch: Надеемся, что дополнительный интерпретатор удовлетворяет требованиям. –

0

На самом деле, у меня есть аналогичный проект и на моем уме. Вы хотите написать компилятор, который работает на голом оборудовании (без каких-либо операционных систем). Компилятор - это просто программа, как и любая другая программа, за исключением того, что она будет работать на голом оборудовании, как в вашем случае.

Возможно, вы захотите использовать загрузчик для своего компилятора (загрузчик не является операционной системой). Загрузочный загрузчик обычно загружает операционную систему с диска в память для выполнения только на этот раз, когда он загружает ваш компилятор, а не операционную систему.

Существует множество бесплатных загрузчиков с открытым исходным кодом (google для них). Выберите тот, который соответствует вашим потребностям, или если вы так же любопытны/любознательны, как и я, вы можете даже написать свое собственное.

Для выбора загрузчика (или записи) требуется, чтобы вы знали, как загружается ваша целевая система - либо через BIOS (старый), либо через UEFI (новый - это замена BIOS). По мере созревания вашего языка программирования вы можете написать свой собственный загрузчик на своем новом языке программирования.

Надеюсь, что это поможет