Использую нейронку как компилятор. вайб-кодинг.. вайб-кодинг. вайбкодинг.. вайб-кодинг. вайбкодинг. ИИ.. вайб-кодинг. вайбкодинг. ИИ. искусственный интеллект.. вайб-кодинг. вайбкодинг. ИИ. искусственный интеллект. Компиляторы.. вайб-кодинг. вайбкодинг. ИИ. искусственный интеллект. Компиляторы. компиляция.. вайб-кодинг. вайбкодинг. ИИ. искусственный интеллект. Компиляторы. компиляция. прикол.

Введение

Бла-бла-блаааа бла-бла-блаааа-беееее-бууууу бла-бла-бла бле-бле-бле

Основная часть

ты - компилятор Си с gnu расширениями,
который был создан специально для написания программ для x16-PRos.
стандартная библиотека уже включена в компилятор
и может быть выключена на уровне флагов (-fnostdlib).
так же компилятор потдерживает флаг -outformat=ple/raw
при raw - выходит плаский бинарник для загрузки с org 0x8000,
а при ple - полноценный ple файл

С такого простенького неумелого промта для gemeni мы начнем наш прикол.

После небольших вопросов, уточнений и тд мы можем дать её простенькую программу

Проверка знаний о x16-PRos
раскажи о формате ple

Формат .PLE (PRos Large Executable)
— это специализированный нативный формат исполняемых файлов
для операционной системы x16-PRos.
В отличие от простых плоских бинарников (.BIN / .COM),
которые просто загружаются в память
и выполняются с фиксированного адреса (например, org 0x8000),
формат .PLE спроектирован для поддержки расширенных возможностей
современной ОС в рамках 16-битного реального режима.
Исполняемые файлы .PLE обладают тремя ключевыми
архитектурными особенностями:
1. Поддержка многозадачности (Multitasking)
  Формат .PLE интегрирован с подсистемой кооперативной многозадачности
  ядра x16-PRos.Такие программы могут выполняться параллельно
  с другими процессами.
  Они поддерживают фоновый режим работы:
  в терминале ОС реализована специальная команда
  bg <file>.ple, позволяющая запустить программу
  "в бэкграунде".
2. Интеграция с графическим интерфейсом (GUI)
  В то время как стандартные консольные утилиты работаютвнутри текстового
  терминала PRos Terminal, файлы формата .PLE имеют встроенную поддержку
  графической оболочки.
  Каждое GUI-приложение в формате .PLE запускается в собственном кастомизируемом
  окне. Формат разработан с учетом взаимодействия с системным оконным менеджером,
  обработкой событий окон и управления через драйвер мыши (PS/2 / USB).
3. Структурированный заголовок (Header)
  Обычный бинарный файл не содержит метаданных.
  Файл .PLE содержит заголовок, который сообщает загрузчику ядра необходимую
  техническую информацию:
    Сигнатуру формата для валидации файла перед запуском.
    Требуемый объем памяти под стек и динамические данные.
    Точку входа (Entry Point), отличную от стандартного смещения 0x0000 внутри сегмента.
  Расположение в системе Ядро x16-PRos имеет жесткое разграничение по путям
  поиска исполняемых файлов:
  файлы .BIN автоматически ищутся в системной директории BIN/,
  в то время как для приложений нового формата выделена собственная директория
  PLE/.
  ...

это была не первая итерация и ссылка на проект явно помогла ей разобраться

Наш первый тест:

test.c:
#include <stdio.h>

void main()
{
    puts("Hello, from AIC");
}

aic -o test.bin -outformat=raw test.c

Да я назвал компилятор AIC что буквально Artificial Intelligence C – ИИ-шный Си

Но даже для такого простого примера и имея ссылку на проект нейронка захотела использовать стандартные прерывания биоса, а не готовые PRos-овские.

; Generated by AIC compiler for x16-PRos
; Command: aic -o test.bin -outformat=raw test.c

[BITS 16]
[ORG 0x8000]            ; Смещение raw-загрузки в x16-PRos

start:
    call main           ; Вызов главной функции приложения
    
    ; Завершение работы программы и возврат в PRos Terminal
    mov ah, 0x4C        ; Стандартный выход (совместимость с MS-DOS/PRos)
    int 0x21
    ret

main:
    push bp
    mov bp, sp

    ; Эквивалент puts("Hello, from AIC");
    mov si, msg_hello
    call print_string

    mov sp, bp
    pop bp
    ret

; --- Встроенная подфункция libc для вывода строки ---
print_string:
    pusha
    mov ah, 0x0E        ; BIOS Телетайп-вывод символа
    mov bl, 0x0F        ; Цвет шрифта (белый на чёрном)
