Skip to content

begoon/c8080-js

Repository files navigation

c8080

Авторство. Оригинальный компилятор c8080 — его архитектура, расширения языка C (__global, __stack, __link, __address, соглашение о вызовах __a_N_<func>), подъязык CMM, форматы магнитофонных файлов RK86 и входящий в проект справочник MANUAL.md — © Алексей Фёдорович Морозов (Aleksey F. Morozov). Лицензии: GPL-3.0 на компилятор и Apache-2.0 на стандартную библиотеку. Источник: https://github.com/alexey-f-morozov/c8080.

Этот репозиторий — независимый порт компилятора на TypeScript. Он воспроизводит язык и ABI; все решения, определяющие поведение, приходят из оригинального проекта. Порт наследует GPL-3.0.

Компилятор C для Intel 8080 на TypeScript. Порт c8080 — компилятора Алексея Морозова на C++ для платформ на базе i8080 / КР580ВМ80А. Работает на Node 18+ и Bun.

Русскоязычное руководство из оригинального проекта включено в виде файла MANUAL.md: §5 описывает соглашения __global / __stack, §11 — форматы выходного файла (rks, rk, rkr, pki, gam), §14 — структуру магнитофонного файла RK86, которую собирают наши обёртки.

Установка

npm install -g c8080          # ставит команду `c8080`
# либо разово, без установки:
npx c8080 file.c

Использование

c8080 [-V] [-Ocpm|-Orks] [-I<dir>] [-D<name>] [-o<bin>] file.c

-Ocpm (по умолчанию) — .bin для CP/M TPA (ORG 0x0100). -Orks — магнитофонный файл Specialist / Radio-86RK.

Полный список форматов: c8080 без аргументов выводит справку.

Разработка

bun install
bun test           # 164 теста (сквозная компиляция + симуляция)
bun run typecheck  # tsc --noEmit
bun run build      # сборка бандла → dist/c8080.js (для npm publish)
bunx c8080 file.c   # (после `bun run build`)

Состояние

Полный конвейер: C source → препроцессор → парсер → подгрузка по запросу (__link) → кодогенерация → ассемблер asm8080 → бинарник. Скомпилированные программы действительно исполняются на встроенном симуляторе 8080, который перехватывает вызовы CP/M BDOS по адресу 0x0005 и обрабатывает ввод-вывод.

Демонстрация с настоящей stdlib от c8080

#include <stdio.h>
int main(void) { puts("Hello from real c8080 stdlib!"); return 0; }
$ npx c8080 -I/path/to/c8080/include demo.c
Done

Компилятор идёт по ссылке __link("stdio_h/puts.c") из stdio.h, парсит указанный файл и добавляет определение puts в программу. Подгрузка по запросу означает, что printf и прочие функции попадают в сборку только если действительно вызваны.

Что сегодня компилируется

Возможность Примечания
Типы char, short, int, long, long long, signed/unsigned, указатели, массивы, struct, enum, typedef
Операторы блоки, if/else, while, do-while, for, break, continue, return, goto, switch/case/default, asm { … } с сохранением построчной структуры
Выражения полная иерархия приоритетов C, присваивание и составное (+= и т. д.), тернарный ?:, унарные -!~*&++-- (pre/post), [] . ->, приведение типов, sizeof, оператор запятая, строковые и символьные литералы
Арифметика + - * / % << >> & | ^ (умножение/деление/сдвиги через рантаймы; арифметика указателей масштабируется по размеру элемента)
Сравнения знаковые 16-битные == != < <= > >=
Управление потоком условные переходы с уникальными метками; switch — линейный диспетчер сравнений
Структуры поля с байтовыми смещениями, вложенные структуры, чтение/запись по . и -> для byte/word-полей и массивов/структур (поля-массивы и поля-структуры «декадируют» в адрес)
Инициализаторы структур списковая инициализация по полям, включая char[] внутри структуры ({ { "ab", 10 }, ... }); недостающие поля обнуляются
Ввод-вывод встроенные putchar / puts через BDOS; пользовательские определения имеют приоритет. Строковые литералы интернированы в бинарник. Мини-printf / sprintf (%d, %s, %c, %%) автоматически линкуются при первом вызове; они делят общий слой маршрутизации вывода, поэтому можно вызывать любой из двух независимо
Препроцессор (полный) #include в обеих формах, #define (объектные и функциоподобные макросы, вариативные ...), #undef, #if/#ifdef/#ifndef/#else/#endif с вычислителем целочисленных выражений C, defined(X), __has_include(...), #pragma once, #error, CLI-флаг -D
__link("file.c") подгрузка по запросу: парсятся только те файлы, чьи функции достижимы из графа вызовов. Ошибки разбора в недостижимых звеньях некритичны
__stack соглашение вызова с поддержкой рекурсии: вызывающая сторона сохраняет слоты __a_* / __l_* вызываемой функции на CPU-стеке перед CALL, заполняет новые аргументы, вызывает, после возврата восстанавливает. Работает и для взаимной рекурсии. Пока только для параметров и локалов размером слово
Вариативные (...) на стороне вызова лишние аргументы складываются в буфер __va_args[]; используется мини-printf. Объявленные параметры по-прежнему передаются по соглашению __a_N_<func>
Глобальные инициализаторы скаляры, строки (char[] → DB, char* → DW на интернированную копию), списковая инициализация массивов (как DW с заполнением)
Экранирования в литералах \n \r \t \0 \\ \' \" \a \b \f \v \xNN \nnn (восьмеричное) — в char- и string-литералах
Рантайм-помощники __o_mul_u16, __o_div_u16, __o_shl_u16, __o_shr_u16, putchar, puts — включаются в бинарник, только если на них есть ссылка

