Стартовый коммит: компилятор РуСи

This commit is contained in:
mzhoot 2026-07-21 10:20:27 +03:00
commit 4a11b8357a
152 changed files with 14638 additions and 0 deletions

24
LICENSE.md Normal file
View file

@ -0,0 +1,24 @@
Copyright (c) 2020-2024, Rui Ueyama
Copyright (c) 2026, Kirichenko Viktor
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

64
Makefile Normal file
View file

@ -0,0 +1,64 @@
# Исполняемый файл компилятора
COMPILER = ./rusi.elf
# Флаги компиляции
COMPILER_FLAGS =
# Исходные файлы
SOURCE_FILES = $(wildcard *.c)
# Директория для stage2
STAGE2_DIR = stage2
STAGE2_BINARY = $(STAGE2_DIR)/rusi.elf
# ============================================================
# Сборка по умолчанию (stage2 — самосборка)
# ============================================================
all: stage2
# ============================================================
# Тесты
# ============================================================
test: $(COMPILER)
@echo "=== Запуск стандартных тестов ==="
python3 test/driver.py $(COMPILER)
test-ru: $(COMPILER)
@echo "=== Запуск русских тестов ==="
python3 test_ru/run_tests.py
test-all: test test-ru
# ============================================================
# Самосборка (stage2)
# ============================================================
$(STAGE2_BINARY): $(COMPILER) $(SOURCE_FILES) руси.з
@mkdir -p $(STAGE2_DIR)
$(COMPILER) $(COMPILER_FLAGS) -o $@ $(SOURCE_FILES)
@if cmp -s $(COMPILER) $@; then \
echo "OK: stage2 побайтово идентичен rusi.elf"; \
else \
echo "OK: stage2 собран (отличается от rusi.elf)"; \
fi
stage2: $(STAGE2_BINARY)
test-stage2: $(STAGE2_BINARY)
@echo "=== Запуск тестов на stage2 ==="
python3 test/driver.py $(STAGE2_BINARY)
# ============================================================
# Очистка
# ============================================================
clean:
rm -rf $(STAGE2_DIR) stage3
rm -f *.o
rm -f test/*.o test/*.elf test/*.s
rm -f test_ru/*.o test_ru/*.elf test_ru/*.s
find . -name '*~' -delete
.PHONY: all test test-ru test-all stage2 test-stage2 clean

762
README.md Normal file
View file

@ -0,0 +1,762 @@
```markdown
# Руси: двуязычный компилятор C с русским синтаксисом
**Руси** — это компилятор языка C, поддерживающий **полноценный двуязычный синтаксис**.
Вы можете писать программы на C, используя как **английские**, так и **русские** ключевые слова, типы данных, операторы и директивы препроцессора — в любом сочетании, в одном файле.
Название проекта — **Руси** — говорит само за себя: это язык C, заговоривший по-русски, но при этом сохранивший родной английский синтаксис для тех, кому он привычнее.
Проект вдохновлен двумя реализациями:
- [chibicc](https://github.com/rui314/chibicc) — небольшой, но мощный C11 компилятор, способный компилировать реальные проекты.(Собственно и сделан на его основе)
- [c89cc.sh](https://gist.github.com/alganet/2b89c4368f8d23d033961d8a3deb5c19) — минималистичный компилятор C89/ELF64 на чистом shell, демонстрирующий невероятную простоту реализации.
Проект **Руси** разработан для портирования компилятора [КВС (kvs)](https://github.com/artradeskz/kvs) — ассемблера с русским синтаксисом, написанного на Python. Вместо того чтобы использовать интерпретатор Python для сборки, **Руси** позволит скомпилировать этот ассемблер в нативный бинарный файл, значительно повысив производительность и удобство использования.
## Двуязычность: как это работает
**Руси** одновременно понимает два языка: английский C и русский C. Это означает, что:
- Вы можете писать код **полностью на английском** — как в любом стандартном C.
- Вы можете писать код **полностью на русском** — используя русские ключевые слова, типы и операторы.
- Вы можете **смешивать** английский и русский синтаксис в одном файле.
Это делает компилятор идеальным инструментом для обучения, миграции проектов и команд с разными языковыми предпочтениями.
### Примеры смешанного синтаксиса
```c
// Английский main с русским типом и оператором
int главн() {
цел x = 42;
if (x == 42) {
возврат 0;
}
return 1;
}
// Русский
цел главн() {
цел ы = 42;
если (ы == 42) {
возврат 0;
}
возврат 1;
}
// Полностью смешанный стиль
цел main() {
int счетчик = 0;
для (счетчик = 0; счетчик < 10; счетчик = счетчик + 1) {
if (счетчик % 2 == 0) {
printf("Четное: %d\n", счетчик);
}
}
возврат 0;
}
```
## Полный список русских слов для программирования
### Типы данных (13)
| Английский | Русский | Пример |
|------------|---------|--------|
| `int` | `цел` | `цел x = 42;` |
| `char` | `символ` | `символ c = 'A';` |
| `short` | `корот` | `корот s = 123;` |
| `long` | `длин` | `длин l = 456789;` |
| `void` | `пусто` | `пусто функция() {}` |
| `float` | `плав` | `плав f = 3.14;` |
| `double` | `двойн` | `двойн d = 2.71;` |
| `struct` | `структ` | `структ Точка {};` |
| `union` | `объед` | `объед Данные {};` |
| `enum` | `переч` | `переч Цвет {};` |
| `_Bool` | `бул` | `бул flag = истина;` |
| `unsigned` | `беззнак` | `беззнак цел u = 42;` |
| `signed` | `знак` | `знак цел s = -42;` |
### Ключевые слова (16)
| Английский | Русский | Пример |
|------------|---------|--------|
| `typedef` | `типдеф` | `типдеф цел МойЦел;` |
| `static` | `стат` | `стат цел счетчик = 0;` |
| `extern` | `внеш` | `внеш цел глобальная;` |
| `inline` | `инлайн` | `инлайн цел квадрат() {}` |
| `const` | `конст` | `конст цел x = 42;` |
| `volatile` | `летуч` | `летуч цел x;` |
| `auto` | `авто` | `авто цел x = 42;` |
| `register` | `регистр` | `регистр цел x;` |
| `restrict` | `огранич` | `цел * огранич ptr;` |
| `_Alignas` | `_Выравнивание` | `_Выравнивание(16) символ buf[32];` |
| `_Alignof` | `_Выравнивание_типа` | `_Выравнивание_типа(цел);` |
| `_Noreturn` | `_Безвозврат` | `_Безвозврат пусто функция() {}` |
| `_Generic` | `_Обобщ` | `_Обобщ(42, цел: 1, умолч: 0);` |
| `_Atomic` | `_Атом` | `_Атом цел x;` |
| `_Thread_local` | `_Поток_лок` | `_Поток_лок цел x;` |
| `__thread` | `__поток` | `__поток цел x;` |
### Операторы (18)
| Английский | Русский | Пример |
|------------|---------|--------|
| `return` | `возврат` | `возврат 0;` |
| `if` | `если` | `если (x == 10) {}` |
| `else` | `иначе` | `иначе {}` |
| `for` | `для` | `для (i = 0; i < 10; i++) {}` |
| `while` | `пока` | `пока (i < 10) {}` |
| `do` | `делай` | `делай {} пока (i < 10);` |
| `switch` | `выбор` | `выбор (x) {}` |
| `case` | `случай` | `случай 1:` |
| `default` | `умолч` | `умолч:` |
| `goto` | `перейти` | `перейти метка;` |
| `break` | `прерви` | `прерви;` |
| `continue` | `продолжи` | `продолжи;` |
| `sizeof` | `размер` | `размер(цел);` |
| `typeof` | `типоф` | `типоф(x) y;` |
| `asm` | `асм` | `асм("nop");` |
| `&&` | Оставлено как есть | `x && y` |
| `\|\|` | Оставлено как есть | `x \|\| y` |
| `!` | Оставлено как есть | `!x` |
### Директивы препроцессора (15)
| Английский | Русский | Пример |
|------------|---------|--------|
| `#include` | `#включить` | `#включить <stdio.h>` |
| `#include_next` | `#включить_след` | `#включить_след "file.h"` |
| `#define` | `#определить` | `#определить ПИ 3.14` |
| `#undef` | `#отменить` | `#отменить ПИ` |
| `#if` | `#если` | `#если ВЕРСИЯ == 2` |
| `#ifdef` | `#еслиопр` | `#еслиопр ТЕСТ` |
| `#ifndef` | `#еслинеопр` | `#еслинеопр ТЕСТ` |
| `#elif` | `#иначеесли` | `#иначеесли ВЕРСИЯ == 2` |
| `#else` | `#иначе` | `#иначе` |
| `#endif` | `#конецесли` | `#конецесли` |
| `#line` | `#строка` | `#строка 100 "file.c"` |
| `#error` | `#ошибка` | `#ошибка "Сообщение"` |
| `#pragma` | `#прагма` | `#прагма once` |
| `defined` | `определено` | `#если определено(ТЕСТ)` |
| `once` | `однократно` | `#прагма однократно` |
### Встроенные макросы (9)
| Английский | Русский | Пример |
|------------|---------|--------|
| `__FILE__` | `__ФАЙЛ__` | `символ *f = __ФАЙЛ__;` |
| `__LINE__` | `__ЛИНИЯ__` | `цел n = __ЛИНИЯ__;` |
| `__func__` | `__функ__` | `символ *f = __функ__;` |
| `__FUNCTION__` | `__ФУНКЦИЯ__` | `символ *f = __ФУНКЦИЯ__;` |
| `__COUNTER__` | `__СЧЕТЧИК__` | `цел n = __СЧЕТЧИК__;` |
| `__TIMESTAMP__` | `__ВРЕМЯ_ФАЙЛА__` | `символ *t = __ВРЕМЯ_ФАЙЛА__;` |
| `__DATE__` | `__ДАТА__` | `символ *d = __ДАТА__;` |
| `__TIME__` | `__ВРЕМЯ__` | `символ *t = __ВРЕМЯ__;` |
| `__BASE_FILE__` | `__БАЗОВЫЙ_ФАЙЛ__` | `символ *b = __БАЗОВЫЙ_ФАЙЛ__;` |
### Функции (1)
| Английский | Русский | Пример |
|------------|---------|--------|
| `main` | `главн` | `цел главн() {}` |
## Особенности
- **Двуязычный синтаксис**: все ключевые слова, типы, операторы и директивы препроцессора доступны как на английском, так и на русском языке.
- **Смешивание языков**: английский и русский синтаксис можно использовать в одном файле в любых сочетаниях.
- **Русские идентификаторы**: можно называть переменные, функции и структуры по-русски.
- **Русские имена файлов и расширения**: компилятор работает с файлами `программа.си` и заголовками `привет.з`.
- **Полная поддержка C11**: включая препроцессор, битовые поля, VLA, атомарные и thread-local переменные.
- **70+ переведенных конструкций**: все ключевые слова, операторы, макросы и директивы покрыты тестами.
## Пример программы (смешанный синтаксис)
```c
#включить <stdio.h>
#включить <stdbool.h>
структ Точка {
цел x;
цел y;
};
цел суммаоординат(структ Точка точка) {
возврат точка.x + точка.y;
}
цел главн() {
цел массив[10];
for (цел i = 0; i < 10; i = i + 1) {
массив[i] = i * 2;
}
int сумма = 0;
для (int i = 0; i < 10; i = i + 1) {
сумма = сумма + массив[i];
}
если (sum == 90) {
printf("Сумма: %d\n", сумма);
} else {
printf("Ошибка!\n");
возврат 1;
}
struct Точка точка = {10, 20};
цел результат = суммаоординат(точка);
если (результат == 30) {
printf("OK\n");
возврат 0;
}
return 1;
}
```
## Импорт файлов с русскими именами
```c
// привет.з - русский заголовочный файл
#еслинеопр ПРИВЕТ_З
#определить ПРИВЕТ_З
#включить <stdio.h>
#define ПЕЧАТЬ printf
#endif
```
```c
// программа.рс - основная программа
#включить "привет.з"
цел главн() {
ПЕЧАТЬ("Привет, мир!\n");
возврат 0;
}
```
## Компиляция русских файлов
```bash
./руси программа.рс -o программа
./программа
# Вывод: Привет, мир!
```
## Внутреннее устройство
Компилятор состоит из четырех этапов:
1. **Токенизация** — разбиение исходного кода на токены (с поддержкой UTF-8 и кириллицы).
2. **Препроцессинг** — обработка директив и макросов (с русскими синонимами).
3. **Парсинг** — построение AST с использованием рекурсивного спуска.
4. **Генерация кода** — создание ассемблерного текста для x86-64 (ELF64).
## Тестирование и самосборка
Проект имеет две независимые системы тестирования:
### 1. Стандартные тесты (английский синтаксис)
Запускаются командой `make test`. Проверяют базовую функциональность компилятора на оригинальном C.
### 2. Русские тесты
Запускаются командой `make test-ru`. Написаны на Python (`test_ru/run_tests.py`) и проверяют все русские синонимы. 70+ тестов покрывают все переведенные конструкции:
```bash
make test-ru
# Вывод: 🎉 Все тесты пройдены!
```
### 3. Самосборка (Stage 2)
Компилятор способен скомпилировать сам себя. Этот процесс называется **самосборкой** (self-hosting) и подтверждает, что компилятор достаточно зрелый для работы с собственным кодом.
```bash
make test-stage2
```
Эта команда:
1. Компилирует компилятор с помощью самого себя (stage2)
2. Проверяет, что stage2-версия проходит все тесты
3. Подтверждает, что компилятор способен воспроизвести себя
Самосборка — важный этап разработки компилятора, доказывающий его надежность и полноту.
## Планы по миграции исходного кода на русский синтаксис
Текущая версия компилятора уже **полностью понимает русский синтаксис** и успешно проходит все тесты (включая 70+ русских тестов). Следующий логический шаг — **переписать сам исходный код компилятора на русском синтаксисе**.
### Что это даст?
1. **Полная русификация**: исходный код компилятора будет написан на том же языке, который он компилирует.
2. **Демонстрация возможностей**: сам компилятор станет лучшим примером использования русского синтаксиса.
3. **Образовательная ценность**: русскоязычные студенты смогут изучать устройство компилятора без языкового барьера.
4. **Двуязычная кодовая база**: английская и русская версии будут существовать параллельно.
### Как это будет сделано
1. **Поэтапная миграция**: исходный код будет переписан на русский синтаксис постепенно, файл за файлом.
2. **Сохранение двуязычности**: компилятор продолжит понимать оба синтаксиса.
3. **Тестирование**: после каждого этапа будет запускаться полный набор тестов.
4. **Самосборка**: после завершения миграции компилятор сможет скомпилировать себя из русскоязычного исходного кода.
### Статус
- ✅ **Компилятор понимает русский синтаксис** — полностью готово.
- ✅ **Функция main переименована в главн** — сделано.
- ⏳ **Миграция исходного кода на русский синтаксис** — в планах.
- ⏳ **Самосборка из русскоязычного исходного кода** — следующий этап.
### Пример того, как будет выглядеть код компилятора на русском
```c
// Токенизатор на русском синтаксисе (планируется)
структ Токен {
переч ВидТокена вид;
Токен *следующий;
цел значение;
символ *позиция;
цел длина;
};
цел прочитать_идентификатор(символ *начало) {
символ *p = начало;
цел c = декодировать_utf8(&p, p);
если (!это_идентификатор1(c)) {
возврат 0;
}
пока (истина) {
символ *q;
c = декодировать_utf8(&q, p);
если (!это_идентификатор2(c)) {
возврат p - начало;
}
p = q;
}
}
```
## Портирование КВС (kvs) с Python на C
Проект **Руси** разработан с прицелом на портирование компилятора [КВС (kvs)](https://github.com/artradeskz/kvs) — ассемблера с русским синтаксисом для x86-64, написанного на Python.
### Зачем это нужно?
КВС (расшифровывается как "Код В Силу" или просто "КВС") — это образовательный ассемблер, который использует русскую лексику для мнемоник инструкций, имён регистров и директив. Однако он написан на Python и работает как интерпретатор, что ограничивает его производительность и распространение.
**Руси** позволит:
1. **Скомпилировать КВС в нативный бинарный файл** — вместо интерпретации Python-скриптов, ассемблер будет работать как обычный исполняемый файл.
2. **Значительно повысить производительность** — компилированный код работает на порядок быстрее интерпретируемого.
3. **Распространять как самостоятельный бинарник** — не требуется устанавливать Python и зависимости.
4. **Улучшить интеграцию** — бинарный файл легче встраивать в различные системы и инструменты.
### Как будет происходить портирование
1. **Анализ архитектуры КВС**: КВС состоит из шести проходов: лексер, парсер, 4 прохода разрешения меток и констант, финальная сборка ELF.
2. **Переписывание на C с русским синтаксисом**: каждый модуль будет переписан на C, используя русские ключевые слова и идентификаторы.
3. **Сохранение логики**: шестипроходная архитектура останется, но будет оптимизирована для нативного выполнения.
4. **Полная совместимость**: бинарный файл должен компилировать те же `.квс` файлы, что и оригинальный Python-скрипт.
### Пример: лексер КВС на русском C
```c
// планируемый код лексера КВС на русском C
структ Токен {
переч ВидТокена вид;
символ *текст;
цел длина;
Токен *следующий;
};
Токен *лексический_анализ(символ *исходник) {
Токен *голова = нуль;
Токен *текущий = нуль;
символ *позиция = исходник;
пока (*позиция != '\0') {
пропустить_пробелы(&позиция);
если (*позиция == '\0') {
прерви;
}
если (*позиция == ';') {
пропустить_комментарий(&позиция);
продолжи;
}
Токен *токен = выделить_токен(&позиция);
если (голова == нуль) {
голова = токен;
} иначе {
текущий->следующий = токен;
}
текущий = токен;
}
возврат голова;
}
```
### Преимущества портирования для КВС
| Аспект | Python-версия (оригинал) | C-версия (план) |
|--------|--------------------------|-----------------|
| **Скорость сборки** | ~0.5-1.0 сек для простых программ | ~0.01-0.05 сек |
| **Установка** | Требуется Python 3.7+ | Ничего не требуется |
| **Распространение** | Исходники или .deb | Один бинарник |
| **Зависимости** | Стандартная библиотека Python | Только libc |
| **Интеграция** | Только как скрипт | Может встраиваться в любую систему |
### План работ по портированию
1. **Этап 1**: Портирование лексера (`квсексер.py` → `лексер.рс`)
2. **Этап 2**: Портирование парсера (`квс_парсер.py` → `парсер.рс`)
3. **Этап 3**: Портирование четырех проходов (`квс_проход*.py` → `проход*.рс`)
4. **Этап 4**: Портирование финальной сборки ELF (`квс_финсбор.py` → `финсбор.рс`)
5. **Этап 5**: Интеграция в единый бинарник (`квс_сборка.рс`)
6. **Этап 6**: Тестирование на всех 26 тестах КВС
## Подсветка синтаксиса для VS Code / VS Codium
В планах разработка **расширения для подсветки синтаксиса** русского C для редакторов VS Code и VS Codium.
### Что будет поддерживаться
- **Русские ключевые слова**: подсветка всех переведенных конструкций (`цел`, `если`, `возврат` и др.)
- **Русские идентификаторы**: правильное распознавание переменных и функций с кириллицей
- **Русские директивы препроцессора**: подсветка `#включить`, `#определить` и др.
- **Русские имена файлов**: корректная работа с файлами `.рс` и `.з`
### Планируемые функции расширения
- **Автодополнение**: подсказки для русских ключевых слов
- **Фрагменты кода**: готовые шаблоны для `если`, `для`, `структ` и др.
- **Форматирование**: автоматическое форматирование кода с русским синтаксисом
- **Проверка синтаксиса**: интеграция с компилятором **Руси** для проверки ошибок
### Статус
- ⏳ **Разработка расширения для подсветки синтаксиса** — в планах.
- ⏳ **Интеграция с компилятором** — следующий этап.
## Планы по русификации стандартной библиотеки
В планах создание **русскоязычной стандартной библиотеки** — заголовочных файлов с русскими именами для всех основных функций и констант.
### Зачем это нужно?
Русификация стандартной библиотеки сделает русский синтаксис по-настоящему завершенным. Программист сможет не только писать ключевые слова на русском, но и использовать функции и константы с русскими именами:
```c
#включить <стандарт.з>
цел главн() {
// Вместо printf("Привет!\n");
печать("Привет!\n");
// Вместо strlen("текст");
цел длина = длина_строки("текст");
// Вместо malloc(100);
пусто *память = выделить(100);
// Вместо free(память);
освободить(память);
возврат 0;
}
```
### Какие функции будут переведены
| Английское имя | Русское имя | Заголовочный файл |
|----------------|-------------|-------------------|
| `printf` | `печать` | `стандарт.з` (stdio.h) |
| `scanf` | `ввод` | `стандарт.з` (stdio.h) |
| `puts` | `вывод_строки` | `стандарт.з` (stdio.h) |
| `gets` | `получить_строку` | `стандарт.з` (stdio.h) |
| `malloc` | `выделить` | `стандарт.з` (stdlib.h) |
| `free` | `освободить` | `стандарт.з` (stdlib.h) |
| `calloc` | `выделить_нули` | `стандарт.з` (stdlib.h) |
| `realloc` | `перевыделить` | `стандарт.з` (stdlib.h) |
| `strlen` | `длина_строки` | `строки.з` (string.h) |
| `strcpy` | опировать_строку` | `строки.з` (string.h) |
| `strcmp` | `сравнить_строки` | `строки.з` (string.h) |
| `strcat` | `склеить_строки` | `строки.з` (string.h) |
| `strchr` | айти_в_строке` | `строки.з` (string.h) |
| `strstr` | айти_подстроку` | `строки.з` (string.h) |
| `memcpy` | опировать_память` | `память.з` (string.h) |
| `memset` | аполнить_память` | `память.з` (string.h) |
| `memcmp` | `сравнить_память` | `память.з` (string.h) |
| `exit` | `завершить` | `стандарт.з` (stdlib.h) |
| `rand` | `случайное` | `стандарт.з` (stdlib.h) |
| `srand` | `инициализировать_случайное` | `стандарт.з` (stdlib.h) |
| `time` | `время` | `время.з` (time.h) |
| `sqrt` | `корень` | `математика.з` (math.h) |
| `sin` | `синус` | `математика.з` (math.h) |
| `cos` | `косинус` | `математика.з` (math.h) |
| `tan` | `тангенс` | `математика.з` (math.h) |
| `pow` | `степень` | `математика.з` (math.h) |
| `abs` | `модуль` | `стандарт.з` (stdlib.h) |
### Как это будет реализовано
1. **Создание заголовочных файлов с русскими именами**: например, `стандарт.з` (аналог stdio.h + stdlib.h), `строки.з` (string.h), `математика.з` (math.h).
2. **Использование макросов**: русские имена будут определены через `#define` или через `typedef`.
3. **Полная совместимость**: можно будет использовать как русские, так и английские имена в одной программе.
### Пример заголовочного файла `стандарт.з`
```c
// стандарт.з - русская стандартная библиотека
#еслинеопр СТАНДАРТ_З
#определить СТАНДАРТ_З
#включить <stdio.h>
#включить <stdlib.h>
#включить <string.h>
#включить <math.h>
// Ввод-вывод
#определить печать printf
#определить ввод scanf
#определить вывод_строки puts
#определить получить_строку gets
#определить вывод_ошибки fprintf
// Управление памятью
#определить выделить malloc
#определить освободить free
#определить выделить_нули calloc
#определить перевыделить realloc
// Завершение программы
#определить завершить exit
// Работа со строками
#определить длина_строки strlen
#определить копировать_строку strcpy
#определить сравнить_строки strcmp
#определить склеить_строки strcat
#определить найти_в_строке strchr
#определить найти_подстроку strstr
// Работа с памятью
#определить копировать_память memcpy
#определить заполнить_память memset
#определить сравнить_память memcmp
// Случайные числа
#определить случайное rand
#определить инициализировать_случайное srand
// Математика
#определить корень sqrt
#определить синус sin
#определить косинус cos
#определить тангенс tan
#определить степень pow
// Константы
#определить ПИ 3.14159265358979323846
#определить Е 2.71828182845904523536
#конецесли
```
### Пример программы с русской стандартной библиотекой
```c
#включить "стандарт.з"
цел главн() {
печать("Введите число: ");
цел x;
ввод("%d", &x);
цел квадрат = степень(x, 2);
печать("Квадрат числа %d равен %d\n", x, квадрат);
печать("Синус числа: %f\n", синус(x));
символ *сообщение = выделить(100);
если (сообщение != нуль) {
копировать_строку(сообщение, "Привет, мир!");
печать("%s\n", сообщение);
освободить(сообщение);
}
завершить(0);
}
```
### Преимущества для образования
Русскоязычная стандартная библиотека станет мощным инструментом для обучения программированию, так как:
1. **Снижает порог входа**: студентам не нужно запоминать английские названия функций.
2. **Ускоряет обучение**: можно сразу переходить к логике, а не тратить время на запоминание терминов.
3. **Сохраняет совместимость**: при необходимости можно использовать английские имена.
### Статус
- ⏳ **Русификация стандартной библиотеки** — в планах.
- ⏳ **Создание заголовочных файлов с русскими именами** — следующий этап.
- ⏳ **Интеграция с компилятором** — после создания библиотеки.
## Настройка русской раскладки для Linux
В планах создание **настройки для русской раскладки клавиатуры в Linux**, чтобы программистам не приходилось переключаться между русской и английской раскладками при вводе знаков препинания.
### Проблема
При написании кода на русском языке программисты сталкиваются с необходимостью часто переключать раскладку:
- Русская раскладка: буквы на русском, но знаки препинания (`.` , `,` , `;` , `:` , `[` , `]` , `{` , `}` , `(` , `)` , `!` , `?` , `@` , `#` , `$` , `%` , `^` , `&` , `*` , `-` , `_` , `+` , `=` , `~` , `|` , `\` , `/` , `<` , `>` ) находятся в других местах или недоступны.
- Английская раскладка: знаки препинания на привычных местах, но буквы на английском.
Постоянное переключение раскладки замедляет написание кода и отвлекает от процесса.
### Решение
Создание **специальной настройки (раскладки или модификации)** для Linux, которая:
1. **Сохраняет расположение букв как в русской раскладке** (ЙЦУКЕН или ЙЦУКЕНГ).
2. **Размещает знаки препинания на тех же клавишах, что и в английской раскладке** (`.` на той же клавише, где в английском, `,` на той же и т.д.).
В результате программист может:
- Писать буквы на русском (без переключения).
- Вводить знаки препинания на тех же клавишах, к которым привык в английской раскладке.
### Как это будет реализовано
1. **Создание файла настройки XKB (xkb)** — стандартный способ настройки раскладок в Linux (Xorg и Wayland).
2. **Интеграция с системой** — установка через скрипт или пакет.
### Пример файла `ru_prog` (русская программистская раскладка)
```xkb
// ru_prog - русская раскладка со знаками препинания как в английской
xkb_symbols "prog" {
include "ru(ru)"
name[Group1] = "Russian (programming)";
// Переопределяем знаки препинания
key <TLDE> { [ apostrophe, asciitilde ] }; // ` ~
key <AE01> { [ 1, exclam ] }; // 1 !
key <AE02> { [ 2, at ] }; // 2 @
key <AE03> { [ 3, numbersign ] }; // 3 #
key <AE04> { [ 4, dollar ] }; // 4 $
key <AE05> { [ 5, percent ] }; // 5 %
key <AE06> { [ 6, asciicircum ] }; // 6 ^
key <AE07> { [ 7, ampersand ] }; // 7 &
key <AE08> { [ 8, asterisk ] }; // 8 *
key <AE09> { [ 9, parenleft ] }; // 9 (
key <AE10> { [ 0, parenright ] }; // 0 )
key <AE11> { [ minus, underscore ] }; // - _
key <AE12> { [ equal, plus ] }; // = +
key <AD01> { [ q, Q ] }; // q
key <AD02> { [ w, W ] }; // w
key <AD03> { [ e, E ] }; // e
key <AD04> { [ r, R ] }; // r
key <AD05> { [ t, T ] }; // t
key <AD06> { [ y, Y ] }; // y
key <AD07> { [ u, U ] }; // u
key <AD08> { [ i, I ] }; // i
key <AD09> { [ o, O ] }; // o
key <AD10> { [ p, P ] }; // p
key <AD11> { [ bracketleft, braceleft ] }; // [ {
key <AD12> { [ bracketright, braceright ] }; // ] }
key <AC01> { [ a, A ] }; // a
key <AC02> { [ s, S ] }; // s
key <AC03> { [ d, D ] }; // d
key <AC04> { [ f, F ] }; // f
key <AC05> { [ g, G ] }; // g
key <AC06> { [ h, H ] }; // h
key <AC07> { [ j, J ] }; // j
key <AC08> { [ k, K ] }; // k
key <AC09> { [ l, L ] }; // l
key <AC10> { [ semicolon, colon ] }; // ; :
key <AC11> { [ apostrophe, quotedbl ] }; // ' "
key <AB01> { [ z, Z ] }; // z
key <AB02> { [ x, X ] }; // x
key <AB03> { [ c, C ] }; // c
key <AB04> { [ v, V ] }; // v
key <AB05> { [ b, B ] }; // b
key <AB06> { [ n, N ] }; // n
key <AB07> { [ m, M ] }; // m
key <AB08> { [ comma, less ] }; // , <
key <AB09> { [ period, greater ] }; // . >
key <AB10> { [ slash, question ] }; // / ?
};
```
### Альтернативный подход: использование `setxkbmap`
Для быстрой настройки можно использовать команду:
```bash
setxkbmap -layout us,ru -variant ,prog -option grp:alt_shift_toggle
```
### Планируемые функции
1. **Установка через скрипт**: `./настроить_раскладку.sh` — автоматически добавляет раскладку в систему.
2. **Переключение по горячим клавишам**: например, `Alt+Shift` переключает между стандартной русской и программистской русской раскладкой.
3. **Интеграция с редакторами**: автоматическое переключение раскладки при открытии `.рс` файлов.
4. **Документация**: инструкции для различных дистрибутивов Linux (Ubuntu, Fedora, Arch, etc.)
### Статус
- ⏳ **Создание файла XKB для русской программистской раскладки** — в планах.
- ⏳ **Скрипт автоматической установки** — следующий этап.
- ⏳ **Документация для различных дистрибутивов** — в планах.
## Сборка и тестирование
```bash
# Сборка компилятора
make
# Запуск стандартных тестов
make test
# Запуск русских тестов
make test-ru
# Запуск всех тестов (стандартные + русские)
make test-all
# Самосборка и тестирование stage2
make test-stage2
# Очистка собранных файлов
make clean
```
## Благодарности
Особая благодарность:
- **Rui Ueyama** за создание [chibicc](https://github.com/rui314/chibicc) — образцово-простого и образовательного компилятора.
- **Alexandre Gaigalas** за [c89cc.sh](https://gist.github.com/alganet/2b89c4368f8d23d033961d8a3deb5c19) — демонстрацию минимализма в реализации компилятора.
## Статус
- ✅ Все основные конструкции переведены и протестированы.
- ✅ Двуязычный синтаксис полностью работоспособен.
- ✅ Поддержка русского синтаксиса и смешанного стиля успешно проходит 70+ тестов.
- ✅ Русские имена файлов и расширений поддерживаются.
- ✅ Самосборка (self-hosting) успешно работает.
- ✅ Функция `main` переименована в `главн`.
- ⏳ Миграция исходного кода на русский синтаксис — в процессе.
- ⏳ Портирование КВС с Python на C — в планах.
- ⏳ Расширение для подсветки синтаксиса VS Code / VS Codium — в планах.
- ⏳ Русификация стандартной библиотеки — в планах.
- ⏳ Настройка русской раскладки для Linux — в планах.
```

1568
codegen.c Normal file

File diff suppressed because it is too large Load diff

320
hashmap.c Normal file
View file

@ -0,0 +1,320 @@
// ============================================================
// Реализация хеш-таблицы с открытой адресацией
// ============================================================
#включить "руси.з"
#включить <stdint.h> // стандартная библиотека
#включить <string.h> // стандартная библиотека
#включить <stdlib.h> // стандартная библиотека
#включить <assert.h> // стандартная библиотека
#включить <stdio.h> // стандартная библиотека
// ============================================================
// Константы
// ============================================================
#определить НАЧАЛЬНЫЙ_РАЗМЕР 16 // Начальный размер таблицы
#определить ВЕРХНИЙ_ПОРОГ 70 // Перестройка при заполнении > 70%
#определить НИЖНИЙ_ПОРОГ 50 // Целевое заполнение после перестройки < 50%
#определить УДАЛЕНО ((пусто *)-1) // Маркер удаленного элемента
// ============================================================
// Хеш-функция FNV-1a
// ============================================================
стат uint64_t хеш_fnv(конст символ *данные, цел длина) {
uint64_t хеш = 0xcbf29ce484222325ULL; // FNV offset basis
для (цел ш = 0; ш < длина; ш++) {
хеш *= 0x100000001b3ULL; // FNV prime
хеш ^= (беззнак символ)данные[ш];
}
возврат хеш;
}
// ============================================================
// Проверка совпадения ключей
// ============================================================
стат бул ключи_совпадают(ЗаписьХеша *запись, конст символ *ключ, цел длина_ключа) {
если (!запись->ключ || запись->ключ == УДАЛЕНО) {
возврат ложь;
}
возврат (запись->длина_ключа == длина_ключа) &&
(memcmp(запись->ключ, ключ, длина_ключа) == 0);
}
// ============================================================
// Перестройка хеш-таблицы
// ============================================================
стат пусто перестроить(ХешТаблица *таблица) {
если (!таблица) возврат;
// Подсчитываем количество активных записей
цел активных = 0;
для (цел ш = 0; ш < таблица->вместимость; ш++) {
пусто *ключ = таблица->корзины[ш].ключ;
если (ключ && ключ != УДАЛЕНО) {
активных++;
}
}
// Вычисляем новый размер
цел новая_вместимость = таблица->вместимость;
пока ((активных * 100) / новая_вместимость >= НИЖНИЙОРОГ) {
новая_вместимость *= 2;
}
assert(новая_вместимость > 0);
// Создаем новую таблицу
ХешТаблица новая = {0};
новая.корзины = (ЗаписьХеша *)calloc(новая_вместимость, размер(ЗаписьХеша));
новая.вместимость = новая_вместимость;
// Копируем все активные записи
для (цел ш = 0; ш < таблица->вместимость; ш++) {
ЗаписьХеша *запись = &таблица->корзины[ш];
если (запись->ключ && запись->ключ != УДАЛЕНО) {
хешставить2(&новая, запись->ключ, запись->длина_ключа, запись->значение);
}
}
assert(новая.использовано == активных);
// Освобождаем старую таблицу
если (таблица->корзины) {
free(таблица->корзины);
}
// Копируем новую таблицу
*таблица = новая;
}
// ============================================================
// Поиск записи по ключу
// ============================================================
стат ЗаписьХеша *найтиапись(ХешТаблица *таблица, конст символ *ключ, цел длина_ключа) {
если (!таблица || !таблица->корзины) {
возврат NULL;
}
uint64_t хеш = хеш_fnv(ключ, длина_ключа);
для (цел ш = 0; ш < таблица->вместимость; ш++) {
цел индекс = (хеш + ш) % таблица->вместимость;
ЗаписьХеша *запись = &таблица->корзины[индекс];
если (ключи_совпадают(запись, ключ, длина_ключа)) {
возврат запись;
}
если (запись->ключ == NULL) {
возврат NULL;
}
}
unreachable();
возврат NULL;
}
// ============================================================
// Поиск или создание записи
// ============================================================
стат ЗаписьХеша *найти_или_создать(ХешТаблица *таблица, конст символ *ключ, цел длина_ключа) {
// Инициализация при первом использовании
если (!таблица->корзины) {
таблица->корзины = (ЗаписьХеша *)calloc(НАЧАЛЬНЫЙ_РАЗМЕР, размер(ЗаписьХеша));
таблица->вместимость = НАЧАЛЬНЫЙ_РАЗМЕР;
если (!таблица->корзины) {
возврат NULL;
}
}
// Перестройка при переполнении
если ((таблица->использовано * 100) / таблица->вместимость >= ВЕРХНИЙОРОГ) {
перестроить(таблица);
}
uint64_t хеш = хеш_fnv(ключ, длина_ключа);
для (цел ш = 0; ш < таблица->вместимость; ш++) {
цел индекс = (хеш + ш) % таблица->вместимость;
ЗаписьХеша *запись = &таблица->корзины[индекс];
// Нашли существующую запись
если (ключи_совпадают(запись, ключ, длина_ключа)) {
возврат запись;
}
// Нашли tombstone - используем его
если (запись->ключ == УДАЛЕНО) {
запись->ключ = (символ *)ключ;
запись->длина_ключа = длина_ключа;
возврат запись;
}
// Нашли пустую запись
если (запись->ключ == NULL) {
запись->ключ = (символ *)ключ;
запись->длина_ключа = длина_ключа;
таблица->использовано++;
возврат запись;
}
}
unreachable();
возврат NULL;
}
// ============================================================
// Публичные функции
// ============================================================
пусто *хеш_получить(ХешТаблица *таблица, символ *ключ) {
если (!таблица || !ключ) возврат NULL;
возврат хеш_получить2(таблица, ключ, (цел)strlen(ключ));
}
пусто *хеш_получить2(ХешТаблица *таблица, символ *ключ, цел длина_ключа) {
если (!таблица || !ключ || длина_ключа <= 0) возврат NULL;
ЗаписьХеша *запись = найтиапись(таблица, ключ, длина_ключа);
возврат запись ? запись->значение : NULL;
}
пусто хешставить(ХешТаблица *таблица, символ *ключ, пусто *значение) {
если (!таблица || !ключ) возврат;
хешставить2(таблица, ключ, (цел)strlen(ключ), значение);
}
пусто хешставить2(ХешТаблица *таблица, символ *ключ, цел длина_ключа, пусто *значение) {
если (!таблица || !ключ || длина_ключа <= 0) возврат;
ЗаписьХеша *запись = найти_или_создать(таблица, ключ, длина_ключа);
если (запись) {
запись->значение = значение;
}
}
пусто хеш_удалить(ХешТаблица *таблица, символ *ключ) {
если (!таблица || !ключ) возврат;
хеш_удалить2(таблица, ключ, (цел)strlen(ключ));
}
пусто хеш_удалить2(ХешТаблица *таблица, символ *ключ, цел длина_ключа) {
если (!таблица || !ключ || длина_ключа <= 0) возврат;
ЗаписьХеша *запись = найтиапись(таблица, ключ, длина_ключа);
если (запись) {
запись->ключ = УДАЛЕНО;
}
}
// ============================================================
// Тестирование хеш-таблицы
// ============================================================
пусто хешест(пусто) {
ХешТаблица *таблица = (ХешТаблица *)calloc(1, размер(ХешТаблица));
если (!таблица) {
fprintf(stderr, "Failed to allocate hashmap for testing\n");
возврат;
}
printf("Testing hashmap...\n");
// Вставка 5000 записей
для (цел ш = 0; ш < 5000; ш++) {
символ *ключ = формат("key %d", ш);
хешставить(таблица, ключ, (пусто *)(intptr_t)ш);
}
// Удаление записей 1000-1999
для (цел ш = 1000; ш < 2000; ш++) {
символ *ключ = формат("key %d", ш);
хеш_удалить(таблица, ключ);
}
// Повторная вставка 1500-1599
для (цел ш = 1500; ш < 1600; ш++) {
символ *ключ = формат("key %d", ш);
хешставить(таблица, ключ, (пусто *)(intptr_t)ш);
}
// Вставка 6000-6999
для (цел ш = 6000; ш < 7000; ш++) {
символ *ключ = формат("key %d", ш);
хешставить(таблица, ключ, (пусто *)(intptr_t)ш);
}
// Проверка записей 0-999
для (цел ш = 0; ш < 1000; ш++) {
символ *ключ = формат("key %d", ш);
пусто *значение = хеш_получить(таблица, ключ);
assert((intptr_t)значение == ш);
}
// Проверка удаленных записей 1000-1499
для (цел ш = 1000; ш < 1500; ш++) {
символ *ключ = формат("key %d", ш);
пусто *значение = хеш_получить(таблица, ключ);
assert(значение == NULL);
}
// Проверка восстановленных записей 1500-1599
для (цел ш = 1500; ш < 1600; ш++) {
символ *ключ = формат("key %d", ш);
пусто *значение = хеш_получить(таблица, ключ);
assert((intptr_t)значение == ш);
}
// Проверка удаленных записей 1600-1999
для (цел ш = 1600; ш < 2000; ш++) {
символ *ключ = формат("key %d", ш);
пусто *значение = хеш_получить(таблица, ключ);
assert(значение == NULL);
}
// Проверка записей 2000-4999
для (цел ш = 2000; ш < 5000; ш++) {
символ *ключ = формат("key %d", ш);
пусто *значение = хеш_получить(таблица, ключ);
assert((intptr_t)значение == ш);
}
// Проверка несуществующих записей 5000-5999
для (цел ш = 5000; ш < 6000; ш++) {
символ *ключ = формат("key %d", ш);
пусто *значение = хеш_получить(таблица, ключ);
assert(значение == NULL);
}
// Обновление записей 6000-6999
для (цел ш = 6000; ш < 7000; ш++) {
символ *ключ = формат("key %d", ш);
хешставить(таблица, ключ, (пусто *)(intptr_t)(ш * 2));
}
// Проверка обновленных записей
для (цел ш = 6000; ш < 7000; ш++) {
символ *ключ = формат("key %d", ш);
пусто *значение = хеш_получить(таблица, ключ);
assert((intptr_t)значение == ш * 2);
}
// Проверка несуществующего ключа
assert(хеш_получить(таблица, "no such key") == NULL);
// Освобождаем память
если (таблица->корзины) {
free(таблица->корзины);
}
free(таблица);
printf("All hashmap tests passed!\n");
}

119
include/common.c Normal file
View file

@ -0,0 +1,119 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
/*
void assert(int expected, int actual, char *code) {
if (expected == actual) {
printf("%s => %d\n", code, actual);
} else {
printf("%s => %d expected but got %d\n", code, expected, actual);
exit(1);
}
}
*/
static int static_fn() { return 5; }
int ext1 = 5;
int *ext2 = &ext1;
int ext3 = 7;
int ext_fn1(int x) { return x; }
int ext_fn2(int x) { return x; }
int common_ext2 = 3;
static int common_local;
int false_fn() { return 512; }
int true_fn() { return 513; }
int char_fn() { return (2<<8)+3; }
int short_fn() { return (2<<16)+5; }
int uchar_fn() { return (2<<10)-1-4; }
int ushort_fn() { return (2<<20)-1-7; }
int schar_fn() { return (2<<10)-1-4; }
int sshort_fn() { return (2<<20)-1-7; }
int add_all(int n, ...) {
va_list ap;
va_start(ap, n);
int sum = 0;
for (int i = 0; i < n; i++)
sum += va_arg(ap, int);
return sum;
}
float add_float(float x, float y) {
return x + y;
}
double add_double(double x, double y) {
return x + y;
}
int add10_int(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10) {
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10;
}
float add10_float(float x1, float x2, float x3, float x4, float x5, float x6, float x7, float x8, float x9, float x10) {
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10;
}
double add10_double(double x1, double x2, double x3, double x4, double x5, double x6, double x7, double x8, double x9, double x10) {
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10;
}
typedef struct { int a,b; short c; char d; } Ty4;
typedef struct { int a; float b; double c; } Ty5;
typedef struct { unsigned char a[3]; } Ty6;
typedef struct { long a, b, c; } Ty7;
int struct_test4(Ty4 x, int n) {
switch (n) {
case 0: return x.a;
case 1: return x.b;
case 2: return x.c;
default: return x.d;
}
}
int struct_test5(Ty5 x, int n) {
switch (n) {
case 0: return x.a;
case 1: return x.b;
default: return x.c;
}
}
int struct_test6(Ty6 x, int n) {
return x.a[n];
}
int struct_test7(Ty7 x, int n) {
switch (n) {
case 0: return x.a;
case 1: return x.b;
default: return x.c;
}
}
Ty4 struct_test24(void) {
return (Ty4){10, 20, 30, 40};
}
Ty5 struct_test25(void) {
return (Ty5){10, 20, 30};
}
Ty6 struct_test26(void) {
return (Ty6){10, 20, 30};
}
typedef struct { unsigned char a[10]; } Ty20;
typedef struct { unsigned char a[20]; } Ty21;
Ty20 struct_test27(void) {
return (Ty20){10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
}
Ty21 struct_test28(void) {
return (Ty21){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
}

358
include/rstdlib.h Normal file
View file

@ -0,0 +1,358 @@
// ============================================================
// СТАНДАРТНАЯ БИБЛИОТЕКА РУСИ
// ============================================================
// Объединение всех стандартных заголовочных файлов C11
// в единый модуль с русскими синонимами.
//
// Включает:
// - float.h — характеристики типов с плавающей точкой
// - stdalign.h — макросы для работы с выравниванием типов
// - stdarg.h — макросы для работы с переменным числом аргументов
// - stdatomic.h — атомарные операции и типы
// - stdbool.h — булевый тип данных
// - stddef.h — стандартные определения типов и макросов
// - stdnoreturn.h — спецификатор невозвратных функций
// ============================================================
#ifndef _STDLIB_RU
#define _STDLIB_RU
// ============================================================
// float.h - Характеристики типов с плавающей точкой
// ============================================================
// Общие параметры представления чисел с плавающей точкой
#define DECIMAL_DIG 21
#define FLT_EVAL_METHOD 0
#define FLT_RADIX 2
#define FLT_ROUNDS 1
// Характеристики типа float (одинарная точность, 32 бита)
#define FLT_DIG 6
#define FLT_EPSILON 0x1p-23
#define FLT_MANT_DIG 24
#define FLT_MAX 0x1.fffffep+127
#define FLT_MAX_10_EXP 38
#define FLT_MAX_EXP 128
#define FLT_MIN 0x1p-126
#define FLT_MIN_10_EXP -37
#define FLT_MIN_EXP -125
#define FLT_TRUE_MIN 0x1p-149
// Характеристики типа double (двойная точность, 64 бита)
#define DBL_DIG 15
#define DBL_EPSILON 0x1p-52
#define DBL_MANT_DIG 53
#define DBL_MAX 0x1.fffffffffffffp+1023
#define DBL_MAX_10_EXP 308
#define DBL_MAX_EXP 1024
#define DBL_MIN 0x1p-1022
#define DBL_MIN_10_EXP -307
#define DBL_MIN_EXP -1021
#define DBL_TRUE_MIN 0x0.0000000000001p-1022
// Характеристики типа long double (расширенная точность, 80/128 бит)
#define LDBL_DIG 15
#define LDBL_EPSILON 0x1p-52
#define LDBL_MANT_DIG 53
#define LDBL_MAX 0x1.fffffffffffffp+1023
#define LDBL_MAX_10_EXP 308
#define LDBL_MAX_EXP 1024
#define LDBL_MIN 0x1p-1022
#define LDBL_MIN_10_EXP -307
#define LDBL_MIN_EXP -1021
#define LDBL_TRUE_MIN 0x0.0000000000001p-1022
// Русские синонимы для float.h
#define ДЕСЯТИЧНЫХ_ЦИФР DECIMAL_DIG
#define МЕТОД_ОЦЕНКИ FLT_EVAL_METHOD
#define ОСНОВАНИЕ FLT_RADIX
#define РЕЖИМ_ОКРУГЛЕНИЯ FLT_ROUNDS
#define ОДИНАР_ЦИФР FLT_DIG
#define ОДИНАР_ЭПСИЛОН FLT_EPSILON
#define ОДИНАР_МАНТИССА FLT_MANT_DIG
#define ОДИНАР_МАКС FLT_MAX
#define ОДИНАР_МАКС_10_СТЕП FLT_MAX_10_EXP
#define ОДИНАР_МАКС_СТЕП FLT_MAX_EXP
#define ОДИНАР_МИН FLT_MIN
#define ОДИНАР_МИН_10_СТЕП FLT_MIN_10_EXP
#define ОДИНАР_МИН_СТЕП FLT_MIN_EXP
#define ОДИНАР_МИНЕНОРМ FLT_TRUE_MIN
#define ДВОЙН_ЦИФР DBL_DIG
#define ДВОЙН_ЭПСИЛОН DBL_EPSILON
#define ДВОЙН_МАНТИССА DBL_MANT_DIG
#define ДВОЙН_МАКС DBL_MAX
#define ДВОЙН_МАКС_10_СТЕП DBL_MAX_10_EXP
#define ДВОЙН_МАКС_СТЕП DBL_MAX_EXP
#define ДВОЙН_МИН DBL_MIN
#define ДВОЙН_МИН_10_СТЕП DBL_MIN_10_EXP
#define ДВОЙН_МИН_СТЕП DBL_MIN_EXP
#define ДВОЙН_МИНЕНОРМ DBL_TRUE_MIN
#define ДЛИН_ЦИФР LDBL_DIG
#define ДЛИН_ЭПСИЛОН LDBL_EPSILON
#define ДЛИН_МАНТИССА LDBL_MANT_DIG
#define ДЛИН_МАКС LDBL_MAX
#define ДЛИН_МАКС_10_СТЕП LDBL_MAX_10_EXP
#define ДЛИН_МАКС_СТЕП LDBL_MAX_EXP
#define ДЛИН_МИН LDBL_MIN
#define ДЛИН_МИН_10_СТЕП LDBL_MIN_10_EXP
#define ДЛИН_МИН_СТЕП LDBL_MIN_EXP
#define ДЛИН_МИНЕНОРМ LDBL_TRUE_MIN
// ============================================================
// stdalign.h - Макросы для работы с выравниванием типов
// ============================================================
#define alignas _Alignas
#define alignof _Alignof
#define __alignas_is_defined 1
#define __alignof_is_defined 1
// Русские синонимы для stdalign.h
#define выравн _Alignas
#define выравн_размер _Alignof
// ============================================================
// stdarg.h - Макросы для работы с переменным числом аргументов
// ============================================================
typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
void *overflow_arg_area;
void *reg_save_area;
} __va_state;
typedef __va_state va_list[1];
#define va_start(ap, last) \
do { *(ap) = *(__va_state *)__va_area__; } while (0)
#define va_end(ap)
static void *__va_read_from_stack(__va_state *ap, int sz, int align) {
void *p = ap->overflow_arg_area;
if (align > 8)
p = (p + 15) / 16 * 16;
ap->overflow_arg_area = ((unsigned long)p + sz + 7) / 8 * 8;
return p;
}
static void *__va_read_from_gp(__va_state *ap, int sz, int align) {
if (ap->gp_offset >= 48)
return __va_read_from_stack(ap, sz, align);
void *r = ap->reg_save_area + ap->gp_offset;
ap->gp_offset += 8;
return r;
}
static void *__va_read_from_fp(__va_state *ap, int sz, int align) {
if (ap->fp_offset >= 112)
return __va_read_from_stack(ap, sz, align);
void *r = ap->reg_save_area + ap->fp_offset;
ap->fp_offset += 8;
return r;
}
#define va_arg(ap, ty) \
({ \
int klass = __builtin_reg_class(ty); \
*(ty *)(klass == 0 ? __va_read_from_gp(ap, sizeof(ty), _Alignof(ty)) : \
klass == 1 ? __va_read_from_fp(ap, sizeof(ty), _Alignof(ty)) : \
__va_read_from_stack(ap, sizeof(ty), _Alignof(ty))); \
})
#define va_copy(dest, src) ((dest)[0] = (src)[0])
#define __GNUC_VA_LIST 1
typedef va_list __gnuc_va_list;
// Русские синонимы для stdarg.h
#define аргументы va_list
#define аргачало va_start
#define аргонец va_end
#define арг_взять va_arg
#define аргопия va_copy
// ============================================================
// stdatomic.h - Атомарные операции и типы
// ============================================================
#define ATOMIC_BOOL_LOCK_FREE 1
#define ATOMIC_CHAR_LOCK_FREE 1
#define ATOMIC_CHAR16_T_LOCK_FREE 1
#define ATOMIC_CHAR32_T_LOCK_FREE 1
#define ATOMIC_WCHAR_T_LOCK_FREE 1
#define ATOMIC_SHORT_LOCK_FREE 1
#define ATOMIC_INT_LOCK_FREE 1
#define ATOMIC_LONG_LOCK_FREE 1
#define ATOMIC_LLONG_LOCK_FREE 1
#define ATOMIC_POINTER_LOCK_FREE 1
typedef enum {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst,
} memory_order;
#define порядок_ослабленный memory_order_relaxed
#define порядок_потребление memory_order_consume
#define порядок_приобретение memory_order_acquire
#define порядок_освобождение memory_order_release
#define порядок_приобретение_освобождение memory_order_acq_rel
#define порядок_последовательный memory_order_seq_cst
#define ATOMIC_FLAG_INIT(x) (x)
#define atomic_init(addr, val) (*(addr) = (val))
#define kill_dependency(x) (x)
#define atomic_thread_fence(order)
#define atomic_signal_fence(order)
#define atomic_is_lock_free(x) 1
#define atomic_load(addr) (*(addr))
#define atomic_store(addr, val) (*(addr) = (val))
#define atomic_load_explicit(addr, order) (*(addr))
#define atomic_store_explicit(addr, val, order) (*(addr) = (val))
#define атом_загрузить(addr) atomic_load(addr)
#define атом_сохранить(addr, val) atomic_store(addr, val)
#define атом_загрузить_явно(addr, order) atomic_load_explicit(addr, order)
#define атом_сохранить_явно(addr, val, order) atomic_store_explicit(addr, val, order)
#define atomic_fetch_add(obj, val) (*(obj) += (val))
#define atomic_fetch_sub(obj, val) (*(obj) -= (val))
#define atomic_fetch_or(obj, val) (*(obj) |= (val))
#define atomic_fetch_xor(obj, val) (*(obj) ^= (val))
#define atomic_fetch_and(obj, val) (*(obj) &= (val))
#define atomic_fetch_add_explicit(obj, val, order) (*(obj) += (val))
#define atomic_fetch_sub_explicit(obj, val, order) (*(obj) -= (val))
#define atomic_fetch_or_explicit(obj, val, order) (*(obj) |= (val))
#define atomic_fetch_xor_explicit(obj, val, order) (*(obj) ^= (val))
#define atomic_fetch_and_explicit(obj, val, order) (*(obj) &= (val))
#define атом_прибавить(obj, val) atomic_fetch_add(obj, val)
#define атом_вычесть(obj, val) atomic_fetch_sub(obj, val)
#define атом_или(obj, val) atomic_fetch_or(obj, val)
#define атом_исключ_или(obj, val) atomic_fetch_xor(obj, val)
#define атом_и(obj, val) atomic_fetch_and(obj, val)
#define атом_прибавить_явно(obj, val, order) atomic_fetch_add_explicit(obj, val, order)
#define атом_вычесть_явно(obj, val, order) atomic_fetch_sub_explicit(obj, val, order)
#define атом_или_явно(obj, val, order) atomic_fetch_or_explicit(obj, val, order)
#define атом_исключ_или_явно(obj, val, order) atomic_fetch_xor_explicit(obj, val, order)
#define атом_и_явно(obj, val, order) atomic_fetch_and_explicit(obj, val, order)
#define atomic_compare_exchange_weak(p, old, new) \
__builtin_compare_and_swap((p), (old), (new))
#define atomic_compare_exchange_strong(p, old, new) \
__builtin_compare_and_swap((p), (old), (new))
#define atomic_exchange(obj, val) __builtin_atomic_exchange((obj), (val))
#define atomic_exchange_explicit(obj, val, order) __builtin_atomic_exchange((obj), (val))
#define атом_сравнить_обменять_слабо(p, old, new) atomic_compare_exchange_weak(p, old, new)
#define атом_сравнить_обменять(p, old, new) atomic_compare_exchange_strong(p, old, new)
#define атом_обменять(obj, val) atomic_exchange(obj, val)
#define атом_обменять_явно(obj, val, order) atomic_exchange_explicit(obj, val, order)
#define atomic_flag_test_and_set(obj) atomic_exchange((obj), 1)
#define atomic_flag_test_and_set_explicit(obj, order) atomic_exchange((obj), 1)
#define atomic_flag_clear(obj) (*(obj) = 0)
#define atomic_flag_clear_explicit(obj, order) (*(obj) = 0)
#define атом_флаг_проверить_установить(obj) atomic_flag_test_and_set(obj)
#define атом_флаг_проверить_установить_явно(obj, order) atomic_flag_test_and_set_explicit(obj, order)
#define атом_флаг_очистить(obj) atomic_flag_clear(obj)
#define атом_флаг_очистить_явно(obj, order) atomic_flag_clear_explicit(obj, order)
typedef _Atomic _Bool atomic_flag;
typedef _Atomic _Bool atomic_bool;
typedef _Atomic char atomic_char;
typedef _Atomic signed char atomic_schar;
typedef _Atomic unsigned char atomic_uchar;
typedef _Atomic short atomic_short;
typedef _Atomic unsigned short atomic_ushort;
typedef _Atomic int atomic_int;
typedef _Atomic unsigned int atomic_uint;
typedef _Atomic long atomic_long;
typedef _Atomic unsigned long atomic_ulong;
typedef _Atomic long long atomic_llong;
typedef _Atomic unsigned long long atomic_ullong;
typedef _Atomic unsigned short atomic_char16_t;
typedef _Atomic unsigned atomic_char32_t;
typedef _Atomic unsigned atomic_wchar_t;
typedef _Atomic signed char atomic_int_least8_t;
typedef _Atomic unsigned char atomic_uint_least8_t;
typedef _Atomic short atomic_int_least16_t;
typedef _Atomic unsigned short atomic_uint_least16_t;
typedef _Atomic int atomic_int_least32_t;
typedef _Atomic unsigned int atomic_uint_least32_t;
typedef _Atomic long atomic_int_least64_t;
typedef _Atomic unsigned long atomic_uint_least64_t;
typedef _Atomic signed char atomic_int_fast8_t;
typedef _Atomic unsigned char atomic_uint_fast8_t;
typedef _Atomic short atomic_int_fast16_t;
typedef _Atomic unsigned short atomic_uint_fast16_t;
typedef _Atomic int atomic_int_fast32_t;
typedef _Atomic unsigned int atomic_uint_fast32_t;
typedef _Atomic long atomic_int_fast64_t;
typedef _Atomic unsigned long atomic_uint_fast64_t;
typedef _Atomic long atomic_intptr_t;
typedef _Atomic unsigned long atomic_uintptr_t;
typedef _Atomic unsigned long atomic_size_t;
typedef _Atomic long atomic_ptrdiff_t;
typedef _Atomic long atomic_intmax_t;
typedef _Atomic unsigned long atomic_uintmax_t;
// ============================================================
// stdbool.h - Булевый тип данных
// ============================================================
#define bool _Bool
#define true 1
#define false 0
#define бул _Bool
#define истина 1
#define ложь 0
#define __bool_true_false_are_defined 1
// ============================================================
// stddef.h - Стандартные определения типов и макросов
// ============================================================
#define NULL ((void *)0)
typedef unsigned long size_t;
typedef long ptrdiff_t;
typedef unsigned int wchar_t;
typedef long max_align_t;
#define offsetof(type, member) ((size_t)&(((type *)0)->member))
#define НУЛЬ NULL
typedef size_t размер_t;
typedef ptrdiff_t разность_t;
typedef wchar_t шсимвол_t;
typedef max_align_t макс_выравн_t;
#define смещение(type, member) offsetof(type, member)
// ============================================================
// stdnoreturn.h - Спецификатор невозвратных функций
// ============================================================
#define noreturn _Noreturn
#define безвозврат _Noreturn
#endif // _STDLIB_RU

145
include/stdarg.h Normal file
View file

@ -0,0 +1,145 @@
// stdarg.h - Макросы для работы с переменным числом аргументов функций
//
// Этот заголовочный файл реализует механизм передачи переменного числа
// аргументов (variadic functions) согласно ABI System V для x86-64.
//
// Структура __va_state отражает внутреннее представление области
// сохранения регистров, создаваемой компилятором для variadic функций.
//
// Поддерживаются как стандартные макросы (va_start, va_arg, va_end, va_copy),
// так и русские синонимы (аргачало, арг_взять, аргонец, аргопия).
#ifndef _STDARG_H_RU
#define _STDARG_H_RU
// ============================================================
// Внутреннее состояние списка аргументов
// ============================================================
// Структура описывает состояние итератора по аргументам variadic функции.
// Она отражает ABI x86-64 System V:
// - gp_offset: смещение в области сохранения регистров общего назначения
// - fp_offset: смещение в области сохранения регистров с плавающей точкой
// - overflow_arg_area: указатель на аргументы, переданные через стек
// - reg_save_area: указатель на область сохранения регистров
typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
void *overflow_arg_area;
void *reg_save_area;
} __va_state;
// Список аргументов — массив из одного элемента __va_state.
// Такое представление позволяет передавать список по ссылке
// и модифицировать его внутри функций.
typedef __va_state va_list[1];
// ============================================================
// Инициализация и завершение работы с аргументами
// ============================================================
// Инициализация списка аргументов.
// Копирует состояние из специальной области __va_area__,
// которая создаётся компилятором для каждой variadic функции.
#define va_start(ap, last) \
do { *(ap) = *(__va_state *)__va_area__; } while (0)
// Завершение работы со списком аргументов.
// В данной реализации не требует никаких действий.
#define va_end(ap)
// ============================================================
// Внутренние функции извлечения аргументов
// ============================================================
// Извлечение аргумента из области переполнения (переданного через стек).
// Выравнивает указатель согласно требованиям типа и продвигает
// область переполнения вперёд с учётом размера и выравнивания.
static void *__va_read_from_stack(__va_state *ap, int sz, int align) {
void *p = ap->overflow_arg_area;
if (align > 8)
p = (p + 15) / 16 * 16;
ap->overflow_arg_area = ((unsigned long)p + sz + 7) / 8 * 8;
return p;
}
// Извлечение аргумента из области сохранения регистров общего назначения.
// Если регистры общего назначения исчерпаны (gp_offset >= 48),
// переключается на извлечение из стека.
static void *__va_read_from_gp(__va_state *ap, int sz, int align) {
if (ap->gp_offset >= 48)
return __va_read_from_stack(ap, sz, align);
void *r = ap->reg_save_area + ap->gp_offset;
ap->gp_offset += 8;
return r;
}
// Извлечение аргумента из области сохранения регистров с плавающей точкой.
// Если регистры с плавающей точкой исчерпаны (fp_offset >= 112),
// переключается на извлечение из стека.
static void *__va_read_from_fp(__va_state *ap, int sz, int align) {
if (ap->fp_offset >= 112)
return __va_read_from_stack(ap, sz, align);
void *r = ap->reg_save_area + ap->fp_offset;
ap->fp_offset += 8;
return r;
}
// ============================================================
// Извлечение следующего аргумента
// ============================================================
// Извлечение следующего аргумента заданного типа из списка.
// Использует встроенную функцию __builtin_reg_class для определения
// класса регистра (0 - общего назначения, 1 - плавающая точка, 2 - память)
// и вызывает соответствующую функцию извлечения.
#define va_arg(ap, ty) \
({ \
int klass = __builtin_reg_class(ty); \
*(ty *)(klass == 0 ? __va_read_from_gp(ap, sizeof(ty), _Alignof(ty)) : \
klass == 1 ? __va_read_from_fp(ap, sizeof(ty), _Alignof(ty)) : \
__va_read_from_stack(ap, sizeof(ty), _Alignof(ty))); \
})
// ============================================================
// Копирование списка аргументов
// ============================================================
// Копирование состояния списка аргументов.
// Позволяет итерироваться по аргументам независимо в разных местах.
#define va_copy(dest, src) ((dest)[0] = (src)[0])
// ============================================================
// Совместимость с GCC
// ============================================================
// Макрос, указывающий, что va_list совместим с GCC
#define __GNUC_VA_LIST 1
// Альтернативное имя типа для совместимости с GCC
typedef va_list __gnuc_va_list;
// ============================================================
// Русские синонимы для удобства
// ============================================================
// Тип списка аргументов
#define аргументы va_list
// Инициализация списка аргументов
// Пример: аргачало(args, последний);
#define аргачало va_start
// Завершение работы со списком аргументов
#define аргонец va_end
// Извлечение следующего аргумента
// Пример: цел x = арг_взять(args, цел);
#define арг_взять va_arg
// Копирование списка аргументов
#define аргопия va_copy
#endif // _STDARG_H_RU