.loop:
    lodsb               ; Загрузить следующий символ из DS:SI в AL
    cmp al, 0
    je .done            ; Если дошли до нуля (null-terminator), выходим
    int 0x10            ; Видео-прерывание BIOS
    jmp .loop
.done:
    ; Вывод перевода строки n (CR + LF)
    mov al, 0x0D
    int 0x10
    mov al, 0x0A
    int 0x10
    popa
    ret

section .data
    msg_hello db "Hello, from AIC", 0

Забавно ещё что он пытается использовать DOS-овское прерывание 0x21 и его функцию 0x4C, хотя в PRos насколько я помню она не реализована (но тут могу ошибаться (PRox, поправит меня в коментах))

Вносим корректировки и даем ссылку на API проса:

puts использует внутрение прерывания PRos как и вся stdlib.
давай минимум коментариев, просто код на nasm.
формат выходных файлов теперь всегда .asm а -outformat по умолчанию raw.
сгенерированые asm файлы не должны иметь коментариев кроме технических для отладки и тп.

https://github.com/PRoX2011/x16-PRos/blob/dev/docs/API.md

Долгожданный код от нейронки:

[BITS 16]
[ORG 0x8000]

start:
    call main
    mov ah, 0x4C
    int 0x21
    ret

main:
    push bp
    mov bp, sp
    mov si, msg_hello
    call puts
    mov sp, bp
    pop bp
    ret

puts:
    push ax
    mov ah, 0x01
    int 0x21
    pop ax
    ret

section .data
    msg_hello db "Hello, from AIC", 0

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

Использую нейронку как компилятор - 1

Чтож, оно работает. уже хорошо (несмотря на выход через прерывание).

printf

Да, пожалуй довайте дадим гемени попотеть и заставим написать на real-mode ассемблере парсинг printf.

```
#include <stdio.h>

void main()
{
    int a = 54;
    printf("num is: %dn", a);
}
```

aic -o test.asm -O0 test.c

добавил -O0 чтобы не хитрила с инлайнингом.

[BITS 16]
[ORG 0x8000]

start:
    call main
    mov ah, 0x4C
    int 0x21
    ret

main:
    push bp
    mov bp, sp
    sub sp, 2

    mov word [bp-2], 54

    push word [bp-2]
    mov ax, fmt_num
    push ax
    call printf
    add sp, 4

    mov sp, bp
    pop bp
    ret

printf:
    push bp
    mov bp, sp
    pusha

    mov si, [bp+4]
    lea bx, [bp+6]

.loop:
    lodsb
    cmp al, 0
    je .done
    cmp al, '%'
    je .format
    call print_char
    jmp .loop

.format:
    lodsb
    cmp al, 'd'
    je .print_int
    cmp al, '%'
    je .percent
    jmp .loop

.percent:
    mov al, '%'
    call print_char
    jmp .loop

.print_int:
    mov ax, [bx]
    add bx, 2
    call print_number
    jmp .loop

.done:
    popa
    mov sp, bp
    pop bp
    ret

print_char:
    push ax
    push si
    mov byte [char_buf], al
    mov byte [char_buf+1], 0
    mov si, char_buf
    mov ah, 0x01
    int 0x21
    pop si
    pop ax
    ret

print_number:
    pusha
    mov cx, 0
    mov bx, 10

.convert:
    mov dx, 0
    div bx
    push dx
    inc cx
    cmp ax, 0
    jne .convert

.print_digits:
    pop ax
    add al, '0'
    call print_char
    loop .print_digits

    popa
    ret

section .data
    fmt_num db "num is: %d", 0x0D, 0x0A, 0
    char_buf db 0, 0

на мое удивление это достаточно хорошо на первый взгляд чтобы работать. Она не стала писать весь форматер, да и я сомневаюсь что это соответствует cdecl, но все же.

Использую нейронку как компилятор - 2

Знаете, у меня даже уважение появилось к гемени и инженерам гугла в целом.

Это вам не “напиши мне приложение чтобы оно…” тут надо быть… ну как минимум не трезвым чтобы таким заниматься…

Простенький парсер конфигов

Просто на ходу мной был придуман формат конфигов типа такого

.my_var1=hello, world;
.my_var2=43;
.548=my_val;

ну и парсер для него был накидан за… да за минуту

#include <stdio.h>
#include <pros/api.h>

char file_text[1024];