Сквозные тесты

Каждый тест в test/codegen/endtoend.test.ts компилирует фрагмент C, ассемблирует через asm8080 и исполняет на встроенном симуляторе 8080 — авторитетный список того, что сегодня работает.

Известные пробелы

  • 8-битный путь по регистрам. Операции над char идут через 16-битный HL, тогда как путь через регистр A был бы короче по инструкциям.
  • Краевые случаи знаковой арифметики. Сравнения используют знак результата SBB, поэтому у границ int16 возможны случаи переполнения, которые игнорируются. Рантаймы умножения/деления/сдвигов — беззнаковые.
  • Интеграция рантайма CP/M. __init и зануление bss из include/c8080/internal.c не подключены. Программы работают, потому что CP/M сам выставляет SP и мы не полагаемся на нулевой bss.
  • Stdlib c8080 со вставками на sjasmplus. Большинство файлов include/string_h/*.c — это ассемблер sjasmplus внутри блоков asm { }. sjasmplus и asm8080 расходятся по синтаксису (label = value против label: EQU value), поэтому такие файлы не ассемблируются. Чистые C-файлы stdlib (puts.c и т. д.) работают.
  • Передача и возврат структур по значению. Ни то ни другое пока не поддерживается; передавайте указатели. Обычное присваивание a = b (включая g = local, s = *p) копирует структуру как надо.

Раскладка проекта

src/
  frontend/
    tokenizer.ts      порт ctokenizer.cpp
    preprocessor.ts   #include / #define / #if
    fs.ts             FileSystem-интерфейс + MemoryFileSystem
    node-fs.ts        NodeFileSystem (вынесена, чтобы браузер-бандл
                      не тянул node:fs)
    lex.ts            поток токенов с произвольным lookahead
    ast.ts            CNode / CType / CVariable / CFunction
    parser.ts         рекурсивный парсер C + захват `__link`
    symbols.ts        таблица символов со скоупами
  codegen/
    i8080/compile.ts  AST → ассемблер 8080 в Intel-синтаксисе
  runtime/
    printf.ts         встроенный C-исходник мини-printf/sprintf
    link.ts           автоматическая линковка встроенных runtime-исходников
  formats/
    rks.ts            Specialist tape envelope
    wrap.ts           диспетчер форматов (Specialist + asm8080's RK86)
  util/dump.ts        человекочитаемый дамп AST (флаг -V)
bin/c8080.ts          CLI: препроцессор + парсер + обход `__link` + кодоген + asm8080
docs/                 браузерный playground (index.html + playground.ts → .js)
test/
  codegen/sim8080.ts          минимальный симулятор 8080 + хуки BDOS
  codegen/endtoend.test.ts    сквозные C-программы: компиляция + запуск + проверка вывода

Проверка сборкой

Препроцессор справляется с 37 из 41 реального исходника c8080 (4 сбоя все контекстные — не хватает архитектурно-специфичных заголовков или флага __CMM, а не баги парсера). Парсер также доходит до всех 41.

Лицензия

GPLv3 (унаследовано от c8080).

About

Intel 8080 C compiler (c8080 port to typescript)

Resources

License

Stars

Watchers

Forks

Packages