45
include/stdbool.h Normal file
View file

@ -0,0 +1,45 @@
// stdbool.h - Заголовочный файл для работы с булевым типом данных
//
// Этот файл определяет макросы для использования булевых значений
// в программах на языке C. Поддерживаются как стандартные английские
// идентификаторы (bool, true, false), так и русские синонимы
// (бул, истина, ложь).
#ifndef _STDBOOL_H_INCLUDED
#define _STDBOOL_H_INCLUDED
// ============================================================
// Стандартные макросы C99
// ============================================================
// Тип булевой переменной (встроенный тип _Bool)
#define bool _Bool
// Логическая истина
#define true 1
// Логическая ложь
#define false 0
// ============================================================
// Русские синонимы для булевых значений
// ============================================================
// Тип булевой переменной (русский синоним)
#define бул _Bool
// Логическая истина (русский синоним)
#define истина 1
// Логическая ложь (русский синоним)
#define ложь 0
// ============================================================
// Служебные макросы
// ============================================================
// Макрос, указывающий, что данный заголовочный файл включён
// и макросы bool/true/false определены
#define __bool_true_false_are_defined 1
#endif // _STDBOOL_H_INCLUDED

82
include/stddef.h Normal file
View file

@ -0,0 +1,82 @@
// stddef.h - Стандартные определения типов и макросов
//
// Этот заголовочный файл определяет фундаментальные типы данных и макросы,
// используемые в программах на языке C. Все размеры и типы соответствуют
// стандарту C11 для архитектуры x86-64 (LP64 модель данных).
//
// Поддерживаются как стандартные идентификаторы (NULL, size_t, offsetof),
// так и русские синонимы (НУЛЬ, размер, смещение).
#ifndef _STDDEF_H_RU
#define _STDDEF_H_RU
// ============================================================
// Нулевой указатель
// ============================================================
// Константа нулевого указателя.
// Используется для обозначения недействительного или неинициализированного
// указателя. Может быть приведён к любому типу указателя.
#define NULL ((void *)0)
// ============================================================
// Фундаментальные типы данных
// ============================================================
// Тип для представления размеров объектов в байтах.
// Беззнаковое целое, способное вместить размер любого объекта.
// На x86-64 это 64-битное беззнаковое целое.
typedef unsigned long size_t;
// Тип для представления разности двух указателей.
// Знаковое целое, способное вместить разность любых двух указателей
// в пределах одного массива. На x86-64 это 64-битное знаковое целое.
typedef long ptrdiff_t;
// Тип для представления широких символов (wide characters).
// Используется для работы с Unicode в кодировках UTF-16/UTF-32.
// На x86-64 Linux это 32-битное беззнаковое целое (UTF-32).
typedef unsigned int wchar_t;
// Тип с максимальным требованием выравнивания.
// Гарантирует, что любой объект этого типа будет выровнен
// по максимальной границе, требуемой любым базовым типом.
typedef long max_align_t;
// ============================================================
// Макрос для вычисления смещения члена структуры
// ============================================================
// Возвращает смещение в байтах указанного члена внутри структуры.
// Использует технику создания указателя по нулевому адресу
// для вычисления смещения без создания реального объекта.
//
// Пример использования:
// struct Point { int x; int y; };
// size_t offset = offsetof(struct Point, y); // вернёт 4
#define offsetof(type, member) ((size_t)&(((type *)0)->member))
// ============================================================
// Русские синонимы для удобства
// ============================================================
// Нулевой указатель (русский синоним)
#define НУЛЬ NULL
// Тип для размеров (русский синоним)
typedef size_t размер_t;
// Тип для разности указателей (русский синоним)
typedef ptrdiff_t разность_t;
// Тип для широких символов (русский синоним)
typedef wchar_t шсимвол_t;
// Тип с максимальным выравниванием (русский синоним)
typedef max_align_t макс_выравн_t;
// Макрос вычисления смещения (русский синоним)
// Пример: размер_t смещ = смещение(struct Точка, y);
#define смещение(type, member) offsetof(type, member)
#endif // _STDDEF_H_RU

49
include/stdnoreturn.h Normal file
View file

@ -0,0 +1,49 @@
// stdnoreturn.h - Спецификатор невозвратных функций
//
// Этот заголовочный файл определяет макрос noreturn, который является
// удобным синонимом ключевого слова _Noreturn из стандарта C11.
//
// Спецификатор noreturn сообщает компилятору, что функция никогда
// не возвращает управление вызывающему коду. Это позволяет компилятору
// выполнять дополнительные оптимизации и выдавать более точные
// предупреждения о недостижимом коде.
//
// Типичные примеры невозвратных функций:
// - exit() — завершение программы
// - abort() — аварийное завершение
// - _Exit() — немедленное завершение без очистки
// - quick_exit() — быстрое завершение
//
// Поддерживается как стандартный идентификатор (noreturn),
// так и русский синоним (безвозврат).
#ifndef _STDNORETURN_H_RU
#define _STDNORETURN_H_RU
// ============================================================
// Стандартный макрос C11
// ============================================================
// Спецификатор невозвратной функции.
// Применяется к объявлениям функций, которые не возвращают управление.
//
// Пример использования:
// #include <stdnoreturn.h>
// noreturn void завершить_программу(цел код) {
// exit(код);
// }
#define noreturn _Noreturn
// ============================================================
// Русский синоним для удобства
// ============================================================
// Спецификатор невозвратной функции (русский синоним).
//
// Пример использования:
// безвозврат пусто аварийный_выход(цел код) {
// выход(код);
// }
#define безвозврат _Noreturn
#endif // _STDNORETURN_H_RU

53
include/stdvv.c Normal file
View file

@ -0,0 +1,53 @@
// stdvv.c - реализация русского ввода/вывода
#include "stdvv.h"
long syscall3(long number, long arg1, long arg2, long arg3) {
asm("mov %rcx, %r10");
asm("mov %rdi, %rax");
asm("mov %rsi, %rdi");
asm("mov %rdx, %rsi");
asm("mov %r10, %rdx");
asm("syscall");
}
long длина_строки(const char *s) {
long len = 0;
while (s[len]) len++;
return len;
}
int печатьф(const char *формат, ...) {
long len = длина_строки(формат);
return (int)syscall3(1, 1, (long)формат, len);
}
int печать(const char *строка) {
long len = длина_строки(строка);
return (int)syscall3(1, 1, (long)строка, len);
}
int вывод_строки(const char *строка) {
int result = печать(строка);
симв_вывод('\n');
return result;
}
int симв_вывод(int c) {
char ch = (char)c;
return (int)syscall3(1, 1, (long)&ch, 1);
}
void завершение(int код) {
syscall3(60, код, 0, 0);
for (;;) {}
}
// assert - проверка условия для тестов
void assert(int expected, int actual, char *code) {
if (expected != actual) {
printf("ОШИБКА: ожидалось %d, получено %d (%s)\n", expected, actual, code);
завершение(1);
}
}