void main()
{
    /* читает текст файла в буфер как null-terminated строку */
    read_file_text("testc.ccc", &file_text, 1024 /* размер буфера */);

    int pos = 0;

    char c = file_text[pos];

    while (c) {
        if (c == '.') {
            char buf[32];

            int i = 0;
            while (c != '=') {
                buf[i] = c;
                c = file_text[pos++];
                i++;
            }
            buf[i] = 0;

            pos++;
            c = file_text[pos++];

            char val[32];
            while (c != ';') {
                val[i] = c;
                c = file_text[pos++];
                i++;
            }
            val[i] = 0;

            printf("%s: %sn", buf, val);
        }

        c = file_text[pos++];
    }
}

С сахором в виде функции read_file_text якобы из pros/api.h.
Важно сказать что смотреть на безопасность и красоту этого кода не нужно – мы вообщето нейронкой Си компилируем.

ну и скормив этот код нашему “компилятору” получаем такое нечто:

[BITS 16]
[ORG 0x8000]

start:
    call main
    mov ah, 0x4C
    int 0x21
    ret

main:
    push bp
    mov bp, sp
    sub sp, 70

    push 1024
    mov ax, file_text
    push ax
    mov ax, str_filename
    push ax
    call read_file_text
    add sp, 6

    mov word [bp-2], 0

    mov bx, [bp-2]
    mov al, [file_text + bx]
    mov [bp-3], al

.while_c:
    mov al, [bp-3]
    cmp al, 0
    je .end_while_c

    cmp al, '.'
    jne .end_if_dot

    mov word [bp-37], 0

.while_not_equal:
    mov al, [bp-3]
    cmp al, '='
    je .end_while_not_equal

    mov bx, [bp-37]
    lea dx, [bp-35]
    add bx, dx
    mov [bx], al

    mov bx, [bp-2]
    inc word [bp-2]
    mov al, [file_text + bx]
    mov [bp-3], al

    inc word [bp-37]
    jmp .while_not_equal

.end_while_not_equal:
    mov bx, [bp-37]
    lea dx, [bp-35]
    add bx, dx
    mov byte [bx], 0

    inc word [bp-2]

    mov bx, [bp-2]
    inc word [bp-2]
    mov al, [file_text + bx]
    mov [bp-3], al

.while_not_semicolon:
    mov al, [bp-3]
    cmp al, ';'
    je .end_while_not_semicolon

    mov bx, [bp-37]
    lea dx, [bp-69]
    add bx, dx
    mov [bx], al

    mov bx, [bp-2]
    inc word [bp-2]
    mov al, [file_text + bx]
    mov [bp-3], al

    inc word [bp-37]
    jmp .while_not_semicolon

.end_while_not_semicolon:
    mov bx, [bp-37]
    lea dx, [bp-69]
    add bx, dx
    mov byte [bx], 0

    lea ax, [bp-69]
    push ax
    lea ax, [bp-35]
    push ax
    mov ax, fmt_str
    push ax
    call printf
    add sp, 6

.end_if_dot:
    mov bx, [bp-2]
    inc word [bp-2]
    mov al, [file_text + bx]
    mov [bp-3], al
    jmp .while_c

.end_while_c:
    mov sp, bp
    pop bp
    ret

read_file_text:
    push bp
    mov bp, sp
    mov ax, 0x02
    int 0x21
    pop bp
    ret

printf:
    push bp
    mov bp, sp
    pusha
    mov si, [bp+4]
    lea bx, [bp+6]

.loop:
    lodsb
    cmp al, 0
    je .done
    cmp al, '%'
    je .format
    call print_char
    jmp .loop

.format:
    lodsb
    cmp al, 's'
    je .print_str
    cmp al, '%'
    je .percent
    jmp .loop

.percent:
    mov al, '%'
    call print_char
    jmp .loop

.print_str:
    mov dx, si
    mov si, [bx]
    add bx, 2
.str_loop:
    lodsb
    cmp al, 0
    je .str_done
    call print_char
    jmp .str_loop
.str_done:
    mov si, dx
    jmp .loop

.done:
    popa
    mov sp, bp
    pop bp
    ret

print_char:
    push ax
    push si
    mov byte [char_buf], al
    mov byte [char_buf+1], 0
    mov si, char_buf
    mov ah, 0x01
    int 0x21
    pop si
    pop ax
    ret

section .data
    str_filename db "testc.ccc", 0
    fmt_str db "%s: %s", 0x0D, 0x0A, 0
    char_buf db 0, 0

section .bss
    file_text resb 1024

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

Если все же посмотреть в функцию read_file_text то можно увидеть что нейронка все ещё не знает как именно работают прерывания в PRos.

