Стартовый коммит: компилятор РуСи
This commit is contained in:
commit
4a11b8357a
24
LICENSE.md
Normal file
24
LICENSE.md
Normal 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
64
Makefile
Normal 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
762
README.md
Normal 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 — в планах.
|
||||
|
||||
```
|
||||
320
hashmap.c
Normal file
320
hashmap.c
Normal 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
119
include/common.c
Normal 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
358
include/rstdlib.h
Normal 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
145
include/stdarg.h
Normal 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
45
include/stdbool.h
Normal 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
82
include/stddef.h
Normal 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
49
include/stdnoreturn.h
Normal 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
53
include/stdvv.c
Normal 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
25
include/stdvv.h
Normal 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
875
main.c
Normal 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;
|
||||
}
|
||||
1037
preprocess.c
Normal file
1037
preprocess.c
Normal file
File diff suppressed because it is too large
Load diff
BIN
stage2/rusi.elf
Executable file
BIN
stage2/rusi.elf
Executable file
Binary file not shown.
253
strings.c
Normal file
253
strings.c
Normal 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
50
test/alignof.c
Normal 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
29
test/alloca.c
Normal 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
145
test/arith.c
Normal 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
24
test/asm.c
Normal 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
64
test/atomic.c
Normal 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
40
test/attribute.c
Normal 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
58
test/bitfield.c
Normal 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
34
test/builtin.c
Normal 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
60
test/cast.c
Normal 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
20
test/commonsym.c
Normal 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
20
test/compat.c
Normal 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
34
test/complit.c
Normal 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
15
test/const.c
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#включить "тест.з"
|
||||
#включить "stdvv.c"
|
||||
|
||||
цел главн() {
|
||||
{ конст х; }
|
||||
{ цел конст х; }
|
||||
{ конст цел х; }
|
||||
{ конст цел конст конст х; }
|
||||
ПРОВЕРИТЬ(5, ({ конст х = 5; х; }));
|
||||
ПРОВЕРИТЬ(8, ({ конст х = 8; цел *конст у=&х; *у; }));
|
||||
ПРОВЕРИТЬ(6, ({ конст х = 6; *(конст * конст)&х; }));
|
||||
|
||||
printf("OK\n");
|
||||
возврат 0;
|
||||
}
|
||||
56
test/constexpr.c
Normal file
56
test/constexpr.c
Normal 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
101
test/control.c
Normal 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
23
test/decl.c
Normal 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
987
test/driver.py
Executable 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
19
test/enum.c
Normal 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
27
test/extern.c
Normal 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
94
test/float.c
Normal 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
397
test/function.c
Normal 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
13
test/generic.c
Normal 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
6
test/include1.h
Normal 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
1
test/include2.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
int include2 = 7;
|
||||
1
test/include3.h
Normal file
1
test/include3.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
#define foo 3
|
||||
1
test/include4.h
Normal file
1
test/include4.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
#define foo 4
|
||||
269
test/initializer.c
Normal file
269
test/initializer.c
Normal 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
23
test/line.c
Normal 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
105
test/literal.c
Normal 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
20
test/offsetof.c
Normal 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
46
test/pointer.c
Normal 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
10
test/pragma-once.c
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#включить "тест.з"
|
||||
|
||||
#прагма однократно
|
||||
|
||||
#включить "test/pragma-once.c"
|
||||
|
||||
цел главн() {
|
||||
printf("OK\n");
|
||||
возврат 0;
|
||||
}
|
||||
107
test/sizeof.c
Normal file
107
test/sizeof.c
Normal 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
8
test/stdhdr.c
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#include "тест.з"
|
||||
#include <rstdlib.h>
|
||||
|
||||
|
||||
int main() {
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
||||
74
test/string.c
Normal file
74
test/string.c
Normal 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
68
test/struct.c
Normal 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
9
test/thirdparty/common
vendored
Normal 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
15
test/thirdparty/cpython.sh
vendored
Executable 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
7
test/thirdparty/git.sh
vendored
Executable 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
10
test/thirdparty/libpng.sh
vendored
Executable 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
10
test/thirdparty/sqlite.sh
vendored
Executable 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
17
test/thirdparty/tinycc.sh
vendored
Executable 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
43
test/tls.c
Normal 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
19
test/typedef.c
Normal 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
15
test/typeof.c
Normal 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
106
test/unicode.c
Normal 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
25
test/union.c
Normal 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
34
test/usualconv.c
Normal 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
52
test/varargs.c
Normal 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
74
test/variable.c
Normal 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
28
test/vla.c
Normal 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
42
test/тест.з
Normal 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
10
test_ru/#else.c
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// #else.c - Проверка директивы #иначе
|
||||
#определить ТЕСТ 42
|
||||
|
||||
цел main(){
|
||||
#еслиопр ТЕСТ
|
||||
возврат 0;
|
||||
#иначе
|
||||
возврат 1;
|
||||
#endif
|
||||
}
|
||||
8
test_ru/alignas.c
Normal file
8
test_ru/alignas.c
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// выравнивание.c - Проверка _Выравнивание
|
||||
цел главн(){
|
||||
_Выравнивание(16) символ буфер[32];
|
||||
если ((беззнак длин)буфер % 16 == 0) {
|
||||
возврат 0;
|
||||
}
|
||||
возврат 1;
|
||||
}
|
||||
8
test_ru/alignof.c
Normal file
8
test_ru/alignof.c
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// alignof.c - Проверка _Выравнивание_типа
|
||||
цел главн(){
|
||||
цел разм = _Выравнивание_типа(цел);
|
||||
если (разм == 4) {
|
||||
возврат 0;
|
||||
}
|
||||
возврат 1;
|
||||
}
|
||||
9
test_ru/asm.c
Normal file
9
test_ru/asm.c
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// asm.c - Проверка оператора asm
|
||||
цел главн(){
|
||||
цел x = 10;
|
||||
асм("nop");
|
||||
если (x == 10) {
|
||||
возврат 0;
|
||||
}
|
||||
возврат 1;
|
||||
}
|
||||
15
test_ru/asm2.c
Normal file
15
test_ru/asm2.c
Normal 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
10
test_ru/atomic.c
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// atomic.c - Проверка типа _Атом
|
||||
#включить <stdatomic.h>
|
||||
|
||||
цел главн() {
|
||||
_Атом цел значение = 42;
|
||||
если (значение == 42) {
|
||||
возврат 0;
|
||||
}
|
||||
возврат 1;
|
||||
}
|
||||
8
test_ru/auto.c
Normal file
8
test_ru/auto.c
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// auto.c - Проверка ключевого слова auto
|
||||
цел главн(){
|
||||
авто цел x = 42;
|
||||
если (x == 42) {
|
||||
возврат 0;
|
||||
}
|
||||
возврат 1;
|
||||
}
|
||||
10
test_ru/bool.c
Normal file
10
test_ru/bool.c
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// bool.c - Проверка типа bool через макрос
|
||||
#включить <stdbool.h>
|
||||
|
||||
цел главн(){
|
||||
бул флаг = истина;
|
||||
если (флаг) {
|
||||
возврат 0;
|
||||
}
|
||||
возврат 1;
|
||||
}
|
||||
14
test_ru/break.c
Normal file
14
test_ru/break.c
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// break.c - Проверка оператора break
|
||||
цел главн(){
|
||||
цел и = 0;
|
||||
пока (1) {
|
||||
и = и + 1;
|
||||
если (и == 5) {
|
||||
прерви;
|
||||
}
|
||||
}
|
||||
если (и == 5) {
|
||||
возврат 0;
|
||||
}
|
||||
возврат 1;
|
||||
}
|
||||
21
test_ru/case.c
Normal file
21
test_ru/case.c
Normal 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
5
test_ru/char.c
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// 2_char.c - Проверка типа char
|
||||
цел главн(){
|
||||
символ с = 'A';
|
||||
возврат с;
|
||||
}
|
||||
8
test_ru/const.c
Normal file
8
test_ru/const.c
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// const.c - Проверка ключевого слова const
|
||||
цел главн(){
|
||||
конст цел х = 42;
|
||||
если (х == 42) {
|
||||
возврат 0;
|
||||
}
|
||||
возврат 1;
|
||||
}
|
||||
16
test_ru/continue.c
Normal file
16
test_ru/continue.c
Normal 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
9
test_ru/counter_ru.c
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// counter_ru.c - Проверка макроса __СЧЕТЧИК__
|
||||
цел главн() {
|
||||
цел счет1 = __СЧЕТЧИК__;
|
||||
цел счет2 = __СЧЕТЧИК__;
|
||||
если (счет1 == 0 && счет2 == 1) {
|
||||
возврат 0;
|
||||
}
|
||||
возврат 1;
|
||||
}
|
||||
27
test_ru/cyrillic_ident.c
Normal file
27
test_ru/cyrillic_ident.c
Normal 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
55
test_ru/cyrillic_ptr.c
Normal 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
11
test_ru/date_ru.c
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// date_ru.c - Проверка макроса __ДАТА__
|
||||
#включить <stdio.h>
|
||||
|
||||
цел главн() {
|
||||
символ *дата = __ДАТА__;
|
||||
// Просто проверяем, что строка не пустая
|
||||
если (дата[0] != '\0') {
|
||||
возврат 0;
|
||||
}
|
||||
возврат 1;
|
||||
}
|
||||
21
test_ru/default.c
Normal file
21
test_ru/default.c
Normal 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
10
test_ru/define.c
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// define.c - Проверка директивы #определить
|
||||
#определить ПИ 3.14
|
||||
|
||||
цел главн(){
|
||||
плав pi = ПИ;
|
||||
если ((цел)pi == 3) {
|
||||
возврат 0;
|
||||
}
|
||||
возврат 1;
|
||||
}
|
||||
10
test_ru/defined.c
Normal file
10
test_ru/defined.c
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// defined.c - Проверка оператора defined
|
||||
#определить ТЕСТ 42
|
||||
|
||||
цел главн(){
|
||||
#если определено(ТЕСТ)
|
||||
возврат 0;
|
||||
#иначе
|
||||
возврат 1;
|
||||
#конецесли
|
||||
}
|
||||
13
test_ru/do.c
Normal file
13
test_ru/do.c
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// do.c - Проверка цикла do-whиle
|
||||
цел главн(){
|
||||
цел и = 0;
|
||||
цел сум = 0;
|
||||
делай {
|
||||
сум = сум + и;
|
||||
и = и + 1;
|
||||
} пока (и < 10);
|
||||
если (сум == 45) {
|
||||
возврат 0;
|
||||
}
|
||||
возврат 1;
|
||||
}
|
||||
5
test_ru/double.c
Normal file
5
test_ru/double.c
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// double.c - Проверка типа double
|
||||
цел главн(){
|
||||
двойн d = 2.71;
|
||||
возврат (цел)d;
|
||||
}
|
||||
12
test_ru/elif.c
Normal file
12
test_ru/elif.c
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// elif.c - Проверка директивы #иначеесли
|
||||
#определить ВЕРСИЯ 2
|
||||
|
||||
цел главн(){
|
||||
#если ВЕРСИЯ == 1
|
||||
возврат 1;
|
||||
#иначеесли ВЕРСИЯ == 2
|
||||
возврат 0;
|
||||
#иначе
|
||||
возврат 2;
|
||||
#конецесли
|
||||
}
|
||||
9
test_ru/else.c
Normal file
9
test_ru/else.c
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// else.c - Проверка оператора else
|
||||
цел главн(){
|
||||
цел х = 5;
|
||||
если (х == 10) {
|
||||
возврат 1;
|
||||
} иначе {
|
||||
возврат 0;
|
||||
}
|
||||
}
|
||||
9
test_ru/endif.c
Normal file
9
test_ru/endif.c
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// endif.c - Проверка директивы #конецесли
|
||||
#определить ТЕСТ 1
|
||||
|
||||
цел главн(){
|
||||
#если ТЕСТ == 1
|
||||
возврат 0;
|
||||
#конецесли
|
||||
возврат 1;
|
||||
}
|
||||
14
test_ru/enum.c
Normal file
14
test_ru/enum.c
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// enum.c - Проверка типа enum
|
||||
переч Цвет {
|
||||
КРАСНЫЙ,
|
||||
ЗЕЛЕНЫЙ,
|
||||
СИНИЙ
|
||||
};
|
||||
|
||||
цел главн(){
|
||||
переч Цвет c = ЗЕЛЕНЫЙ;
|
||||
если (c == 1) {
|
||||
возврат 0;
|
||||
}
|
||||
возврат 1;
|
||||
}
|
||||
BIN
test_ru/error
Executable file
BIN
test_ru/error
Executable file
Binary file not shown.
11
test_ru/error.c
Normal file
11
test_ru/error.c
Normal 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
Loading…
Reference in a new issue