25
include/stdvv.h Normal file
View file

@ -0,0 +1,25 @@
// stdvv.h - стандартный ввод/вывод для русского C
#ifndef _STDVV_H
#define _STDVV_H
#define NULL ((void*)0)
// Системные вызовы
long syscall3(long number, long arg1, long arg2, long arg3);
// Функции вывода
int печатьф(const char *формат, ...);
int печать(const char *строка);
int симв_вывод(int c);
int вывод_строки(const char *строка);
// Завершение программы
void завершение(int код);
// Длина строки
long длина_строки(const char *s);
// assert для тестов
void assert(int expected, int actual, char *code);
#endif

875
main.c Normal file
View file

@ -0,0 +1,875 @@
#включить "руси.з"
// Типы входных файлов
типдеф переч {
FILE_NONE, FILE_C, FILE_ASM, FILE_OBJ, FILE_AR, FILE_DSO,
} FileType;
// Глобальные переменные (публичные интерфейсы)
МассивСтрок include_paths; // было StringArray
бул opt_fcommon = истина;
бул opt_fpic;
символ *base_file;
// Статические переменные для опций командной строки
стат FileType source_type_override;
стат МассивСтрок forced_includes; // было StringArray
стат бул option_preprocess_only;
стат бул option_make_depend;
стат бул option_make_depend_with_compile;
стат бул option_make_depend_only;
стат бул option_phony_targets;
стат бул option_assembly_only;
стат бул option_compile_only;
стат бул option_cc1_mode;
стат бул option_verbose_commands;
стат бул option_static_link;
стат бул option_shared_lib;
стат символ *option_depend_file;
стат символ *option_target_name;
стат символ *option_output_file;
стат МассивСтрок linker_extra_args; // было StringArray
стат МассивСтрок standard_include_paths; // было StringArray
стат символ *compiler_output_path;
стат МассивСтрок input_files; // было StringArray
стат МассивСтрок temporary_files; // было StringArray
// Вывод справки по использованию
стат пусто show_usage(цел status) {
fprintf(stderr, "rusi [ -o <path> ] <file>\n");
exit(status);
}
// Проверка, требует ли опция аргумент
стат бул option_requires_argument(символ *arg) {
символ *options_with_args[] = {
"-o", "-I", "-idirafter", "-include", "-x", "-MF", "-MT", "-Xlinker",
};
для (цел i = 0; i < размер(options_with_args) / размер(*options_with_args); i++)
если (!strcmp(arg, options_with_args[i]))
возврат истина;
возврат ложь;
}
// Добавление стандартных путей поиска include-файлов
стат пусто setup_default_include_paths(символ *executable_path) {
// Ожидаем, что include-файлы rusi установлены в ./include относительно argv[0]
массив_строк_добавить(&include_paths, формат("%s/include", dirname(strdup(executable_path))));
// Добавляем стандартные системные пути
массив_строк_добавить(&include_paths, "/usr/local/include");
массив_строк_добавить(&include_paths, "/usr/include/x86_64-linux-gnu");
массив_строк_добавить(&include_paths, "/usr/include");
// Сохраняем копию стандартных путей для опции -MMD
для (цел i = 0; i < include_paths.len; i++)
массив_строк_добавить(&standard_include_paths, include_paths.data[i]);
}
// Обработка определения макроса из командной строки
стат пусто process_macro_definition(символ *str) {
символ *equals = strchr(str, '=');
если (equals)
define_macro(strndup(str, equals - str), equals + 1);
иначе
define_macro(str, "1");
}
// Разбор значения опции -x (тип исходного файла)
стат FileType parse_source_type(символ *type_str) {
если (!strcmp(type_str, "c"))
возврат FILE_C;
если (!strcmp(type_str, "assembler"))
возврат FILE_ASM;
если (!strcmp(type_str, "none"))
возврат FILE_NONE;
error("<command line>: unknown argument for -x: %s", type_str);
}
// Экранирование строки для использования в Makefile
стат символ *escape_for_makefile(символ *input) {
символ *buffer = calloc(1, strlen(input) * 2 + 1);
для (цел i = 0, j = 0; input[i]; i++) {
выбор (input[i]) {
случай '$':
// Символ $ экранируется как $$
buffer[j++] = '$';
buffer[j++] = '$';
прерви;
случай '#':
// Символ # экранируется как \#
buffer[j++] = '\\';
buffer[j++] = '#';
прерви;
случай ' ':
случай '\t':
// Пробелы и табуляции экранируются обратными слешами
для (цел k = i - 1; k >= 0 && input[k] == '\\'; k--)
buffer[j++] = '\\';
buffer[j++] = '\\';
buffer[j++] = input[i];
прерви;
умолч:
buffer[j++] = input[i];
прерви;
}
}
возврат buffer;
}
// Разбор аргументов командной строки
стат пусто parse_command_line(цел argc, символ **argv) {
// Проверяем, что все опции, требующие аргумента, его имеют
для (цел i = 1; i < argc; i++)
если (option_requires_argument(argv[i]))
если (!argv[++i])
show_usage(1);
МассивСтрок deferred_includes = {}; // было StringArray
для (цел i = 1; i < argc; i++) {
// Опция ###: вывод команд подпроцессов
если (!strcmp(argv[i], "-###")) {
option_verbose_commands = истина;
продолжи;
}
// Опция -cc1: прямой вызов компилятора
если (!strcmp(argv[i], "-cc1")) {
option_cc1_mode = истина;
продолжи;
}
// Справка
если (!strcmp(argv[i], "--help"))
show_usage(0);
// Опция -o: выходной файл
если (!strcmp(argv[i], "-o")) {
option_output_file = argv[++i];
продолжи;
}
если (!strncmp(argv[i], "-o", 2)) {
option_output_file = argv[i] + 2;
продолжи;
}
// Опция -S: только ассемблер
если (!strcmp(argv[i], "-S")) {
option_assembly_only = истина;
продолжи;
}
// Опции -fcommon и -fno-common
если (!strcmp(argv[i], "-fcommon")) {
opt_fcommon = истина;
продолжи;
}
если (!strcmp(argv[i], "-fno-common")) {
opt_fcommon = ложь;
продолжи;
}
// Опция -c: только компиляция
если (!strcmp(argv[i], "-c")) {
option_compile_only = истина;
продолжи;
}
// Опция -E: только препроцессор
если (!strcmp(argv[i], "-E")) {
option_preprocess_only = истина;
продолжи;
}
// Опция -I: путь поиска include
если (!strncmp(argv[i], "-I", 2)) {
массив_строк_добавить(&include_paths, argv[i] + 2);
продолжи;
}
// Опция -D: определение макроса
если (!strcmp(argv[i], "-D")) {
process_macro_definition(argv[++i]);
продолжи;
}
если (!strncmp(argv[i], "-D", 2)) {
process_macro_definition(argv[i] + 2);
продолжи;
}
// Опция -U: отмена определения макроса
если (!strcmp(argv[i], "-U")) {
undef_macro(argv[++i]);
продолжи;
}
если (!strncmp(argv[i], "-U", 2)) {
undef_macro(argv[i] + 2);
продолжи;
}
// Опция -include: принудительное включение файла
если (!strcmp(argv[i], "-include")) {
массив_строк_добавить(&forced_includes, argv[++i]);
продолжи;
}
// Опция -x: указание типа исходного файла
если (!strcmp(argv[i], "-x")) {
source_type_override = parse_source_type(argv[++i]);
продолжи;
}
если (!strncmp(argv[i], "-x", 2)) {
source_type_override = parse_source_type(argv[i] + 2);
продолжи;
}
// Опции -l и -Wl,: передача линкеру
если (!strncmp(argv[i], "-l", 2) || !strncmp(argv[i], "-Wl,", 4)) {
массив_строк_добавить(&input_files, argv[i]);
продолжи;
}
// Опция -Xlinker: передача аргумента линкеру
если (!strcmp(argv[i], "-Xlinker")) {
массив_строк_добавить(&linker_extra_args, argv[++i]);
продолжи;
}
// Опция -s: удаление символов
если (!strcmp(argv[i], "-s")) {
массив_строк_добавить(&linker_extra_args, "-s");
продолжи;
}
// Опции генерации зависимостей
если (!strcmp(argv[i], "-M")) {
option_make_depend = истина;
продолжи;
}
если (!strcmp(argv[i], "-MF")) {
option_depend_file = argv[++i];
продолжи;
}
если (!strcmp(argv[i], "-MP")) {
option_phony_targets = истина;
продолжи;
}
если (!strcmp(argv[i], "-MT")) {
если (option_target_name == NULL)
option_target_name = argv[++i];
иначе
option_target_name = формат("%s %s", option_target_name, argv[++i]);
продолжи;
}
если (!strcmp(argv[i], "-MD")) {
option_make_depend_with_compile = истина;
продолжи;
}
если (!strcmp(argv[i], "-MQ")) {
если (option_target_name == NULL)
option_target_name = escape_for_makefile(argv[++i]);
иначе
option_target_name = формат("%s %s", option_target_name, escape_for_makefile(argv[++i]));
продолжи;
}
если (!strcmp(argv[i], "-MMD")) {
option_make_depend_with_compile = option_make_depend_only = истина;
продолжи;
}
// Опции -fpic и -fPIC: position-independent code
если (!strcmp(argv[i], "-fpic") || !strcmp(argv[i], "-fPIC")) {
opt_fpic = истина;
продолжи;
}
// Опции cc1: входной и выходной файлы
если (!strcmp(argv[i], "-cc1-input")) {
base_file = argv[++i];
продолжи;
}
если (!strcmp(argv[i], "-cc1-output")) {
compiler_output_path = argv[++i];
продолжи;
}
// Опция -idirafter: отложенный поиск include
если (!strcmp(argv[i], "-idirafter")) {
массив_строк_добавить(&deferred_includes, argv[i++]);
продолжи;
}
// Опции -static и -shared: тип линковки
если (!strcmp(argv[i], "-static")) {
option_static_link = истина;
массив_строк_добавить(&linker_extra_args, "-static");
продолжи;
}
если (!strcmp(argv[i], "-shared")) {
option_shared_lib = истина;
массив_строк_добавить(&linker_extra_args, "-shared");
продолжи;
}
// Опция -L: путь поиска библиотек
если (!strcmp(argv[i], "-L")) {
массив_строк_добавить(&linker_extra_args, "-L");
массив_строк_добавить(&linker_extra_args, argv[++i]);
продолжи;
}
если (!strncmp(argv[i], "-L", 2)) {
массив_строк_добавить(&linker_extra_args, "-L");
массив_строк_добавить(&linker_extra_args, argv[i] + 2);
продолжи;
}
// Тестовая опция для hashmap
если (!strcmp(argv[i], "-hashmap-test")) {
хешест();
exit(0);
}
// Игнорируемые опции (для совместимости с GCC)
если (!strncmp(argv[i], "-O", 2) ||
!strncmp(argv[i], "-W", 2) ||
!strncmp(argv[i], "-g", 2) ||
!strncmp(argv[i], "-std=", 5) ||
!strcmp(argv[i], "-ffreestanding") ||
!strcmp(argv[i], "-fno-builtin") ||
!strcmp(argv[i], "-fno-omit-frame-pointer") ||
!strcmp(argv[i], "-fno-stack-protector") ||
!strcmp(argv[i], "-fno-strict-aliasing") ||
!strcmp(argv[i], "-m64") ||
!strcmp(argv[i], "-mno-red-zone") ||
!strcmp(argv[i], "-w"))
продолжи;
// Проверка на неизвестную опцию
если (argv[i][0] == '-' && argv[i][1] != '\0')
error("unknown argument: %s", argv[i]);
// Добавление входного файла
массив_строк_добавить(&input_files, argv[i]);
}
// Добавляем отложенные include-пути в конец
для (цел i = 0; i < deferred_includes.len; i++)
массив_строк_добавить(&include_paths, deferred_includes.data[i]);
если (input_files.len == 0)
error("no input files");
// -E подразумевает, что входной файл - это C код
если (option_preprocess_only)
source_type_override = FILE_C;
}
// Открытие файла для записи
стат FILE *open_output_file(символ *path) {
если (!path || strcmp(path, "-") == 0)
возврат stdout;
FILE *out = fopen(path, "w");
если (!out)
error("cannot open output file: %s: %s", path, strerror(errno));
возврат out;
}
// Проверка, заканчивается ли строка указанным суффиксом
стат бул string_ends_with(символ *str, символ *suffix) {
цел str_len = strlen(str);
цел suffix_len = strlen(suffix);
возврат (str_len >= suffix_len) && !strcmp(str + str_len - suffix_len, suffix);
}
// Замена расширения файла
стат символ *change_extension(символ *template, символ *new_ext) {
символ *filename = basename(strdup(template));
символ *dot = strrchr(filename, '.');
если (dot)
*dot = '\0';
возврат формат("%s%s", filename, new_ext);
}
// Очистка временных файлов при выходе
стат пусто cleanup_temporary_files(пусто) {
для (цел i = 0; i < temporary_files.len; i++)
unlink(temporary_files.data[i]);
}
// Создание временного файла
стат символ *create_temporary_file(пусто) {
символ *path = strdup("/tmp/rusi-XXXXXX");
цел fd = mkstemp(path);
если (fd == -1)
error("mkstemp failed: %s", strerror(errno));
close(fd);
массив_строк_добавить(&temporary_files, path);
возврат path;
}
// Запуск подпроцесса
стат пусто execute_subprocess(символ **argv) {
// Если указана опция -###, выводим команду подпроцесса
если (option_verbose_commands) {
fprintf(stderr, "%s", argv[0]);
для (цел i = 1; argv[i]; i++)
fprintf(stderr, " %s", argv[i]);
fprintf(stderr, "\n");
}
если (fork() == 0) {
// Дочерний процесс: выполняем команду
execvp(argv[0], argv);
fprintf(stderr, "exec failed: %s: %s\n", argv[0], strerror(errno));
_exit(1);
}
// Родительский процесс: ждём завершения дочернего
цел status;
пока (wait(&status) > 0);
если (status != 0)
exit(1);
}
// Запуск компилятора в режиме cc1
стат пусто invoke_compiler_cc1(цел argc, символ **argv, символ *input, символ *output) {
символ **args = calloc(argc + 10, размер(символ *));
memcpy(args, argv, argc * размер(символ *));
args[argc++] = "-cc1";
если (input) {
args[argc++] = "-cc1-input";
args[argc++] = input;
}
если (output) {
args[argc++] = "-cc1-output";
args[argc++] = output;
}
execute_subprocess(args);
}
// Вывод токенов в stdout (для опции -E)
стат пусто output_preprocessed_tokens(Token *tok) {
FILE *out = open_output_file(option_output_file ? option_output_file : "-");
цел line_num = 1;
для (; tok->kind != TK_EOF; tok = tok->next) {
если (line_num > 1 && tok->at_bol)
fprintf(out, "\n");
если (tok->has_space && !tok->at_bol)
fprintf(out, " ");
fprintf(out, "%.*s", tok->len, tok->loc);
line_num++;
}
fprintf(out, "\n");
}
// Проверка, находится ли путь в стандартных include-путях
стат бул is_standard_include_path(символ *path) {
для (цел i = 0; i < standard_include_paths.len; i++) {
символ *dir = standard_include_paths.data[i];
цел dir_len = strlen(dir);
если (strncmp(dir, path, dir_len) == 0 && path[dir_len] == '/')
возврат истина;
}
возврат ложь;
}
// Вывод зависимостей файлов для make (опции -M, -MD)
стат пусто output_file_dependencies(пусто) {
символ *output_path;
если (option_depend_file)
output_path = option_depend_file;
иначе если (option_make_depend_with_compile)
output_path = change_extension(option_output_file ? option_output_file : base_file, ".d");
иначе если (option_output_file)
output_path = option_output_file;
иначе
output_path = "-";
FILE *out = open_output_file(output_path);
если (option_target_name)
fprintf(out, "%s:", option_target_name);
иначе
fprintf(out, "%s:", escape_for_makefile(change_extension(base_file, ".o")));
File **files = get_input_files();
для (цел i = 0; files[i]; i++) {
если (option_make_depend_only && is_standard_include_path(files[i]->name))
продолжи;
fprintf(out, " \\\n %s", files[i]->name);
}
fprintf(out, "\n\n");
// Создание фиктивных целей для каждой зависимости
если (option_phony_targets) {
для (цел i = 1; files[i]; i++) {
если (option_make_depend_only && is_standard_include_path(files[i]->name))
продолжи;
fprintf(out, "%s:\n\n", escape_for_makefile(files[i]->name));
}
}
}
// Токенизация файла с обработкой ошибок
стат Token *tokenize_input_file(символ *path) {
Token *tok = tokenize_file(path);
если (!tok)
error("%s: %s", path, strerror(errno));
возврат tok;
}
// Объединение двух списков токенов
стат Token *concatenate_token_lists(Token *list1, Token *list2) {
если (!list1 || list1->kind == TK_EOF)
возврат list2;
Token *current = list1;
пока (current->next->kind != TK_EOF)
current = current->next;
current->next = list2;
возврат list1;
}
// Основная функция компиляции (режим cc1)
стат пусто compile_cc1(пусто) {
Token *tokens = NULL;
// Обработка опции -include: принудительное включение файлов
для (цел i = 0; i < forced_includes.len; i++) {
символ *include_file = forced_includes.data[i];
символ *path;
если (file_exists(include_file)) {
path = include_file;
} иначе {
path = search_include_paths(include_file);
если (!path)
error("-include: %s: %s", include_file, strerror(errno));
}
Token *file_tokens = tokenize_input_file(path);
tokens = concatenate_token_lists(tokens, file_tokens);
}
// Токенизация и парсинг основного файла
Token *main_tokens = tokenize_input_file(base_file);
tokens = concatenate_token_lists(tokens, main_tokens);
tokens = preprocess(tokens);
// Если указаны опции -M или -MD, выводим зависимости
если (option_make_depend || option_make_depend_with_compile) {
output_file_dependencies();
если (option_make_depend) {
free_all_types();
free_all_tokens();
free_all_preprocess();
возврат;
}
}
// Если указана опция -E, выводим результат препроцессора
если (option_preprocess_only) {
output_preprocessed_tokens(tokens);
free_all_types();
free_all_tokens();
free_all_preprocess();
возврат;
}
// Парсинг в AST
Obj *program = parse(tokens);
// Открываем временный буфер для вывода
символ *buffer;
size_t buffer_size;
FILE *output_buffer = open_memstream(&buffer, &buffer_size);
// Обход AST и генерация ассемблера
codegen(program, output_buffer);
fclose(output_buffer);
// Запись ассемблера в файл
FILE *out = open_output_file(compiler_output_path);
fwrite(buffer, buffer_size, 1, out);
fclose(out);
free(buffer);
free_all_types();
free_all_tokens();
free_all_preprocess();
}
// Запуск ассемблера
стат пусто run_assembler(символ *input, символ *output) {
символ *cmd[] = {"as", "-c", input, "-o", output, NULL};
execute_subprocess(cmd);
}
// Поиск файла по шаблону (glob)
стат символ *find_matching_file(символ *pattern) {
символ *path = NULL;
glob_t buf = {};
glob(pattern, 0, NULL, &buf);
если (buf.gl_pathc > 0)
path = strdup(buf.gl_pathv[buf.gl_pathc - 1]);
globfree(&buf);
возврат path;
}
// Проверка существования файла
бул file_exists(символ *path) {
структ stat st;
возврат !stat(path, &st);
}
// Поиск пути к системным библиотекам
стат символ *locate_library_path(пусто) {
если (file_exists("/usr/lib/x86_64-linux-gnu/crti.o"))
возврат "/usr/lib/x86_64-linux-gnu";
если (file_exists("/usr/lib64/crti.o"))
возврат "/usr/lib64";
error("library path is not found");
}
// Поиск пути к библиотекам GCC
стат символ *locate_gcc_library_path(пусто) {
символ *search_patterns[] = {
"/usr/lib/gcc/x86_64-linux-gnu/*/crtbegin.o",
"/usr/lib/gcc/x86_64-pc-linux-gnu/*/crtbegin.o", // Для Gentoo
"/usr/lib/gcc/x86_64-redhat-linux/*/crtbegin.o", // Для Fedora
};
для (цел i = 0; i < размер(search_patterns) / размер(*search_patterns); i++) {
символ *path = find_matching_file(search_patterns[i]);
если (path)
возврат dirname(path);
}
error("gcc library path is not found");
}
// Запуск линкера
стат пусто invoke_linker(МассивСтрок *inputs, символ *output) { // было StringArray
МассивСтрок args = {}; // было StringArray
массив_строк_добавить(&args, "ld");
массив_строк_добавить(&args, "-o");
массив_строк_добавить(&args, output);
массив_строк_добавить(&args, "-m");
массив_строк_добавить(&args, "elf_x86_64");
символ *lib_path = locate_library_path();
символ *gcc_lib_path = locate_gcc_library_path();
// Добавляем стартовые объекты в зависимости от типа линковки
если (option_shared_lib) {
массив_строк_добавить(&args, формат("%s/crti.o", lib_path));
массив_строк_добавить(&args, формат("%s/crtbeginS.o", gcc_lib_path));
} иначе {
массив_строк_добавить(&args, формат("%s/crt1.o", lib_path));
массив_строк_добавить(&args, формат("%s/crti.o", lib_path));
массив_строк_добавить(&args, формат("%s/crtbegin.o", gcc_lib_path));
}
// Добавляем пути поиска библиотек
массив_строк_добавить(&args, формат("-L%s", gcc_lib_path));
массив_строк_добавить(&args, "-L/usr/lib/x86_64-linux-gnu");
массив_строк_добавить(&args, "-L/usr/lib64");
массив_строк_добавить(&args, "-L/lib64");
массив_строк_добавить(&args, "-L/usr/lib/x86_64-linux-gnu");
массив_строк_добавить(&args, "-L/usr/lib/x86_64-pc-linux-gnu");
массив_строк_добавить(&args, "-L/usr/lib/x86_64-redhat-linux");
массив_строк_добавить(&args, "-L/usr/lib");
массив_строк_добавить(&args, "-L/lib");
// Добавляем динамический линкер для не-статической линковки
если (!option_static_link) {
массив_строк_добавить(&args, "-dynamic-linker");
массив_строк_добавить(&args, "/lib64/ld-linux-x86-64.so.2");
}
// Добавляем дополнительные аргументы линкера
для (цел i = 0; i < linker_extra_args.len; i++)
массив_строк_добавить(&args, linker_extra_args.data[i]);
// Добавляем входные файлы
для (цел i = 0; i < inputs->len; i++)
массив_строк_добавить(&args, inputs->data[i]);
// Добавляем стандартные библиотеки
если (option_static_link) {
массив_строк_добавить(&args, "--start-group");
массив_строк_добавить(&args, "-lgcc");
массив_строк_добавить(&args, "-lgcc_eh");
массив_строк_добавить(&args, "-lc");
массив_строк_добавить(&args, "--end-group");
} иначе {
массив_строк_добавить(&args, "-lc");
массив_строк_добавить(&args, "-lgcc");
массив_строк_добавить(&args, "--as-needed");
массив_строк_добавить(&args, "-lgcc_s");
массив_строк_добавить(&args, "--no-as-needed");
}
// Добавляем конечные объекты
если (option_shared_lib)
массив_строк_добавить(&args, формат("%s/crtendS.o", gcc_lib_path));
иначе
массив_строк_добавить(&args, формат("%s/crtend.o", gcc_lib_path));
массив_строк_добавить(&args, формат("%s/crtn.o", lib_path));
массив_строк_добавить(&args, NULL);
execute_subprocess(args.data);
}
// Определение типа файла по расширению
стат FileType determine_file_type(символ *filename) {
если (source_type_override != FILE_NONE)
возврат source_type_override;
если (string_ends_with(filename, ".a"))
возврат FILE_AR;
если (string_ends_with(filename, ".so"))
возврат FILE_DSO;
если (string_ends_with(filename, ".o"))
возврат FILE_OBJ;
если (string_ends_with(filename, ".c") || string_ends_with(filename, ".рс") || string_ends_with(filename, ".си"))
возврат FILE_C;
если (string_ends_with(filename, ".s"))
возврат FILE_ASM;
error("<command line>: unknown file extension: %s", filename);
}
// Главная функция программы
цел главн(цел argc, символ **argv) {
// Регистрируем функцию очистки временных файлов
atexit(cleanup_temporary_files);
init_macros();
parse_command_line(argc, argv);
// Режим прямого вызова компилятора (cc1)
если (option_cc1_mode) {
setup_default_include_paths(argv[0]);
compile_cc1();
free_all_types();
free_all_tokens();
free_all_preprocess();
возврат 0;
}
// Проверка несовместимых опций
если (input_files.len > 1 && option_output_file && (option_compile_only || option_assembly_only || option_preprocess_only))
error("cannot specify '-o' with '-c,' '-S' or '-E' with multiple files");
МассивСтрок linker_args = {}; // было StringArray
// Обработка всех входных файлов
для (цел i = 0; i < input_files.len; i++) {
символ *input = input_files.data[i];
// Обработка опций -l (библиотеки)
если (!strncmp(input, "-l", 2)) {
массив_строк_добавить(&linker_args, input);
продолжи;
}
// Обработка опций -Wl, (передача линкеру)
если (!strncmp(input, "-Wl,", 4)) {
символ *s = strdup(input + 4);
символ *arg = strtok(s, ",");
пока (arg) {
массив_строк_добавить(&linker_args, arg);
arg = strtok(NULL, ",");
}
продолжи;
}
// Определение выходного файла
символ *output;
если (option_output_file)
output = option_output_file;
иначе если (option_assembly_only)
output = change_extension(input, ".s");
иначе
output = change_extension(input, ".o");
FileType file_type = determine_file_type(input);
// Обработка объектных файлов и архивов
если (file_type == FILE_OBJ || file_type == FILE_AR || file_type == FILE_DSO) {
массив_строк_добавить(&linker_args, input);
продолжи;
}
// Обработка ассемблерных файлов
если (file_type == FILE_ASM) {
если (!option_assembly_only)
run_assembler(input, output);
продолжи;
}
// Дальше предполагаем, что это C файл
assert(file_type == FILE_C);
// Только препроцессор
если (option_preprocess_only || option_make_depend) {
invoke_compiler_cc1(argc, argv, input, NULL);
продолжи;
}
// Только компиляция в ассемблер
если (option_assembly_only) {
invoke_compiler_cc1(argc, argv, input, output);
продолжи;
}
// Компиляция и ассемблирование
если (option_compile_only) {
символ *temp = create_temporary_file();
invoke_compiler_cc1(argc, argv, input, temp);
run_assembler(temp, output);
продолжи;
}
// Полный цикл: компиляция, ассемблирование и линковка
символ *temp_asm = create_temporary_file();
символ *temp_obj = create_temporary_file();
invoke_compiler_cc1(argc, argv, input, temp_asm);
run_assembler(temp_asm, temp_obj);
массив_строк_добавить(&linker_args, temp_obj);
продолжи;
}
// Запуск линкера, если есть что линковать
если (linker_args.len > 0)
invoke_linker(&linker_args, option_output_file ? option_output_file : "a.out");
возврат 0;
}

BIN
md2.o Normal file

Binary file not shown.

2096
parse.c Normal file

File diff suppressed because it is too large Load diff

1037
preprocess.c Normal file

File diff suppressed because it is too large Load diff

BIN
rusi.elf Executable file

Binary file not shown.

BIN
stage2/rusi.elf Executable file

Binary file not shown.

253
strings.c Normal file
View file

@ -0,0 +1,253 @@
// ============================================================
// Управление динамическим массивом строк
// ============================================================
#включить "руси.з"
#включить <stdio.h> // стандартная библиотека
#включить <stdlib.h> // стандартная библиотека
#включить <stdarg.h> // стандартная библиотека
#включить <string.h> // стандартная библиотека
// ============================================================
// Управление динамическим массивом строк
// ============================================================
пусто массив_строк_добавить(МассивСтрок *массив, символ *строка) {
если (!массив) возврат;
// Инициализация массива при первом использовании
если (!массив->data) {
массив->data = (символ **)calloc(8, размер(символ *));
если (!массив->data) {
// Ошибка выделения памяти - выходим
возврат;
}
массив->capacity = 8;
массив->len = 0;
}
// Расширение массива при необходимости
если (массив->capacity == массив->len) {
size_t новая_ёмкость = массив->capacity * 2;
символ **новыеанные = (символ **)realloc(массив->data, размер(символ *) * новая_ёмкость);
если (!новыеанные) {
// Ошибка перевыделения памяти
возврат;
}
массив->data = новыеанные;
массив->capacity = новая_ёмкость;
// Инициализация новых элементов нулями
для (size_t ш = массив->len; ш < массив->capacity; ш++) {
массив->data[ш] = NULL;
}
}
// Добавление строки
массив->data[массив->len++] = строка;
}
// ============================================================
// Форматирование строки в стиле printf
// ============================================================
символ *формат(символ *строкаормата, ...) {
если (!строкаормата) возврат NULL;
символ *буфер = NULL;
size_t разм_буфера = 0;
// Открываем поток в память
FILE *поток = open_memstream(&буфер, &разм_буфера);
если (!поток) {
возврат NULL;
}
// Форматируем вывод
va_list арг;
va_start(арг, строкаормата);
цел рез = vfprintf(поток, строкаормата, арг);
va_end(арг);
// Закрываем поток (это освобождает внутренние ресурсы)
fclose(поток);
// Проверяем успешность записи
если (рез < 0) {
free(буфер);
возврат NULL;
}
возврат буфер;
}
// ============================================================
// Дополнительные полезные функции для работы со строками
// ============================================================
// Создает копию строки с выделением памяти
символ *строкаублировать(конст символ *исходная) {
если (!исходная) возврат NULL;
size_t длина = strlen(исходная) + 1;
символ *копия = (символ *)malloc(длина);
если (!копия) возврат NULL;
memcpy(копия, исходная, длина);
возврат копия;
}
// Объединяет две строки в новую
символ *строка_склеить(конст символ *первая, конст символ *вторая) {
если (!первая) возврат строкаублировать(вторая);
если (!вторая) возврат строкаублировать(первая);
size_t дл1 = strlen(первая);
size_t дл2 = strlen(вторая);
символ *рез = (символ *)malloc(дл1 + дл2 + 1);
если (!рез) возврат NULL;
memcpy(рез, первая, дл1);
memcpy(рез + дл1, вторая, дл2 + 1);
возврат рез;
}
// Объединяет три строки в новую
символ *строка_склеить3(конст символ *первая, конст символ *вторая, конст символ *третья) {
если (!первая && !вторая && !третья) возврат NULL;
если (!первая) возврат строка_склеить(вторая, третья);
если (!вторая) возврат строка_склеить(первая, третья);
если (!третья) возврат строка_склеить(первая, вторая);
size_t дл1 = strlen(первая);
size_t дл2 = strlen(вторая);
size_t дл3 = strlen(третья);
символ *рез = (символ *)malloc(дл1 + дл2 + дл3 + 1);
если (!рез) возврат NULL;
memcpy(рез, первая, дл1);
memcpy(рез + дл1, вторая, дл2);
memcpy(рез + дл1 + дл2, третья, дл3 + 1);
возврат рез;
}
// Освобождает массив строк
пусто массив_строк_освободить(МассивСтрок *массив) {
если (!массив) возврат;
если (массив->data) {
// Освобождаем каждую строку
для (size_t ш = 0; ш < массив->len; ш++) {
если (массив->data[ш]) {
free(массив->data[ш]);
массив->data[ш] = NULL;
}
}
// Освобождаем массив указателей
free(массив->data);
массив->data = NULL;
}
массив->len = 0;
массив->capacity = 0;
}
// Очищает массив строк без освобождения памяти под него
пусто массив_строк_очистить(МассивСтрок *массив) {
если (!массив || !массив->data) возврат;
// Освобождаем только строки, но не массив указателей
для (size_t ш = 0; ш < массив->len; ш++) {
если (массив->data[ш]) {
free(массив->data[ш]);
массив->data[ш] = NULL;
}
}
массив->len = 0;
}
// Получает строку по индексу с проверкой границ
символ *массив_строк_получить(конст МассивСтрок *массив, size_t инд) {
если (!массив || !массив->data || инд >= массив->len) {
возврат NULL;
}
возврат массив->data[инд];
}
// Устанавливает строку по индексу с проверкой границ
бул массив_строк_установить(МассивСтрок *массив, size_t инд, символ *строка) {
если (!массив || !массив->data || инд >= массив->len) {
возврат ложь;
}
// Освобождаем старую строку
если (массив->data[инд]) {
free(массив->data[инд]);
}
массив->data[инд] = строка;
возврат истина;
}
// Вставляет строку в указанную позицию
бул массив_строк_вставить(МассивСтрок *массив, size_t поз, символ *строка) {
если (!массив || !строка) возврат ложь;
если (поз > массив->len) возврат ложь;
// Добавляем в конец
если (поз == массив->len) {
массив_строк_добавить(массив, строка);
возврат истина;
}
// Вставляем в середину - сначала добавляем элемент в конец
массив_строк_добавить(массив, NULL);
если (!массив->data) возврат ложь;
// Сдвигаем элементы вправо
для (size_t ш = массив->len - 1; ш > поз; ш--) {
массив->data[ш] = массив->data[ш - 1];
}
массив->data[поз] = строка;
возврат истина;
}
// Удаляет строку по индексу
бул массив_строк_удалить(МассивСтрок *массив, size_t инд) {
если (!массив || !массив->data || инд >= массив->len) {
возврат ложь;
}
// Освобождаем удаляемую строку
если (массив->data[инд]) {
free(массив->data[инд]);
}
// Сдвигаем элементы влево
для (size_t ш = инд; ш < массив->len - 1; ш++) {
массив->data[ш] = массив->data[ш + 1];
}
массив->len--;
массив->data[массив->len] = NULL;
возврат истина;
}
// Ищет строку в массиве
ssize_t массив_строк_найти(конст МассивСтрок *массив, конст символ *строка) {
если (!массив || !массив->data || !строка) возврат -1;
для (size_t ш = 0; ш < массив->len; ш++) {
если (массив->data[ш] && strcmp(массив->data[ш], строка) == 0) {
возврат (ssize_t)ш;
}
}
возврат -1;
}
// Проверяет, содержит ли массив строку
бул массив_строк_содержит(конст МассивСтрок *массив, конст символ *строка) {
возврат массив_строк_найти(массив, строка) >= 0;
}

50
test/alignof.c Normal file
View file