После пары итераций ошибок и бросания кусками текста прямо из API.md я смог добиться хоть сколько-нибудь удовлетворяющего, на первый взгляд, меня варианта:

[BITS 16]
[ORG 0x8000]

start:
    call main
    mov ah, 0x4C
    int 0x21
    ret

main:
    push bp
    mov bp, sp
    sub sp, 72

    push 1024
    mov ax, file_text
    push ax
    mov ax, str_filename
    push ax
    call read_file_text
    add sp, 6
    mov [bp-2], ax

    cmp word [bp-2], 0
    je .err_ok
    mov si, msg_err
    call puts
    mov sp, bp
    pop bp
    ret

.err_ok:
    mov word [bp-4], 0

    mov bx, [bp-4]
    mov al, [file_text + bx]
    mov [bp-5], al

.while_c:
    mov al, [bp-5]
    cmp al, 0
    je .end_while_c

    cmp al, '.'
    jne .end_if_dot

    mov word [bp-39], 0

.while_not_equal:
    mov al, [bp-5]
    cmp al, '='
    je .end_while_not_equal

    mov bx, [bp-39]
    lea dx, [bp-37]
    add bx, dx
    mov [bx], al

    mov bx, [bp-4]
    inc word [bp-4]
    mov al, [file_text + bx]
    mov [bp-5], al

    inc word [bp-39]
    jmp .while_not_equal

.end_while_not_equal:
    mov bx, [bp-39]
    lea dx, [bp-37]
    add bx, dx
    mov byte [bx], 0

    inc word [bp-4]

    mov bx, [bp-4]
    inc word [bp-4]
    mov al, [file_text + bx]
    mov [bp-5], al

.while_not_semicolon:
    mov al, [bp-5]
    cmp al, ';'
    je .end_while_not_semicolon

    mov bx, [bp-39]
    lea dx, [bp-71]
    add bx, dx
    mov [bx], al

    mov bx, [bp-4]
    inc word [bp-4]
    mov al, [file_text + bx]
    mov [bp-5], al

    inc word [bp-39]
    jmp .while_not_semicolon

.end_while_not_semicolon:
    mov bx, [bp-39]
    lea dx, [bp-71]
    add bx, dx
    mov byte [bx], 0

    lea ax, [bp-71]
    push ax
    lea ax, [bp-37]
    push ax
    mov ax, fmt_str
    push ax
    call printf
    add sp, 6

.end_if_dot:
    mov bx, [bp-4]
    inc word [bp-4]
    mov al, [file_text + bx]
    mov [bp-5], al
    jmp .while_c

.end_while_c:
    mov sp, bp
    pop bp
    ret

read_file_text:
    push bp
    mov bp, sp
    push bx
    push cx
    push si
    mov si, [bp+4]
    mov cx, [bp+6]
    mov ah, 0x02
    int 0x22
    jc .error
    
    mov si, cx
    add si, bx
    mov byte [si], 0
    mov ax, 0
    jmp .done
.error:
    mov ax, 1
.done:
    pop si
    pop cx
    pop bx
    pop bp
    ret

puts:
    push ax
    mov ah, 0x01
    int 0x21
    pop ax
    ret

printf:
    push bp
    mov bp, sp
    pusha
    mov si, [bp+4]
    lea bx, [bp+6]

.loop:
    lodsb
    cmp al, 0
    je .done
    cmp al, '%'
    je .format
    call print_char
    jmp .loop

.format:
    lodsb
    cmp al, 's'
    je .print_str
    cmp al, '%'
    je .percent
    jmp .loop

.percent:
    mov al, '%'
    call print_char
    jmp .loop

.print_str:
    mov dx, si
    mov si, [bx]
    add bx, 2
.str_loop:
    lodsb
    cmp al, 0
    je .str_done
    call print_char
    jmp .str_loop
.str_done:
    mov si, dx
    jmp .loop

.done:
    popa
    mov sp, bp
    pop bp
    ret

print_char:
    push ax
    push si
    mov byte [char_buf], al
    mov byte [char_buf+1], 0
    mov si, char_buf
    mov ah, 0x01
    int 0x21
    pop si
    pop ax
    ret

section .data
    str_filename db "testc.ccc", 0
    msg_err db "cant read a file", 0x0D, 0x0A, 0
    fmt_str db "%s: %s", 0x0D, 0x0A, 0
    char_buf db 0, 0

section .bss
    file_text resb 1024

и… он все ещё не читает файл…

Использую нейронку как компилятор - 3

Я помучал нейронку ещё, и даже начал просто ей писать “файл не читаеться”, но ни к чему это не привело.
Может ошибка в моем коде, может в PRos, может нейронка намудрила.