@ -0,0 +1,50 @@
#включить "тест.з"
#включить "stdvv.c"
цел _Выравнивание(512) г1;
цел _Выравнивание(512) г2;
символ г3;
цел г4;
длин г5;
символ г6;
цел главн() {
ПРОВЕРИТЬ(1, _Выравнивание_типа(символ));
ПРОВЕРИТЬ(2, _Выравнивание_типа(short));
ПРОВЕРИТЬ(4, _Выравнивание_типа(цел));
ПРОВЕРИТЬ(8, _Выравнивание_типа(длин));
ПРОВЕРИТЬ(8, _Выравнивание_типа(длин длин));
ПРОВЕРИТЬ(1, _Выравнивание_типа(символ[3]));
ПРОВЕРИТЬ(4, _Выравнивание_типа(цел[3]));
ПРОВЕРИТЬ(1, _Выравнивание_типа(структ {символ а; символ б;}[2]));
ПРОВЕРИТЬ(8, _Выравнивание_типа(структ {символ а; длин б;}[2]));
ПРОВЕРИТЬ(1, ({ _Выравнивание(символ) символ х, у; &у-&х; }));
ПРОВЕРИТЬ(8, ({ _Выравнивание(длин) символ х, у; &у-&х; }));
ПРОВЕРИТЬ(32, ({ _Выравнивание(32) символ х, у; &у-&х; }));
ПРОВЕРИТЬ(32, ({ _Выравнивание(32) цел *х, *у; ((символ *)&у)-((символ *)&х); }));
ПРОВЕРИТЬ(16, ({ структ { _Выравнивание(16) символ х, у; } а; &а.у-&а.х; }));
ПРОВЕРИТЬ(8, ({ структ T { _Выравнивание(8) символ а; }; _Выравнивание_типа(структ T); }));
ПРОВЕРИТЬ(0, (длин)(символ *)&г1 % 512);
ПРОВЕРИТЬ(0, (длин)(символ *)&г2 % 512);
ПРОВЕРИТЬ(0, (длин)(символ *)&г4 % 4);
ПРОВЕРИТЬ(0, (длин)(символ *)&г5 % 8);
ПРОВЕРИТЬ(1, ({ символ х; _Выравнивание_типа(х); }));
ПРОВЕРИТЬ(4, ({ цел х; _Выравнивание_типа(х); }));
ПРОВЕРИТЬ(1, ({ символ х; _Выравнивание_типа х; }));
ПРОВЕРИТЬ(4, ({ цел х; _Выравнивание_типа х; }));
ПРОВЕРИТЬ(1, _Выравнивание_типа(символ) << 31 >> 31);
ПРОВЕРИТЬ(1, _Выравнивание_типа(символ) << 63 >> 63);
ПРОВЕРИТЬ(1, ({ символ х; _Выравнивание_типа(х) << 63 >> 63; }));
ПРОВЕРИТЬ(0, ({ символ х[16]; (беззнак длин)&х % 16; }));
ПРОВЕРИТЬ(0, ({ символ х[17]; (беззнак длин)&х % 16; }));
ПРОВЕРИТЬ(0, ({ символ х[100]; (беззнак длин)&х % 16; }));
ПРОВЕРИТЬ(0, ({ символ х[101]; (беззнак длин)&х % 16; }));
печатьф("OK\n");
возврат 0;
}

29
test/alloca.c Normal file
View file

@ -0,0 +1,29 @@
#включить "тест.з"
#включить "stdvv.c"
пусто *функция(цел x, пусто *p, цел y) { возврат p; }
цел главн() {
цел i = 0;
символ *p1 = alloca(16);
символ *p2 = alloca(16);
символ *p3 = 1 + (символ *)alloca(3) + 1;
p3 -= 2;
символ *p4 = функция(1, alloca(16), 3);
ПРОВЕРИТЬ(16, p1 - p2);
ПРОВЕРИТЬ(16, p2 - p3);
ПРОВЕРИТЬ(16, p3 - p4);
memcpy(p1, "0123456789abcdef", 16);
memcpy(p2, "ghijklmnopqrstuv", 16);
memcpy(p3, "wxy", 3);
ПРОВЕРИТЬ(0, memcmp(p1, "0123456789abcdef", 16));
ПРОВЕРИТЬ(0, memcmp(p2, "ghijklmnopqrstuv", 16));
ПРОВЕРИТЬ(0, memcmp(p3, "wxy", 3));
печатьф("OK\n");
возврат 0;
}

145
test/arith.c Normal file
View file

@ -0,0 +1,145 @@
#включить "тест.з"
#включить "stdvv.c"
цел главн() {
ПРОВЕРИТЬ(0, 0);
ПРОВЕРИТЬ(42, 42);
ПРОВЕРИТЬ(21, 5+20-4);
ПРОВЕРИТЬ(41, 12 + 34 - 5 );
ПРОВЕРИТЬ(47, 5+6*7);
ПРОВЕРИТЬ(15, 5*(9-6));
ПРОВЕРИТЬ(4, (3+5)/2);
ПРОВЕРИТЬ(10, -10+20);
ПРОВЕРИТЬ(10, - -10);
ПРОВЕРИТЬ(10, - - +10);
ПРОВЕРИТЬ(0, 0==1);
ПРОВЕРИТЬ(1, 42==42);
ПРОВЕРИТЬ(1, 0!=1);
ПРОВЕРИТЬ(0, 42!=42);
ПРОВЕРИТЬ(1, 0<1);
ПРОВЕРИТЬ(0, 1<1);
ПРОВЕРИТЬ(0, 2<1);
ПРОВЕРИТЬ(1, 0<=1);
ПРОВЕРИТЬ(1, 1<=1);
ПРОВЕРИТЬ(0, 2<=1);
ПРОВЕРИТЬ(1, 1>0);
ПРОВЕРИТЬ(0, 1>1);
ПРОВЕРИТЬ(0, 1>2);
ПРОВЕРИТЬ(1, 1>=0);
ПРОВЕРИТЬ(1, 1>=1);
ПРОВЕРИТЬ(0, 1>=2);
ПРОВЕРИТЬ(0, 1073741824 * 100 / 100);
ПРОВЕРИТЬ(7, ({ цел и=2; и+=5; и; }));
ПРОВЕРИТЬ(7, ({ цел и=2; и+=5; }));
ПРОВЕРИТЬ(3, ({ цел и=5; и-=2; и; }));
ПРОВЕРИТЬ(3, ({ цел и=5; и-=2; }));
ПРОВЕРИТЬ(6, ({ цел и=3; и*=2; и; }));
ПРОВЕРИТЬ(6, ({ цел и=3; и*=2; }));
ПРОВЕРИТЬ(3, ({ цел и=6; и/=2; и; }));
ПРОВЕРИТЬ(3, ({ цел и=6; и/=2; }));
ПРОВЕРИТЬ(3, ({ цел и=2; ++и; }));
ПРОВЕРИТЬ(2, ({ цел а[3]; а[0]=0; а[1]=1; а[2]=2; цел *п=а+1; ++*п; }));
ПРОВЕРИТЬ(0, ({ цел а[3]; а[0]=0; а[1]=1; а[2]=2; цел *п=а+1; --*п; }));
ПРОВЕРИТЬ(2, ({ цел и=2; и++; }));
ПРОВЕРИТЬ(2, ({ цел и=2; и--; }));
ПРОВЕРИТЬ(3, ({ цел и=2; и++; и; }));
ПРОВЕРИТЬ(1, ({ цел и=2; и--; и; }));
ПРОВЕРИТЬ(1, ({ цел а[3]; а[0]=0; а[1]=1; а[2]=2; цел *п=а+1; *п++; }));
ПРОВЕРИТЬ(1, ({ цел а[3]; а[0]=0; а[1]=1; а[2]=2; цел *п=а+1; *п--; }));
ПРОВЕРИТЬ(0, ({ цел а[3]; а[0]=0; а[1]=1; а[2]=2; цел *п=а+1; (*п++)--; а[0]; }));
ПРОВЕРИТЬ(0, ({ цел а[3]; а[0]=0; а[1]=1; а[2]=2; цел *п=а+1; (*(п--))--; а[1]; }));
ПРОВЕРИТЬ(2, ({ цел а[3]; а[0]=0; а[1]=1; а[2]=2; цел *п=а+1; (*п)--; а[2]; }));
ПРОВЕРИТЬ(2, ({ цел а[3]; а[0]=0; а[1]=1; а[2]=2; цел *п=а+1; (*п)--; п++; *п; }));
ПРОВЕРИТЬ(0, ({ цел а[3]; а[0]=0; а[1]=1; а[2]=2; цел *п=а+1; (*п++)--; а[0]; }));
ПРОВЕРИТЬ(0, ({ цел а[3]; а[0]=0; а[1]=1; а[2]=2; цел *п=а+1; (*п++)--; а[1]; }));
ПРОВЕРИТЬ(2, ({ цел а[3]; а[0]=0; а[1]=1; а[2]=2; цел *п=а+1; (*п++)--; а[2]; }));
ПРОВЕРИТЬ(2, ({ цел а[3]; а[0]=0; а[1]=1; а[2]=2; цел *п=а+1; (*п++)--; *п; }));
ПРОВЕРИТЬ(0, !1);
ПРОВЕРИТЬ(0, !2);
ПРОВЕРИТЬ(1, !0);
ПРОВЕРИТЬ(1, !(символ)0);
ПРОВЕРИТЬ(0, !(длин)3);
ПРОВЕРИТЬ(4, размер(!(символ)0));
ПРОВЕРИТЬ(4, размер(!(длин)0));
ПРОВЕРИТЬ(-1, ~0);
ПРОВЕРИТЬ(0, ~-1);
ПРОВЕРИТЬ(5, 17%6);
ПРОВЕРИТЬ(5, ((длин)17)%6);
ПРОВЕРИТЬ(2, ({ цел и=10; и%=4; и; }));
ПРОВЕРИТЬ(2, ({ длин и=10; и%=4; и; }));
ПРОВЕРИТЬ(0, 0&1);
ПРОВЕРИТЬ(1, 3&1);
ПРОВЕРИТЬ(3, 7&3);
ПРОВЕРИТЬ(10, -1&10);
ПРОВЕРИТЬ(1, 0|1);
ПРОВЕРИТЬ(0b10011, 0b10000|0b00011);
ПРОВЕРИТЬ(0, 0^0);
ПРОВЕРИТЬ(0, 0b1111^0b1111);
ПРОВЕРИТЬ(0b110100, 0b111000^0b001100);
ПРОВЕРИТЬ(2, ({ цел и=6; и&=3; и; }));
ПРОВЕРИТЬ(7, ({ цел и=6; и|=3; и; }));
ПРОВЕРИТЬ(10, ({ цел и=15; и^=5; и; }));
ПРОВЕРИТЬ(1, 1<<0);
ПРОВЕРИТЬ(8, 1<<3);
ПРОВЕРИТЬ(10, 5<<1);
ПРОВЕРИТЬ(2, 5>>1);
ПРОВЕРИТЬ(-1, -1>>1);
ПРОВЕРИТЬ(1, ({ цел и=1; и<<=0; и; }));
ПРОВЕРИТЬ(8, ({ цел и=1; и<<=3; и; }));
ПРОВЕРИТЬ(10, ({ цел и=5; и<<=1; и; }));
ПРОВЕРИТЬ(2, ({ цел и=5; и>>=1; и; }));
ПРОВЕРИТЬ(-1, -1);
ПРОВЕРИТЬ(-1, ({ цел и=-1; и; }));
ПРОВЕРИТЬ(-1, ({ цел и=-1; и>>=1; и; }));
ПРОВЕРИТЬ(2, 0?1:2);
ПРОВЕРИТЬ(1, 1?1:2);
ПРОВЕРИТЬ(-1, 0?-2:-1);
ПРОВЕРИТЬ(-2, 1?-2:-1);
ПРОВЕРИТЬ(4, размер(0?1:2));
ПРОВЕРИТЬ(8, размер(0?(длин)1:(длин)2));
ПРОВЕРИТЬ(-1, 0?(длин)-2:-1);
ПРОВЕРИТЬ(-1, 0?-2:(длин)-1);
ПРОВЕРИТЬ(-2, 1?(длин)-2:-1);
ПРОВЕРИТЬ(-2, 1?-2:(длин)-1);
1 ? -2 : (пусто)-1;
ПРОВЕРИТЬ(20, ({ цел х; цел *п=&х; п+20-п; }));
ПРОВЕРИТЬ(1, ({ цел х; цел *п=&х; п+20-п>0; }));
ПРОВЕРИТЬ(-20, ({ цел х; цел *п=&х; п-20-п; }));
ПРОВЕРИТЬ(1, ({ цел х; цел *п=&х; п-20-п<0; }));
ПРОВЕРИТЬ(15, (символ *)0xffffffffffffffff - (символ *)0xfffffffffffffff0);
ПРОВЕРИТЬ(-15, (символ *)0xfffffffffffffff0 - (символ *)0xffffffffffffffff);
ПРОВЕРИТЬ(1, (пусто *)0xffffffffffffffff > (пусто *)0);
ПРОВЕРИТЬ(3, 3?:5);
ПРОВЕРИТЬ(5, 0?:5);
ПРОВЕРИТЬ(4, ({ цел и = 3; ++и?:10; }));
ПРОВЕРИТЬ(3, (длин двойн)3);
ПРОВЕРИТЬ(5, (длин двойн)3+2);
ПРОВЕРИТЬ(6, (длин двойн)3*2);
ПРОВЕРИТЬ(5, (длин двойн)3+2.0);
printf("OK\n");
возврат 0;
}

24
test/asm.c Normal file
View file

@ -0,0 +1,24 @@
#включить "тест.з"
#включить "stdvv.c"
символ *асмункция1(пусто) {
асм("mov $50, %rax\n\t"
"mov %rbp, %rsp\n\t"
"pop %rbp\n\t"
"ret");
}
символ *асмункция2(пусто) {
асм inline volatile("mov $55, %rax\n\t"
"mov %rbp, %rsp\n\t"
"pop %rbp\n\t"
"ret");
}
цел главн() {
ПРОВЕРИТЬ(50, асмункция1());
ПРОВЕРИТЬ(55, асмункция2());
printf("OK\n");
возврат 0;
}

64
test/atomic.c Normal file
View file

@ -0,0 +1,64 @@
#включить "тест.з"
#включить "stdvv.c"
#include <rstdlib.h>
#include <pthread.h>
static int incr(_Atomic int *p) {
int oldval = *p;
int newval;
do {
newval = oldval + 1;
} while (!atomic_compare_exchange_weak(p, &oldval, newval));
return newval;
}
static int add1(void *arg) {
_Atomic int *x = arg;
for (int i = 0; i < 1000*1000; i++)
incr(x);
return 0;
}
static int add2(void *arg) {
_Atomic int *x = arg;
for (int i = 0; i < 1000*1000; i++)
(*x)++;
return 0;
}
static int add3(void *arg) {
_Atomic int *x = arg;
for (int i = 0; i < 1000*1000; i++)
*x += 5;
return 0;
}
static int add_millions(void) {
_Atomic int x = 0;
pthread_t thr1;
pthread_t thr2;
pthread_t thr3;
pthread_create(&thr1, NULL, add1, &x);
pthread_create(&thr2, NULL, add2, &x);
pthread_create(&thr3, NULL, add3, &x);
for (int i = 0; i < 1000*1000; i++)
x--;
pthread_join(thr1, NULL);
pthread_join(thr2, NULL);
pthread_join(thr3, NULL);
return x;
}
int main() {
ASSERT(6*1000*1000, add_millions());
ASSERT(3, ({ int x=3; atomic_exchange(&x, 5); }));
ASSERT(5, ({ int x=3; atomic_exchange(&x, 5); x; }));
printf("OK\n");
return 0;
}

40
test/attribute.c Normal file
View file

@ -0,0 +1,40 @@
#включить "тест.з"
#включить "stdvv.c"
#включить "rstdlib.h"
цел главн() {
ПРОВЕРИТЬ(5, ({ структ { символ a; цел b; } __attribute__((packed)) x; размер(x); }));
ПРОВЕРИТЬ(0, offsetof(структ __attribute__((packed)) { символ a; цел b; }, a));
ПРОВЕРИТЬ(1, offsetof(структ __attribute__((packed)) { символ a; цел b; }, b));
ПРОВЕРИТЬ(5, ({ структ __attribute__((packed)) { символ a; цел b; } x; размер(x); }));
ПРОВЕРИТЬ(0, offsetof(структ { символ a; цел b; } __attribute__((packed)), a));
ПРОВЕРИТЬ(1, offsetof(структ { символ a; цел b; } __attribute__((packed)), b));
ПРОВЕРИТЬ(9, ({ типдеф структ { символ a; цел b[2]; } __attribute__((packed)) T; размер(T); }));
ПРОВЕРИТЬ(9, ({ типдеф структ __attribute__((packed)) { символ a; цел b[2]; } T; размер(T); }));
ПРОВЕРИТЬ(1, offsetof(структ __attribute__((packed)) T { символ a; цел b[2]; }, b));
ПРОВЕРИТЬ(1, _Выравнивание_типа(структ __attribute__((packed)) { символ a; цел b[2]; }));
ПРОВЕРИТЬ(8, ({ структ __attribute__((aligned(8))) { цел a; } x; _Выравнивание_типа(x); }));
ПРОВЕРИТЬ(8, ({ структ { цел a; } __attribute__((aligned(8))) x; _Выравнивание_типа(x); }));
ПРОВЕРИТЬ(8, ({ структ __attribute__((aligned(8), packed)) { символ a; цел b; } x; _Выравнивание_типа(x); }));
ПРОВЕРИТЬ(8, ({ структ { символ a; цел b; } __attribute__((aligned(8), packed)) x; _Выравнивание_типа(x); }));
ПРОВЕРИТЬ(1, offsetof(структ __attribute__((aligned(8), packed)) { символ a; цел b; }, b));
ПРОВЕРИТЬ(1, offsetof(структ { символ a; цел b; } __attribute__((aligned(8), packed)), b));
ПРОВЕРИТЬ(8, ({ структ __attribute__((aligned(8))) __attribute__((packed)) { символ a; цел b; } x; _Выравнивание_типа(x); }));
ПРОВЕРИТЬ(8, ({ структ { символ a; цел b; } __attribute__((aligned(8))) __attribute__((packed)) x; _Выравнивание_типа(x); }));
ПРОВЕРИТЬ(1, offsetof(структ __attribute__((aligned(8))) __attribute__((packed)) { символ a; цел b; }, b));
ПРОВЕРИТЬ(1, offsetof(структ { символ a; цел b; } __attribute__((aligned(8))) __attribute__((packed)), b));
ПРОВЕРИТЬ(8, ({ структ __attribute__((aligned(8))) { символ a; цел b; } __attribute__((packed)) x; _Выравнивание_типа(x); }));
ПРОВЕРИТЬ(1, offsetof(структ __attribute__((aligned(8))) { символ a; цел b; } __attribute__((packed)), b));
ПРОВЕРИТЬ(16, ({ структ __attribute__((aligned(8+8))) { символ a; цел b; } x; _Выравнивание_типа(x); }));
printf("OK\n");
возврат 0;
}

58
test/bitfield.c Normal file
View file

@ -0,0 +1,58 @@
#включить "тест.з"
#включить "stdvv.c"
структ {
символ а;
цел б : 5;
цел в : 10;
} г45 = {1, 2, 3}, г46={};
цел главн() {
ПРОВЕРИТЬ(4, размер(структ {цел х:1; }));
ПРОВЕРИТЬ(8, размер(структ {длин х:1; }));
структ бит1 {
корот а;
символ б;
цел в : 2;
цел г : 3;
цел д : 3;
};
ПРОВЕРИТЬ(4, размер(структ бит1));
ПРОВЕРИТЬ(1, ({ структ бит1 х; х.а=1; х.б=2; х.в=3; х.г=4; х.д=5; х.а; }));
ПРОВЕРИТЬ(1, ({ структ бит1 х={1,2,3,4,5}; х.а; }));
ПРОВЕРИТЬ(2, ({ структ бит1 х={1,2,3,4,5}; х.б; }));
ПРОВЕРИТЬ(-1, ({ структ бит1 х={1,2,3,4,5}; х.в; }));
ПРОВЕРИТЬ(-4, ({ структ бит1 х={1,2,3,4,5}; х.г; }));
ПРОВЕРИТЬ(-3, ({ структ бит1 х={1,2,3,4,5}; х.д; }));
ПРОВЕРИТЬ(1, г45.а);
ПРОВЕРИТЬ(2, г45.б);
ПРОВЕРИТЬ(3, г45.в);
ПРОВЕРИТЬ(0, г46.а);
ПРОВЕРИТЬ(0, г46.б);
ПРОВЕРИТЬ(0, г46.в);
типдеф структ {
цел а : 10;
цел б : 10;
цел в : 10;
} Т3;
ПРОВЕРИТЬ(1, ({ Т3 х={1,2,3}; х.а++; }));
ПРОВЕРИТЬ(2, ({ Т3 х={1,2,3}; х.б++; }));
ПРОВЕРИТЬ(3, ({ Т3 х={1,2,3}; х.в++; }));
ПРОВЕРИТЬ(2, ({ Т3 х={1,2,3}; ++х.а; }));
ПРОВЕРИТЬ(3, ({ Т3 х={1,2,3}; ++х.б; }));
ПРОВЕРИТЬ(4, ({ Т3 х={1,2,3}; ++х.в; }));
ПРОВЕРИТЬ(4, размер(структ {цел а:3; цел в:1; цел в:5;}));
ПРОВЕРИТЬ(8, размер(структ {цел а:3; цел:0; цел в:5;}));
ПРОВЕРИТЬ(4, размер(структ {цел а:3; цел:0;}));
printf("OK\n");
возврат 0;
}

34
test/builtin.c Normal file
View file

@ -0,0 +1,34 @@
#включить "тест.з"
#включить "stdvv.c"
цел главн() {
ПРОВЕРИТЬ(1, __builtin_types_compatible_p(цел, цел));
ПРОВЕРИТЬ(1, __builtin_types_compatible_p(двойн, двойн));
ПРОВЕРИТЬ(0, __builtin_types_compatible_p(цел, длин));
ПРОВЕРИТЬ(0, __builtin_types_compatible_p(длин, плав));
ПРОВЕРИТЬ(1, __builtin_types_compatible_p(цел *, цел *));
ПРОВЕРИТЬ(0, __builtin_types_compatible_p(корот *, цел *));
ПРОВЕРИТЬ(0, __builtin_types_compatible_p(цел **, цел *));
ПРОВЕРИТЬ(1, __builtin_types_compatible_p(конст цел, цел));
ПРОВЕРИТЬ(0, __builtin_types_compatible_p(беззнак, цел));
ПРОВЕРИТЬ(1, __builtin_types_compatible_p(знак, цел));
ПРОВЕРИТЬ(0, __builtin_types_compatible_p(структ {цел а;}, структ {цел а;}));
ПРОВЕРИТЬ(1, __builtin_types_compatible_p(цел (*)(пусто), цел (*)(пусто)));
ПРОВЕРИТЬ(1, __builtin_types_compatible_p(пусто (*)(цел), пусто (*)(цел)));
ПРОВЕРИТЬ(1, __builtin_types_compatible_p(пусто (*)(цел, двойн), пусто (*)(цел, двойн)));
ПРОВЕРИТЬ(1, __builtin_types_compatible_p(цел (*)(плав, двойн), цел (*)(плав, двойн)));
ПРОВЕРИТЬ(0, __builtin_types_compatible_p(цел (*)(плав, двойн), цел));
ПРОВЕРИТЬ(0, __builtin_types_compatible_p(цел (*)(плав, двойн), цел (*)(плав)));
ПРОВЕРИТЬ(0, __builtin_types_compatible_p(цел (*)(плав, двойн), цел (*)(плав, двойн, цел)));
ПРОВЕРИТЬ(1, __builtin_types_compatible_p(двойн (*)(...), двойн (*)(...)));
ПРОВЕРИТЬ(0, __builtin_types_compatible_p(двойн (*)(...), двойн (*)(пусто)));
ПРОВЕРИТЬ(1, ({ типдеф структ {цел а;} Т; __builtin_types_compatible_p(Т, Т); }));
ПРОВЕРИТЬ(1, ({ типдеф структ {цел а;} Т; __builtin_types_compatible_p(Т, конст Т); }));
ПРОВЕРИТЬ(1, ({ структ {цел а; цел б;} х; __builtin_types_compatible_p(типоф(х.а), типоф(х.б)); }));
printf("OK\n");
возврат 0;
}

60
test/cast.c Normal file
View file

@ -0,0 +1,60 @@
#включить "тест.з"
#включить "stdvv.c"
цел главн() {
ПРОВЕРИТЬ(131585, (цел)8590066177);
ПРОВЕРИТЬ(513, (корот)8590066177);
ПРОВЕРИТЬ(1, (символ)8590066177);
ПРОВЕРИТЬ(1, (длин)1);
ПРОВЕРИТЬ(0, (длин)&*(цел *)0);
ПРОВЕРИТЬ(513, ({ цел х=512; *(символ *)&х=1; х; }));
ПРОВЕРИТЬ(5, ({ цел х=5; длин у=(длин)&х; *(цел*)у; }));
(пусто)1;
ПРОВЕРИТЬ(-1, (символ)255);
ПРОВЕРИТЬ(-1, (знак символ)255);
ПРОВЕРИТЬ(255, (беззнак символ)255);
ПРОВЕРИТЬ(-1, (корот)65535);
ПРОВЕРИТЬ(65535, (беззнак корот)65535);
ПРОВЕРИТЬ(-1, (цел)0xffffffff);
ПРОВЕРИТЬ(0xffffffff, (беззнак)0xffffffff);
ПРОВЕРИТЬ(1, -1<1);
ПРОВЕРИТЬ(0, -1<(беззнак)1);
ПРОВЕРИТЬ(254, (символ)127+(символ)127);
ПРОВЕРИТЬ(65534, (корот)32767+(корот)32767);
ПРОВЕРИТЬ(-1, -1>>1);
ПРОВЕРИТЬ(-1, (беззнак длин)-1);
ПРОВЕРИТЬ(2147483647, ((беззнак)-1)>>1);
ПРОВЕРИТЬ(-50, (-100)/2);
ПРОВЕРИТЬ(2147483598, ((беззнак)-100)/2);
ПРОВЕРИТЬ(9223372036854775758, ((беззнак длин)-100)/2);
ПРОВЕРИТЬ(0, ((длин)-1)/(беззнак)100);
ПРОВЕРИТЬ(-2, (-100)%7);
ПРОВЕРИТЬ(2, ((беззнак)-100)%7);
ПРОВЕРИТЬ(6, ((беззнак длин)-100)%9);
ПРОВЕРИТЬ(65535, (цел)(беззнак корот)65535);
ПРОВЕРИТЬ(65535, ({ беззнак корот х = 65535; х; }));
ПРОВЕРИТЬ(65535, ({ беззнак корот х = 65535; (цел)х; }));
ПРОВЕРИТЬ(-1, ({ типдеф корот Т; Т х = 65535; (цел)х; }));
ПРОВЕРИТЬ(65535, ({ типдеф беззнак корот Т; Т х = 65535; (цел)х; }));
ПРОВЕРИТЬ(0, (_Bool)0.0);
ПРОВЕРИТЬ(1, (_Bool)0.1);
ПРОВЕРИТЬ(3, (символ)3.0);
ПРОВЕРИТЬ(1000, (корот)1000.3);
ПРОВЕРИТЬ(3, (цел)3.99);
ПРОВЕРИТЬ(2000000000000000, (длин)2e15);
ПРОВЕРИТЬ(3, (плав)3.5);
ПРОВЕРИТЬ(5, (двойн)(плав)5.5);
ПРОВЕРИТЬ(3, (плав)3);
ПРОВЕРИТЬ(3, (двойн)3);
ПРОВЕРИТЬ(3, (плав)3L);
ПРОВЕРИТЬ(3, (двойн)3L);
printf("OK\n");
возврат 0;
}

20
test/commonsym.c Normal file
View file

@ -0,0 +1,20 @@
#включить "тест.з"
#включить "stdvv.c"
цел x;
цел x = 5;
цел y = 7;
цел y;
цел common_ext1;
цел common_ext2 = 3; // <-- ДОБАВИТЬ ИНИЦИАЛИЗАЦИЮ!
стат цел common_local;
цел главн() {
ПРОВЕРИТЬ(5, x);
ПРОВЕРИТЬ(7, y);
ПРОВЕРИТЬ(0, common_ext1);
ПРОВЕРИТЬ(3, common_ext2);
печатьф("OK\n");
возврат 0;
}

20
test/compat.c Normal file
View file

@ -0,0 +1,20 @@
#включить "тест.з"
#включить "stdvv.c"
_Noreturn noreturn_fn(int restrict x) {
exit(0);
}
void funcy_type(int arg[restrict static 3]) {}
int main() {
{ volatile x; }
{ int volatile x; }
{ volatile int x; }
{ volatile int volatile volatile x; }
{ int volatile * volatile volatile x; }
{ auto ** restrict __restrict __restrict__ const volatile *x; }
printf("OK\n");
return 0;
}

34
test/complit.c Normal file
View file

@ -0,0 +1,34 @@
#включить "тест.з"
#включить "stdvv.c"
типдеф структ Дерево {
цел значение;
структ Дерево *левый;
структ Дерево *правый;
} Дерево;
Дерево *дерево = &(Дерево){
1,
&(Дерево){
2,
&(Дерево){ 3, 0, 0 },
&(Дерево){ 4, 0, 0 }
},
0
};
цел главн() {
ПРОВЕРИТЬ(1, (цел){1});
ПРОВЕРИТЬ(2, ((цел[]){0,1,2})[2]);
ПРОВЕРИТЬ('a', ((структ {символ а; цел б;}){'a', 3}).а);
ПРОВЕРИТЬ(3, ({ цел х=3; (цел){х}; }));
(цел){3} = 5;
ПРОВЕРИТЬ(1, дерево->значение);
ПРОВЕРИТЬ(2, дерево->левый->значение);
ПРОВЕРИТЬ(3, дерево->левый->левый->значение);
ПРОВЕРИТЬ(4, дерево->левый->правый->значение);
printf("OK\n");
возврат 0;
}

15
test/const.c Normal file
View file

@ -0,0 +1,15 @@
#включить "тест.з"
#включить "stdvv.c"
цел главн() {
{ конст х; }
{ цел конст х; }
{ конст цел х; }
{ конст цел конст конст х; }
ПРОВЕРИТЬ(5, ({ конст х = 5; х; }));
ПРОВЕРИТЬ(8, ({ конст х = 8; цел *конст у=&х; *у; }));
ПРОВЕРИТЬ(6, ({ конст х = 6; *(конст * конст)&х; }));
printf("OK\n");
возврат 0;
}

56
test/constexpr.c Normal file
View file

@ -0,0 +1,56 @@
#включить "тест.з"
#включить "stdvv.c"
плав г40 = 1.5;
двойн г41 = 0.0 ? 55 : (0, 1 + 1 * 5.0 / 2 * (двойн)2 * (цел)2.0);
цел главн() {
ПРОВЕРИТЬ(10, ({ переч { десять=1+2+3+4 }; десять; }));
ПРОВЕРИТЬ(1, ({ цел и=0; выбор(3) { случай 5-2+0*3: и++; } и; }));
ПРОВЕРИТЬ(8, ({ цел х[1+1]; размер(х); }));
ПРОВЕРИТЬ(6, ({ символ х[8-2]; размер(х); }));
ПРОВЕРИТЬ(6, ({ символ х[2*3]; размер(х); }));
ПРОВЕРИТЬ(3, ({ символ х[12/4]; размер(х); }));
ПРОВЕРИТЬ(2, ({ символ х[12%10]; размер(х); }));
ПРОВЕРИТЬ(0b100, ({ символ х[0b110&0b101]; размер(х); }));
ПРОВЕРИТЬ(0b111, ({ символ х[0b110|0b101]; размер(х); }));
ПРОВЕРИТЬ(0b110, ({ символ х[0b111^0b001]; размер(х); }));
ПРОВЕРИТЬ(4, ({ символ х[1<<2]; размер(х); }));
ПРОВЕРИТЬ(2, ({ символ х[4>>1]; размер(х); }));
ПРОВЕРИТЬ(2, ({ символ х[(1==1)+1]; размер(х); }));
ПРОВЕРИТЬ(1, ({ символ х[(1!=1)+1]; размер(х); }));
ПРОВЕРИТЬ(1, ({ символ х[(1<1)+1]; размер(х); }));
ПРОВЕРИТЬ(2, ({ символ х[(1<=1)+1]; размер(х); }));
ПРОВЕРИТЬ(2, ({ символ х[1?2:3]; размер(х); }));
ПРОВЕРИТЬ(3, ({ символ х[0?2:3]; размер(х); }));
ПРОВЕРИТЬ(3, ({ символ х[(1,3)]; размер(х); }));
ПРОВЕРИТЬ(2, ({ символ х[!0+1]; размер(х); }));
ПРОВЕРИТЬ(1, ({ символ х[!1+1]; размер(х); }));
ПРОВЕРИТЬ(2, ({ символ х[~-3]; размер(х); }));
ПРОВЕРИТЬ(2, ({ символ х[(5||6)+1]; размер(х); }));
ПРОВЕРИТЬ(1, ({ символ х[(0||0)+1]; размер(х); }));
ПРОВЕРИТЬ(2, ({ символ х[(1&&1)+1]; размер(х); }));
ПРОВЕРИТЬ(1, ({ символ х[(1&&0)+1]; размер(х); }));
ПРОВЕРИТЬ(3, ({ символ х[(цел)3]; размер(х); }));
ПРОВЕРИТЬ(15, ({ символ х[(символ)0xffffff0f]; размер(х); }));
ПРОВЕРИТЬ(0x10f, ({ символ х[(корот)0xffff010f]; размер(х); }));
ПРОВЕРИТЬ(4, ({ символ х[(цел)0xfffffffffff+5]; размер(х); }));
ПРОВЕРИТЬ(8, ({ символ х[(цел*)0+2]; размер(х); }));
ПРОВЕРИТЬ(12, ({ символ х[(цел*)16-1]; размер(х); }));
ПРОВЕРИТЬ(3, ({ символ х[(цел*)16-(цел*)4]; размер(х); }));
ПРОВЕРИТЬ(4, ({ символ х[(-1>>31)+5]; размер(х); }));
ПРОВЕРИТЬ(255, ({ символ х[(беззнак символ)0xffffffff]; размер(х); }));
ПРОВЕРИТЬ(0x800f, ({ символ х[(беззнак корот)0xffff800f]; размер(х); }));
ПРОВЕРИТЬ(1, ({ символ х[(беззнак цел)0xfffffffffff>>31]; размер(х); }));
ПРОВЕРИТЬ(1, ({ символ х[(длин)-1/((длин)1<<62)+1]; размер(х); }));
ПРОВЕРИТЬ(4, ({ символ х[(беззнак длин)-1/((длин)1<<62)+1]; размер(х); }));
ПРОВЕРИТЬ(1, ({ символ х[(беззнак)1<-1]; размер(х); }));
ПРОВЕРИТЬ(1, ({ символ х[(беззнак)1<=-1]; размер(х); }));
ПРОВЕРИТЬ(1, г40==1.5);
ПРОВЕРИТЬ(1, г41==11);
printf("OK\n");
возврат 0;
}

101
test/control.c Normal file
View file

@ -0,0 +1,101 @@
#включить "тест.з"
#включить "stdvv.c"
/*
* Это блочный комментарий.
*/
цел главн() {
ПРОВЕРИТЬ(3, ({ цел х; если (0) х=2; иначе х=3; х; }));
ПРОВЕРИТЬ(3, ({ цел х; если (1-1) х=2; иначе х=3; х; }));
ПРОВЕРИТЬ(2, ({ цел х; если (1) х=2; иначе х=3; х; }));
ПРОВЕРИТЬ(2, ({ цел х; если (2-1) х=2; иначе х=3; х; }));
ПРОВЕРИТЬ(55, ({ цел и=0; цел й=0; для (и=0; и<=10; и=и+1) й=и+й; й; }));
ПРОВЕРИТЬ(10, ({ цел и=0; пока(и<10) и=и+1; и; }));
ПРОВЕРИТЬ(3, ({ 1; {2;} 3; }));
ПРОВЕРИТЬ(5, ({ ;;; 5; }));
ПРОВЕРИТЬ(10, ({ цел и=0; пока(и<10) и=и+1; и; }));
ПРОВЕРИТЬ(55, ({ цел и=0; цел й=0; пока(и<=10) {й=и+й; и=и+1;} й; }));
ПРОВЕРИТЬ(3, (1,2,3));
ПРОВЕРИТЬ(5, ({ цел и=2, й=3; (и=5,й)=6; и; }));
ПРОВЕРИТЬ(6, ({ цел и=2, й=3; (и=5,й)=6; й; }));
ПРОВЕРИТЬ(55, ({ цел й=0; для (цел и=0; и<=10; и=и+1) й=й+и; й; }));
ПРОВЕРИТЬ(3, ({ цел и=3; цел й=0; для (цел и=0; и<=10; и=и+1) й=й+и; и; }));
ПРОВЕРИТЬ(1, 0||1);
ПРОВЕРИТЬ(1, 0||(2-2)||5);
ПРОВЕРИТЬ(0, 0||0);
ПРОВЕРИТЬ(0, 0||(2-2));
ПРОВЕРИТЬ(0, 0&&1);
ПРОВЕРИТЬ(0, (2-2)&&5);
ПРОВЕРИТЬ(1, 1&&5);
ПРОВЕРИТЬ(3, ({ цел и=0; перейти а; а: и++; б: и++; в: и++; и; }));
ПРОВЕРИТЬ(2, ({ цел и=0; перейти е; г: и++; д: и++; е: и++; ж: и++; и; }));
ПРОВЕРИТЬ(1, ({ цел и=0; перейти и; з: и++; к: и++; и: и++; и; }));
ПРОВЕРИТЬ(1, ({ типдеф цел фу; перейти фу; фу:; 1; }));
ПРОВЕРИТЬ(3, ({ цел и=0; для(;и<10;и++) { если (и == 3) прерви; } и; }));
ПРОВЕРИТЬ(4, ({ цел и=0; пока (1) { если (и++ == 3) прерви; } и; }));
ПРОВЕРИТЬ(3, ({ цел и=0; для(;и<10;и++) { для (;;) прерви; если (и == 3) прерви; } и; }));
ПРОВЕРИТЬ(4, ({ цел и=0; пока (1) { пока(1) прерви; если (и++ == 3) прерви; } и; }));
ПРОВЕРИТЬ(10, ({ цел и=0; цел й=0; для (;и<10;и++) { если (и>5) продолжи; й++; } и; }));
ПРОВЕРИТЬ(6, ({ цел и=0; цел й=0; для (;и<10;и++) { если (и>5) продолжи; й++; } й; }));
ПРОВЕРИТЬ(10, ({ цел и=0; цел й=0; для(;!и;) { для (;й!=10;й++) продолжи; прерви; } й; }));
ПРОВЕРИТЬ(11, ({ цел и=0; цел й=0; пока (и++<10) { если (и>5) продолжи; й++; } и; }));
ПРОВЕРИТЬ(5, ({ цел и=0; цел й=0; пока (и++<10) { если (и>5) продолжи; й++; } й; }));
ПРОВЕРИТЬ(11, ({ цел и=0; цел й=0; пока(!и) { пока (й++!=10) продолжи; прерви; } й; }));
ПРОВЕРИТЬ(5, ({ цел и=0; выбор(0) { случай 0:и=5;прерви; случай 1:и=6;прерви; случай 2:и=7;прерви; } и; }));
ПРОВЕРИТЬ(6, ({ цел и=0; выбор(1) { случай 0:и=5;прерви; случай 1:и=6;прерви; случай 2:и=7;прерви; } и; }));
ПРОВЕРИТЬ(7, ({ цел и=0; выбор(2) { случай 0:и=5;прерви; случай 1:и=6;прерви; случай 2:и=7;прерви; } и; }));
ПРОВЕРИТЬ(0, ({ цел и=0; выбор(3) { случай 0:и=5;прерви; случай 1:и=6;прерви; случай 2:и=7;прерви; } и; }));
ПРОВЕРИТЬ(5, ({ цел и=0; выбор(0) { случай 0:и=5;прерви; умолч:и=7; } и; }));
ПРОВЕРИТЬ(7, ({ цел и=0; выбор(1) { случай 0:и=5;прерви; умолч:и=7; } и; }));
ПРОВЕРИТЬ(2, ({ цел и=0; выбор(1) { случай 0: 0; случай 1: 0; случай 2: 0; и=2; } и; }));
ПРОВЕРИТЬ(0, ({ цел и=0; выбор(3) { случай 0: 0; случай 1: 0; случай 2: 0; и=2; } и; }));
ПРОВЕРИТЬ(3, ({ цел и=0; выбор(-1) { случай 0xffffffff: и=3; прерви; } и; }));
ПРОВЕРИТЬ(7, ({ цел и=0; цел й=0; делай { й++; } пока (и++ < 6); й; }));
ПРОВЕРИТЬ(4, ({ цел и=0; цел й=0; цел к=0; делай { если (++й > 3) прерви; продолжи; к++; } пока (1); й; }));
ПРОВЕРИТЬ(0, 0.0 && 0.0);
ПРОВЕРИТЬ(0, 0.0 && 0.1);
ПРОВЕРИТЬ(0, 0.3 && 0.0);
ПРОВЕРИТЬ(1, 0.3 && 0.5);
ПРОВЕРИТЬ(0, 0.0 || 0.0);
ПРОВЕРИТЬ(1, 0.0 || 0.1);
ПРОВЕРИТЬ(1, 0.3 || 0.0);
ПРОВЕРИТЬ(1, 0.3 || 0.5);
ПРОВЕРИТЬ(5, ({ цел х; если (0.0) х=3; иначе х=5; х; }));
ПРОВЕРИТЬ(3, ({ цел х; если (0.1) х=3; иначе х=5; х; }));
ПРОВЕРИТЬ(5, ({ цел х=5; если (0.0) х=3; х; }));
ПРОВЕРИТЬ(3, ({ цел х=5; если (0.1) х=3; х; }));
ПРОВЕРИТЬ(10, ({ двойн и=10.0; цел й=0; для (; и; и--, й++); й; }));
ПРОВЕРИТЬ(10, ({ двойн и=10.0; цел й=0; делай й++; пока(--и); й; }));
ПРОВЕРИТЬ(2, ({ цел и=0; выбор(7) { случай 0 ... 5: и=1; прерви; случай 6 ... 20: и=2; прерви; } и; }));
ПРОВЕРИТЬ(1, ({ цел и=0; выбор(7) { случай 0 ... 7: и=1; прерви; случай 8 ... 10: и=2; прерви; } и; }));
ПРОВЕРИТЬ(1, ({ цел и=0; выбор(7) { случай 0: и=1; прерви; случай 7 ... 7: и=1; прерви; } и; }));
ПРОВЕРИТЬ(3, ({ пусто *п = &&в11; цел и=0; перейти *п; в11:и++; в12:и++; в13:и++; и; }));
ПРОВЕРИТЬ(2, ({ пусто *п = &&в22; цел и=0; перейти *п; в21:и++; в22:и++; в23:и++; и; }));
ПРОВЕРИТЬ(1, ({ пусто *п = &&в33; цел и=0; перейти *п; в31:и++; в32:и++; в33:и++; и; }));
ПРОВЕРИТЬ(3, ({ стат пусто *п[]={&&в41,&&в42,&&в43}; цел и=0; перейти *п[0]; в41:и++; в42:и++; в43:и++; и; }));
ПРОВЕРИТЬ(2, ({ стат пусто *п[]={&&в52,&&в52,&&в53}; цел и=0; перейти *п[1]; в51:и++; в52:и++; в53:и++; и; }));
ПРОВЕРИТЬ(1, ({ стат пусто *п[]={&&в62,&&в62,&&в63}; цел и=0; перейти *п[2]; в61:и++; в62:и++; в63:и++; и; }));
printf("OK\n");
возврат 0;
}

23
test/decl.c Normal file
View file

@ -0,0 +1,23 @@
#включить "тест.з"
#включить "stdvv.c"
цел главн() {
ПРОВЕРИТЬ(1, ({ символ х; размер(х); }));
ПРОВЕРИТЬ(2, ({ корот цел х; размер(х); }));
ПРОВЕРИТЬ(2, ({ цел корот х; размер(х); }));
ПРОВЕРИТЬ(4, ({ цел х; размер(х); }));
ПРОВЕРИТЬ(8, ({ длин цел х; размер(х); }));
ПРОВЕРИТЬ(8, ({ цел длин х; размер(х); }));
ПРОВЕРИТЬ(8, ({ длин длин х; размер(х); }));
ПРОВЕРИТЬ(0, ({ _Bool х=0; х; }));
ПРОВЕРИТЬ(1, ({ _Bool х=1; х; }));
ПРОВЕРИТЬ(1, ({ _Bool х=2; х; }));
ПРОВЕРИТЬ(1, (_Bool)1);
ПРОВЕРИТЬ(1, (_Bool)2);
ПРОВЕРИТЬ(0, (_Bool)(символ)256);
printf("OK\n");
возврат 0;
}

987
test/driver.py Executable file
View file