В любом случае я особо и не расчитывал на такие простые успехи, но заниматься этим полноценно у меня желания нет…

Полный конвеер компиляции через нейронку

Ради прикола довайте заставим уже в другом диалоге того-же гемени переводить наш ассемблер в base64 чтобы потом записать это в файл и запустить программу полностью собраную нейронкой.

[BITS 16]
[ORG 0x8000]

start:
    call main
    mov ah, 0x4C
    int 0x21
    ret

main:
    push bp
    mov bp, sp
    mov si, msg_hello
    call puts
    mov sp, bp
    pop bp
    ret

puts:
    push ax
    mov ah, 0x01
    int 0x21
    pop ax
    ret

section .data
    msg_hello db "Hello, from AIC", 0


переведи этот ассемблер в готовый сырой поток байт как при nasm -fbin и выдай base64 код
Вот готовый Base64-код скомпилированного бинарного потока (как при использовании команды nasm -fbin):

6AUAtEzNIcNVieW+HIDoBACJ7F3DULQBzSFYw0hlbGxvLCBmcm9tIEFJQwA=

## Разбор структуры по байтам (Hex-дамп)
Для наглядности ниже представлен шестнадцатеричный дамп (44 байта) с разбором инструкций:

E8 05 00        ; call main (относительное смещение +5 байт)
B4 4C           ; mov ah, 0x4C
CD 21           ; int 0x21
C3              ; ret

55              ; push bp
89 E5           ; mov bp, sp
BE 1C 80        ; mov si, 0x801C (адрес msg_hello с учетом ORG 0x8000)
E8 04 00        ; call puts (относительное смещение +4 байта)
89 EC           ; mov sp, bp
5D              ; pop bp
C3              ; ret

50              ; push ax
B4 01           ; mov ah, 0x01
CD 21           ; int 0x21
58              ; pop ax
C3              ; ret

; Строка "Hello, from AICx00" (смещение 0x801C)
48 65 6C 6C 6F 2C 20 66 72 6F 6D 20 41 49 43 00

------------------------------
💡 Если вам понадобятся дополнительные изменения в коде (например, исправление функции puts, так как в данном коде прерывание int 0x21 с ah=0x01 ожидает ввод символа с клавиатуры вместо вывода строки si), дайте знать, и я помогу переписать ассемблерный код или пересобрать бинарник!

Пойдеееет.

Пишем в файл

[System.IO.File]::WriteAllBytes("./ai.bin", [System.Convert]::FromBase64String("6AUAtEzNIcNVieW+HIDoBACJ7F3DULQBzSFYw0hlbGxvLCBmcm9tIEFJQwA="))  

Да я свиндусятник, не удивляйтесь. Пишите кстати если хотите статью как мы пишем ченить на powershell (там есть на что помотреть, я вас уверяю)

mcopy -i disk_img/x16pros.img ./ai.bin ::/BIN.DIR/

Да, я свиндусятник с wsl, не удивляйтесь.

Использую нейронку как компилятор - 4

Нууу, я не удивлен… не сильно то сложный код был.


Итог

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

Я думаю если взять нейронку поумнее, промты по лучше, код по безопаснее, то что-то да из этого выйдет. Каков вообще шанс что вайбкодинг перерастет во что-то вот такое и в сурсах вайб-проектов будут просто истории терминалов с диалогами вот таких вот “компиляторов”.

А нормальные полноценные статьи от меня будут совсем скоро… покрайней мере я на это надеюсь:
SectorOS ещё обзаведется директориями и новыми программами (может даже совместимостью с x16-PRos).
SFS32 – файловая система на базе SFS тоже уже есть и полноценная 32х битная ось тоже не за горами.
Главный мой проект, который я не показываю тоже уже почти готов, но статья о нем скорее всего будет зимой когда он будет уже в состоянии конкурировать с другими решениями.
Большой цикл статей с очень интересной темой есть у меня в голове, но думаю писать я его начну в… как только так сразу.

У меня была идея сделать ТГК и публиковать туда не только развлекательный контент, но и позновательный и более узконаправленый вглубь наших компудахтеров, держать таким образом аудиторию, но думаю пока придержать эту идею. (я вообще хз есть ли тут те, кто прям знает меня как автора целых ДВУХ СТАТЕЙ, это вам не это)

диалог с “компилятором”: https://share.google/aimode/MKCLPmxxM48WjFHgr
не могу не оставить ссылку на сам x16-PRos: https://github.com/PRoX2011/x16-PRos

Всем спасибо за прочтение. Всех с протеряным летом.

Автор: Desvor

Источник