@ -0,0 +1,987 @@
#!/usr/bin/env python3
import os
import sys
import tempfile
import shutil
import subprocess
import re
import atexit
import signal
import traceback
import glob
# Цвета для терминала
GREEN = '\033[92m'
RED = '\033[91m'
YELLOW = '\033[93m'
BLUE = '\033[94m'
RESET = '\033[0m'
BOLD = '\033[1m'
# Глобальные переменные для состояния тестов
_TESTS_PASSED = 0
_TESTS_FAILED = 0
_TESTS_TOTAL = 0
_TEST_RESULTS: list = []
def main():
# Проверяем, что передан путь к исполняемому файлу rusi
if len(sys.argv) < 2:
print("Использование: {} <путь-к-rusi>".format(sys.argv[0]), file=sys.stderr)
sys.exit(1)
rusi = sys.argv[1] # Путь к тестируемому компилятору
# Создаем временную папку для тестов
tmp = tempfile.mkdtemp(prefix='rusi-test-')
def cleanup():
# Удаляем временную папку после завершения тестов
shutil.rmtree(tmp, ignore_errors=True)
atexit.register(cleanup) # Регистрируем функцию очистки
# Обработчики сигналов для корректного завершения
signal.signal(signal.SIGINT, lambda s, f: завершить_тесты())
signal.signal(signal.SIGTERM, lambda s, f: завершить_тесты())
if hasattr(signal, 'SIGHUP'):
signal.signal(signal.SIGHUP, lambda s, f: завершить_тесты())
# Создаем пустой C-файл для тестирования
tmp_c = os.path.join(tmp, 'tmp.c')
with open(tmp_c, 'w') as f:
f.write('')
# Запускаем все тесты
try:
запустить_тесты(rusi, tmp, tmp_c)
except (AssertionError, subprocess.CalledProcessError, Exception) as e:
# При падении любого теста выводим отчет и выходим с ошибкой
вывести_отчет()
print(f"\n{RED}❌ ТЕСТЫ НЕ ПРОЙДЕНЫ: {str(e)}{RESET}")
sys.exit(1)
# Если все тесты прошли успешно
вывести_отчет()
if _TESTS_FAILED == 0:
print(f"\n{GREEN}{BOLD}🎉 ВСЕ ТЕСТЫ ПРОЙДЕНЫ УСПЕШНО!{RESET}")
sys.exit(0)
else:
print(f"\n{RED}{BOLD}НЕ ПРОЙДЕНО {_TESTS_FAILED} ТЕСТОВ ИЗ {_TESTS_TOTAL}{RESET}")
sys.exit(1)
def завершить_тесты():
"""Принудительное завершение с выводом отчета"""
вывести_отчет()
sys.exit(1)
def запустить_тесты(rusi: str, tmp: str, tmp_c: str):
"""Запускает все тесты"""
global _TESTS_TOTAL
# Список всех тестов с их описаниями
тесты = [
("-o", lambda: тест_o(rusi, tmp, tmp_c)),
("--help", lambda: тест_help(rusi)),
("-S", lambda: тест_S(rusi)),
("имя выходного файла по умолчанию", lambda: тест_имя_выходногоайла(rusi, tmp)),
("несколько входных файлов", lambda: тест_несколькоходных(rusi, tmp)),
("линковщик", lambda: тест_линковщик(rusi, tmp)),
("a.out", lambda: тест_a_out(rusi, tmp)),
("-E", lambda: тест_E(rusi, tmp)),
("-E и -o", lambda: тест_E_o(rusi, tmp)),
("-I", lambda: тест_I(rusi, tmp)),
("-D", lambda: тест_D(rusi)),
("-D со значением", lambda: тест_D_значение(rusi)),
("-U", lambda: тест_U(rusi)),
("игнорируемые опции", lambda: тест_игнорируемые(rusi, tmp_c)),
("маркер BOM", lambda: тест_BOM(rusi)),
("inline", lambda: тест_inline(rusi, tmp)),
("-idirafter", lambda: тест_idirafter(rusi, tmp)),
("-fcommon (по умолчанию)", lambda: тест_fcommon_по_умолчанию(rusi)),
("-fcommon", lambda: тест_fcommon(rusi)),
("-fno-common", lambda: тест_fno_common(rusi)),
("-include", lambda: тест_include(rusi, tmp)),
("-include stdio.h", lambda: тест_include_stdio(rusi)),
("-xc", lambda: тест_xc(rusi, tmp)),
("-x assembler", lambda: тест_x_assembler(rusi, tmp)),
("-x none", lambda: тест_x_none(rusi, tmp)),
("-E без -xc", lambda: тест_E_без_xc(rusi)),
(".a", lambda: тест_a_архив(rusi, tmp)),
(".so", lambda: тест_so_библиотека(rusi, tmp)),
("хеш-таблица", lambda: тест_хеш_таблица(rusi)),
("-M", lambda: тест_M(rusi, tmp)),
("-MF", lambda: тест_MF(rusi, tmp)),
("-MP", lambda: тест_MP(rusi, tmp)),
("-MT", lambda: тест_MT(rusi, tmp)),
("-MT несколько целей", lambda: тест_MT_несколько(rusi, tmp)),
("-MD", lambda: тест_MD(rusi, tmp)),
("-MD с -MF", lambda: тест_MD_MF(rusi, tmp)),
("-fPIC", lambda: тест_fPIC(rusi, tmp)),
("#include_next", lambda: тест_include_next(rusi, tmp)),
("-static", lambda: тест_static(rusi, tmp)),
("-shared", lambda: тест_shared(rusi, tmp)),
("-L", lambda: тест_L(rusi, tmp)),
("-Wl,", lambda: тест_Wl(rusi, tmp)),
("-Xlinker", lambda: тест_Xlinker(rusi, tmp)),
# ============================================================
# НОВЫЕ ТЕСТЫ: Сборка и запуск .c файлов из папки test/
# ============================================================
("Сборка тестов .c", lambda: тест_сборка_c_файлов(rusi)),
]
_TESTS_TOTAL = len(тесты)
# Вычисляем максимальную длину названия теста для выравнивания
макс_длина = 0
for название, _ in тесты:
макс_длина = max(макс_длина, len(название))
for название, тест_функция in тесты:
выполнить_тест(название, тест_функция, макс_длина)
def выполнить_тест(название: str, тест_функция, макс_длина: int):
"""Выполняет отдельный тест - при ошибке сразу прерывает выполнение"""
global _TESTS_PASSED, _TESTS_FAILED
try:
тест_функция()
_TESTS_PASSED += 1
_TEST_RESULTS.append((название, True, None))
print(f"{GREEN}{RESET} {название:<{макс_длина}} ... {GREEN}ПРОЙДЕНО{RESET}")
except AssertionError as e:
_TESTS_FAILED += 1
ошибка = str(e) if str(e) else "проверка не пройдена"
_TEST_RESULTS.append((название, False, ошибка))
print(f"{RED}{RESET} {название:<{макс_длина}} ... {RED}НЕ ПРОЙДЕНО{RESET}: {ошибка}")
raise # Прерываем выполнение при падении теста
except subprocess.CalledProcessError as e:
_TESTS_FAILED += 1
ошибка = f"команда завершилась с кодом {e.returncode}"
_TEST_RESULTS.append((название, False, ошибка))
print(f"{RED}{RESET} {название:<{макс_длина}} ... {RED}НЕ ПРОЙДЕНО{RESET}: {ошибка}")
raise # Прерываем выполнение при падении теста
except Exception as e:
_TESTS_FAILED += 1
ошибка = f"{type(e).__name__}: {str(e)}"
_TEST_RESULTS.append((название, False, ошибка))
print(f"{RED}{RESET} {название:<{макс_длина}} ... {RED}НЕ ПРОЙДЕНО{RESET}: {ошибка}")
traceback.print_exc()
raise # Прерываем выполнение при падении теста
def вывести_отчет():
"""Выводит итоговый отчет о тестировании"""
global _TESTS_PASSED, _TESTS_FAILED, _TESTS_TOTAL
print("\n" + "=" * 60)
print(f"{BOLD}ИТОГОВЫЙ ОТЧЕТ О ТЕСТИРОВАНИИ{RESET}")
print("=" * 60)
if _TEST_RESULTS:
print("\nПОДРОБНЫЕ РЕЗУЛЬТАТЫ:")
for название, успешно, ошибка in _TEST_RESULTS:
if успешно:
статус = f"{GREEN}✓ ПРОЙДЕНО{RESET}"
else:
статус = f"{RED}НЕ ПРОЙДЕНО{RESET}"
строка = f" {статус} {название}"
if not успешно and ошибка:
строка += f" ({RED}ошибка: {ошибка}{RESET})"
print(строка)
print("\n" + "-" * 60)
print(f"ВСЕГО ТЕСТОВ: {_TESTS_TOTAL}")
print(f"ПРОЙДЕНО: {GREEN}{_TESTS_PASSED}{RESET}")
print(f"НЕ ПРОЙДЕНО: {RED}{_TESTS_FAILED}{RESET}")
print("=" * 60)
def проверка_существования_файла(путь: str, сообщение: str = ""):
"""Вспомогательная функция для проверки существования файла"""
if not os.path.exists(путь):
raise AssertionError(f"файл {путь} не создан {сообщение}")
def проверка_содержимого(текст: str, паттерн, сообщение: str = ""):
"""Вспомогательная функция для проверки содержимого"""
if isinstance(паттерн, str):
if паттерн not in текст:
raise AssertionError(f"'{паттерн}' не найден в выводе {сообщение}")
else: # регулярное выражение
if not паттерн.search(текст):
raise AssertionError(f"паттерн не найден в выводе {сообщение}")
def run_rusi(rusi: str, *args, **kwargs):
"""Запускает rusi с заданными аргументами"""
cmd = [rusi] + list(args)
if 'input' in kwargs:
input_text = kwargs.pop('input')
kwargs['input'] = input_text
if 'capture_output' not in kwargs and 'stdout' not in kwargs and 'stderr' not in kwargs:
kwargs['capture_output'] = True
kwargs['text'] = True
return subprocess.run(cmd, **kwargs)
# ============================================================================
# НОВАЯ ФУНКЦИЯ: Сборка и запуск .c файлов из папки test/
# ============================================================================
def тест_сборка_c_файлов(rusi: str):
"""Собирает и запускает все .c файлы из папки test/, проверяя вывод на OK"""
# Находим все .c файлы в папке test/
test_dir = "test"
if not os.path.exists(test_dir):
raise AssertionError(f"Папка {test_dir} не найдена")
c_files = glob.glob(os.path.join(test_dir, "*.c"))
if not c_files:
raise AssertionError("В папке test/ нет .c файлов")
# Файлы, которые нужно исключить (требуют специальной линковки или не являются тестами)
исключения = [] # atomic.c теперь работает
# Файлы, которые требуют stdvv.c
stdvv = os.path.join(test_dir, "stdvv.c")
if not os.path.exists(stdvv):
stdvv = None
# Файлы, которые требуют test.c (если есть)
test_c = os.path.join(test_dir, "test.c")
if os.path.exists(test_c):
runtime = test_c
elif stdvv:
runtime = stdvv
else:
runtime = None
# Счетчики для отчета
всегоестов = 0
пройденоестов = 0
пропущеноестов = 0
# Вычисляем максимальную длину имени файла для выравнивания
макс_длина = 0
for c_file in c_files:
имя = os.path.basename(c_file)
if имя not in ["stdvv.c", "test.c", "тест.з"]:
макс_длина = max(макс_длина, len(имя))
print(f"\n{BOLD}=== ЗАПУСК СЕМАНТИЧЕСКИХ ТЕСТОВ ==={RESET}")
print()
# Проходим по всем .c файлам
for c_file in sorted(c_files):
имя_файла = os.path.basename(c_file)
имя_без_расш = os.path.splitext(имя_файла)[0]
# Пропускаем исключения
if имя_файла in исключения:
пропущеноестов += 1
print(f"{YELLOW}{RESET} {имя_файла:<{макс_длина}} ... {YELLOW}ПРОПУЩЕН{RESET} (требует специальной линковки)")
continue
# Пропускаем runtime файлы (не тесты)
if имя_файла in ["stdvv.c", "test.c", "тест.з"]:
continue
всегоестов += 1
# Определяем, нужен ли runtime для этого теста
with open(c_file, 'r', encoding='utf-8', errors='ignore') as f:
содержимое = f.read()
нужен_runtime = 'ASSERT' in содержимое or 'ПРОВЕРИТЬ' in содержимое or 'printf' not in содержимое
# Собираем команду компиляции
выходной_файл = os.path.join(test_dir, f"test_{имя_без_расш}")
аргументы = [rusi, "-o", выходной_файл, c_file]
# Добавляем runtime если нужен
if нужен_runtime and runtime and os.path.exists(runtime):
аргументы.append(runtime)
# Собираем
try:
subprocess.run(аргументы, capture_output=True, text=True, check=True)
except subprocess.CalledProcessError as e:
raise AssertionError(f"Ошибка компиляции {имя_файла}: {e.stderr}")
# Проверяем, что исполняемый файл создан
if not os.path.exists(выходной_файл):
raise AssertionError(f"Исполняемый файл не создан для {имя_файла}")
# Запускаем и проверяем вывод
try:
результат = subprocess.run([выходной_файл], capture_output=True, text=True, timeout=5)
except subprocess.TimeoutExpired:
raise AssertionError(f"Таймаут при выполнении {имя_файла}")
# Проверяем, что программа завершилась успешно
if результат.returncode != 0:
raise AssertionError(f"{имя_файла} завершилась с кодом {результат.returncode}: {результат.stderr}")
# Проверяем, что вывод содержит OK
if "OK" not in результат.stdout:
raise AssertionError(f"{имя_файла} не вывела OK. Вывод: {результат.stdout}")
# Тест пройден!
пройденоестов += 1
print(f"{GREEN}{RESET} {имя_файла:<{макс_длина}} ... {GREEN}ПРОЙДЕНО{RESET}")
# Удаляем исполняемый файл
try:
os.unlink(выходной_файл)
except:
pass
# Выводим итоговый отчет по семантическим тестам
print()
print(f"{BOLD}=== ИТОГ СЕМАНТИЧЕСКИХ ТЕСТОВ ==={RESET}")
print(f" Всего тестов: {всегоестов}")
print(f" {GREEN}Пройдено:{RESET} {пройденоестов}")
if пропущеноестов > 0:
print(f" {YELLOW}Пропущено:{RESET} {пропущеноестов}")
print()
# ============================================================================
# ОСТАЛЬНЫЕ ТЕСТЫ (без изменений)
# ============================================================================
def тест_o(rusi: str, tmp: str, tmp_c: str):
"""Тест опции -o"""
out_file = os.path.join(tmp, 'out')
if os.path.exists(out_file):
os.unlink(out_file)
subprocess.run([rusi, '-c', '-o', out_file, tmp_c], check=True)
проверка_существования_файла(out_file)
def тест_help(rusi: str):
"""Тест --help"""
result = subprocess.run([rusi, '--help'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
if not result.stdout.strip():
raise AssertionError("пустой вывод справки")
def тест_S(rusi: str):
"""Тест -S"""
result = subprocess.run([rusi, '-S', '-o-', '-xc', '-'],
input='int main() {}', capture_output=True, text=True)
проверка_содержимого(result.stdout, 'main:', "метка main не найдена в ассемблерном коде")
def тест_имя_выходногоайла(rusi: str, tmp: str):
"""Тест имени выходного файла по умолчанию"""
out_c = os.path.join(tmp, 'out.c')
with open(out_c, 'w') as f:
f.write('int main() {}')
out_o = os.path.join(tmp, 'out.o')
out_s = os.path.join(tmp, 'out.s')
for f in [out_o, out_s]:
if os.path.exists(f):
os.unlink(f)
old_pwd = os.getcwd()
os.chdir(tmp)
try:
subprocess.run([os.path.join(old_pwd, rusi), '-c', 'out.c'], check=True)
проверка_существования_файла(out_o)
finally:
os.chdir(old_pwd)
os.chdir(tmp)
try:
subprocess.run([os.path.join(old_pwd, rusi), '-c', '-S', 'out.c'], check=True)
проверка_существования_файла(out_s)
finally:
os.chdir(old_pwd)
def тест_несколькоходных(rusi: str, tmp: str):
"""Тест с несколькими входными файлами"""
foo_o = os.path.join(tmp, 'foo.o')
bar_o = os.path.join(tmp, 'bar.o')
for f in [foo_o, bar_o]:
if os.path.exists(f):
os.unlink(f)
foo_c = os.path.join(tmp, 'foo.c')
bar_c = os.path.join(tmp, 'bar.c')
with open(foo_c, 'w') as f:
f.write('int x;')
with open(bar_c, 'w') as f:
f.write('int y;')
old_pwd = os.getcwd()
os.chdir(tmp)
try:
subprocess.run([os.path.join(old_pwd, rusi), '-c', foo_c, bar_c], check=True)
проверка_существования_файла(foo_o)
проверка_существования_файла(bar_o)
finally:
os.chdir(old_pwd)
foo_s = os.path.join(tmp, 'foo.s')
bar_s = os.path.join(tmp, 'bar.s')
for f in [foo_s, bar_s]:
if os.path.exists(f):
os.unlink(f)
os.chdir(tmp)
try:
subprocess.run([os.path.join(old_pwd, rusi), '-c', '-S', foo_c, bar_c], check=True)
проверка_существования_файла(foo_s)
проверка_существования_файла(bar_s)
finally:
os.chdir(old_pwd)
def тест_линковщик(rusi: str, tmp: str):
"""Тест линковщика"""
foo_exe = os.path.join(tmp, 'foo')
if os.path.exists(foo_exe):
os.unlink(foo_exe)
subprocess.run([rusi, '-o', foo_exe, '-xc', '-xc', '-'],
input='int main() { return 0; }', text=True, check=True)
result = subprocess.run([foo_exe])
if result.returncode != 0:
raise AssertionError(f"программа вернула {result.returncode}, ожидалось 0")
if os.path.exists(foo_exe):
os.unlink(foo_exe)
foo_c = os.path.join(tmp, 'foo.c')
bar_c = os.path.join(tmp, 'bar.c')
with open(foo_c, 'w') as f:
f.write('int bar(); int main() { return bar(); }')
with open(bar_c, 'w') as f:
f.write('int bar() { return 42; }')
subprocess.run([rusi, '-o', foo_exe, foo_c, bar_c], check=True)
result = subprocess.run([foo_exe])
if result.returncode != 42:
raise AssertionError(f"программа вернула {result.returncode}, ожидалось 42")
def тест_a_out(rusi: str, tmp: str):
"""Тест a.out"""
a_out = os.path.join(tmp, 'a.out')
if os.path.exists(a_out):
os.unlink(a_out)
foo_c = os.path.join(tmp, 'foo.c')
with open(foo_c, 'w') as f:
f.write('int main() {}')
old_pwd = os.getcwd()
os.chdir(tmp)
try:
subprocess.run([os.path.join(old_pwd, rusi), 'foo.c'], check=True)
проверка_существования_файла(a_out)
finally:
os.chdir(old_pwd)
def тест_E(rusi: str, tmp: str):
"""Тест -E"""
out_file = os.path.join(tmp, 'out')
with open(out_file, 'w') as f:
f.write('foo')
result = subprocess.run([rusi, '-E', '-xc', '-'],
input=f'#include "{out_file}"\n', capture_output=True, text=True)
проверка_содержимого(result.stdout, 'foo', "препроцессор не вставил содержимое файла")
def тест_E_o(rusi: str, tmp: str):
"""Тест -E и -o"""
out1 = os.path.join(tmp, 'out1')
with open(out1, 'w') as f:
f.write('foo')
out2 = os.path.join(tmp, 'out2')
subprocess.run([rusi, '-E', '-o', out2, '-xc', '-'],
input=f'#include "{out1}"\n', text=True, check=True)
with open(out2) as f:
content = f.read()
проверка_содержимого(content, 'foo', "результат препроцессинга не записан в файл")
def тест_I(rusi: str, tmp: str):
"""Тест -I"""
dir_path = os.path.join(tmp, 'dir')
os.makedirs(dir_path, exist_ok=True)
i_test = os.path.join(dir_path, 'i-option-test')
with open(i_test, 'w') as f:
f.write('foo')
result = subprocess.run([rusi, f'-I{dir_path}', '-E', '-xc', '-'],
input='#include "i-option-test"\n', capture_output=True, text=True)
проверка_содержимого(result.stdout, 'foo', "файл не найден в указанной папке")
def тест_D(rusi: str):
"""Тест -D"""
result = subprocess.run([rusi, '-Dfoo', '-E', '-xc', '-'],
input='foo', capture_output=True, text=True)
проверка_содержимого(result.stdout, '1', "макрос без значения не подставлен как 1")
def тест_D_значение(rusi: str):
"""Тест -D со значением"""
result = subprocess.run([rusi, '-Dfoo=bar', '-E', '-xc', '-'],
input='foo', capture_output=True, text=True)
проверка_содержимого(result.stdout, 'bar', "макрос не подставлен с указанным значением")
def тест_U(rusi: str):
"""Тест -U"""
result = subprocess.run([rusi, '-Dfoo=bar', '-Ufoo', '-E', '-xc', '-'],
input='foo', capture_output=True, text=True)
проверка_содержимого(result.stdout, 'foo', "макрос не остался неопределенным")
def тест_игнорируемые(rusi: str, tmp_c: str):
"""Тест игнорируемых опций"""
subprocess.run([rusi, '-c', '-O', '-Wall', '-g', '-std=c11', '-ffreestanding',
'-fno-builtin', '-fno-omit-frame-pointer', '-fno-stack-protector',
'-fno-strict-aliasing', '-m64', '-mno-red-zone', '-w',
'-o', '/dev/null', tmp_c], check=True)
def тест_BOM(rusi: str):
"""Тест маркера BOM"""
result = subprocess.run([rusi, '-E', '-o-', '-xc', '-'],
input='\ufeffxyz\n', capture_output=True, text=True)
проверка_содержимого(result.stdout, re.compile(r'^xyz', re.MULTILINE), "BOM не удален")
def тест_inline(rusi: str, tmp: str):
"""Тесты inline-функций"""
inline1 = os.path.join(tmp, 'inline1.c')
inline2 = os.path.join(tmp, 'inline2.c')
inline3 = os.path.join(tmp, 'inline3.c')
# Две одинаковые inline-функции в разных файлах
with open(inline1, 'w') as f:
f.write('inline void foo() {}')
with open(inline2, 'w') as f:
f.write('inline void foo() {}')
with open(inline3, 'w') as f:
f.write('int main() { return 0; }')
subprocess.run([rusi, '-o', '/dev/null', inline1, inline2, inline3], check=True)
# extern inline
with open(inline1, 'w') as f:
f.write('extern inline void foo() {}')
with open(inline2, 'w') as f:
f.write('int foo(); int main() { foo(); }')
subprocess.run([rusi, '-o', '/dev/null', inline1, inline2], check=True)
# static inline не используется
result = subprocess.run([rusi, '-o-', '-S', '-xc', '-'],
input='static inline void f1() {}', capture_output=True, text=True)
if 'f1:' in result.stdout:
raise AssertionError("static inline функция сгенерировала код без использования")
# static inline используется
result = subprocess.run([rusi, '-o-', '-S', '-xc', '-'],
input='static inline void f1() {} void foo() { f1(); }',
capture_output=True, text=True)
проверка_содержимого(result.stdout, 'f1:', "static inline функция не сгенерировала код при использовании")
# Дополнительные проверки inline
test_input = 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }'
result = subprocess.run([rusi, '-o-', '-S', '-xc', '-'],
input=test_input, capture_output=True, text=True)
проверка_содержимого(result.stdout, 'f1:', "f1 должна быть сгенерирована")
if 'f2:' in result.stdout:
raise AssertionError("f2 сгенерирована, хотя не используется")
def тест_idirafter(rusi: str, tmp: str):
"""Тест -idirafter"""
dir1 = os.path.join(tmp, 'dir1')
dir2 = os.path.join(tmp, 'dir2')
os.makedirs(dir1, exist_ok=True)
os.makedirs(dir2, exist_ok=True)
idirafter1 = os.path.join(dir1, 'idirafter')
idirafter2 = os.path.join(dir2, 'idirafter')
with open(idirafter1, 'w') as f:
f.write('foo')
with open(idirafter2, 'w') as f:
f.write('bar')
# Обычная -I ищет в первой папке
result = subprocess.run([rusi, f'-I{dir1}', f'-I{dir2}', '-E', '-xc', '-'],
input='#include "idirafter"\n', capture_output=True, text=True)
проверка_содержимого(result.stdout, 'foo', "-I не нашла файл в первой папке")
# -idirafter ищет после -I
result = subprocess.run([rusi, f'-idirafter', dir1, f'-I{dir2}', '-E', '-xc', '-'],
input='#include "idirafter"\n', capture_output=True, text=True)
проверка_содержимого(result.stdout, 'bar', "-idirafter не нашла файл после -I")
def тест_fcommon_по_умолчанию(rusi: str):
"""Тест -fcommon (по умолчанию)"""
result = subprocess.run([rusi, '-S', '-o-', '-xc', '-'],
input='int foo;', capture_output=True, text=True)
проверка_содержимого(result.stdout, '.comm foo', "директива .comm не сгенерирована")
def тест_fcommon(rusi: str):
"""Тест -fcommon"""
result = subprocess.run([rusi, '-fcommon', '-S', '-o-', '-xc', '-'],
input='int foo;', capture_output=True, text=True)
проверка_содержимого(result.stdout, '.comm foo', "директива .comm не сгенерирована с -fcommon")
def тест_fno_common(rusi: str):
"""Тест -fno-common"""
result = subprocess.run([rusi, '-fno-common', '-S', '-o-', '-xc', '-'],
input='int foo;', capture_output=True, text=True)
проверка_содержимого(result.stdout, re.compile(r'^foo:', re.MULTILINE), "foo не сгенерирована как обычная переменная")
def тест_include(rusi: str, tmp: str):
"""Тест -include"""
out_h = os.path.join(tmp, 'out.h')
with open(out_h, 'w') as f:
f.write('foo')
result = subprocess.run([rusi, '-include', out_h, '-E', '-o-', '-xc', '-'],
input='bar', capture_output=True, text=True)
проверка_содержимого(result.stdout, 'foo', "файл не включен через -include")
проверка_содержимого(result.stdout, 'bar', "входной текст отсутствует после -include")
def тест_include_stdio(rusi: str):
"""Тест -include stdio.h"""
result = subprocess.run([rusi, '-Iinclude', '-include', 'stdio.h', '-E', '-o-', '-xc', '-'],
input='NULL', capture_output=True, text=True)
проверка_содержимого(result.stdout, '0', "NULL не определен через -include stdio.h")
def тест_xc(rusi: str, tmp: str):
"""Тест -xc"""
foo_o = os.path.join(tmp, 'foo.o')
subprocess.run([rusi, '-c', '-xc', '-o', foo_o, '-'],
input='int x;', text=True, check=True)
def тест_x_assembler(rusi: str, tmp: str):
"""Тест -x assembler"""
foo_o = os.path.join(tmp, 'foo.o')
subprocess.run([rusi, '-c', '-x', 'assembler', '-o', foo_o, '-'],
input='x:', text=True, check=True)
def тест_x_none(rusi: str, tmp: str):
"""Тест -x none"""
foo_o = os.path.join(tmp, 'foo.o')
foo_c = os.path.join(tmp, 'foo.c')
with open(foo_c, 'w') as f:
f.write('int x;')
subprocess.run([rusi, '-c', '-x', 'assembler', '-x', 'none', '-o', foo_o, foo_c], check=True)
def тест_E_без_xc(rusi: str):
"""Тест -E без -xc"""
result = subprocess.run([rusi, '-E', '-'],
input='foo', capture_output=True, text=True)
проверка_содержимого(result.stdout, 'foo', "препроцессинг без -xc не прошел")
def тест_a_архив(rusi: str, tmp: str):
"""Тест работы с архивными файлами (.a)"""
foo_o = os.path.join(tmp, 'foo.o')
bar_o = os.path.join(tmp, 'bar.o')
subprocess.run([rusi, '-c', '-xc', '-o', foo_o, '-'],
input='void foo() {}', text=True, check=True)
subprocess.run([rusi, '-c', '-xc', '-o', bar_o, '-'],
input='void bar() {}', text=True, check=True)
foo_a = os.path.join(tmp, 'foo.a')
subprocess.run(['ar', 'rcs', foo_a, foo_o, bar_o], check=True)
main_c = os.path.join(tmp, 'main.c')
with open(main_c, 'w') as f:
f.write('void foo(); void bar(); int main() { foo(); bar(); }')
foo_exe = os.path.join(tmp, 'foo')
subprocess.run([rusi, '-o', foo_exe, main_c, foo_a], check=True)
def тест_so_библиотека(rusi: str, tmp: str):
"""Тест работы с динамическими библиотеками (.so)"""
foo_o = os.path.join(tmp, 'foo.o')
bar_o = os.path.join(tmp, 'bar.o')
subprocess.run(['cc', '-fPIC', '-c', '-xc', '-o', foo_o, '-'],
input='void foo() {}', text=True, check=True)
subprocess.run(['cc', '-fPIC', '-c', '-xc', '-o', bar_o, '-'],
input='void bar() {}', text=True, check=True)
foo_so = os.path.join(tmp, 'foo.so')
subprocess.run(['cc', '-shared', '-o', foo_so, foo_o, bar_o], check=True)
main_c = os.path.join(tmp, 'main.c')
with open(main_c, 'w') as f:
f.write('void foo(); void bar(); int main() { foo(); bar(); }')
foo_exe = os.path.join(tmp, 'foo')
subprocess.run([rusi, '-o', foo_exe, main_c, foo_so], check=True)
def тест_хеш_таблица(rusi: str):
"""Тест хеш-таблицы"""
subprocess.run([rusi, '-hashmap-test'], check=True)
def тест_M(rusi: str, tmp: str):
"""Тест -M"""
out_c = os.path.join(tmp, 'out.c')
with open(out_c, 'w') as f:
f.write('#include "out2.h"\n')
f.write('#include "out3.h"\n')
out2_h = os.path.join(tmp, 'out2.h')
out3_h = os.path.join(tmp, 'out3.h')
for f in [out2_h, out3_h]:
with open(f, 'w') as fh:
fh.write('')
result = subprocess.run([rusi, '-M', f'-I{tmp}', out_c],
capture_output=True, text=True)
проверка_содержимого(result.stdout, 'out.o:', "цель out.o не найдена")
проверка_содержимого(result.stdout, 'out.c', "зависимость out.c не найдена")
проверка_содержимого(result.stdout, 'out2.h', "зависимость out2.h не найдена")
проверка_содержимого(result.stdout, 'out3.h', "зависимость out3.h не найдена")
def тест_MF(rusi: str, tmp: str):
"""Тест -MF"""
out_c = os.path.join(tmp, 'out.c')
with open(out_c, 'w') as f:
f.write('#include "out2.h"\n')
f.write('#include "out3.h"\n')
out2_h = os.path.join(tmp, 'out2.h')
out3_h = os.path.join(tmp, 'out3.h')
for f in [out2_h, out3_h]:
with open(f, 'w') as fh:
fh.write('')
mf_file = os.path.join(tmp, 'mf')
subprocess.run([rusi, '-MF', mf_file, '-M', f'-I{tmp}', out_c], check=True)
with open(mf_file) as f:
content = f.read()
проверка_содержимого(content, 'out.o:', "цель out.o не найдена в MF")
проверка_содержимого(content, 'out.c', "зависимость out.c не найдена в MF")
проверка_содержимого(content, 'out2.h', "зависимость out2.h не найдена в MF")
проверка_содержимого(content, 'out3.h', "зависимость out3.h не найдена в MF")
def тест_MP(rusi: str, tmp: str):
"""Тест -MP"""
out_c = os.path.join(tmp, 'out.c')
with open(out_c, 'w') as f:
f.write('#include "out2.h"\n')
f.write('#include "out3.h"\n')
out2_h = os.path.join(tmp, 'out2.h')
out3_h = os.path.join(tmp, 'out3.h')
for f in [out2_h, out3_h]:
with open(f, 'w') as fh:
fh.write('')
mp_file = os.path.join(tmp, 'mp')
subprocess.run([rusi, '-MF', mp_file, '-MP', '-M', f'-I{tmp}', out_c], check=True)
with open(mp_file) as f:
content = f.read()
if not re.search(r'out2\.h:', content):
raise AssertionError("цель out2.h не найдена в MP")
if not re.search(r'out3\.h:', content):
raise AssertionError("цель out3.h не найдена в MP")
def тест_MT(rusi: str, tmp: str):
"""Тест -MT"""
out_c = os.path.join(tmp, 'out.c')
with open(out_c, 'w') as f:
f.write('#include "out2.h"\n')
out2_h = os.path.join(tmp, 'out2.h')
with open(out2_h, 'w') as f:
f.write('')
result = subprocess.run([rusi, '-MT', 'foo', '-M', f'-I{tmp}', out_c],
capture_output=True, text=True)
if not result.stdout.startswith('foo:'):
raise AssertionError("цель не изменена на foo")
def тест_MT_несколько(rusi: str, tmp: str):
"""Тест -MT с несколькими целями"""
out_c = os.path.join(tmp, 'out.c')
with open(out_c, 'w') as f:
f.write('#include "out2.h"\n')
out2_h = os.path.join(tmp, 'out2.h')
with open(out2_h, 'w') as f:
f.write('')
result = subprocess.run([rusi, '-MT', 'foo', '-MT', 'bar', '-M', f'-I{tmp}', out_c],
capture_output=True, text=True)
if not result.stdout.startswith('foo bar:'):
raise AssertionError("несколько целей не установлены")
def тест_MD(rusi: str, tmp: str):
"""Тест -MD"""
md2_c = os.path.join(tmp, 'md2.c')
md3_c = os.path.join(tmp, 'md3.c')
with open(md2_c, 'w') as f:
f.write('#include "out2.h"\n')
with open(md3_c, 'w') as f:
f.write('#include "out3.h"\n')
out2_h = os.path.join(tmp, 'out2.h')
out3_h = os.path.join(tmp, 'out3.h')
for f in [out2_h, out3_h]:
with open(f, 'w') as fh:
fh.write('')
old_pwd = os.getcwd()
os.chdir(tmp)
try:
subprocess.run([os.path.join(old_pwd, rusi), '-c', '-MD', '-I.', 'md2.c', 'md3.c'], check=True)
finally:
os.chdir(old_pwd)
md2_d = os.path.join(tmp, 'md2.d')
md3_d = os.path.join(tmp, 'md3.d')
with open(md2_d) as f:
content = f.read()
проверка_содержимого(content, 'md2.o:', "цель md2.o не найдена в MD")
проверка_содержимого(content, 'md2.c', "зависимость md2.c не найдена в MD")
проверка_содержимого(content, 'out2.h', "зависимость out2.h не найдена в MD")
with open(md3_d) as f:
content = f.read()
проверка_содержимого(content, 'md3.o:', "цель md3.o не найдена в MD")
проверка_содержимого(content, 'md3.c', "зависимость md3.c не найдена в MD")
проверка_содержимого(content, 'out3.h', "зависимость out3.h не найдена в MD")
def тест_MD_MF(rusi: str, tmp: str):
"""Тест -MD с -MF"""
md2_c = os.path.join(tmp, 'md2.c')
with open(md2_c, 'w') as f:
f.write('#include "out2.h"\n')
out2_h = os.path.join(tmp, 'out2.h')
with open(out2_h, 'w') as f:
f.write('')
md_mf_d = os.path.join(tmp, 'md-mf.d')
subprocess.run([rusi, '-c', '-MD', '-MF', md_mf_d, '-I.', md2_c], check=True)
with open(md_mf_d) as f:
content = f.read()
проверка_содержимого(content, 'md2.o:', "цель md2.o не найдена в MD+MF")
проверка_содержимого(content, 'md2.c', "зависимость md2.c не найдена в MD+MF")
проверка_содержимого(content, 'out2.h', "зависимость out2.h не найдена в MD+MF")
def тест_fPIC(rusi: str, tmp: str):
"""Тест -fPIC"""
foo_o = os.path.join(tmp, 'foo.o')
subprocess.run([rusi, '-fPIC', '-xc', '-c', '-o', foo_o, '-'],
input='extern int bar; int foo() { return bar; }', text=True, check=True)
foo_so = os.path.join(tmp, 'foo.so')
subprocess.run(['cc', '-shared', '-o', foo_so, foo_o], check=True)
main_c = os.path.join(tmp, 'main.c')
with open(main_c, 'w') as f:
f.write('int foo(); int bar=3; int main() { foo(); }')
foo_exe = os.path.join(tmp, 'foo')
subprocess.run([rusi, '-o', foo_exe, main_c, foo_so], check=True)
def тест_include_next(rusi: str, tmp: str):
"""Тест #include_next"""
next1 = os.path.join(tmp, 'next1')
next2 = os.path.join(tmp, 'next2')
next3 = os.path.join(tmp, 'next3')
os.makedirs(next1, exist_ok=True)
os.makedirs(next2, exist_ok=True)
os.makedirs(next3, exist_ok=True)
file_c = os.path.join(tmp, 'file.c')
with open(file_c, 'w') as f:
f.write('#include "file1.h"\n')
with open(os.path.join(next1, 'file1.h'), 'w') as f:
f.write('#include_next "file1.h"\n')
with open(os.path.join(next2, 'file1.h'), 'w') as f:
f.write('#include_next "file2.h"\n')
with open(os.path.join(next3, 'file2.h'), 'w') as f:
f.write('foo')
result = subprocess.run([rusi, f'-I{next1}', f'-I{next2}', f'-I{next3}', '-E', file_c],
capture_output=True, text=True)
проверка_содержимого(result.stdout, 'foo', "цепочка include_next не привела к foo")
def тест_static(rusi: str, tmp: str):
"""Тест -static"""
foo_c = os.path.join(tmp, 'foo.c')
bar_c = os.path.join(tmp, 'bar.c')
with open(foo_c, 'w') as f:
f.write('extern int bar; int foo() { return bar; }')
with open(bar_c, 'w') as f:
f.write('int foo(); int bar=3; int main() { foo(); }')
foo_exe = os.path.join(tmp, 'foo')
subprocess.run([rusi, '-static', '-o', foo_exe, foo_c, bar_c], check=True)
result = subprocess.run(['file', foo_exe], capture_output=True, text=True)
if 'statically linked' not in result.stdout:
raise AssertionError("файл не является статически слинкованным")
def тест_shared(rusi: str, tmp: str):
"""Тест -shared"""
foo_so = os.path.join(tmp, 'foo.so')
foo_c = os.path.join(tmp, 'foo.c')
bar_c = os.path.join(tmp, 'bar.c')
with open(foo_c, 'w') as f:
f.write('extern int bar; int foo() { return bar; }')
with open(bar_c, 'w') as f:
f.write('int foo(); int bar=3; int main() { foo(); }')
subprocess.run([rusi, '-fPIC', '-shared', '-o', foo_so, foo_c, bar_c], check=True)
def тест_L(rusi: str, tmp: str):
"""Тест -L"""
foo_c = os.path.join(tmp, 'foo.c')
with open(foo_c, 'w') as f:
f.write('extern int bar; int foo() { return bar; }')
libfoobar_so = os.path.join(tmp, 'libfoobar.so')
subprocess.run([rusi, '-fPIC', '-shared', '-o', libfoobar_so, foo_c], check=True)
bar_c = os.path.join(tmp, 'bar.c')
with open(bar_c, 'w') as f:
f.write('int foo(); int bar=3; int main() { foo(); }')
foo_exe = os.path.join(tmp, 'foo')
subprocess.run([rusi, '-o', foo_exe, bar_c, f'-L{tmp}', '-lfoobar'], check=True)
def тест_Wl(rusi: str, tmp: str):
"""Тест -Wl,"""
foo_o = os.path.join(tmp, 'foo.o')
bar_o = os.path.join(tmp, 'bar.o')
baz_o = os.path.join(tmp, 'baz.o')
subprocess.run([rusi, '-c', '-o', foo_o, '-xc', '-'],
input='int foo() {}', text=True, check=True)
subprocess.run([rusi, '-c', '-o', bar_o, '-xc', '-'],
input='int foo() {}', text=True, check=True)
subprocess.run([rusi, '-c', '-o', baz_o, '-xc', '-'],
input='int main() {}', text=True, check=True)
foo_exe = os.path.join(tmp, 'foo')
subprocess.run(['cc', '-Wl,-z,muldefs,--gc-sections', '-o', foo_exe, foo_o, bar_o, baz_o], check=True)
def тест_Xlinker(rusi: str, tmp: str):
"""Тест -Xlinker"""
foo_o = os.path.join(tmp, 'foo.o')
bar_o = os.path.join(tmp, 'bar.o')
baz_o = os.path.join(tmp, 'baz.o')
subprocess.run([rusi, '-c', '-o', foo_o, '-xc', '-'],
input='int foo() {}', text=True, check=True)
subprocess.run([rusi, '-c', '-o', bar_o, '-xc', '-'],
input='int foo() {}', text=True, check=True)
subprocess.run([rusi, '-c', '-o', baz_o, '-xc', '-'],
input='int main() {}', text=True, check=True)
foo_exe = os.path.join(tmp, 'foo')
subprocess.run(['cc', '-Xlinker', '-z', '-Xlinker', 'muldefs', '-Xlinker', '--gc-sections',
'-o', foo_exe, foo_o, bar_o, baz_o], check=True)
if __name__ == '__main__':
main()

19
test/enum.c Normal file
View file

@ -0,0 +1,19 @@
#включить "тест.з"
#включить "stdvv.c"
цел главн() {
ПРОВЕРИТЬ(0, ({ переч { ноль, один, два }; ноль; }));
ПРОВЕРИТЬ(1, ({ переч { ноль, один, два }; один; }));
ПРОВЕРИТЬ(2, ({ переч { ноль, один, два }; два; }));
ПРОВЕРИТЬ(5, ({ переч { пять=5, шесть, семь }; пять; }));
ПРОВЕРИТЬ(6, ({ переч { пять=5, шесть, семь }; шесть; }));
ПРОВЕРИТЬ(0, ({ переч { ноль, пять=5, три=3, четыре }; ноль; }));
ПРОВЕРИТЬ(5, ({ переч { ноль, пять=5, три=3, четыре }; пять; }));
ПРОВЕРИТЬ(3, ({ переч { ноль, пять=5, три=3, четыре }; три; }));
ПРОВЕРИТЬ(4, ({ переч { ноль, пять=5, три=3, четыре }; четыре; }));
ПРОВЕРИТЬ(4, ({ переч { ноль, один, два } х; размер(х); }));
ПРОВЕРИТЬ(4, ({ переч т { ноль, один, два }; переч т у; размер(у); }));
printf("OK\n");
возврат 0;
}

27
test/extern.c Normal file
View file

@ -0,0 +1,27 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
extern int ext1;
extern int *ext2;
inline int inline_fn(void) {
return 3;
}
int main() {
ASSERT(5, ext1);
ASSERT(5, *ext2);
extern int ext3;
ASSERT(7, ext3);
int ext_fn1(int x);
ASSERT(5, ext_fn1(5));
extern int ext_fn2(int x);
ASSERT(8, ext_fn2(8));
printf("OK\n");
return 0;
}

94
test/float.c Normal file
View file

@ -0,0 +1,94 @@
#включить "тест.з"
#включить "stdvv.c"
цел главн() {
ПРОВЕРИТЬ(35, (плав)(символ)35);
ПРОВЕРИТЬ(35, (плав)(корот)35);
ПРОВЕРИТЬ(35, (плав)(цел)35);
ПРОВЕРИТЬ(35, (плав)(длин)35);
ПРОВЕРИТЬ(35, (плав)(беззнак символ)35);
ПРОВЕРИТЬ(35, (плав)(беззнак корот)35);
ПРОВЕРИТЬ(35, (плав)(беззнак цел)35);
ПРОВЕРИТЬ(35, (плав)(беззнак длин)35);
ПРОВЕРИТЬ(35, (двойн)(символ)35);
ПРОВЕРИТЬ(35, (двойн)(корот)35);
ПРОВЕРИТЬ(35, (двойн)(цел)35);
ПРОВЕРИТЬ(35, (двойн)(длин)35);
ПРОВЕРИТЬ(35, (двойн)(беззнак символ)35);
ПРОВЕРИТЬ(35, (двойн)(беззнак корот)35);
ПРОВЕРИТЬ(35, (двойн)(беззнак цел)35);
ПРОВЕРИТЬ(35, (двойн)(беззнак длин)35);
ПРОВЕРИТЬ(35, (символ)(плав)35);
ПРОВЕРИТЬ(35, (корот)(плав)35);
ПРОВЕРИТЬ(35, (цел)(плав)35);
ПРОВЕРИТЬ(35, (длин)(плав)35);
ПРОВЕРИТЬ(35, (беззнак символ)(плав)35);
ПРОВЕРИТЬ(35, (беззнак корот)(плав)35);
ПРОВЕРИТЬ(35, (беззнак цел)(плав)35);
ПРОВЕРИТЬ(35, (беззнак длин)(плав)35);
ПРОВЕРИТЬ(35, (символ)(двойн)35);
ПРОВЕРИТЬ(35, (корот)(двойн)35);
ПРОВЕРИТЬ(35, (цел)(двойн)35);
ПРОВЕРИТЬ(35, (длин)(двойн)35);
ПРОВЕРИТЬ(35, (беззнак символ)(двойн)35);
ПРОВЕРИТЬ(35, (беззнак корот)(двойн)35);
ПРОВЕРИТЬ(35, (беззнак цел)(двойн)35);
ПРОВЕРИТЬ(35, (беззнак длин)(двойн)35);
ПРОВЕРИТЬ(-2147483648, (двойн)(беззнак длин)(длин)-1);
ПРОВЕРИТЬ(1, 2e3==2e3);
ПРОВЕРИТЬ(0, 2e3==2e5);
ПРОВЕРИТЬ(1, 2.0==2);
ПРОВЕРИТЬ(0, 5.1<5);
ПРОВЕРИТЬ(0, 5.0<5);
ПРОВЕРИТЬ(1, 4.9<5);
ПРОВЕРИТЬ(0, 5.1<=5);
ПРОВЕРИТЬ(1, 5.0<=5);
ПРОВЕРИТЬ(1, 4.9<=5);
ПРОВЕРИТЬ(1, 2e3f==2e3);
ПРОВЕРИТЬ(0, 2e3f==2e5);
ПРОВЕРИТЬ(1, 2.0f==2);
ПРОВЕРИТЬ(0, 5.1f<5);
ПРОВЕРИТЬ(0, 5.0f<5);
ПРОВЕРИТЬ(1, 4.9f<5);
ПРОВЕРИТЬ(0, 5.1f<=5);
ПРОВЕРИТЬ(1, 5.0f<=5);
ПРОВЕРИТЬ(1, 4.9f<=5);
ПРОВЕРИТЬ(6, 2.3+3.8);
ПРОВЕРИТЬ(-1, 2.3-3.8);
ПРОВЕРИТЬ(-3, -3.8);
ПРОВЕРИТЬ(13, 3.3*4);
ПРОВЕРИТЬ(2, 5.0/2);
ПРОВЕРИТЬ(6, 2.3f+3.8f);
ПРОВЕРИТЬ(6, 2.3f+3.8);
ПРОВЕРИТЬ(-1, 2.3f-3.8);
ПРОВЕРИТЬ(-3, -3.8f);
ПРОВЕРИТЬ(13, 3.3f*4);
ПРОВЕРИТЬ(2, 5.0f/2);
ПРОВЕРИТЬ(0, 0.0/0.0 == 0.0/0.0);
ПРОВЕРИТЬ(1, 0.0/0.0 != 0.0/0.0);
ПРОВЕРИТЬ(0, 0.0/0.0 < 0);
ПРОВЕРИТЬ(0, 0.0/0.0 <= 0);
ПРОВЕРИТЬ(0, 0.0/0.0 > 0);
ПРОВЕРИТЬ(0, 0.0/0.0 >= 0);
ПРОВЕРИТЬ(0, !3.);
ПРОВЕРИТЬ(1, !0.);
ПРОВЕРИТЬ(0, !3.f);
ПРОВЕРИТЬ(1, !0.f);
ПРОВЕРИТЬ(5, 0.0 ? 3 : 5);
ПРОВЕРИТЬ(3, 1.2 ? 3 : 5);
printf("OK\n");
возврат 0;
}

397
test/function.c Normal file
View file

@ -0,0 +1,397 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
int ret3(void) {
return 3;
return 5;
}
int add2(int x, int y) {
return x + y;
}
int sub2(int x, int y) {
return x - y;
}
int add6(int a, int b, int c, int d, int e, int f) {
return a + b + c + d + e + f;
}
int addx(int *x, int y) {
return *x + y;
}
int sub_char(char a, char b, char c) {
return a - b - c;
}
int fib(int x) {
if (x<=1)
return 1;
return fib(x-1) + fib(x-2);
}
int sub_long(long a, long b, long c) {
return a - b - c;
}
int sub_short(short a, short b, short c) {
return a - b - c;
}
int g1;
int *g1_ptr(void) { return &g1; }
char int_to_char(int x) { return x; }
int div_long(long a, long b) {
return a / b;
}
_Bool bool_fn_add(_Bool x) { return x + 1; }
_Bool bool_fn_sub(_Bool x) { return x - 1; }
int param_decay(int x[]) { return x[0]; }
int counter() {
static int i;
static int j = 1+1;
return i++ + j++;
}
void ret_none() {
return;
}
_Bool true_fn();
_Bool false_fn();
char char_fn();
short short_fn();
unsigned char uchar_fn();
unsigned short ushort_fn();
char schar_fn();
short sshort_fn();
int add_all(int n, ...);
typedef struct {
int gp_offset;
int fp_offset;
void *overflow_arg_area;
void *reg_save_area;
} __va_elem;
typedef __va_elem va_list[1];
int add_all(int n, ...);
int sprintf(char *buf, char *fmt, ...);
int vsprintf(char *buf, char *fmt, va_list ap);
char *fmt(char *buf, char *fmt, ...) {
va_list ap;
*ap = *(__va_elem *)__va_area__;
vsprintf(buf, fmt, ap);
}
double add_double(double x, double y);
float add_float(float x, float y);
float add_float3(float x, float y, float z) {
return x + y + z;
}
double add_double3(double x, double y, double z) {
return x + y + z;
}
int (*fnptr(int (*fn)(int n, ...)))(int, ...) {
return fn;
}
int param_decay2(int x()) { return x(); }
char *func_fn(void) {
return __func__;
}
char *function_fn(void) {
return __FUNCTION__;
}
int add10_int(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10);
float add10_float(float x1, float x2, float x3, float x4, float x5, float x6, float x7, float x8, float x9, float x10);
double add10_double(double x1, double x2, double x3, double x4, double x5, double x6, double x7, double x8, double x9, double x10);
int many_args1(int a, int b, int c, int d, int e, int f, int g, int h) {
return g / h;
}
double many_args2(double a, double b, double c, double d, double e,
double f, double g, double h, double i, double j) {
return i / j;
}
int many_args3(int a, double b, int c, int d, double e, int f,
double g, int h, double i, double j, double k,
double l, double m, int n, int o, double p) {
return o / p;
}
typedef struct { int a,b; short c; char d; } Ty4;
typedef struct { int a; float b; double c; } Ty5;
typedef struct { unsigned char a[3]; } Ty6;
typedef struct { long a, b, c; } Ty7;
int struct_test5(Ty5 x, int n);
int struct_test4(Ty4 x, int n);
int struct_test6(Ty6 x, int n);
int struct_test7(Ty7 x, int n);
int struct_test14(Ty4 x, int n) {
switch (n) {
case 0: return x.a;
case 1: return x.b;
case 2: return x.c;
default: return x.d;
}
}
int struct_test15(Ty5 x, int n) {
switch (n) {
case 0: return x.a;
case 1: return x.b;
default: return x.c;
}
}
typedef struct { unsigned char a[10]; } Ty20;
typedef struct { unsigned char a[20]; } Ty21;
Ty4 struct_test24(void);
Ty5 struct_test25(void);
Ty6 struct_test26(void);
Ty20 struct_test27(void);
Ty21 struct_test28(void);
Ty4 struct_test34(void) {
return (Ty4){10, 20, 30, 40};
}
Ty5 struct_test35(void) {
return (Ty5){10, 20, 30};
}
Ty6 struct_test36(void) {
return (Ty6){10, 20, 30};
}
Ty20 struct_test37(void) {
return (Ty20){10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
}
Ty21 struct_test38(void) {
return (Ty21){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
}
inline int inline_fn(void) {
return 3;
}
double to_double(long double x) {
return x;
}
long double to_ldouble(int x) {
return x;
}
int main() {
ASSERT(3, ret3());
ASSERT(8, add2(3, 5));
ASSERT(2, sub2(5, 3));
ASSERT(21, add6(1,2,3,4,5,6));
ASSERT(66, add6(1,2,add6(3,4,5,6,7,8),9,10,11));
ASSERT(136, add6(1,2,add6(3,add6(4,5,6,7,8,9),10,11,12,13),14,15,16));
ASSERT(7, add2(3,4));
ASSERT(1, sub2(4,3));
ASSERT(55, fib(9));
ASSERT(1, ({ sub_char(7, 3, 3); }));
ASSERT(1, sub_long(7, 3, 3));
ASSERT(1, sub_short(7, 3, 3));
g1 = 3;
ASSERT(3, *g1_ptr());
ASSERT(5, int_to_char(261));
ASSERT(5, int_to_char(261));
ASSERT(-5, div_long(-10, 2));
ASSERT(1, bool_fn_add(3));
ASSERT(0, bool_fn_sub(3));
ASSERT(1, bool_fn_add(-3));
ASSERT(0, bool_fn_sub(-3));
ASSERT(1, bool_fn_add(0));
ASSERT(1, bool_fn_sub(0));
ASSERT(5, static_fn());
ASSERT(3, ({ int x[2]; x[0]=3; param_decay(x); }));
ASSERT(2, counter());
ASSERT(4, counter());
ASSERT(6, counter());
ret_none();
// Используем значения из common.c (без переопределения функций)
ASSERT(513, true_fn());
ASSERT(512, false_fn());
ASSERT(515, char_fn()); // (2<<8)+3 = 515
ASSERT(131077, short_fn()); // (2<<16)+5 = 131077
ASSERT(6, add_all(3,1,2,3));
ASSERT(5, add_all(4,1,2,3,-1));
{ char buf[100]; fmt(buf, "%d %d %s", 1, 2, "foo"); printf("%s\n", buf); }
ASSERT(0, ({ char buf[100]; sprintf(buf, "%d %d %s", 1, 2, "foo"); strcmp("1 2 foo", buf); }));
ASSERT(0, ({ char buf[100]; fmt(buf, "%d %d %s", 1, 2, "foo"); strcmp("1 2 foo", buf); }));
ASSERT(2043, uchar_fn());
ASSERT(2097144, ushort_fn());
ASSERT(2043, schar_fn());
ASSERT(2097144, sshort_fn());
ASSERT(6, add_float(2.3, 3.8));
ASSERT(6, add_double(2.3, 3.8));
ASSERT(7, add_float3(2.5, 2.5, 2.5));
ASSERT(7, add_double3(2.5, 2.5, 2.5));
ASSERT(0, ({ char buf[100]; sprintf(buf, "%.1f", (float)3.5); strcmp(buf, "3.5"); }));
ASSERT(0, ({ char buf[100]; fmt(buf, "%.1f", (float)3.5); strcmp(buf, "3.5"); }));
ASSERT(5, (add2)(2,3));
ASSERT(5, (&add2)(2,3));
ASSERT(7, ({ int (*fn)(int,int) = add2; fn(2,5); }));
ASSERT(6, fnptr(add_all)(3, 1, 2, 3));
ASSERT(3, param_decay2(ret3));
ASSERT(5, sizeof(__func__));
ASSERT(0, strcmp("main", __func__));
ASSERT(0, strcmp("func_fn", func_fn()));
ASSERT(0, strcmp("main", __FUNCTION__));
ASSERT(0, strcmp("function_fn", function_fn()));
ASSERT(55, add10_int(1,2,3,4,5,6,7,8,9,10));
ASSERT(55, add10_float(1,2,3,4,5,6,7,8,9,10));
ASSERT(55, add10_double(1,2,3,4,5,6,7,8,9,10));
ASSERT(0, ({ char buf[200]; sprintf(buf, "%d %.1f %.1f %.1f %d %d %.1f %d %d %d %d %.1f %d %d %.1f %.1f %.1f %.1f %d", 1, 1.0, 1.0, 1.0, 1, 1, 1.0, 1, 1, 1, 1, 1.0, 1, 1, 1.0, 1.0, 1.0, 1.0, 1); strcmp("1 1.0 1.0 1.0 1 1 1.0 1 1 1 1 1.0 1 1 1.0 1.0 1.0 1.0 1", buf); }));
ASSERT(4, many_args1(1,2,3,4,5,6,40,10));
ASSERT(4, many_args2(1,2,3,4,5,6,7,8,40,10));
ASSERT(8, many_args3(1,2,3,4,5,6,7,8,9,10,11,12,13,14,80,10));
ASSERT(10, ({ Ty4 x={10,20,30,40}; struct_test4(x, 0); }));
ASSERT(20, ({ Ty4 x={10,20,30,40}; struct_test4(x, 1); }));
ASSERT(30, ({ Ty4 x={10,20,30,40}; struct_test4(x, 2); }));
ASSERT(40, ({ Ty4 x={10,20,30,40}; struct_test4(x, 3); }));
ASSERT(10, ({ Ty5 x={10,20,30}; struct_test5(x, 0); }));
ASSERT(20, ({ Ty5 x={10,20,30}; struct_test5(x, 1); }));
ASSERT(30, ({ Ty5 x={10,20,30}; struct_test5(x, 2); }));
ASSERT(10, ({ Ty6 x={10,20,30}; struct_test6(x, 0); }));
ASSERT(20, ({ Ty6 x={10,20,30}; struct_test6(x, 1); }));
ASSERT(30, ({ Ty6 x={10,20,30}; struct_test6(x, 2); }));
ASSERT(10, ({ Ty7 x={10,20,30}; struct_test7(x, 0); }));
ASSERT(20, ({ Ty7 x={10,20,30}; struct_test7(x, 1); }));
ASSERT(30, ({ Ty7 x={10,20,30}; struct_test7(x, 2); }));
ASSERT(10, ({ Ty4 x={10,20,30,40}; struct_test14(x, 0); }));
ASSERT(20, ({ Ty4 x={10,20,30,40}; struct_test14(x, 1); }));
ASSERT(30, ({ Ty4 x={10,20,30,40}; struct_test14(x, 2); }));
ASSERT(40, ({ Ty4 x={10,20,30,40}; struct_test14(x, 3); }));
ASSERT(10, ({ Ty5 x={10,20,30}; struct_test15(x, 0); }));
ASSERT(20, ({ Ty5 x={10,20,30}; struct_test15(x, 1); }));
ASSERT(30, ({ Ty5 x={10,20,30}; struct_test15(x, 2); }));
ASSERT(10, struct_test24().a);
ASSERT(20, struct_test24().b);
ASSERT(30, struct_test24().c);
ASSERT(40, struct_test24().d);
ASSERT(10, struct_test25().a);
ASSERT(20, struct_test25().b);
ASSERT(30, struct_test25().c);
ASSERT(10, struct_test26().a[0]);
ASSERT(20, struct_test26().a[1]);
ASSERT(30, struct_test26().a[2]);
ASSERT(10, struct_test27().a[0]);
ASSERT(60, struct_test27().a[5]);
ASSERT(100, struct_test27().a[9]);
ASSERT(1, struct_test28().a[0]);
ASSERT(5, struct_test28().a[4]);
ASSERT(10, struct_test28().a[9]);
ASSERT(15, struct_test28().a[14]);
ASSERT(20, struct_test28().a[19]);
ASSERT(10, struct_test34().a);
ASSERT(20, struct_test34().b);
ASSERT(30, struct_test34().c);
ASSERT(40, struct_test34().d);
ASSERT(10, struct_test35().a);
ASSERT(20, struct_test35().b);
ASSERT(30, struct_test35().c);
ASSERT(10, struct_test36().a[0]);
ASSERT(20, struct_test36().a[1]);
ASSERT(30, struct_test36().a[2]);
ASSERT(10, struct_test37().a[0]);
ASSERT(60, struct_test37().a[5]);
ASSERT(100, struct_test37().a[9]);
ASSERT(1, struct_test38().a[0]);
ASSERT(5, struct_test38().a[4]);
ASSERT(10, struct_test38().a[9]);
ASSERT(15, struct_test38().a[14]);
ASSERT(20, struct_test38().a[19]);
ASSERT(5, (***add2)(2,3));
ASSERT(3, inline_fn());
ASSERT(0, ({ char buf[100]; sprintf(buf, "%Lf", (long double)12.3); strncmp(buf, "12.3", 4); }));
ASSERT(1, to_double(3.5) == 3.5);
ASSERT(0, to_double(3.5) == 3);
ASSERT(1, (long double)5.0 == (long double)5.0);
ASSERT(0, (long double)5.0 == (long double)5.2);
ASSERT(1, to_ldouble(5.0) == 5.0);
ASSERT(0, to_ldouble(5.0) == 5.2);
печатьф("OK\n");
}

13
test/generic.c Normal file
View file

@ -0,0 +1,13 @@
#включить "тест.з"
#включить "stdvv.c"
цел главн() {
ПРОВЕРИТЬ(1, _Обобщ(100.0, двойн: 1, цел *: 2, цел: 3, плав: 4));
ПРОВЕРИТЬ(2, _Обобщ((цел *)0, двойн: 1, цел *: 2, цел: 3, плав: 4));
ПРОВЕРИТЬ(2, _Обобщ((цел[3]){}, двойн: 1, цел *: 2, цел: 3, плав: 4));
ПРОВЕРИТЬ(3, _Обобщ(100, двойн: 1, цел *: 2, цел: 3, плав: 4));
ПРОВЕРИТЬ(4, _Обобщ(100f, двойн: 1, цел *: 2, цел: 3, плав: 4));
printf("OK\n");
возврат 0;
}

6
test/include1.h Normal file
View file

@ -0,0 +1,6 @@
#include "include2.h"
char *include1_filename = __FILE__;
int include1_line = __LINE__;
int include1 = 5;

1
test/include2.h Normal file
View file

@ -0,0 +1 @@
int include2 = 7;

1
test/include3.h Normal file
View file

@ -0,0 +1 @@
#define foo 3

1
test/include4.h Normal file
View file

@ -0,0 +1 @@
#define foo 4

269
test/initializer.c Normal file
View file

@ -0,0 +1,269 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
char g3 = 3;
short g4 = 4;
int g5 = 5;
long g6 = 6;
int g9[3] = {0, 1, 2};
struct {char a; int b;} g11[2] = {{1, 2}, {3, 4}};
struct {int a[2];} g12[2] = {{{1, 2}}};
union { int a; char b[8]; } g13[2] = {0x01020304, 0x05060708};
char g17[] = "foobar";
char g18[10] = "foobar";
char g19[3] = "foobar";
char *g20 = g17+0;
char *g21 = g17+3;
char *g22 = &g17-3;
char *g23[] = {g17+0, g17+3, g17-3};
int g24=3;
int *g25=&g24;
int g26[3] = {1, 2, 3};
int *g27 = g26 + 1;
int *g28 = &g11[1].a;
long g29 = (long)(long)g26;
struct { struct { int a[3]; } a; } g30 = {{{1,2,3}}};
int *g31=g30.a.a;
struct {int a[2];} g40[2] = {{1, 2}, 3, 4};
struct {int a[2];} g41[2] = {1, 2, 3, 4};
char g43[][4] = {'f', 'o', 'o', 0, 'b', 'a', 'r', 0};
char *g44 = {"foo"};
union { int a; char b[4]; } g50 = {.b[2]=0x12};
union { int a; } g51[2] = {};
typedef char T60[];
T60 g60 = {1, 2, 3};
T60 g61 = {1, 2, 3, 4, 5, 6};
typedef struct { char a, b[]; } T65;
T65 g65 = {'f','o','o',0};
T65 g66 = {'f','o','o','b','a','r',0};
int main() {
ASSERT(1, ({ int x[3]={1,2,3}; x[0]; }));
ASSERT(2, ({ int x[3]={1,2,3}; x[1]; }));
ASSERT(3, ({ int x[3]={1,2,3}; x[2]; }));
ASSERT(3, ({ int x[3]={1,2,3}; x[2]; }));
ASSERT(2, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[0][1]; }));
ASSERT(4, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[1][0]; }));
ASSERT(6, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[1][2]; }));
ASSERT(0, ({ int x[3]={}; x[0]; }));
ASSERT(0, ({ int x[3]={}; x[1]; }));
ASSERT(0, ({ int x[3]={}; x[2]; }));
ASSERT(2, ({ int x[2][3]={{1,2}}; x[0][1]; }));
ASSERT(0, ({ int x[2][3]={{1,2}}; x[1][0]; }));
ASSERT(0, ({ int x[2][3]={{1,2}}; x[1][2]; }));
ASSERT('a', ({ char x[4]="abc"; x[0]; }));
ASSERT('c', ({ char x[4]="abc"; x[2]; }));
ASSERT(0, ({ char x[4]="abc"; x[3]; }));
ASSERT('a', ({ char x[2][4]={"abc","def"}; x[0][0]; }));
ASSERT(0, ({ char x[2][4]={"abc","def"}; x[0][3]; }));
ASSERT('d', ({ char x[2][4]={"abc","def"}; x[1][0]; }));
ASSERT('f', ({ char x[2][4]={"abc","def"}; x[1][2]; }));
ASSERT(4, ({ int x[]={1,2,3,4}; x[3]; }));
ASSERT(16, ({ int x[]={1,2,3,4}; sizeof(x); }));
ASSERT(4, ({ char x[]="foo"; sizeof(x); }));
ASSERT(4, ({ typedef char T[]; T x="foo"; T y="x"; sizeof(x); }));
ASSERT(2, ({ typedef char T[]; T x="foo"; T y="x"; sizeof(y); }));
ASSERT(2, ({ typedef char T[]; T x="x"; T y="foo"; sizeof(x); }));
ASSERT(4, ({ typedef char T[]; T x="x"; T y="foo"; sizeof(y); }));
ASSERT(1, ({ struct {int a; int b; int c;} x={1,2,3}; x.a; }));
ASSERT(2, ({ struct {int a; int b; int c;} x={1,2,3}; x.b; }));
ASSERT(3, ({ struct {int a; int b; int c;} x={1,2,3}; x.c; }));
ASSERT(1, ({ struct {int a; int b; int c;} x={1}; x.a; }));
ASSERT(0, ({ struct {int a; int b; int c;} x={1}; x.b; }));
ASSERT(0, ({ struct {int a; int b; int c;} x={1}; x.c; }));
ASSERT(1, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[0].a; }));
ASSERT(2, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[0].b; }));
ASSERT(3, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[1].a; }));
ASSERT(4, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[1].b; }));
ASSERT(0, ({ struct {int a; int b;} x[2]={{1,2}}; x[1].b; }));
ASSERT(0, ({ struct {int a; int b;} x={}; x.a; }));
ASSERT(0, ({ struct {int a; int b;} x={}; x.b; }));
ASSERT(5, ({ typedef struct {int a,b,c,d,e,f;} T; T x={1,2,3,4,5,6}; T y; y=x; y.e; }));
ASSERT(2, ({ typedef struct {int a,b;} T; T x={1,2}; T y, z; z=y=x; z.b; }));
ASSERT(1, ({ typedef struct {int a,b;} T; T x={1,2}; T y=x; y.a; }));
ASSERT(4, ({ union { int a; char b[4]; } x={0x01020304}; x.b[0]; }));
ASSERT(3, ({ union { int a; char b[4]; } x={0x01020304}; x.b[1]; }));
ASSERT(0x01020304, ({ union { struct { char a,b,c,d; } e; int f; } x={{4,3,2,1}}; x.f; }));
ASSERT(3, g3);
ASSERT(4, g4);
ASSERT(5, g5);
ASSERT(6, g6);
ASSERT(0, g9[0]);
ASSERT(1, g9[1]);
ASSERT(2, g9[2]);
ASSERT(1, g11[0].a);
ASSERT(2, g11[0].b);
ASSERT(3, g11[1].a);
ASSERT(4, g11[1].b);
ASSERT(1, g12[0].a[0]);
ASSERT(2, g12[0].a[1]);
ASSERT(0, g12[1].a[0]);
ASSERT(0, g12[1].a[1]);
ASSERT(4, g13[0].b[0]);
ASSERT(3, g13[0].b[1]);
ASSERT(8, g13[1].b[0]);
ASSERT(7, g13[1].b[1]);
ASSERT(7, sizeof(g17));
ASSERT(10, sizeof(g18));
ASSERT(3, sizeof(g19));
ASSERT(0, memcmp(g17, "foobar", 7));
ASSERT(0, memcmp(g18, "foobar\0\0\0", 10));
ASSERT(0, memcmp(g19, "foo", 3));
ASSERT(0, strcmp(g20, "foobar"));
ASSERT(0, strcmp(g21, "bar"));
ASSERT(0, strcmp(g22+3, "foobar"));
ASSERT(0, strcmp(g23[0], "foobar"));
ASSERT(0, strcmp(g23[1], "bar"));
ASSERT(0, strcmp(g23[2]+3, "foobar"));
ASSERT(3, g24);
ASSERT(3, *g25);
ASSERT(2, *g27);
ASSERT(3, *g28);
ASSERT(1, *(int *)g29);
ASSERT(1, g31[0]);
ASSERT(2, g31[1]);
ASSERT(3, g31[2]);
ASSERT(1, g40[0].a[0]);
ASSERT(2, g40[0].a[1]);
ASSERT(3, g40[1].a[0]);
ASSERT(4, g40[1].a[1]);
ASSERT(1, g41[0].a[0]);
ASSERT(2, g41[0].a[1]);
ASSERT(3, g41[1].a[0]);
ASSERT(4, g41[1].a[1]);
ASSERT(0, ({ int x[2][3]={0,1,2,3,4,5}; x[0][0]; }));
ASSERT(3, ({ int x[2][3]={0,1,2,3,4,5}; x[1][0]; }));
ASSERT(0, ({ struct {int a; int b;} x[2]={0,1,2,3}; x[0].a; }));
ASSERT(2, ({ struct {int a; int b;} x[2]={0,1,2,3}; x[1].a; }));
ASSERT(0, strcmp(g43[0], "foo"));
ASSERT(0, strcmp(g43[1], "bar"));
ASSERT(0, strcmp(g44, "foo"));
ASSERT(3, ({ int a[]={1,2,3,}; a[2]; }));
ASSERT(1, ({ struct {int a,b,c;} x={1,2,3,}; x.a; }));
ASSERT(1, ({ union {int a; char b;} x={1,}; x.a; }));
ASSERT(2, ({ enum {x,y,z,}; z; }));
ASSERT(3, sizeof(g60));
ASSERT(6, sizeof(g61));
ASSERT(4, sizeof(g65));
ASSERT(7, sizeof(g66));
ASSERT(0, strcmp(g65.b, "oo"));
ASSERT(0, strcmp(g66.b, "oobar"));
ASSERT(4, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[0]; }));
ASSERT(5, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[1]; }));
ASSERT(3, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[2]; }));
ASSERT(10, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][0]; }));
ASSERT(11, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][1]; }));
ASSERT(8, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][2]; }));
ASSERT(12, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][0]; }));
ASSERT(5, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][1]; }));
ASSERT(6, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][2]; }));
ASSERT(7, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][0]; }));
ASSERT(8, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][1]; }));
ASSERT(3, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][2]; }));
ASSERT(9, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][0]; }));
ASSERT(10, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][1]; }));
ASSERT(6, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][2]; }));
ASSERT(7, ((int[10]){ [3]=7 })[3]);
ASSERT(0, ((int[10]){ [3]=7 })[4]);
ASSERT(10, ({ char x[]={[10-3]=1,2,3}; sizeof(x); }));
ASSERT(20, ({ char x[][2]={[8][1]=1,2}; sizeof(x); }));
ASSERT(3, sizeof(g60));
ASSERT(6, sizeof(g61));
ASSERT(4, sizeof(g65));
ASSERT(7, sizeof(g66));
ASSERT(0, strcmp(g65.b, "oo"));
ASSERT(0, strcmp(g66.b, "oobar"));
ASSERT(7, ((int[10]){ [3] 7 })[3]);
ASSERT(0, ((int[10]){ [3] 7 })[4]);
ASSERT(4, ({ struct { int a,b; } x={1,2,.b=3,.a=4}; x.a; }));
ASSERT(3, ({ struct { int a,b; } x={1,2,.b=3,.a=4}; x.b; }));
ASSERT(1, ({ struct { struct { int a,b; } c; } x={.c=1,2}; x.c.a; }));
ASSERT(2, ({ struct { struct { int a,b; } c; } x={.c=1,2}; x.c.b; }));
ASSERT(0, ({ struct { struct { int a,b; } c; } x={.c.b=1}; x.c.a; }));
ASSERT(1, ({ struct { struct { int a,b; } c; } x={.c.b=1}; x.c.b; }));
ASSERT(1, ({ struct { int a[2]; } x={.a=1,2}; x.a[0]; }));
ASSERT(2, ({ struct { int a[2]; } x={.a=1,2}; x.a[1]; }));
ASSERT(0, ({ struct { int a[2]; } x={.a[1]=1}; x.a[0]; }));
ASSERT(1, ({ struct { int a[2]; } x={.a[1]=1}; x.a[1]; }));
ASSERT(3, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[0].a; }));
ASSERT(4, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[0].b; }));
ASSERT(0, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[1].a; }));
ASSERT(1, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[1].b; }));
ASSERT(2, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[2].a; }));
ASSERT(0, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[2].b; }));
ASSERT(1, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x}; y[0].a; }));
ASSERT(2, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x}; y[0].b; }));
ASSERT(0, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x, [0].b=3}; y[0].a; }));
ASSERT(3, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x, [0].b=3}; y[0].b; }));
ASSERT(5, ((struct { int a,b,c; }){ .c=5 }).c);
ASSERT(0, ((struct { int a,b,c; }){ .c=5 }).a);
ASSERT(0x00ff, ({ union { unsigned short a; char b[2]; } x={.b[0]=0xff}; x.a; }));
ASSERT(0xff00, ({ union { unsigned short a; char b[2]; } x={.b[1]=0xff}; x.a; }));
ASSERT(0x00120000, g50.a);
ASSERT(0, g51[0].a);
ASSERT(0, g51[1].a);
ASSERT(1, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.a; }));
ASSERT(4, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.b; }));
ASSERT(5, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.c; }));
ASSERT(16, ({ char x[]={[2 ... 10]='a', [7]='b', [15 ... 15]='c', [3 ... 5]='d'}; sizeof(x); }));
ASSERT(0, ({ char x[]={[2 ... 10]='a', [7]='b', [15 ... 15]='c', [3 ... 5]='d'}; memcmp(x, "\0\0adddabaaa\0\0\0\0c", 16); }));
printf("OK\n");
return 0;
}

23
test/line.c Normal file
View file

@ -0,0 +1,23 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
int main() {
#line 500 "foo"
ASSERT(501, __LINE__);
ASSERT(0, strcmp(__FILE__, "foo"));
#line 800 "bar"
ASSERT(801, __LINE__);
ASSERT(0, strcmp(__FILE__, "bar"));
#line 1
ASSERT(2, __LINE__);
# 200 "xyz" 2 3
ASSERT(201, __LINE__);
ASSERT(0, strcmp(__FILE__, "xyz"));
printf("OK\n");
return 0;
}

105
test/literal.c Normal file
View file

@ -0,0 +1,105 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
цел главн() {
ПРОВЕРИТЬ(97, 'a');
ПРОВЕРИТЬ(10, '\n');
ПРОВЕРИТЬ(-128, '\x80');
ПРОВЕРИТЬ(511, 0777);
ПРОВЕРИТЬ(0, 0x0);
ПРОВЕРИТЬ(10, 0xa);
ПРОВЕРИТЬ(10, 0XA);
ПРОВЕРИТЬ(48879, 0xbeef);
ПРОВЕРИТЬ(48879, 0xBEEF);
ПРОВЕРИТЬ(48879, 0XBEEF);
ПРОВЕРИТЬ(0, 0b0);
ПРОВЕРИТЬ(1, 0b1);
ПРОВЕРИТЬ(47, 0b101111);
ПРОВЕРИТЬ(47, 0B101111);
ПРОВЕРИТЬ(4, размер(0));
ПРОВЕРИТЬ(8, размер(0L));
ПРОВЕРИТЬ(8, размер(0LU));
ПРОВЕРИТЬ(8, размер(0UL));
ПРОВЕРИТЬ(8, размер(0LL));
ПРОВЕРИТЬ(8, размер(0LLU));
ПРОВЕРИТЬ(8, размер(0Ull));
ПРОВЕРИТЬ(8, размер(0l));
ПРОВЕРИТЬ(8, размер(0ll));
ПРОВЕРИТЬ(8, размер(0x0L));
ПРОВЕРИТЬ(8, размер(0b0L));
ПРОВЕРИТЬ(4, размер(2147483647));
ПРОВЕРИТЬ(8, размер(2147483648));
ПРОВЕРИТЬ(-1, 0xffffffffffffffff);
ПРОВЕРИТЬ(8, размер(0xffffffffffffffff));
ПРОВЕРИТЬ(4, размер(4294967295U));
ПРОВЕРИТЬ(8, размер(4294967296U));
ПРОВЕРИТЬ(3, -1U>>30);
ПРОВЕРИТЬ(3, -1Ul>>62);
ПРОВЕРИТЬ(3, -1ull>>62);
ПРОВЕРИТЬ(1, 0xffffffffffffffffl>>63);
ПРОВЕРИТЬ(1, 0xffffffffffffffffll>>63);
ПРОВЕРИТЬ(-1, 18446744073709551615);
ПРОВЕРИТЬ(8, размер(18446744073709551615));
ПРОВЕРИТЬ(-1, 18446744073709551615>>63);
ПРОВЕРИТЬ(-1, 0xffffffffffffffff);
ПРОВЕРИТЬ(8, размер(0xffffffffffffffff));
ПРОВЕРИТЬ(1, 0xffffffffffffffff>>63);
ПРОВЕРИТЬ(-1, 01777777777777777777777);
ПРОВЕРИТЬ(8, размер(01777777777777777777777));
ПРОВЕРИТЬ(1, 01777777777777777777777>>63);
ПРОВЕРИТЬ(-1, 0b1111111111111111111111111111111111111111111111111111111111111111);
ПРОВЕРИТЬ(8, размер(0b1111111111111111111111111111111111111111111111111111111111111111));
ПРОВЕРИТЬ(1, 0b1111111111111111111111111111111111111111111111111111111111111111>>63);
ПРОВЕРИТЬ(8, размер(2147483648));
ПРОВЕРИТЬ(4, размер(2147483647));
ПРОВЕРИТЬ(8, размер(0x1ffffffff));
ПРОВЕРИТЬ(4, размер(0xffffffff));
ПРОВЕРИТЬ(1, 0xffffffff>>31);
ПРОВЕРИТЬ(8, размер(040000000000));
ПРОВЕРИТЬ(4, размер(037777777777));
ПРОВЕРИТЬ(1, 037777777777>>31);
ПРОВЕРИТЬ(8, размер(0b111111111111111111111111111111111));
ПРОВЕРИТЬ(4, размер(0b11111111111111111111111111111111));
ПРОВЕРИТЬ(1, 0b11111111111111111111111111111111>>31);
ПРОВЕРИТЬ(-1, 1 << 31 >> 31);
ПРОВЕРИТЬ(-1, 01 << 31 >> 31);
ПРОВЕРИТЬ(-1, 0x1 << 31 >> 31);
ПРОВЕРИТЬ(-1, 0b1 << 31 >> 31);
0.0;
1.0;
3e+8;
0x10.1p0;
.1E4f;
ПРОВЕРИТЬ(4, размер(8f));
ПРОВЕРИТЬ(4, размер(0.3F));
ПРОВЕРИТЬ(8, размер(0.));
ПРОВЕРИТЬ(8, размер(.0));
ПРОВЕРИТЬ(16, размер(5.l));
ПРОВЕРИТЬ(16, размер(2.0L));
assert(1, размер\
(символ), \
"размер(символ)");
ПРОВЕРИТЬ(4, размер(L'\0'));
ПРОВЕРИТЬ(97, L'a');
printf("OK\n");
возврат 0;
}

20
test/offsetof.c Normal file
View file

@ -0,0 +1,20 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
типдеф структ {
цел а;
символ б;
цел в;
двойн г;
} Т;
цел главн() {
ПРОВЕРИТЬ(0, offsetof(Т, а));
ПРОВЕРИТЬ(4, offsetof(Т, б));
ПРОВЕРИТЬ(8, offsetof(Т, в));
ПРОВЕРИТЬ(16, offsetof(Т, г));
printf("OK\n");
возврат 0;
}

46
test/pointer.c Normal file
View file

@ -0,0 +1,46 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
цел главн() {
ПРОВЕРИТЬ(3, ({ цел х=3; *&х; }));
ПРОВЕРИТЬ(3, ({ цел х=3; цел *у=&х; цел **з=&у; **з; }));
ПРОВЕРИТЬ(5, ({ цел х=3; цел у=5; *(&х+1); }));
ПРОВЕРИТЬ(3, ({ цел х=3; цел у=5; *(&у-1); }));
ПРОВЕРИТЬ(5, ({ цел х=3; цел у=5; *(&х-(-1)); }));
ПРОВЕРИТЬ(5, ({ цел х=3; цел *у=&х; *у=5; х; }));
ПРОВЕРИТЬ(7, ({ цел х=3; цел у=5; *(&х+1)=7; у; }));
ПРОВЕРИТЬ(7, ({ цел х=3; цел у=5; *(&у-2+1)=7; х; }));
ПРОВЕРИТЬ(5, ({ цел х=3; (&х+2)-&х+3; }));
ПРОВЕРИТЬ(8, ({ цел х, у; х=3; у=5; х+у; }));
ПРОВЕРИТЬ(8, ({ цел х=3, у=5; х+у; }));
ПРОВЕРИТЬ(3, ({ цел х[2]; цел *у=&х; *у=3; *х; }));
ПРОВЕРИТЬ(3, ({ цел х[3]; *х=3; *(х+1)=4; *(х+2)=5; *х; }));
ПРОВЕРИТЬ(4, ({ цел х[3]; *х=3; *(х+1)=4; *(х+2)=5; *(х+1); }));
ПРОВЕРИТЬ(5, ({ цел х[3]; *х=3; *(х+1)=4; *(х+2)=5; *(х+2); }));
ПРОВЕРИТЬ(0, ({ цел х[2][3]; цел *у=х; *у=0; **х; }));
ПРОВЕРИТЬ(1, ({ цел х[2][3]; цел *у=х; *(у+1)=1; *(*х+1); }));
ПРОВЕРИТЬ(2, ({ цел х[2][3]; цел *у=х; *(у+2)=2; *(*х+2); }));
ПРОВЕРИТЬ(3, ({ цел х[2][3]; цел *у=х; *(у+3)=3; **(х+1); }));
ПРОВЕРИТЬ(4, ({ цел х[2][3]; цел *у=х; *(у+4)=4; *(*(х+1)+1); }));
ПРОВЕРИТЬ(5, ({ цел х[2][3]; цел *у=х; *(у+5)=5; *(*(х+1)+2); }));
ПРОВЕРИТЬ(3, ({ цел х[3]; *х=3; х[1]=4; х[2]=5; *х; }));
ПРОВЕРИТЬ(4, ({ цел х[3]; *х=3; х[1]=4; х[2]=5; *(х+1); }));
ПРОВЕРИТЬ(5, ({ цел х[3]; *х=3; х[1]=4; х[2]=5; *(х+2); }));
ПРОВЕРИТЬ(5, ({ цел х[3]; *х=3; х[1]=4; х[2]=5; *(х+2); }));
ПРОВЕРИТЬ(5, ({ цел х[3]; *х=3; х[1]=4; 2[х]=5; *(х+2); }));
ПРОВЕРИТЬ(0, ({ цел х[2][3]; цел *у=х; у[0]=0; х[0][0]; }));
ПРОВЕРИТЬ(1, ({ цел х[2][3]; цел *у=х; у[1]=1; х[0][1]; }));
ПРОВЕРИТЬ(2, ({ цел х[2][3]; цел *у=х; у[2]=2; х[0][2]; }));
ПРОВЕРИТЬ(3, ({ цел х[2][3]; цел *у=х; у[3]=3; х[1][0]; }));
ПРОВЕРИТЬ(4, ({ цел х[2][3]; цел *у=х; у[4]=4; х[1][1]; }));
ПРОВЕРИТЬ(5, ({ цел х[2][3]; цел *у=х; у[5]=5; х[1][2]; }));
printf("OK\n");
возврат 0;
}

10
test/pragma-once.c Normal file
View file

@ -0,0 +1,10 @@
#включить "тест.з"
#прагма однократно
#включить "test/pragma-once.c"
цел главн() {
printf("OK\n");
возврат 0;
}

107
test/sizeof.c Normal file
View file

@ -0,0 +1,107 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
цел главн() {
ПРОВЕРИТЬ(1, размер(символ));
ПРОВЕРИТЬ(2, размер(корот));
ПРОВЕРИТЬ(2, размер(корот цел));
ПРОВЕРИТЬ(2, размер(цел корот));
ПРОВЕРИТЬ(4, размер(цел));
ПРОВЕРИТЬ(8, размер(длин));
ПРОВЕРИТЬ(8, размер(длин цел));
ПРОВЕРИТЬ(8, размер(длин цел));
ПРОВЕРИТЬ(8, размер(символ *));
ПРОВЕРИТЬ(8, размер(цел *));
ПРОВЕРИТЬ(8, размер(длин *));
ПРОВЕРИТЬ(8, размер(цел **));
ПРОВЕРИТЬ(8, размер(цел(*)[4]));
ПРОВЕРИТЬ(32, размер(цел*[4]));
ПРОВЕРИТЬ(16, размер(цел[4]));
ПРОВЕРИТЬ(48, размер(цел[3][4]));
ПРОВЕРИТЬ(8, размер(структ {цел а; цел б;}));
ПРОВЕРИТЬ(8, размер(-10 + (длин)5));
ПРОВЕРИТЬ(8, размер(-10 - (длин)5));
ПРОВЕРИТЬ(8, размер(-10 * (длин)5));
ПРОВЕРИТЬ(8, размер(-10 / (длин)5));
ПРОВЕРИТЬ(8, размер((длин)-10 + 5));
ПРОВЕРИТЬ(8, размер((длин)-10 - 5));
ПРОВЕРИТЬ(8, размер((длин)-10 * 5));
ПРОВЕРИТЬ(8, размер((длин)-10 / 5));
ПРОВЕРИТЬ(1, ({ символ и; размер(++и); }));
ПРОВЕРИТЬ(1, ({ символ и; размер(и++); }));
ПРОВЕРИТЬ(8, размер(цел(*)[10]));
ПРОВЕРИТЬ(8, размер(цел(*)[][10]));
ПРОВЕРИТЬ(4, размер(структ { цел х, у[]; }));
ПРОВЕРИТЬ(1, размер(символ));
ПРОВЕРИТЬ(1, размер(знак символ));
ПРОВЕРИТЬ(1, размер(знак символ знак));
ПРОВЕРИТЬ(1, размер(беззнак символ));
ПРОВЕРИТЬ(1, размер(беззнак символ беззнак));
ПРОВЕРИТЬ(2, размер(корот));
ПРОВЕРИТЬ(2, размер(цел корот));
ПРОВЕРИТЬ(2, размер(корот цел));
ПРОВЕРИТЬ(2, размер(знак корот));
ПРОВЕРИТЬ(2, размер(цел корот знак));
ПРОВЕРИТЬ(2, размер(беззнак корот));
ПРОВЕРИТЬ(2, размер(цел корот беззнак));
ПРОВЕРИТЬ(4, размер(цел));
ПРОВЕРИТЬ(4, размер(знак цел));
ПРОВЕРИТЬ(4, размер(знак));
ПРОВЕРИТЬ(4, размер(знак знак));
ПРОВЕРИТЬ(4, размер(беззнак цел));
ПРОВЕРИТЬ(4, размер(беззнак));
ПРОВЕРИТЬ(4, размер(беззнак беззнак));
ПРОВЕРИТЬ(8, размер(длин));
ПРОВЕРИТЬ(8, размер(знак длин));
ПРОВЕРИТЬ(8, размер(знак длин цел));
ПРОВЕРИТЬ(8, размер(беззнак длин));
ПРОВЕРИТЬ(8, размер(беззнак длин цел));
ПРОВЕРИТЬ(8, размер(длин длин));
ПРОВЕРИТЬ(8, размер(знак длин длин));
ПРОВЕРИТЬ(8, размер(знак длин длин цел));
ПРОВЕРИТЬ(8, размер(беззнак длин длин));
ПРОВЕРИТЬ(8, размер(беззнак длин длин цел));
ПРОВЕРИТЬ(1, размер((символ)1));
ПРОВЕРИТЬ(2, размер((корот)1));
ПРОВЕРИТЬ(4, размер((цел)1));
ПРОВЕРИТЬ(8, размер((длин)1));
ПРОВЕРИТЬ(4, размер((символ)1 + (символ)1));
ПРОВЕРИТЬ(4, размер((корот)1 + (корот)1));
ПРОВЕРИТЬ(4, размер(1?2:3));
ПРОВЕРИТЬ(4, размер(1?(корот)2:(символ)3));
ПРОВЕРИТЬ(8, размер(1?(длин)2:(символ)3));
ПРОВЕРИТЬ(1, размер(символ) << 31 >> 31);
ПРОВЕРИТЬ(1, размер(символ) << 63 >> 63);
ПРОВЕРИТЬ(4, размер(плав));
ПРОВЕРИТЬ(8, размер(двойн));
ПРОВЕРИТЬ(4, размер(1f+2));
ПРОВЕРИТЬ(8, размер(1.0+2));
ПРОВЕРИТЬ(4, размер(1f-2));
ПРОВЕРИТЬ(8, размер(1.0-2));
ПРОВЕРИТЬ(4, размер(1f*2));
ПРОВЕРИТЬ(8, размер(1.0*2));
ПРОВЕРИТЬ(4, размер(1f/2));
ПРОВЕРИТЬ(8, размер(1.0/2));
ПРОВЕРИТЬ(16, размер(длин двойн));
ПРОВЕРИТЬ(1, размер(главн));
printf("OK\n");
возврат 0;
}

8
test/stdhdr.c Normal file
View file

@ -0,0 +1,8 @@
#include "тест.з"
#include <rstdlib.h>
int main() {
printf("OK\n");
return 0;
}

74
test/string.c Normal file
View file

@ -0,0 +1,74 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
int main() {
ASSERT(0, ""[0]);
ASSERT(1, sizeof(""));
ASSERT(97, "abc"[0]);
ASSERT(98, "abc"[1]);
ASSERT(99, "abc"[2]);
ASSERT(0, "abc"[3]);
ASSERT(4, sizeof("abc"));
ASSERT(7, "\a"[0]);
ASSERT(8, "\b"[0]);
ASSERT(9, "\t"[0]);
ASSERT(10, "\n"[0]);
ASSERT(11, "\v"[0]);
ASSERT(12, "\f"[0]);
ASSERT(13, "\r"[0]);
ASSERT(27, "\e"[0]);
ASSERT(106, "\j"[0]);
ASSERT(107, "\k"[0]);
ASSERT(108, "\l"[0]);
ASSERT(7, "\ax\ny"[0]);
ASSERT(120, "\ax\ny"[1]);
ASSERT(10, "\ax\ny"[2]);
ASSERT(121, "\ax\ny"[3]);
ASSERT(0, "\0"[0]);
ASSERT(16, "\20"[0]);
ASSERT(65, "\101"[0]);
ASSERT(104, "\1500"[0]);
ASSERT(0, "\x00"[0]);
ASSERT(119, "\x77"[0]);
ASSERT(7, sizeof("abc" "def"));
ASSERT(9, sizeof("abc" "d" "efgh"));
ASSERT(0, strcmp("abc" "d" "\nefgh", "abcd\nefgh"));
ASSERT(0, !strcmp("abc" "d", "abcd\nefgh"));
ASSERT(0, strcmp("\x9" "0", "\t0"));
ASSERT(16, sizeof(L"abc" ""));
ASSERT(28, sizeof(L"abc" "def"));
ASSERT(28, sizeof(L"abc" L"def"));
ASSERT(14, sizeof(u"abc" "def"));
ASSERT(14, sizeof(u"abc" u"def"));
ASSERT(L'a', (L"abc" "def")[0]);
ASSERT(L'd', (L"abc" "def")[3]);
ASSERT(L'\0', (L"abc" "def")[6]);
ASSERT(u'a', (u"abc" "def")[0]);
ASSERT(u'd', (u"abc" "def")[3]);
ASSERT(u'\0', (u"abc" "def")[6]);
ASSERT(L'', ("" L"")[0]);
ASSERT(0343, ("\343\201\202" L"")[0]);
ASSERT(0201, ("\343\201\202" L"")[1]);
ASSERT(0202, ("\343\201\202" L"")[2]);
ASSERT(0, ("\343\201\202" L"")[3]);
ASSERT(L'a', ("a" "b" L"c")[0]);
ASSERT(L'b', ("a" "b" L"c")[1]);
ASSERT(L'c', ("a" "b" L"c")[2]);
ASSERT(0, ("a" "b" L"c")[3]);
printf("OK\n");
return 0;
}

68
test/struct.c Normal file
View file

@ -0,0 +1,68 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
цел главн() {
ПРОВЕРИТЬ(1, ({ структ {цел а; цел б;} х; х.а=1; х.б=2; х.а; }));
ПРОВЕРИТЬ(2, ({ структ {цел а; цел б;} х; х.а=1; х.б=2; х.б; }));
ПРОВЕРИТЬ(1, ({ структ {символ а; цел б; символ в;} х; х.а=1; х.б=2; х.в=3; х.а; }));
ПРОВЕРИТЬ(2, ({ структ {символ а; цел б; символ в;} х; х.б=1; х.б=2; х.в=3; х.б; }));
ПРОВЕРИТЬ(3, ({ структ {символ а; цел б; символ в;} х; х.а=1; х.б=2; х.в=3; х.в; }));
ПРОВЕРИТЬ(0, ({ структ {символ а; символ б;} х[3]; символ *п=х; п[0]=0; х[0].а; }));
ПРОВЕРИТЬ(1, ({ структ {символ а; символ б;} х[3]; символ *п=х; п[1]=1; х[0].б; }));
ПРОВЕРИТЬ(2, ({ структ {символ а; символ б;} х[3]; символ *п=х; п[2]=2; х[1].а; }));
ПРОВЕРИТЬ(3, ({ структ {символ а; символ б;} х[3]; символ *п=х; п[3]=3; х[1].б; }));
ПРОВЕРИТЬ(6, ({ структ {символ а[3]; символ б[5];} х; символ *п=&х; х.а[0]=6; п[0]; }));
ПРОВЕРИТЬ(7, ({ структ {символ а[3]; символ б[5];} х; символ *п=&х; х.б[0]=7; п[3]; }));
ПРОВЕРИТЬ(6, ({ структ { структ { символ б; } а; } х; х.а.б=6; х.а.б; }));
ПРОВЕРИТЬ(4, ({ структ {цел а;} х; размер(х); }));
ПРОВЕРИТЬ(8, ({ структ {цел а; цел б;} х; размер(х); }));
ПРОВЕРИТЬ(8, ({ структ {цел а, б;} х; размер(х); }));
ПРОВЕРИТЬ(12, ({ структ {цел а[3];} х; размер(х); }));
ПРОВЕРИТЬ(16, ({ структ {цел а;} х[4]; размер(х); }));
ПРОВЕРИТЬ(24, ({ структ {цел а[3];} х[2]; размер(х); }));
ПРОВЕРИТЬ(2, ({ структ {символ а; символ б;} х; размер(х); }));
ПРОВЕРИТЬ(0, ({ структ {} х; размер(х); }));
ПРОВЕРИТЬ(8, ({ структ {символ а; цел б;} х; размер(х); }));
ПРОВЕРИТЬ(8, ({ структ {цел а; символ б;} х; размер(х); }));
ПРОВЕРИТЬ(8, ({ структ т {цел а; цел б;} х; структ т у; размер(у); }));
ПРОВЕРИТЬ(8, ({ структ т {цел а; цел б;}; структ т у; размер(у); }));
ПРОВЕРИТЬ(2, ({ структ т {символ а[2];}; { структ т {символ а[4];}; } структ т у; размер(у); }));
ПРОВЕРИТЬ(3, ({ структ т {цел х;}; цел т=1; структ т у; у.х=2; т+у.х; }));
ПРОВЕРИТЬ(3, ({ структ т {символ а;} х; структ т *у = &х; х.а=3; у->а; }));
ПРОВЕРИТЬ(3, ({ структ т {символ а;} х; структ т *у = &х; у->а=3; х.а; }));
ПРОВЕРИТЬ(3, ({ структ {цел а,б;} х,у; х.а=3; у=х; у.а; }));
ПРОВЕРИТЬ(7, ({ структ т {цел а,б;}; структ т х; х.а=7; структ т у; структ т *з=&у; *з=х; у.а; }));
ПРОВЕРИТЬ(7, ({ структ т {цел а,б;}; структ т х; х.а=7; структ т у, *п=&х, *к=&у; *к=*п; у.а; }));
ПРОВЕРИТЬ(5, ({ структ т {символ а, б;} х, у; х.а=5; у=х; у.а; }));
ПРОВЕРИТЬ(3, ({ структ {цел а,б;} х,у; х.а=3; у=х; у.а; }));
ПРОВЕРИТЬ(7, ({ структ т {цел а,б;}; структ т х; х.а=7; структ т у; структ т *з=&у; *з=х; у.а; }));
ПРОВЕРИТЬ(7, ({ структ т {цел а,б;}; структ т х; х.а=7; структ т у, *п=&х, *к=&у; *к=*п; у.а; }));
ПРОВЕРИТЬ(5, ({ структ т {символ а, б;} х, у; х.а=5; у=х; у.а; }));
ПРОВЕРИТЬ(8, ({ структ т {цел а; цел б;} х; структ т у; размер(у); }));
ПРОВЕРИТЬ(8, ({ структ т {цел а; цел б;}; структ т у; размер(у); }));
ПРОВЕРИТЬ(16, ({ структ {символ а; длин б;} х; размер(х); }));
ПРОВЕРИТЬ(4, ({ структ {символ а; корот б;} х; размер(х); }));
ПРОВЕРИТЬ(8, ({ структ фу *бар; размер(бар); }));
ПРОВЕРИТЬ(4, ({ структ Т *фу; структ Т {цел х;}; размер(структ Т); }));
ПРОВЕРИТЬ(1, ({ структ Т { структ Т *след; цел х; } а; структ Т б; б.х=1; а.след=&б; а.след->х; }));
ПРОВЕРИТЬ(4, ({ типдеф структ Т Т; структ Т { цел х; }; размер(Т); }));
ПРОВЕРИТЬ(2, ({ структ {цел а;} х={1}, у={2}; (х=у).а; }));
ПРОВЕРИТЬ(1, ({ структ {цел а;} х={1}, у={2}; (1?х:у).а; }));
ПРОВЕРИТЬ(2, ({ структ {цел а;} х={1}, у={2}; (0?х:у).а; }));
printf("OK\n");
возврат 0;
}

9
test/thirdparty/common vendored Normal file
View file

@ -0,0 +1,9 @@
chibicc=`pwd`/rusi.elf
make="make -j$(nproc)"
dir=$(basename -s .git $repo)
mkdir -p thirdparty
cd thirdparty
[ -d $dir ] || git clone $repo
cd $dir

15
test/thirdparty/cpython.sh vendored Executable file
View file

@ -0,0 +1,15 @@
#!/bin/bash
repo='git@github.com:python/cpython.git'
. test/thirdparty/common
git reset --hard c75330605d4795850ec74fdc4d69aa5d92f76c00
# Python's './configure' command misidentifies chibicc as icc
# (Intel C Compiler) because icc is a substring of chibicc.
# Modify the configure file as a workaround.
sed -i -e 1996,2011d configure.ac
autoreconf
CC=$chibicc ./configure
$make clean
$make
$make test

7
test/thirdparty/git.sh vendored Executable file
View file

@ -0,0 +1,7 @@
#!/bin/bash
repo='git@github.com:git/git.git'
. test/thirdparty/common
git reset --hard 54e85e7af1ac9e9a92888060d6811ae767fea1bc
$make clean
$make V=1 CC=$chibicc test

10
test/thirdparty/libpng.sh vendored Executable file
View file

@ -0,0 +1,10 @@
#!/bin/bash
repo='git@github.com:rui314/libpng.git'
. test/thirdparty/common
git reset --hard dbe3e0c43e549a1602286144d94b0666549b18e6
CC=$chibicc ./configure
sed -i 's/^wl=.*/wl=-Wl,/; s/^pic_flag=.*/pic_flag=-fPIC/' libtool
$make clean
$make
$make test

10
test/thirdparty/sqlite.sh vendored Executable file
View file

@ -0,0 +1,10 @@
#!/bin/bash
repo='https://github.com/sqlite/sqlite.git'
. test/thirdparty/common
git reset --hard 86f477edaa17767b39c7bae5b67cac8580f7a8c1
CC=$chibicc CFLAGS=-D_GNU_SOURCE ./configure
sed -i 's/^wl=.*/wl=-Wl,/; s/^pic_flag=.*/pic_flag=-fPIC/' libtool
$make clean
$make
$make test

17
test/thirdparty/tinycc.sh vendored Executable file
View file

@ -0,0 +1,17 @@
#!/bin/bash
repo='https://github.com/TinyCC/tinycc.git'
. test/thirdparty/common
dir=$(basename -s .git $repo)
set -e -x
mkdir -p thirdparty
cd thirdparty
[ -d $dir ] || git clone $repo
cd $dir
git reset --hard df67d8617b7d1d03a480a28f9f901848ffbfb7ec
./configure --cc=$chibicc
$make clean
$make
$make CC=cc test

43
test/tls.c Normal file
View file

@ -0,0 +1,43 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
#include <stdio.h>
#include <pthread.h>
_Thread_local int v1;
_Thread_local int v2 = 5;
int v3 = 7;
int thread_main(void *unused) {
ASSERT(0, v1);
ASSERT(5, v2);
ASSERT(7, v3);
v1 = 1;
v2 = 2;
v3 = 3;
ASSERT(1, v1);
ASSERT(2, v2);
ASSERT(3, v3);
return 0;
}
int main() {
pthread_t thr;
ASSERT(0, v1);
ASSERT(5, v2);
ASSERT(7, v3);
ASSERT(0, pthread_create(&thr, NULL, thread_main, NULL));
ASSERT(0, pthread_join(thr, NULL));
ASSERT(0, v1);
ASSERT(5, v2);
ASSERT(3, v3);
printf("OK\n");
return 0;
}

19
test/typedef.c Normal file
View file

@ -0,0 +1,19 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
типдеф цел МойЦел, МойЦел2[4];
типдеф цел;
цел главн() {
ПРОВЕРИТЬ(1, ({ типдеф цел т; т х=1; х; }));
ПРОВЕРИТЬ(1, ({ типдеф структ {цел а;} т; т х; х.а=1; х.а; }));
ПРОВЕРИТЬ(1, ({ типдеф цел т; т т=1; т; }));
ПРОВЕРИТЬ(2, ({ типдеф структ {цел а;} т; { типдеф цел т; } т х; х.а=2; х.а; }));
ПРОВЕРИТЬ(4, ({ типдеф т; т х; размер(х); }));
ПРОВЕРИТЬ(3, ({ МойЦел х=3; х; }));
ПРОВЕРИТЬ(16, ({ МойЦел2 х; размер(х); }));
printf("OK\n");
возврат 0;
}

15
test/typeof.c Normal file
View file

@ -0,0 +1,15 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
цел главн() {
ПРОВЕРИТЬ(3, ({ типоф(цел) х=3; х; }));
ПРОВЕРИТЬ(3, ({ типоф(1) х=3; х; }));
ПРОВЕРИТЬ(4, ({ цел х; типоф(х) у; размер(у); }));
ПРОВЕРИТЬ(8, ({ цел х; типоф(&х) у; размер(у); }));
ПРОВЕРИТЬ(4, ({ типоф("foo") х; размер(х); }));
ПРОВЕРИТЬ(12, размер(типоф(структ { цел а, б, в; })));
printf("OK\n");
возврат 0;
}

106
test/unicode.c Normal file
View file

@ -0,0 +1,106 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
#define STR(x) #x
typedef unsigned short char16_t;
typedef unsigned int char32_t;
typedef int wchar_t;
int π = 3;
int main() {
ASSERT(4, sizeof(L'\0'));
ASSERT(97, L'a');
ASSERT(0, strcmp("αβγ", "\u03B1\u03B2\u03B3"));
ASSERT(0, strcmp("日本語", "\u65E5\u672C\u8A9E"));
ASSERT(0, strcmp("日本語", "\U000065E5\U0000672C\U00008A9E"));
ASSERT(0, strcmp("🌮", "\U0001F32E"));
ASSERT(-1, L'\xffffffff'>>31);
ASSERT(946, L'β');
ASSERT(12354, L'');
ASSERT(127843, L'🍣');
ASSERT(2, sizeof(u'\0'));
ASSERT(1, u'\xffff'>>15);
ASSERT(97, u'a');
ASSERT(946, u'β');
ASSERT(12354, u'');
ASSERT(62307, u'🍣');
ASSERT(0, strcmp(STR(u'a'), "u'a'"));
ASSERT(4, sizeof(U'\0'));
ASSERT(1, U'\xffffffff'>>31);
ASSERT(97, U'a');
ASSERT(946, U'β');
ASSERT(12354, U'');
ASSERT(127843, U'🍣');
ASSERT(0, strcmp(STR(U'a'), "U'a'"));
ASSERT(4, sizeof(u8"abc"));
ASSERT(0, strcmp(u8"abc", "abc"));
ASSERT(0, strcmp(STR(u8"a"), "u8\"a\""));
ASSERT(2, sizeof(u""));
ASSERT(10, sizeof(u"\xffzzz"));
ASSERT(0, memcmp(u"", "\0\0", 2));
ASSERT(0, memcmp(u"abc", "a\0b\0c\0\0\0", 8));
ASSERT(0, memcmp(u"日本語", "\345e,g\236\212\0\0", 8));
ASSERT(0, memcmp(u"🍣", "<\330c\337\0\0", 6));
ASSERT(u'β', u"βb"[0]);
ASSERT(u'b', u"βb"[1]);
ASSERT(0, u"βb"[2]);
ASSERT(0, strcmp(STR(u"a"), "u\"a\""));
ASSERT(4, sizeof(U""));
ASSERT(20, sizeof(U"\xffzzz"));
ASSERT(0, memcmp(U"", "\0\0\0\0", 4));
ASSERT(0, memcmp(U"abc", "a\0\0\0b\0\0\0c\0\0\0\0\0\0\0", 16));
ASSERT(0, memcmp(U"日本語", "\345e\0\0,g\0\0\236\212\0\0\0\0\0\0", 16));
ASSERT(0, memcmp(U"🍣", "c\363\001\0\0\0\0\0", 8));
ASSERT(u'β', U"βb"[0]);
ASSERT(u'b', U"βb"[1]);
ASSERT(0, U"βb"[2]);
ASSERT(1, U"\xffffffff"[0] >> 31);
ASSERT(0, strcmp(STR(U"a"), "U\"a\""));
ASSERT(4, sizeof(L""));
ASSERT(20, sizeof(L"\xffzzz"));
ASSERT(0, memcmp(L"", "\0\0\0\0", 4));
ASSERT(0, memcmp(L"abc", "a\0\0\0b\0\0\0c\0\0\0\0\0\0\0", 16));
ASSERT(0, memcmp(L"日本語", "\345e\0\0,g\0\0\236\212\0\0\0\0\0\0", 16));
ASSERT(0, memcmp(L"🍣", "c\363\001\0\0\0\0\0", 8));
ASSERT(u'β', L"βb"[0]);
ASSERT(u'b', L"βb"[1]);
ASSERT(0, L"βb"[2]);
ASSERT(-1, L"\xffffffff"[0] >> 31);
ASSERT(0, strcmp(STR(L"a"), "L\"a\""));
ASSERT(u'α', ({ char16_t x[] = u"αβ"; x[0]; }));
ASSERT(u'β', ({ char16_t x[] = u"αβ"; x[1]; }));
ASSERT(6, ({ char16_t x[] = u"αβ"; sizeof(x); }));
ASSERT(U'🤔', ({ char32_t x[] = U"🤔x"; x[0]; }));
ASSERT(U'x', ({ char32_t x[] = U"🤔x"; x[1]; }));
ASSERT(12, ({ char32_t x[] = U"🤔x"; sizeof(x); }));
ASSERT(L'🤔', ({ wchar_t x[] = L"🤔x"; x[0]; }));
ASSERT(L'x', ({ wchar_t x[] = L"🤔x"; x[1]; }));
ASSERT(12, ({ wchar_t x[] = L"🤔x"; sizeof(x); }));
ASSERT(3, π);
ASSERT(3, ({ int β0¾=3; β0¾; }));
ASSERT(5, ({ int $$$=5; $$$; }));
printf("OK\n");
return 0;
}

25
test/union.c Normal file
View file

@ -0,0 +1,25 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
цел главн() {
ПРОВЕРИТЬ(8, ({ объед { цел а; символ б[6]; } х; размер(х); }));
ПРОВЕРИТЬ(3, ({ объед { цел а; символ б[4]; } х; х.а = 515; х.б[0]; }));
ПРОВЕРИТЬ(2, ({ объед { цел а; символ б[4]; } х; х.а = 515; х.б[1]; }));
ПРОВЕРИТЬ(0, ({ объед { цел а; символ б[4]; } х; х.а = 515; х.б[2]; }));
ПРОВЕРИТЬ(0, ({ объед { цел а; символ б[4]; } х; х.а = 515; х.б[3]; }));
ПРОВЕРИТЬ(3, ({ объед {цел а,б;} х,у; х.а=3; у.а=5; у=х; у.а; }));
ПРОВЕРИТЬ(3, ({ объед {структ {цел а,б;} в;} х,у; х.в.б=3; у.в.б=5; у=х; у.в.б; }));
ПРОВЕРИТЬ(0xef, ({ объед { структ { беззнак символ а,б,в,г; }; длин д; } х; х.д=0xdeadbeef; х.а; }));
ПРОВЕРИТЬ(0xbe, ({ объед { структ { беззнак символ а,б,в,г; }; длин д; } х; х.д=0xdeadbeef; х.б; }));
ПРОВЕРИТЬ(0xad, ({ объед { структ { беззнак символ а,б,в,г; }; длин д; } х; х.д=0xdeadbeef; х.в; }));
ПРОВЕРИТЬ(0xde, ({ объед { структ { беззнак символ а,б,в,г; }; длин д; } х; х.д=0xdeadbeef; х.г; }));
ПРОВЕРИТЬ(3, ({структ { объед { цел а,б; }; объед { цел в,г; }; } х; х.а=3; х.б; }));
ПРОВЕРИТЬ(5, ({структ { объед { цел а,б; }; объед { цел в,г; }; } х; х.г=5; х.в; }));
printf("OK\n");
возврат 0;
}

34
test/usualconv.c Normal file
View file

@ -0,0 +1,34 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
стат цел возврат10(пусто) { возврат 10; }
цел главн() {
ПРОВЕРИТЬ((длин)-5, -10 + (длин)5);
ПРОВЕРИТЬ((длин)-15, -10 - (длин)5);
ПРОВЕРИТЬ((длин)-50, -10 * (длин)5);
ПРОВЕРИТЬ((длин)-2, -10 / (длин)5);
ПРОВЕРИТЬ(1, -2 < (длин)-1);
ПРОВЕРИТЬ(1, -2 <= (длин)-1);
ПРОВЕРИТЬ(0, -2 > (длин)-1);
ПРОВЕРИТЬ(0, -2 >= (длин)-1);
ПРОВЕРИТЬ(1, (длин)-2 < -1);
ПРОВЕРИТЬ(1, (длин)-2 <= -1);
ПРОВЕРИТЬ(0, (длин)-2 > -1);
ПРОВЕРИТЬ(0, (длин)-2 >= -1);
ПРОВЕРИТЬ(0, 2147483647 + 2147483647 + 2);
ПРОВЕРИТЬ((длин)-1, ({ длин х; х=-1; х; }));
ПРОВЕРИТЬ(1, ({ символ х[3]; х[0]=0; х[1]=1; х[2]=2; символ *у=х+1; у[0]; }));
ПРОВЕРИТЬ(0, ({ символ х[3]; х[0]=0; х[1]=1; х[2]=2; символ *у=х+1; у[-1]; }));
ПРОВЕРИТЬ(5, ({ структ т {символ а;} х, у; х.а=5; у=х; у.а; }));
ПРОВЕРИТЬ(10, (1 ? возврат10 : (пусто *)0)());
printf("OK\n");
возврат 0;
}

52
test/varargs.c Normal file
View file

@ -0,0 +1,52 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
#включить <stdarg.h>
цел сумма1(цел х, ...) {
va_list ap;
va_start(ap, x);
для (;;) {
цел у = va_arg(ap, цел);
если (у == 0)
возврат х;
х += у;
}
}
цел сумма2(цел х, ...) {
va_list ap;
va_start(ap, x);
для (;;) {
двойн у = va_arg(ap, двойн);
х += у;
цел з = va_arg(ap, цел);
если (з == 0)
возврат х;
х += з;
}
}
пусто формат(символ *буф, символ *формат, ...) {
va_list ap;
va_start(ap, формат);
va_list ap2;
va_copy(ap2, ap);
vsprintf(буф, формат, ap2);
va_end(ap2);
}
цел главн() {
ПРОВЕРИТЬ(6, сумма1(1, 2, 3, 0));
ПРОВЕРИТЬ(55, сумма1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0));
ПРОВЕРИТЬ(21, сумма2(1, 2.0, 3, 4.0, 5, 6.0, 0));
ПРОВЕРИТЬ(210, сумма2(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 14.0, 15, 16.0, 17, 18.0, 19, 20.0, 0));
ПРОВЕРИТЬ(0, ({ символ буф[100]; формат(буф, "%d %d", 2, 3); strcmp(буф, "2 3"); }));
printf("OK\n");
возврат 0;
}

74
test/variable.c Normal file
View file

@ -0,0 +1,74 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
цел г1, г2[4];
стат цел г3 = 3;
цел главн() {
ПРОВЕРИТЬ(3, ({ цел а; а=3; а; }));
ПРОВЕРИТЬ(3, ({ цел а=3; а; }));
ПРОВЕРИТЬ(8, ({ цел а=3; цел з=5; а+з; }));
ПРОВЕРИТЬ(3, ({ цел а=3; а; }));
ПРОВЕРИТЬ(8, ({ цел а=3; цел з=5; а+з; }));
ПРОВЕРИТЬ(6, ({ цел а; цел б; а=б=3; а+б; }));
ПРОВЕРИТЬ(3, ({ цел фу=3; фу; }));
ПРОВЕРИТЬ(8, ({ цел фу123=3; цел бар=5; фу123+бар; }));
ПРОВЕРИТЬ(4, ({ цел х; размер(х); }));
ПРОВЕРИТЬ(4, ({ цел х; размер х; }));
ПРОВЕРИТЬ(8, ({ цел *х; размер(х); }));
ПРОВЕРИТЬ(16, ({ цел х[4]; размер(х); }));
ПРОВЕРИТЬ(48, ({ цел х[3][4]; размер(х); }));
ПРОВЕРИТЬ(16, ({ цел х[3][4]; размер(*х); }));
ПРОВЕРИТЬ(4, ({ цел х[3][4]; размер(**х); }));
ПРОВЕРИТЬ(5, ({ цел х[3][4]; размер(**х) + 1; }));
ПРОВЕРИТЬ(5, ({ цел х[3][4]; размер **х + 1; }));
ПРОВЕРИТЬ(4, ({ цел х[3][4]; размер(**х + 1); }));
ПРОВЕРИТЬ(4, ({ цел х=1; размер(х=2); }));
ПРОВЕРИТЬ(1, ({ цел х=1; размер(х=2); х; }));
ПРОВЕРИТЬ(0, г1);
ПРОВЕРИТЬ(3, ({ г1=3; г1; }));
ПРОВЕРИТЬ(0, ({ г2[0]=0; г2[1]=1; г2[2]=2; г2[3]=3; г2[0]; }));
ПРОВЕРИТЬ(1, ({ г2[0]=0; г2[1]=1; г2[2]=2; г2[3]=3; г2[1]; }));
ПРОВЕРИТЬ(2, ({ г2[0]=0; г2[1]=1; г2[2]=2; г2[3]=3; г2[2]; }));
ПРОВЕРИТЬ(3, ({ г2[0]=0; г2[1]=1; г2[2]=2; г2[3]=3; г2[3]; }));
ПРОВЕРИТЬ(4, размер(г1));
ПРОВЕРИТЬ(16, размер(г2));
ПРОВЕРИТЬ(1, ({ символ х=1; х; }));
ПРОВЕРИТЬ(1, ({ символ х=1; символ у=2; х; }));
ПРОВЕРИТЬ(2, ({ символ х=1; символ у=2; у; }));
ПРОВЕРИТЬ(1, ({ символ х; размер(х); }));
ПРОВЕРИТЬ(10, ({ символ х[10]; размер(х); }));
ПРОВЕРИТЬ(2, ({ цел х=2; { цел х=3; } х; }));
ПРОВЕРИТЬ(2, ({ цел х=2; { цел х=3; } цел у=4; х; }));
ПРОВЕРИТЬ(3, ({ цел х=2; { х=3; } х; }));
ПРОВЕРИТЬ(7, ({ цел х; цел у; символ з; символ *а=&у; символ *б=&з; б-а; }));
ПРОВЕРИТЬ(1, ({ цел х; символ у; цел з; символ *а=&у; символ *б=&з; б-а; }));
ПРОВЕРИТЬ(8, ({ длин х; размер(х); }));
ПРОВЕРИТЬ(2, ({ корот х; размер(х); }));
ПРОВЕРИТЬ(24, ({ символ *х[3]; размер(х); }));
ПРОВЕРИТЬ(8, ({ символ (*х)[3]; размер(х); }));
ПРОВЕРИТЬ(1, ({ символ (х); размер(х); }));
ПРОВЕРИТЬ(3, ({ символ (х)[3]; размер(х); }));
ПРОВЕРИТЬ(12, ({ символ (х[3])[4]; размер(х); }));
ПРОВЕРИТЬ(4, ({ символ (х[3])[4]; размер(х[0]); }));
ПРОВЕРИТЬ(3, ({ символ *х[3]; символ у; х[0]=&у; у=3; х[0][0]; }));
ПРОВЕРИТЬ(4, ({ символ х[3]; символ (*у)[3]=х; у[0][0]=4; у[0][0]; }));
{ пусто *х; }
ПРОВЕРИТЬ(3, г3);
printf("OK\n");
возврат 0;
}

28
test/vla.c Normal file
View file

@ -0,0 +1,28 @@
#включить "тест.з"
#включить "stdvv.c"
#include "common.c"
цел главн() {
ПРОВЕРИТЬ(20, ({ цел н=5; цел х[н]; размер(х); }));
ПРОВЕРИТЬ((5+1)*(8*2)*4, ({ цел м=5, н=8; цел х[м+1][н*2]; размер(х); }));
ПРОВЕРИТЬ(8, ({ символ н=10; цел (*х)[н][н+2]; размер(х); }));
ПРОВЕРИТЬ(480, ({ символ н=10; цел (*х)[н][н+2]; размер(*х); }));
ПРОВЕРИТЬ(48, ({ символ н=10; цел (*х)[н][н+2]; размер(**х); }));
ПРОВЕРИТЬ(4, ({ символ н=10; цел (*х)[н][н+2]; размер(***х); }));
ПРОВЕРИТЬ(60, ({ символ н=3; цел х[5][н]; размер(х); }));
ПРОВЕРИТЬ(12, ({ символ н=3; цел х[5][н]; размер(*х); }));
ПРОВЕРИТЬ(60, ({ символ н=3; цел х[н][5]; размер(х); }));
ПРОВЕРИТЬ(20, ({ символ н=3; цел х[н][5]; размер(*х); }));
ПРОВЕРИТЬ(0, ({ цел н=10; цел х[н+1][н+6]; цел *п=х; для (цел и = 0; и<размер(х)/4; и++) п[и]=и; х[0][0]; }));
ПРОВЕРИТЬ(5, ({ цел н=10; цел х[н+1][н+6]; цел *п=х; для (цел и = 0; и<размер(х)/4; и++) п[и]=и; х[0][5]; }));
ПРОВЕРИТЬ(5*16+2, ({ цел н=10; цел х[н+1][н+6]; цел *п=х; для (цел и = 0; и<размер(х)/4; и++) п[и]=и; х[5][2]; }));
ПРОВЕРИТЬ(10, ({ цел н=5; размер(символ[2][н]); }));
printf("OK\n");
возврат 0;
}

42
test/тест.з Normal file
View file

@ -0,0 +1,42 @@
#ifndef TEST_H
#define TEST_H
// ============================================================
// АНГЛИЙСКАЯ ВЕРСИЯ
// ============================================================
#define ASSERT(x, y) assert(x, y, #y)
void assert(int expected, int actual, char *code);
int printf(char *fmt, ...);
int sprintf(char *buf, char *fmt, ...);
int vsprintf(char *buf, char *fmt, void *ap);
int strcmp(char *p, char *q);
int strncmp(char *p, char *q, long n);
int memcmp(char *p, char *q, long n);
void exit(int n);
int vsprintf();
long strlen(char *s);
void *memcpy(void *dest, void *src, long n);
void *memset(void *s, int c, long n);
// ============================================================
// РУССКАЯ ВЕРСИЯ (полные дубликаты с русскими именами)
// ============================================================
#определить ПРОВЕРИТЬ(x, y) assert(x, y, #y)
пусто проверить(цел ожидаемое, цел фактическое, символ *код);
цел печать(символ *формат, ...);
цел спечать(символ *буфер, символ *формат, ...);
цел вспечать(символ *буфер, символ *формат, пусто *ap);
цел сравнить_строки(символ *p, символ *q);
цел сравнить_строки_n(символ *p, символ *q, длин n);
цел сравнить_память(символ *p, символ *q, длин n);
пусто завершить(цел n);
цел вспечать();
длин длина_строки(символ *s);
пусто *копировать_память(пусто *назначение, пусто *источник, длин n);
пусто *заполнить_память(пусто *s, цел c, длин n);
#конецесли

10
test_ru/#else.c Normal file
View file

@ -0,0 +1,10 @@
// #else.c - Проверка директивы #иначе
#определить ТЕСТ 42
цел main(){
#еслиопр ТЕСТ
возврат 0;
#иначе
возврат 1;
#endif
}

8
test_ru/alignas.c Normal file
View file

@ -0,0 +1,8 @@
// выравнивание.c - Проверка _Выравнивание
цел главн(){
_Выравнивание(16) символ буфер[32];
если ((беззнак длин)буфер % 16 == 0) {
возврат 0;
}
возврат 1;
}

8
test_ru/alignof.c Normal file
View file

@ -0,0 +1,8 @@
// alignof.c - Проверка _Выравнивание_типа
цел главн(){
цел разм = _Выравнивание_типа(цел);
если (разм == 4) {
возврат 0;
}
возврат 1;
}

9
test_ru/asm.c Normal file
View file

@ -0,0 +1,9 @@
// asm.c - Проверка оператора asm
цел главн(){
цел x = 10;
асм("nop");
если (x == 10) {
возврат 0;
}
возврат 1;
}

15
test_ru/asm2.c Normal file
View file

@ -0,0 +1,15 @@
// asm2.c - Проверка оператора asm с системным вызовом
длин сис_вызов(длин номер, длин арг1, длин арг2, длин арг3) {
асм("mov %rcx, %r10");
асм("mov %rdi, %rax");
асм("mov %rsi, %rdi");
асм("mov %rdx, %rsi");
асм("mov %r10, %rdx");
асм("syscall");
}
цел главн(){
// syscall 60 = exit, аргумент 0
сис_вызов(60, 0, 0, 0);
возврат 1; // Сюда не должны попасть
}

10
test_ru/atomic.c Normal file
View file

@ -0,0 +1,10 @@
// atomic.c - Проверка типа _Атом
#включить <stdatomic.h>
цел главн() {
_Атом цел значение = 42;
если (значение == 42) {
возврат 0;
}
возврат 1;
}

8
test_ru/auto.c Normal file
View file

@ -0,0 +1,8 @@
// auto.c - Проверка ключевого слова auto
цел главн(){
авто цел x = 42;
если (x == 42) {
возврат 0;
}
возврат 1;
}

10
test_ru/bool.c Normal file
View file

@ -0,0 +1,10 @@
// bool.c - Проверка типа bool через макрос
#включить <stdbool.h>
цел главн(){
бул флаг = истина;
если (флаг) {
возврат 0;
}
возврат 1;
}

14
test_ru/break.c Normal file
View file

@ -0,0 +1,14 @@
// break.c - Проверка оператора break
цел главн(){
цел и = 0;
пока (1) {
и = и + 1;
если (и == 5) {
прерви;
}
}
если (и == 5) {
возврат 0;
}
возврат 1;
}

21
test_ru/case.c Normal file
View file

@ -0,0 +1,21 @@
// case.c - Проверка оператора case
цел главн(){
цел х = 1;
цел рез = 0;
выбор (х) {
случай 1:
рез = 100;
прерви;
случай 2:
рез = 200;
прерви;
умолч:
рез = 300;
}
если (рез == 100) {
возврат 0;
}
возврат 1;
}

5
test_ru/char.c Normal file
View file

@ -0,0 +1,5 @@
// 2_char.c - Проверка типа char
цел главн(){
символ с = 'A';
возврат с;
}

8
test_ru/const.c Normal file
View file

@ -0,0 +1,8 @@
// const.c - Проверка ключевого слова const
цел главн(){
конст цел х = 42;
если (х == 42) {
возврат 0;
}
возврат 1;
}

16
test_ru/continue.c Normal file
View file

@ -0,0 +1,16 @@
// contиnue.c - Проверка оператора contиnue
цел главн(){
цел и;
цел сум = 0;
для (и = 0; и < 10; и = и + 1) {
если (и == 5) {
продолжи;
}
сум = сум + и;
}
// сум = 0+1+2+3+4+6+7+8+9 = 40 (пропустили 5)
если (сум == 40) {
возврат 0;
}
возврат 1;
}

9
test_ru/counter_ru.c Normal file
View file

@ -0,0 +1,9 @@
// counter_ru.c - Проверка макроса __СЧЕТЧИК__
цел главн() {
цел счет1 = __СЧЕТЧИК__;
цел счет2 = __СЧЕТЧИК__;
если (счет1 == 0 && счет2 == 1) {
возврат 0;
}
возврат 1;
}

27
test_ru/cyrillic_ident.c Normal file
View file

@ -0,0 +1,27 @@
// cyrillic_ident.c - Проверка кириллических идентификаторов
цел глобальная_переменная = 42;
цел сумма(цел а, цел б) {
возврат а + б;
}
структ Точка {
цел координата_x;
цел координата_y;
};
цел главн() {
цел локальная_переменная = 10;
цел результат = сумма(локальная_переменная, глобальная_переменная);
структ Точка точка;
точка.координата_x = 5;
точка.координата_y = 7;
цел итог = точка.координата_x + точка.координата_y + результат;
если (итог == 64) { // 5 + 7 + 10 + 42 = 64
возврат 0;
}
возврат 1;
}

55
test_ru/cyrillic_ptr.c Normal file
View file

@ -0,0 +1,55 @@
// cyrillic_ptr.c - Проверка указателей и указателей на указатели с кириллическими идентификаторами
цел главн() {
// Обычный указатель
цел значение = 42;
цел *указатель = &значение;
если (*указатель != 42) {
возврат 1;
}
// Указатель на указатель
цел **указательа_указатель = &указатель;
если (**указательа_указатель != 42) {
возврат 1;
}
// Изменение через указатель
*указатель = 100;
если (значение != 100) {
возврат 1;
}
// Изменение через указатель на указатель
**указательа_указатель = 200;
если (значение != 200) {
возврат 1;
}
// Указатель на структуру
структ Данные {
цел поле;
};
структ Данные объект;
объект.поле = 123;
структ Данные *указательа_структуру = &объект;
если (указательа_структуру->поле != 123) {
возврат 1;
}
указательа_структуру->поле = 456;
если (объект.поле != 456) {
возврат 1;
}
// Указатель на указатель на структуру
структ Данные **указательа_указатель_на_структуру = &указательа_структуру;
если ((*указательа_указатель_на_структуру)->поле != 456) {
возврат 1;
}
возврат 0;
}

11
test_ru/date_ru.c Normal file
View file

@ -0,0 +1,11 @@
// date_ru.c - Проверка макроса __ДАТА__
#включить <stdio.h>
цел главн() {
символ *дата = __ДАТА__;
// Просто проверяем, что строка не пустая
если (дата[0] != '\0') {
возврат 0;
}
возврат 1;
}

21
test_ru/default.c Normal file
View file

@ -0,0 +1,21 @@
// default.c - Проверка оператора default
цел главн(){
цел x = 999;
цел рез = 0;
выбор (x) {
случай 1:
рез = 100;
прерви;
случай 2:
рез = 200;
прерви;
умолч:
рез = 999;
}
если (рез == 999) {
возврат 0;
}
возврат 1;
}

10
test_ru/define.c Normal file
View file

@ -0,0 +1,10 @@
// define.c - Проверка директивы #определить
#определить ПИ 3.14
цел главн(){
плав pi = ПИ;
если ((цел)pi == 3) {
возврат 0;
}
возврат 1;
}

10
test_ru/defined.c Normal file
View file

@ -0,0 +1,10 @@
// defined.c - Проверка оператора defined
#определить ТЕСТ 42
цел главн(){
#если определено(ТЕСТ)
возврат 0;
#иначе
возврат 1;
#конецесли
}

13
test_ru/do.c Normal file
View file

@ -0,0 +1,13 @@
// do.c - Проверка цикла do-whиle
цел главн(){
цел и = 0;
цел сум = 0;
делай {
сум = сум + и;
и = и + 1;
} пока (и < 10);
если (сум == 45) {
возврат 0;
}
возврат 1;
}

5
test_ru/double.c Normal file
View file

@ -0,0 +1,5 @@
// double.c - Проверка типа double
цел главн(){
двойн d = 2.71;
возврат (цел)d;
}

12
test_ru/elif.c Normal file
View file

@ -0,0 +1,12 @@
// elif.c - Проверка директивы #иначеесли
#определить ВЕРСИЯ 2
цел главн(){
#если ВЕРСИЯ == 1
возврат 1;
#иначеесли ВЕРСИЯ == 2
возврат 0;
#иначе
возврат 2;
#конецесли
}

9
test_ru/else.c Normal file
View file

@ -0,0 +1,9 @@
// else.c - Проверка оператора else
цел главн(){
цел х = 5;
если (х == 10) {
возврат 1;
} иначе {
возврат 0;
}
}

9
test_ru/endif.c Normal file
View file

@ -0,0 +1,9 @@
// endif.c - Проверка директивы #конецесли
#определить ТЕСТ 1
цел главн(){
#если ТЕСТ == 1
возврат 0;
#конецесли
возврат 1;
}

14
test_ru/enum.c Normal file
View file

@ -0,0 +1,14 @@
// enum.c - Проверка типа enum
переч Цвет {
КРАСНЫЙ,
ЗЕЛЕНЫЙ,
СИНИЙ
};
цел главн(){
переч Цвет c = ЗЕЛЕНЫЙ;
если (c == 1) {
возврат 0;
}
возврат 1;
}

BIN
test_ru/error Executable file

Binary file not shown.

11
test_ru/error.c Normal file
View file

@ -0,0 +1,11 @@
// error.c - Проверка директивы #ошибка
#определить ТЕСТ 1
цел главн(){
#если ТЕСТ != 1
// Нормальный код
возврат 0;
#иначе
#ошибка "Тестовая ошибка - не должно произойти"
#конецесли
}

Some files were not shown because too many files have changed in this diff Show more