Статья посвящена системному программированию на русском языке с C-подобным синтаксисом. Компилятор для языков программирования РУСИ, РУСИ++ и объектный-РУСИ создан путём модификации и пересборки компилятора GCC 14й версии с превращением его в полноценный русско-английский билингвальный компилятор. Отдельно дана инструкция модификации русской раскладки клавиатуры для добавления в неё фигурных, угловых и квадратных скобок - дабы не переключаться и не терять поток.


Оглавление


Предыстория

В предыдущей статье был описан концепт билингвального самособирающегося компилятора языка Си, в котором кириллица уравнялась с оригинальным синтаксисом и можно писать на русском и английском Си одновременно. Код, напомню, выглядит так:

// Английский main с русским типом и оператором
int main() {
    int x = 42;
    if (x == 42) {
        возврат 0;
    }
    return 1;
}

// Полностью русский синтаксис
цел главн() {
    цел ъ = 42;
    если (ъ == 42) {
        возврат  0;
    }
    возврат 1;
}

// Смешанный стиль
цел main() {
    printf("Легкоступов! Ты чего написал?");
    возврат 0;
}

Создан он был на базе chibicc для написания на нём кириллического ассемблера КВС https://xn–d1alm1bt.xn–p1ai/administrator/kvs. По сути, это был путь к своеобразной концептуальной полноте: кириллический ассемблер на кириллическом же Си. И для той задачи это было идеальным решением. Минималистичный русский компилятор под Linux. Ничего лишнего. Байты в бинарь складывать может. Задачу свою решает.

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

И действительно: во «взрослых» компиляторах есть ряд преимуществ как маркеров качества - множественное покрытие тестами и 40 лет ассемблерных оптимизаций. И как человек, пишущий свой ассемблер, я на это обратил внимание. Это тысячи человеко-лет работы, сотни оптимизационных проходов, отладка на миллионах строк кода.

Гипотетически: каким бы был полноценный продакшеновый русский Си?

Из спортивного интереса я решил попробовать. Смогу ли оседлать GCC и сделать его билингвом? Ранее мне поддались pascalABC.NET, Blaise и PHP. Вшивал я в них великий и могучий с целью поизучать на практике компиляторостроение. Отличный метод обучаться, кстати.

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

GCC сложнее, чем chibicc. Множество стандартов Си, поддерживаемых им, не могли не наложить свой отпечаток на его внутреннюю архитектуру.

Что получилось: RUSI на GCC 14.2.0. Русский Си, который компилируется в тот же самый машинный код, что и английский Си. С теми же оптимизациями. С той же производительностью.

Побочными продуктами получились РУСИ++ и объектный-РУСИ.


Зачем это всё

Эрик Рэймонд, «Собор и Базар» (1997), предисловие:

«Every good work of software starts by scratching a developer’s personal itch.»

Точный перевод: «Каждая хорошая программа начинается с того, что разработчик почесал свою личную нужду».

И где-то в России программист решил создать то, что считает нужным. И создаёт.

Линус Торвальдс, предисловие к книге Пекки Химанена «Хакерская этика и дух информационной эры» (2001):

«Linux был в значительной степени хобби (но серьёзным, лучшим из всех).»

Это не «продукт». Не «стартап». Не «проект для галочки». Хобби, но серьёзное. Работа, которая является игрой. Не потому, что «надо», а потому что интересно. Внутренний ребёнок радуется в процессе творчества.

Химанен в книге формулирует суть этики так:

«Хакер - это тот, кто решает проблему, а не тот, кто пользуется готовым решением. Если машина не делает то, что нужно, - хакер открывает её. Если система неудобна - хакер меняет её. Не потому, что заплатили, а потому что интересно. Не потому, что велели, а потому что сам захотел.»

И ведь можно открыть и переделать всё. Компилятор, раскладку, стандарт, технологию, чьё-то мнение.

RUSI - ровно это. Личное творчество. Захотел - переделал. Сделал. Сам захотел - и получилось.

Частично взгляды описаны в предыдущей статье Программисты на Руси программируют на Си. RUSI: Концепт билингвального компилятора.

В конце статьи есть список промптов для анализа текста статьи через призму различных подходов и взглядов.


Где взять и что внутри

Репозиторий: https://github.com/artradeskz/rgcc

Что внутри: GCC 14.2.0 с патчами для русского синтаксиса. Полный diff огромен - здесь не привожу. Но он есть в конце статьи под спойлером.

Краткая выжимка: что именно изменено и зачем.

1. UTF-8 в лексере (libcpp/lex.cc)

Традиционно работая с исходниками, GCC читает не по буквам, а по байтам. Так сложилось исторически. В интернете можно встретить утверждение, что GCC умеет работать с идентификаторами на UTF-8. Про то, что он может так же работать со служебными словами, там не будет сказано. Одна английская буква - один байт. Кириллица же в UTF-8 - это 2 байта на букву. И прежние алгоритмы чтения уже не сработают. Для русификации добавлена обработка UTF-8-последовательностей в forms_identifier_p, чтобы лексер парсил посимвольно, а не побайтово.

if (*buffer->cur == 0xD0 || *buffer->cur == 0xD1)
  {
    unsigned char first = *buffer->cur;
    unsigned char second = *(buffer->cur + 1);

    if (first == 0xD0 && second >= 0x90 && second <= 0xBF)
      {
        buffer->cur += 2;
        return true;
      }
    if (first == 0xD1 && second >= 0x80 && second <= 0x8F)
      {
        buffer->cur += 2;
        return true;
      }
  }

2. Синонимы ключевых слов (gcc/c-family/c-common.cc)

Добавлено ~250 русских синонимов в таблицу c_common_reswords[]:

{ "int",     RID_INT,     0 },
{ "цел",     RID_INT_RU,  0 },
{ "if",      RID_IF,      0 },
{ "если",    RID_IF,      0 },
{ "return",  RID_RETURN,  0 },
{ "возврат", RID_RETURN,  0 },
{ "char",    RID_CHAR,    0 },
{ "символ",  RID_CHAR,    0 },

3. Русские встроенные макросы (libcpp/init.cc)

B("__ФАЙЛ__",        BT_FILE,         false),
B("__ЛИНИЯ__",       BT_SPECLINE,     true),
B("__ДАТА__",        BT_DATE,         false),
B("__СЧЁТЧИК__",     BT_COUNTER,      true),
B("__ВРЕМЯ_ФАЙЛА__", BT_TIMESTAMP,    false),

4. Русские директивы препроцессора (libcpp/directives.cc и libcpp/expr.cc)

Директивы препроцессора - это команды, которые начинаются с #. Они не являются частью языка C в том смысле, что парсер их не видит. Их обрабатывает libcpp до того, как парсер получит лексемы. Именно поэтому удалось добавить русские директивы без изменения парсера: достаточно было добавить синонимы в таблицу директив.

В libcpp/directives.cc есть таблица dtable[] - список всех директив. Туда добавлены русские аналоги:

{ do_define,   UC"определить",  sizeof "определить" - 1,   KANDR, IN_I },
{ do_include,  UC"включить",    sizeof "включить" - 1,     KANDR, INCL | EXPAND },
{ do_if,       UC"если",        sizeof "если" - 1,         KANDR, COND | IF_COND | EXPAND },
{ do_endif,    UC"конецесли",   sizeof "конецесли" - 1,    KANDR, COND },

Теперь #включить <stdio.h> работает так же, как #include <stdio.h>. #определить - как #define. #если - как #if. И так далее.

Теперь можно писать:

#если определено(ОТЛАДКА)
    printf("Отладка включена\n");
#конецесли

Это полный русский аналог английского:

#if defined(DEBUG)
    printf("Отладка включена\n");
#endif

Немного хулиганства

Чтоб не перепутать стандартный и патченный компиляторы, было бы неплохо иметь возможность различать русифицированный GCC и обычный. Для этого можно доработать вывод команды с информацией о версии компилятора.

Где пропатчить команду gcc --version:

Файл: gcc/gcc.cc, 8900-я строка.

Там зашиты строка копирайта и текст про гарантию. Их можно заменить на свой текст.

  if (print_version)
    {
      printf (_("%s %s%s\n"), progname, pkgversion_string,
	      version_string);
      printf ("Copyright %s 2026 Coded by @artrades.\n",
	      _("(C)"));
      fputs (_("Использовать можно и нужно. Но никто ни за что ответственность не несет(очевидно). This is free software; see the source for copying conditions.  There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"),
	     stdout);
      if (! verbose_flag)
	return 0;

После сборки:

$ gcc --version
gcc (GCC) 14.2.0
Copyright (C) 2026 Coded by @artrades.
Использовать можно и нужно. Но никто ни за что ответственность не несет(очевидно).
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

В репозитории в данный участок кода - оригинальный. Текст можно менять на свое усмотрение.


Теория: почему русский синтаксис работает

Компилятор - это цепочка преобразований

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

Упрощённая схема для любого компилятора высокого уровня:

Исходник → лексемы → AST → ассемблер → лексемы → AST → исполняемый файл

Между каждым этапом работает преобразователь со своей логикой.

Что такое «знаково-логическая система»

На каждом этапе есть:

  • Алфавит - набор допустимых символов

  • Правила - как из символов строить конструкции

  • Семантика - что эти конструкции означают

Примеры:

Этап

Алфавит

Что описывает

Исходник

ASCII + UTF-8

текст программы

Лексемы

TK_INT, TK_IF, TK_RETURN

ключевые слова, операторы, идентификаторы

AST

VarDecl, IfStmt, ReturnStmt

структура программы

Ассемблер

mov, add, call

инструкции процессора

Лексемы

MOV, ADD, CALL, REG_EAX, IMM, MEM

мнемоники, регистры, непосредственные значения, адреса памяти

AST

Instruction(mov, src=REG, dst=REG), Label, Directive(.text)

инструкции, метки, директивы

Бинарь

байты

готовая программа

Что изменено

Только первые два преобразования:

  1. Исходник → лексемы (лексер libcpp)

  2. Лексемы → AST (парсер c-parser.cc)

На этапе первого AST компилятору уже безразлично, как выглядели слова на человеческом языке.

Вот два исходника:

int x = 42;
цел x = 42;

После преобразований оба превращаются в один и тот же узел AST:

VarDecl(name="x", type=Int, init=42)

Дальше компилятор работает только с абстрактным синтаксическим деревом: оптимизирует его, преобразует в ассемблер, в объектный код. Информация о том, что ты написал int или цел, была актуальна лишь на этапе парсера.

Почему производительность идентична

Именно потому, что после AST всё одинаково:

int x = 42;    ─┐
                ├─ AST - ассемблер - объектный код - линкер - бинарь
цел x = 42;    ─┘

Русский и английский исходники дают идентичный AST, значит, идентичный ассемблер, идентичный объектный код, идентичный бинарь.

Это подтверждено экспериментально: секция .text (исполняемый код) русского и английского исходников побайтово идентична.

Ключевой вывод

RUSI - это не «новый язык». Это билингвальный фасад к существующему языку C.

GCC научили понимать русские слова на входе, на этапе лексера и парсера. Всё остальное - стандартный GCC 14.2.

Русский синтаксис не добавляет ни одной инструкции в машинный код. Потому что после парсера разницы между русским и английским C не существует, есть только AST.


Сборка: от исходников до установки

Проверено на Ubuntu 26 с установленным в систему GCC 12 или с GCC 15.

Качаем:

git clone --depth 1 https://github.com/artradeskz/rgcc.git

Зависимости:

sudo apt install flex bison libgmp-dev libmpfr-dev libmpc-dev

Или, если не хочется ставить dev-пакеты, используется встроенный скрипт:

cd rgcc
./contrib/download_prerequisites

Он скачает GMP, MPFR, MPC, ISL в дерево исходников:

2026-10-03 18:13:45 URL:https://gcc.gnu.org/pub/gcc/infrastructure/gettext-0.22.tar.gz [26105696/26105696] -> "gettext-0.22.tar.gz" [1]
2026-10-03 18:13:47 URL:http://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.2.1.tar.bz2 [2493916/2493916] -> "gmp-6.2.1.tar.bz2" [1]
2026-10-03 18:13:49 URL:http://gcc.gnu.org/pub/gcc/infrastructure/mpfr-4.1.0.tar.bz2 [1747243/1747243] -> "mpfr-4.1.0.tar.bz2" [1]
2026-10-03 18:13:50 URL:http://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.2.1.tar.gz [838731/838731] -> "mpc-1.2.1.tar.gz" [1]
2026-10-03 18:13:52 URL:http://gcc.gnu.org/pub/gcc/infrastructure/isl-0.24.tar.bz2 [2261594/2261594] -> "isl-0.24.tar.bz2" [1]
gettext-0.22.tar.gz: OK
gmp-6.2.1.tar.bz2: OK
mpfr-4.1.0.tar.bz2: OK
mpc-1.2.1.tar.gz: OK
isl-0.24.tar.bz2: OK
All prerequisites downloaded successfully.

Конфигурация:

mkdir build && cd build

../configure \
    --enable-languages=c,c++ \
    --disable-multilib \
    --disable-nls \
    --disable-libgomp \  
    --disable-libquadmath \
    --disable-libssp \
    --disable-libvtv \
    --disable-libcc1 \
    --disable-libmpx \
    --disable-libcilkrts \
    --disable-libsanitizer \
    --disable-isl \
    --disable-bootstrap \
    --disable-graphite \
    --prefix=/usr/local/gcc-rus

Пояснения:

  • --enable-languages=c,c++ - собираем только C и C++

  • --disable-isl - отключает ISL и Graphite

  • --disable-bootstrap - отключен автоматический самосбор(об этом ниже)

  • --prefix=/usr/local/gcc-rus - изолированная установка

Сборка (2 потока, можно и быстрее):

make -j2 2>&1 | tee build.log

На Aspire 5742G - около часа. На современной машине - 15–20 минут.

Установка:

sudo make install

Проверка:

/usr/local/gcc-rus/bin/gcc --version

Добавление в PATH:

echo 'export PATH=/usr/local/gcc-rus/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

Тесты из chibicc-rusi

Методика

Взяты тесты из chibicc-RUSI без изменений. Прогнаны на RUSI-GCC.

cd тесты

python3 run_tests.py \
    --compiler ~/Документы/RUSI++/rgcc/build-full/gcc/xgcc \
    --build-dir ~/Документы/RUSI++/rgcc/build-full/gcc \
    --dir test_ru \
    --verbose

Результат: 63 из 65 (96.9%).

Полный вывод тестов

? Результат прогона тестов
============================================================
               ЗАПУСК РУССКИХ ТЕСТОВ ДЛЯ RUSI               
============================================================

Найдено тестов: 65
Компилятор: /home/me/Документы/RUSI++/rgcc/build-full/gcc/xgcc
Папка сборки (-B): /home/me/Документы/RUSI++/rgcc/build-full/gcc
Папка тестов: test_ru

[1/65] #else                     ✓ ОК (код 0)
[2/65] alignas                   ✓ ОК (код 0)
[3/65] alignof                   ✓ ОК (код 0)
[4/65] asm                       ✓ ОК (код 0)
[5/65] asm2                      ✓ ОК (код 0)
[6/65] atomic                    ✓ ОК (код 0)
[7/65] auto                      ✓ ОК (код 0)
[8/65] bool                      ✓ ОК (код 0)
[9/65] break                     ✓ ОК (код 0)
[10/65] case                     ✓ ОК (код 0)
[11/65] char                     ✓ ОК (код 65)
[12/65] const                    ✓ ОК (код 0)
[13/65] continue                 ✓ ОК (код 0)
[14/65] counter_ru               ✓ ОК (код 0)
[15/65] cyrillic_ident           ✓ ОК (код 0)
[16/65] cyrillic_ptr             ✓ ОК (код 0)
[17/65] date_ru                  ✓ ОК (код 0)
[18/65] default                  ✓ ОК (код 0)
[19/65] define                   ✓ ОК (код 0)
[20/65] defined                  ✓ ОК (код 0)
[21/65] do                       ✓ ОК (код 0)
[22/65] double                   ✓ ОК (код 2)
[23/65] elif                     ✓ ОК (код 0)
[24/65] else                     ✓ ОК (код 0)
[25/65] endif                    ✓ ОК (код 0)
[26/65] enum                     ✓ ОК (код 0)
[27/65] extern                   ✓ ОК (код 0)
[28/65] file_ru                  ✓ ОК (код 0)
[29/65] float                    ✓ ОК (код 3)
[30/65] for                      ✓ ОК (код 0)
[31/65] func_ru                  ✓ ОК (код 0)
[32/65] function_ru              ✓ ОК (код 0)
[33/65] generic                  ✓ ОК (код 0)
[34/65] goto                     ✓ ОК (код 0)
[35/65] if                       ✓ ОК (код 0)
[36/65] ifdef                    ✓ ОК (код 0)
[37/65] ifndef                   ✓ ОК (код 0)
[38/65] include                  ✓ ОК (код 0)
[39/65] inline                   ОШИБКА КОМПИЛЯЦИИ
    /usr/bin/x86_64-linux-gnu-ld.bfd: /tmp/ccvZ6sZh.o: в функции «main»:
    /home/me/Документы/RUSI++/rgcc/тесты/test_ru/inline.c:7:(.text+0xe): undefined reference to `квадрат'
    collect2: error: ld returned 1 exit status
[40/65] int                       ✓ ОК (код 0)
[41/65] line                      ✓ ОК (код 0)
[42/65] line_ru                   ✓ ОК (код 0)
[43/65] long                      ✓ ОК (код 0)
[44/65] main                      ✓ ОК (код 0)
[45/65] noreturn                  ✗ ОШИБКА ожидался 0, получен -11
[46/65] once                      ✓ ОК (код 0)
[47/65] register                  ✓ ОК (код 0)
[48/65] restrict                  ✓ ОК (код 0)
[49/65] return                    ✓ ОК (код 0)
[50/65] short                     ✓ ОК (код 123)
[51/65] signed                    ✓ ОК (код 0)
[52/65] sizeof                    ✓ ОК (код 0)
[53/65] static                    ✓ ОК (код 0)
[54/65] struct                    ✓ ОК (код 0)
[55/65] switch                    ✓ ОК (код 0)
[56/65] test_import               ✓ ОК (код 0)
[57/65] thread_local              ✓ ОК (код 0)
[58/65] time_ru                   ✓ ОК (код 0)
[59/65] typedef                   ✓ ОК (код 0)
[60/65] typeof                    ✓ ОК (код 0)
[61/65] undef                     ✓ ОК (код 0)
[62/65] union                     ✓ ОК (код 0)
[63/65] unsigned                  ✓ ОК (код 0)
[64/65] volatile                  ✓ ОК (код 0)
[65/65] while                     ✓ ОК (код 0)

============================================================
                  РЕЗУЛЬТАТЫ ТЕСТИРОВАНИЯ                   
============================================================

Итого:
  Пройдено: 63
  Провалено: 2
  Ошибок компиляции: 1
  Всего: 65
  Успешность: 96.9%

Два «провала» и почему это не баг GCC

inline.c:

// inline.c - Проверка ключевого слова inline
инлайн цел квадрат(цел х) {
    возврат х * х;
}

цел главн(){
    цел рез = квадрат(5);
    если (рез == 25) {
        возврат 0;
    }
    возврат 1;
}

Ошибка линковки: undefined reference to 'квадрат'.

Причина: в C99 inline без static/extern - это внутренняя функция, которая может не создаваться как внешняя. chibicc игнорирует inline и создаёт функцию. GCC следует стандарту и не создаёт. GCC прав.

noreturn.c:

// noreturn.c - Проверка _Безвозврат
_Безвозврат пусто завершение() {
    // Функция помечена как _Безвозврат, но на самом деле возвращается
    возврат;
}

цел главн(){
    завершение();
    возврат 0;
}

Падение с SIGSEGV (-11).

Причина: _Noreturn - это обещание компилятору, что функция не вернётся. Если она возвращается, это неопределённое поведение (согласно C11 §6.7.4). chibicc игнорирует _Noreturn. GCC применяет его для оптимизации (выбрасывает недостижимый код). Программа падает. GCC прав.

Вывод

Два «провала» - это не баги GCC, а разница семантики между chibicc и GCC. chibicc не проверяет типы и игнорирует атрибуты. GCC следует стандарту C. RUSI-GCC работает корректнее, чем chibicc-RUSI.


Самосбор

Лучшим способом проверить, что оригинальный Си и Си++ не отвалились, будет сбор GCC самим же собой. После установки в систему это делается аналогичной командой с аналогичной же конфигурацией(см.выше). Затем можно прогнать тесты. Для уверенности можно собрать еще раз.

В отличие от компилятора chibbic, GCC я не стал переписывать на русифицированном Си. Это огромный объем кодовой базы. Однако испытать РУСИ путем вкрапления в исходный код компилятора сам факт выполняемой задачи обязывает. Нужный компилятор в системе есть - можно приступать. Для испытания я выбрал файл gcc/c-family/c-common.cc (таблица ключевых слов).

Две директивы в начале.

#определить GCC_C_COMMON_C  

#включить "config.h"
#include "system.h"

И функцию c_addr_space_name().

/* Return identifier for address space AS.  */

конст char *
c_addr_space_name (addr_space_t as)
{
  цел rid = RID_FIRST_ADDR_SPACE + as;
  gcc_assert (ridpointers [rid]);
  возврат IDENTIFIER_POINTER (ridpointers [rid]);
}

С такими изменениями собирать это стандартным компилятором уже не получится!

После сборки можно снова прогнать тесты. И для верности собрать и протестировать еще раз.

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

В статье приведена команда для сборки с отключенным бутстрапом. Каждый этап запускается вручную приведенный выше командой. Это сделано чтоб не сломать сборку внутренними тестами, не рассчитанными на задвоенные ключевые слова(-fself-test не даст запустить Stage 2 и Stage 3).


Сравнительные сборки

«Привет, мир»

Исходник у нас будет один, но соберём мы его двумя компиляторами. Содержимое файла:

#включить <stdio.h>

цел главн(пусто) {
    printf("Привет, мир!\n");
    возврат 0;
}

Обратите внимание: здесь смешанный синтаксис. Директива #включить - русская. Тип цел - русский. Ключевое слово возврат - русское. А printf и stdio.h - латиница, потому что это имена из стандартной библиотеки, их мы не переводим.

Сохраним файл в двух вариантах: привет.си для chibicc (он понимает расширение .си) и привет.c для GCC (он понимает .c). Содержимое одинаковое.

Собираем через chibicc-RUSI:

./rusi.elf -o привет_chibicc привет.си

Собираем через GCC-RUSI (с оптимизацией -O2):

/usr/local/gcc-rus-full/bin/gcc -O2 привет.c -o привет_gcc

Сравнение размеров:

$ stat -c '%n %s байт' привет_chibicc привет_gcc
привет_chibicc 17640 байт
привет_gcc 15688 байт
$ size привет_chibicc привет_gcc
   text    data     bss     dec     hex filename
   1623     933       3    2559     9ff привет_chibicc
    949     544       8    1501     5dd привет_gcc

Сведём в таблицу:

Метрика

chibicc

GCC -O2

Разница

Размер файла

17 640 байт

15 688 байт

−11%

.text (код)

1 623 байт

949 байт

−42%

.data

933 байта

544 байта

−42%

.bss

3 байта

8 байт

+5 байт

Итог (dec)

2 559

1 501

−41%

Файл от GCC на 11% меньше. Но самое интересное - секция .text: код от GCC почти в 2 раза компактнее. .bss чуть больше у GCC, но это 8 байт против 3 - несущественно.

Проверим, что оба работают:

$ ./привет_chibicc
Привет, мир!
$ ./привет_gcc
Привет, мир!

Ответ одинаковый. Теперь посмотрим, почему код от GCC компактнее.

Дизассемблер chibicc-RUSI

0000000000401106 <главн>:
  401106:	55                   	push   %rbp
  401107:	48 89 e5             	mov    %rsp,%rbp
  40110a:	48 83 ec 10          	sub    $0x10,%rsp
  40110e:	48 89 65 f8          	mov    %rsp,-0x8(%rbp)
  401112:	48 8d 05 f7 2e 00 00 	lea    0x2ef7(%rip),%rax
  401119:	50                   	push   %rax
  40111a:	48 8b 05 b7 2e 00 00 	mov    0x2eb7(%rip),%rax
  401121:	5f                   	pop    %rdi
  401122:	49 89 c2             	mov    %rax,%r10
  401125:	48 c7 c0 00 00 00 00 	mov    $0x0,%rax
  40112c:	41 ff d2             	call   *%r10
  40112f:	48 83 c4 00          	add    $0x0,%rsp
  401133:	48 c7 c0 00 00 00 00 	mov    $0x0,%rax
  40113a:	eb 07                	jmp    401143 <главн+0x3d>
  40113c:	48 c7 c0 00 00 00 00 	mov    $0x0,%rax
  401143:	48 89 ec             	mov    %rbp,%rsp
  401146:	5d                   	pop    %rbp
  401147:	c3                   	ret

Дизассемблер GCC-RUSI

0000000000401040 <main>:
  401040:	48 83 ec 08          	sub    $0x8,%rsp
  401044:	bf 04 20 40 00       	mov    $0x402004,%edi
  401049:	e8 e2 ff ff ff       	call   401030 <puts@plt>
  40104e:	31 c0                	xor    %eax,%eax
  401050:	48 83 c4 08          	add    $0x8,%rsp
  401054:	c3                   	ret

Что видно

Разница драматическая. Пройдёмся по пунктам.

1. Передача аргумента.

chibicc:

lea    0x2ef7(%rip),%rax
push   %rax
...
pop    %rdi

Адрес строки сначала кладётся в rax, потом пушится в стек, потом вытаскивается в rdi. Три инструкции вместо одной.

GCC:

mov    $0x402004,%edi

Адрес строки сразу попадает в edi (младшие 32 бита rdi). Одна инструкция.

2. Вызов функции.

chibicc:

mov    0x2eb7(%rip),%rax
mov    %rax,%r10
mov    $0x0,%rax
call   *%r10

Адрес printf загружается из GOT в регистр, потом перекладывается в r10, потом вызов через указатель. Ещё и rax обнуляется (для variadic-функций).

GCC:

call   401030 <puts@plt>

Прямой вызов puts через PLT. Одна инструкция.

3. printf против puts.

GCC заменил printf("Привет, мир!\n") на puts("Привет, мир!"). Это классическая оптимизация: если строка заканчивается на \n и нет форматирования, puts работает быстрее. chibicc не делает этого - вызывает printf напрямую.

4. Возврат значения.

chibicc:

mov    $0x0,%rax
jmp    401143
...
mov    $0x0,%rax

Два mov $0x0,%rax и лишний jmp.

GCC:

xor    %eax,%eax

Одна инструкция. xor регистра с самим собой - идиоматический способ обнуления, работает быстрее, чем mov.

5. Frame pointer.

chibicc:

push   %rbp
mov    %rsp,%rbp
...
pop    %rbp

Сохраняет frame pointer, потому что chibicc не оптимизирует. GCC в -O2 выбрасывает его: sub $0x8,%rsp вместо push %rbp; mov %rsp,%rbp. Меньше инструкций, меньше стекового фрейма.

6. Лишние инструкции.

chibicc:

sub    $0x10,%rsp
mov    %rsp,-0x8(%rbp)
...
add    $0x0,%rsp

Выделяет 16 байт стека, сохраняет указатель стека в память (зачем?), потом прибавляет 0 к rsp. Безсмысленные операции.

GCC:

sub    $0x8,%rsp
...
add    $0x8,%rsp

Выделяет ровно столько, сколько нужно для выравнивания стека. Никаких лишних операций.

Итог

Что

chibicc

GCC

Передача аргумента

через стек (push/pop)

прямо в регистр (mov … %edi)

Вызов функции

через указатель (call *%r10)

напрямую (call puts@plt)

printf vs puts

printf

puts (оптимизация)

return 0

mov $0x0,%rax + jmp

xor %eax,%eax

Frame pointer

есть (push %rbp)

нет

Лишние инструкции

add $0x0,%rsp, mov %rsp,-0x8(%rbp)

нет

Размер кода

~66 байт

~21 байт

Именно поэтому секция .text от GCC в 1.7 раза меньше. chibicc генерирует наивный код: каждая операция через стек, вызов через указатель, лишние jmp и mov. GCC оптимизирует: аргументы в регистрах, прямой вызов, puts вместо printf.

И самое главное: это тот же самый исходник. Один и тот же русский C. Разница только в компиляторе. В конце статьи под спойлером полные дизассемблерные тексты.

Простые числа до 100 000

Исходник (prost.c):

#включить <stdio.h>

цел простые(цел н) {
    цел счёт = 0;
    для (цел и = 2; и <= н; и++) {
        цел флаг = 1;
        для (цел й = 2; й * й <= и; й++) {
            если (и % й == 0) { флаг = 0; прерви; }
        }
        если (флаг) счёт++;
    }
    возврат счёт;
}

цел главн(пусто) {
    printf("Простых до 100000: %d\n", простые(100000));
    возврат 0;
}

Тот же алгоритм на английском C для проверки, что ответ идентичен:

#include <stdio.h>

int simple(int n) {
    int count = 0;
    for (int i = 2; i <= n; i++) {
        int flag = 1;
        for (int j = 2; j * j <= i; j++) {
            if (i % j == 0) { flag = 0; break; }
        }
        if (flag) count++;
    }
    return count;
}

int main(void) {
    printf("Простых до 100000: %d\n", simple(100000));
    return 0;
}

Собираем тремя способами:

./rusi.elf -o prost_chibicc prost.c
/usr/local/gcc-rus-full/bin/gcc -O0 prost.c -o prost_gcc_O0
/usr/local/gcc-rus-full/bin/gcc -O2 prost.c -o prost_gcc_O2

Запускаем и проверяем, что ответ одинаковый:

$ ./prost_chibicc
Простых до 100000: 9592
$ ./prost_gcc_O0
Простых до 100000: 9592
$ ./prost_gcc_O2
Простых до 100000: 9592

Все три дают одинаковый ответ.

Сравнение размеров:

$ stat -c '%n %s байт' prost_chibicc prost_gcc_O0 prost_gcc_O2
prost_chibicc 17872 байт
prost_gcc_O0 15728 байт
prost_gcc_O2 15728 байт
$ size prost_chibicc prost_gcc_O0 prost_gcc_O2
   text    data     bss     dec     hex filename
   2139     997       3    3139     c43 prost_chibicc
   1125     544       8    1677     68d prost_gcc_O0
   1106     544       8    1658     67a prost_gcc_O2

Замер скорости:

$ time ./prost_chibicc
=== chibicc ===
Простых до 100000: 9592

real    0m0,039s
user    0m0,038s
sys     0m0,002s

$ time ./prost_gcc_O0
=== gcc -O0 ===
Простых до 100000: 9592

real    0m0,016s
user    0m0,012s
sys     0m0,002s

$ time ./prost_gcc_O2
=== gcc -O2 ===
Простых до 100000: 9592

real    0m0,015s
user    0m0,011s
sys     0m0,004s

Итоговая таблица:

Метрика

chibicc

gcc -O0

gcc -O2

Разница (chibicc → gcc -O2)

Размер файла

17 872 байт

15 728 байт

15 728 байт

−12%

.text (код)

2 139 байт

1 125 байт

1 106 байт

−48% (почти в 2 раза!)

.data

997 байт

544 байта

544 байта

−45%

Итог (dec)

3 139

1 677

1 658

−47%

Время (real)

0,039 с

0,016 с

0,015 с

−62% (в 2,6 раза!)

Время (user)

0,038 с

0,012 с

0,011 с

−71% (в 3,5 раза!)

Ответ

9592

9592

9592

одинаковый

Почему так

GCC:

  • Держит переменные в регистрах, а не в стеке

  • Оптимизирует условие й * й <= и

  • Разматывает циклы

  • Инлайнит мелкие функции

  • Заменяет printf на puts, где возможно

chibicc:

  • Каждая операция через стек

  • Нет оптимизаций

  • Наивный код

Ассемблерные оптимизации работают.


РУСИ++: побочный продукт

Если перебирать компилятор, который парсит не только Си, а еще и Си++, то есть смысл сделать билингвальный построитель AST полностью. Были добавлены синонимы для всех слов.

Что это

RUSI++ - это C++ с русским синтаксисом. Работают:

  • Классы (класс)

  • Конструкторы

  • private / public (без перевода, оставлено как есть)

  • Шаблоны (шаблон<имя_типа T>)

  • Наследование

  • Виртуальные функции

Пример

#включить <iostream>
#включить <string>

класс Приветствие {
закрыт:
    std::string имя;

открыт:
    Приветствие(конст std::string& н) : имя(н) {}

    пусто поздороваться() конст {
        std::cout << "Привет, " << имя << "!" << std::endl;
    }
};

цел главн() {
    Приветствие п("мир");
    п.поздороваться();
    возврат 0;
}

Сравнение с английским C++

#include <iostream>
#include <string>

class Greeting {
private:
    std::string name;

public:
    Greeting(const std::string& n) : name(n) {}

    void greet() const {
        std::cout << "Привет, " << name << "!" << std::endl;
    }
};

int main() {
    Greeting g("мир");
    g.greet();
    return 0;
}

Собран тот же код на английском C++ через тот же RUSI++:

/usr/local/gcc-rus-full/bin/g++ -O2 привет_класс.cpp -o привет_класс
/usr/local/gcc-rus-full/bin/g++ -O2 privet_class_en.cpp -o privet_class_en

Проверка запуска:

$ ./привет_класс
Привет, мир!
$ ./privet_class_en
Привет, мир!

Сравнение размеров:

$ stat -c '%n %s байт' привет_класс privet_class_en
привет_класс 16672 байт
privet_class_en 16664 байт
$ size привет_класс privet_class_en
   text    data     bss     dec     hex filename
   2690     656     280    3626     e2a привет_класс
   2690     656     280    3626     e2a privet_class_en

Сравнение кода:

$ objcopy -O binary --only-section=.text привет_класс /tmp/ru.bin
$ objcopy -O binary --only-section=.text privet_class_en /tmp/en.bin
$ cmp /tmp/ru.bin /tmp/en.bin && echo "✅ КОД ИДЕНТИЧЕН" || echo "❌ РАЗЛИЧАЕТСЯ"
✅ КОД ИДЕНТИЧЕН

Таблица:

Метрика

привет_класс (рус)

privet_class_en (англ)

Разница

Размер файла

16 672 байт

16 664 байта

8 байт (0,05%)

.text (код)

2 690 байт

2 690 байт

0

.data

656 байт

656 байт

0

.bss

280 байт

280 байт

0

Машинный код

идентичен

идентичен

0

Разница в 8 байт - это имена функций и классов в таблице символов (главн() vs main(), Приветствие vs Greeting). Сам код один и тот же.

Вывод

RUSI++ - это не переопределение слов через дефайны. Это полноценный C++ с русским синтаксисом. Классы, шаблоны, ООП - всё работает и компилируется в тот же машинный код, что и английский C++. Это побочный продукт работы над РУСИ: раз GCC поддерживает C++, а фронтенд русифицирован, C++ тоже стал русским.


Итог: форк chibicc породил три более совершенных языка

Что было: RUSI на chibicc - учебный компилятор для русского C.

Что стало:

Компилятор

База

Что умеет

РУСИ (GCC)

GCC 14.2

Русский C, оптимизации, все архитектуры

РУСИ++

GCC 14.2

Русский C++, классы, шаблоны, ООП

Объектный-РУСИ

GCC 14.2

Русский Objective-C (не тестировался)

Ключевое: все три - не «перевод ключевых слов», а полноценные фронтенды GCC с русским синтаксисом. После парсера AST идентичен английскому, дальше работает стандартный бэкенд GCC.


Перспективы применения

Куда можно применить технологию, с помощью которой создано почти всё? Преимуществом тут будет факт того, что Си все знают. Никого переучивать не нужно. Билингвальность же даёт обратную совместимость: всё, что написано ранее, можно без проблем применять. Да и переписывание такого компилятора на кириллическом Си - способ быстро прокачать инженерную школу.

Операционные системы

  • Linux - можно писать модули ядра

  • Windows - MinGW / Cygwin

  • macOS - через кросс-компиляцию

  • FreeBSD - нативная поддержка

  • Экзотические системы - всё, что поддерживает GCC

Встроенные системы

  • Прошивки для микроконтроллеров

  • Контроллеры (ARM Cortex-M, RISC-V)

  • Arduino (AVR)

  • Bare-metal

Процессоры

  • x86, x86-64

  • ARM, ARM64

  • RISC-V

  • MIPS

  • PowerPC

  • AVR

  • Всё, что поддерживает GCC

Отрасли

  • Приборостроение - уникальные приборы, измерительная техника

  • Робототехника - управление роботами

  • Системы связи - телекоммуникационное оборудование

  • Транспорт - встроенные системы автомобилей, поездов, самолётов

Образование

КуМир - школьный язык для обучения. RUSI может заменить его профессиональным инструментом с тем же русским синтаксисом, но с реальными возможностями GCC.

Экспорт в страны с кириллическим алфавитом

Болгария, Монголия, Сербия, Северная Македония, Казахстан, Кыргызстан - страны, где кириллица является официальной или широко используемой письменностью.

Создание отечественного стандарта ЯП Си

РУСИ может стать основой для отечественного стандарта языка системного программирования. Не «новый язык с нуля», а билингвальный стандарт:

  • Полная совместимость с международным стандартом C (ISO/IEC 9899)

  • Кириллический синтаксис как равноправный с латинским

  • Промышленная база GCC 14.2, а не учебный компилятор

Такой стандарт может быть принят для использования в … - везде, где требуется русскоязычная документация и код.

Появление нового стандарта раскладки.

Новая ru-раскладка с фигурными, квадратными и угловыми скобками однозначно продвинет применение русского языка в различных технологиях.


СПбГУ. RuC. Интерпретатор Терехова

До появления проекта RUSI в СПбГУ зародился свой Си с русскими словами - RuC. Виртуальная машина. Не сборщик в бинарь.

RuC - компилятор русского C в байт-код виртуальной машины. Автор - Андрей Терехов (СПбГУ). Проект остановился в 2023 году.

Почему остановился? Академический проект. Всё держалось на профессоре.

Названия похожи. Наверняка найдутся желающие столкнуть проекты по части именования. Оба могут сосуществовать со своими именами как Java и JavaScript.

Но есть идея даже концептуально развить RuC Терехова. И тут скорее win/win получится.

RuC написан на C++. RUSI++ - это C++ с русским синтаксисом. Значит:

  1. Берём исходники RuC

  2. Заменяем ключевые слова на русские (class → класс, int → цел, return → возврат)

  3. Собираем через РУСИ++

  4. Получаем тот же самый RuC, но с исходниками на русском

И возможно, в процессе появятся идеи развития проекта.


Заключение

Что сделано:

  • GCC 14.2.0 русифицирован

  • Тесты chibicc-RUSI проходят на 96.9% (два «провала» - баги chibicc, не RUSI)

  • RUSI-GCC быстрее и компактнее chibicc-RUSI в 2–3.5 раза

  • RUSI++ работает: классы, шаблоны, ООП

Что дальше:

  • Кросс-компиляция под ARM, RISC-V

  • Bare-metal поддержка (newlib, linker scripts)

  • Русификация стандартной библиотеки

  • Написание документации

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


Ссылки


Бонус: фигурные скобки в русской раскладке

Проблема

Стандартная русская раскладка в Ubuntu 26 не имеет {, }, [, ], <, >. Клавиши, где они лежат в английской (Shift + [, Shift + ], Shift + ,, Shift + .), в русской заняты буквами х, ъ, б, ю.

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

Решение: задействуем правый Alt (AltGr). Он даёт третий уровень клавиатуры, специально созданный для ввода дополнительных символов. Он не конфликтует с Ctrl+X, Ctrl+C и другими системными сокращениями.

Что получится:

AltGr + х → {
AltGr + ъ → }
AltGr + щ → [
AltGr + з → ]
AltGr + б → <
AltGr + ю → >
Левый Alt, оба Ctrl, Shift → работают как обычно

Почему именно щ и з для квадратных скобок: это самый простой способ. Можно, конечно, заморочиться и на правый Ctrl сделать комбинацию с кнопками «х» и «ъ» - путь сложный. Зато теперь конструкция вида если (щ[ы] < щ[ю]) { } не представляет никаких сложностей.

Патчим раскладку

Шаг 1. Резервная копия

sudo cp /usr/share/X11/xkb/symbols/ru /usr/share/X11/xkb/symbols/ru.orig

Шаг 2. Открыть файл раскладки

sudo nano /usr/share/X11/xkb/symbols/ru

Шаг 3. Найти блок winkeys

В самом начале файла:

// Windows layout
default partial alphanumeric_keys
xkb_symbols "winkeys" {

    include "ru(common)"
    name[Group1]= "Russian";

    key <AE03>	{[          3,  numerosign  ]};
    key <AE04>	{[          4,   semicolon  ]};
    ...
    key <AB10>	{[     period,       comma  ]};
    key <BKSL>	{[  backslash,       slash  ]};
};

Шаг 4. Заменить блок winkeys целиком

// Windows layout
default partial alphanumeric_keys
xkb_symbols "winkeys" {

    include "ru(common)"
    name[Group1]= "Russian";

    key <AE03>  {[          3,  numerosign  ]};
    key <AE04>  {[          4,   semicolon  ]};
    key <AE05>  {[          5,     percent  ]};
    key <AE06>  {[          6,       colon  ]};
    key <AE07>  {[          7,    question  ]};
    key <AE08>  {[          8,    asterisk,      U20BD  ]}; // ruble

    key <AB10>  {[     period,       comma  ]};
    key <BKSL>  {[  backslash,       slash  ]};


    // --- добавлено для C-подобных языков ---
    key <AD11> {
        type[Group1] = "FOUR_LEVEL",
        symbols[Group1] = [ Cyrillic_ha, Cyrillic_HA, braceleft, braceleft ]
    };
    key <AD12> {
        type[Group1] = "FOUR_LEVEL",
        symbols[Group1] = [ Cyrillic_hardsign, Cyrillic_HARDSIGN, braceright, braceright ]
    };

    // --- квадратные скобки на AltGr: щ → [, з → ] ---
    key <AD09> {
        type = "FOUR_LEVEL",
        symbols[Group1] = [ Cyrillic_shcha, Cyrillic_SHCHA, bracketleft, bracketleft ]
    };
    key <AD10> {
        type = "FOUR_LEVEL",
        symbols[Group1] = [ Cyrillic_ze, Cyrillic_ZE, bracketright, bracketright ]
    };

    // --- угловые скобки на AltGr: б → <, ю → > ---
    key <AB08> {
        type = "FOUR_LEVEL",
        symbols[Group1] = [ Cyrillic_be, Cyrillic_BE, less, less ]
    };
    key <AB09> {
        type = "FOUR_LEVEL",
        symbols[Group1] = [ Cyrillic_yu, Cyrillic_YU, greater, greater ]
    };



    include "level3(ralt_switch)"

};

Пояснения:

  • <AD11> - физическая клавиша [, в русской раскладке х

  • <AD12> - физическая клавиша ], в русской раскладке ъ

  • <AD09> - физическая клавиша O, в русской раскладке щ

  • <AD10> - физическая клавиша P, в русской раскладке з

  • <AB08> - физическая клавиша ,, в русской раскладке б

  • <AB09> - физическая клавиша ., в русской раскладке ю

  • FOUR_LEVEL - четыре уровня: без модификатора, Shift, AltGr, Shift+AltGr

  • braceleft/braceright - { и }

  • bracketleft/bracketright - [ и ]

  • less/greater - < и >

  • level3(ralt_switch) - включает правый Alt как AltGr

Шаг 5. Перезагрузить систему

sudo reboot

Шаг 6. Проверить

Открыть любой текстовый редактор:

х → х,  Shift + х → Х,  AltGr + х → {
ъ → ъ,  Shift + ъ → Ъ,  AltGr + ъ → }
щ → щ,  Shift + щ → Щ,  AltGr + щ → [
з → з,  Shift + з → З,  AltGr + з → ]
б → б,  Shift + б → Б,  AltGr + б → <
ю → ю,  Shift + ю → Ю,  AltGr + ю → >

Если AltGr + х даёт { - всё готово.

Кастомная XKB-раскладка работает на уровне системы, без конфликтов. Левый Alt, оба Ctrl, Shift - как обычно.


Спойлеры

Ниже приведены спойлеры для тех, кто хочет вникнуть в детали.

? Git diff
[diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index aae998d0f73..6c12d22fc17 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -383,245 +383,465 @@ static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT);
    reserved word too, but only if it follows an '@' sign.
 */
 const struct c_common_resword c_common_reswords[] =
-{
+{ 
   { "_Alignas",		RID_ALIGNAS,   D_CONLY },
+  { "_Выравнивание",	RID_ALIGNAS,   D_CONLY },
   { "_Alignof",		RID_ALIGNOF,   D_CONLY },
+  { "_Выравнивание_типа",	RID_ALIGNOF,   D_CONLY },
   { "_Atomic",		RID_ATOMIC,    D_CONLY },
+  { "_Атом",		RID_ATOMIC,    D_CONLY },
   { "_BitInt",		RID_BITINT,    D_CONLY },
+  { "_бит_цел",		RID_BITINT,    D_CONLY },
   { "_Bool",		RID_BOOL,      D_CONLY },
+  { "_лог",		RID_BOOL,      D_CONLY },
   { "_Complex",		RID_COMPLEX,	0 },
+  { "_комплекс",	RID_COMPLEX,	0 },
   { "_Imaginary",	RID_IMAGINARY, D_CONLY },
+  { "_мнимое",		RID_IMAGINARY, D_CONLY },
   { "_Float16",         RID_FLOAT16,    0 },
+  { "_вещ16",         RID_FLOAT16,    0 },
   { "_Float32",         RID_FLOAT32,    0 },
+  { "_вещ32",         RID_FLOAT32,    0 },
   { "_Float64",         RID_FLOAT64,    0 },
+  { "_вещ64",         RID_FLOAT64,    0 },
   { "_Float128",        RID_FLOAT128,   0 },
+  { "_вещ128",        RID_FLOAT128,   0 },
   { "_Float32x",        RID_FLOAT32X,   0 },
+  { "_вещ32x",        RID_FLOAT32X,   0 },
   { "_Float64x",        RID_FLOAT64X,   0 },
+  { "_вещ64x",        RID_FLOAT64X,   0 },
   { "_Float128x",       RID_FLOAT128X,  0 },
+  { "_вещ128x",       RID_FLOAT128X,  0 },
   { "_Decimal32",       RID_DFLOAT32,  D_CONLY },
+  { "_десят32",       RID_DFLOAT32,  D_CONLY },
   { "_Decimal64",       RID_DFLOAT64,  D_CONLY },
+  { "_десят64",       RID_DFLOAT64,  D_CONLY },
   { "_Decimal128",      RID_DFLOAT128, D_CONLY },
+  { "_десят128",      RID_DFLOAT128, D_CONLY },
   { "_Fract",           RID_FRACT,     D_CONLY | D_EXT },
+  { "_дробь",           RID_FRACT,     D_CONLY | D_EXT },
   { "_Accum",           RID_ACCUM,     D_CONLY | D_EXT },
+  { "_аккум",           RID_ACCUM,     D_CONLY | D_EXT },
   { "_Sat",             RID_SAT,       D_CONLY | D_EXT },
+  { "_насыщ",           RID_SAT,       D_CONLY | D_EXT },
   { "_Static_assert",   RID_STATIC_ASSERT, D_CONLY },
+  { "_стат_проверка",   RID_STATIC_ASSERT, D_CONLY },
   { "_Noreturn",        RID_NORETURN,  D_CONLY },
+  { "_Безвозврат",        RID_NORETURN,  D_CONLY },
   { "_Generic",         RID_GENERIC,   D_CONLY },
+  { "_Обобщ",           RID_GENERIC,   D_CONLY },
   { "_Thread_local",    RID_THREAD,    D_CONLY },
+  { "_Поток_лок",     RID_THREAD,    D_CONLY },
   { "__FUNCTION__",	RID_FUNCTION_NAME, 0 },
+  { "__ФУНКЦИЯ__",	RID_FUNCTION_NAME, 0 },
   { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
+  { "__КРАСИВАЯ_ФУНКЦИЯ__", RID_PRETTY_FUNCTION_NAME, 0 },
   { "__alignof",	RID_ALIGNOF,	0 },
+  { "__выравн_от",	RID_ALIGNOF,	0 },
   { "__alignof__",	RID_ALIGNOF,	0 },
+  { "__выравн_от__",	RID_ALIGNOF,	0 },
   { "__asm",		RID_ASM,	0 },
+  { "__ассемблер",	RID_ASM,	0 },
   { "__asm__",		RID_ASM,	0 },
+  { "__ассемблер__",	RID_ASM,	0 },
   { "__attribute",	RID_ATTRIBUTE,	0 },
+  { "__атрибут",	RID_ATTRIBUTE,	0 },
   { "__attribute__",	RID_ATTRIBUTE,	0 },
+  { "__атрибут__",	RID_ATTRIBUTE,	0 },
   { "__auto_type",	RID_AUTO_TYPE,	D_CONLY },
+  { "__авто_тип",	RID_AUTO_TYPE,	D_CONLY },
   { "__builtin_addressof", RID_ADDRESSOF, D_CXXONLY },
+  { "__встр_адрес_от", RID_ADDRESSOF, D_CXXONLY },
   { "__builtin_assoc_barrier", RID_BUILTIN_ASSOC_BARRIER, 0 },
+  { "__встр_барьер_ассоц", RID_BUILTIN_ASSOC_BARRIER, 0 },
   { "__builtin_bit_cast", RID_BUILTIN_BIT_CAST, D_CXXONLY },
+  { "__встр_бит_преобр", RID_BUILTIN_BIT_CAST, D_CXXONLY },
   { "__builtin_call_with_static_chain",
     RID_BUILTIN_CALL_WITH_STATIC_CHAIN, D_CONLY },
+  { "__встр_вызов_со_стат_цепью",
+    RID_BUILTIN_CALL_WITH_STATIC_CHAIN, D_CONLY },
   { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY },
+  { "__встр_выбор_выраж", RID_CHOOSE_EXPR, D_CONLY },
   { "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY },
+  { "__встр_комплекс", RID_BUILTIN_COMPLEX, D_CONLY },
   { "__builtin_convertvector", RID_BUILTIN_CONVERTVECTOR, 0 },
+  { "__встр_преобр_вектор", RID_BUILTIN_CONVERTVECTOR, 0 },
   { "__builtin_has_attribute", RID_BUILTIN_HAS_ATTRIBUTE, 0 },
+  { "__встр_имеет_атрибут", RID_BUILTIN_HAS_ATTRIBUTE, 0 },
   { "__builtin_launder", RID_BUILTIN_LAUNDER, D_CXXONLY },
+  { "__встр_очистка", RID_BUILTIN_LAUNDER, D_CXXONLY },
   { "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 },
+  { "__встр_перемешать", RID_BUILTIN_SHUFFLE, 0 },
   { "__builtin_shufflevector", RID_BUILTIN_SHUFFLEVECTOR, 0 },
+  { "__встр_перемешать_вектор", RID_BUILTIN_SHUFFLEVECTOR, 0 },
   { "__builtin_stdc_bit_ceil", RID_BUILTIN_STDC, D_CONLY },
+  { "__встр_stdc_бит_потолок", RID_BUILTIN_STDC, D_CONLY },
   { "__builtin_stdc_bit_floor", RID_BUILTIN_STDC, D_CONLY },
+  { "__встр_stdc_бит_пол", RID_BUILTIN_STDC, D_CONLY },
   { "__builtin_stdc_bit_width", RID_BUILTIN_STDC, D_CONLY },
+  { "__встр_stdc_бит_ширина", RID_BUILTIN_STDC, D_CONLY },
   { "__builtin_stdc_count_ones", RID_BUILTIN_STDC, D_CONLY },
+  { "__встр_stdc_считать_единицы", RID_BUILTIN_STDC, D_CONLY },
   { "__builtin_stdc_count_zeros", RID_BUILTIN_STDC, D_CONLY },
+  { "__встр_stdc_считать_нули", RID_BUILTIN_STDC, D_CONLY },
   { "__builtin_stdc_first_leading_one", RID_BUILTIN_STDC, D_CONLY },
+  { "__встр_stdc_первый_ведущий_один", RID_BUILTIN_STDC, D_CONLY },
   { "__builtin_stdc_first_leading_zero", RID_BUILTIN_STDC, D_CONLY },
+  { "__встр_stdc_первый_ведущий_нуль", RID_BUILTIN_STDC, D_CONLY },
   { "__builtin_stdc_first_trailing_one", RID_BUILTIN_STDC, D_CONLY },
+  { "__встр_stdc_первый_хвостовой_один", RID_BUILTIN_STDC, D_CONLY },
   { "__builtin_stdc_first_trailing_zero", RID_BUILTIN_STDC, D_CONLY },
+  { "__встр_stdc_первый_хвостовой_нуль", RID_BUILTIN_STDC, D_CONLY },
   { "__builtin_stdc_has_single_bit", RID_BUILTIN_STDC, D_CONLY },
+  { "__встр_stdc_имеет_один_бит", RID_BUILTIN_STDC, D_CONLY },
   { "__builtin_stdc_leading_ones", RID_BUILTIN_STDC, D_CONLY },
+  { "__встр_stdc_ведущие_единицы", RID_BUILTIN_STDC, D_CONLY },
   { "__builtin_stdc_leading_zeros", RID_BUILTIN_STDC, D_CONLY },
+  { "__встр_stdc_ведущие_нули", RID_BUILTIN_STDC, D_CONLY },
   { "__builtin_stdc_trailing_ones", RID_BUILTIN_STDC, D_CONLY },
+  { "__встр_stdc_хвостовые_единицы", RID_BUILTIN_STDC, D_CONLY },
   { "__builtin_stdc_trailing_zeros", RID_BUILTIN_STDC, D_CONLY },
+  { "__встр_stdc_хвостовые_нули", RID_BUILTIN_STDC, D_CONLY },
   { "__builtin_tgmath", RID_BUILTIN_TGMATH, D_CONLY },
+  { "__встр_tgmath", RID_BUILTIN_TGMATH, D_CONLY },
   { "__builtin_offsetof", RID_OFFSETOF, 0 },
+  { "__встр_смещение", RID_OFFSETOF, 0 },
   { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, D_CONLY },
+  { "__встр_типы_совместимы", RID_TYPES_COMPATIBLE_P, D_CONLY },
   { "__builtin_va_arg",	RID_VA_ARG,	0 },
+  { "__встр_va_arg",	RID_VA_ARG,	0 },
   { "__complex",	RID_COMPLEX,	0 },
+  { "__комплекс",	RID_COMPLEX,	0 },
   { "__complex__",	RID_COMPLEX,	0 },
+  { "__комплекс__",	RID_COMPLEX,	0 },
   { "__const",		RID_CONST,	0 },
+  { "конст",		RID_CONST,	0 },
   { "__const__",	RID_CONST,	0 },
+  { "__неизм__",	RID_CONST,	0 },
   { "__constinit",	RID_CONSTINIT,	D_CXXONLY },
+  { "__конст_иниц",	RID_CONSTINIT,	D_CXXONLY },
   { "__decltype",       RID_DECLTYPE,   D_CXXONLY },
+  { "__тип_выраж",      RID_DECLTYPE,   D_CXXONLY },
   { "__extension__",	RID_EXTENSION,	0 },
+  { "__расширение__",	RID_EXTENSION,	0 },
   { "__func__",		RID_C99_FUNCTION_NAME, 0 },
+  { "__функ__",		RID_C99_FUNCTION_NAME, 0 },
   { "__imag",		RID_IMAGPART,	0 },
+  { "__мнимая",		RID_IMAGPART,	0 },
   { "__imag__",		RID_IMAGPART,	0 },
+  { "__мнимая__",	RID_IMAGPART,	0 },
   { "__inline",		RID_INLINE,	0 },
+  { "__встр",		RID_INLINE,	0 },
   { "__inline__",	RID_INLINE,	0 },
+  { "__встр__",		RID_INLINE,	0 },
   { "__label__",	RID_LABEL,	0 },
+  { "__метка__",	RID_LABEL,	0 },
   { "__null",		RID_NULL,	0 },
+  { "__нуль",		RID_NULL,	0 },
   { "__real",		RID_REALPART,	0 },
+  { "__действ",		RID_REALPART,	0 },
   { "__real__",		RID_REALPART,	0 },
+  { "__действ__",	RID_REALPART,	0 },
   { "__restrict",	RID_RESTRICT,	0 },
+  { "__огран",	        RID_RESTRICT,	0 },
   { "__restrict__",	RID_RESTRICT,	0 },
+  { "__огран__",	RID_RESTRICT,	0 },
   { "__signed",		RID_SIGNED,	0 },
+  { "__знак",		RID_SIGNED,	0 },
   { "__signed__",	RID_SIGNED,	0 },
+  { "__знак__",		RID_SIGNED,	0 },
   { "__thread",		RID_THREAD,	0 },
+  { "__поток",		RID_THREAD,	0 },
   { "__transaction_atomic", RID_TRANSACTION_ATOMIC, 0 },
+  { "__транзакция_атомарн", RID_TRANSACTION_ATOMIC, 0 },
   { "__transaction_relaxed", RID_TRANSACTION_RELAXED, 0 },
+  { "__транзакция_расслабл", RID_TRANSACTION_RELAXED, 0 },
   { "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 },
+  { "__транзакция_отмена", RID_TRANSACTION_CANCEL, 0 },
   { "__typeof",		RID_TYPEOF,	0 },
+  { "__тип_от",		RID_TYPEOF,	0 },
   { "__typeof__",	RID_TYPEOF,	0 },
+  { "__тип_от__",	RID_TYPEOF,	0 },
   { "__typeof_unqual",	RID_TYPEOF_UNQUAL, D_CONLY },
+  { "__тип_от_без_квал",	RID_TYPEOF_UNQUAL, D_CONLY },
   { "__typeof_unqual__", RID_TYPEOF_UNQUAL, D_CONLY },
+  { "__тип_от_без_квал__", RID_TYPEOF_UNQUAL, D_CONLY },
   { "__volatile",	RID_VOLATILE,	0 },
+  { "__неуст",	        RID_VOLATILE,	0 },
   { "__volatile__",	RID_VOLATILE,	0 },
+  { "__неуст__",	RID_VOLATILE,	0 },
   { "__GIMPLE",		RID_GIMPLE,	D_CONLY },
-  { "__PHI",		RID_PHI,	D_CONLY },
+  { "__PHI",		RID_PHI,	D_CONLY },    // 
   { "__RTL",		RID_RTL,	D_CONLY },
   { "alignas",		RID_ALIGNAS,	D_C23 | D_CXX11 | D_CXXWARN },
+  { "выравн_как",	RID_ALIGNAS,	D_C23 | D_CXX11 | D_CXXWARN },
   { "alignof",		RID_ALIGNOF,	D_C23 | D_CXX11 | D_CXXWARN },
+  { "выравн_от",	RID_ALIGNOF,	D_C23 | D_CXX11 | D_CXXWARN },
   { "asm",		RID_ASM,	D_ASM },
+  { "асм",		RID_ASM,	D_ASM },
   { "auto",		RID_AUTO,	0 },
+  { "авто",		RID_AUTO,	0 },
   { "bool",		RID_BOOL,	D_C23 | D_CXXWARN },
+  //{ "бул",		RID_BOOL,	D_C23 | D_CXXWARN },
+  { "бул", RID_BOOL, 0 },
   { "break",		RID_BREAK,	0 },
+  { "прерви",		RID_BREAK,	0 },
   { "case",		RID_CASE,	0 },
+  { "случай",		RID_CASE,	0 },
   { "catch",		RID_CATCH,	D_CXX_OBJC | D_CXXWARN },
+  { "поймать",		RID_CATCH,	D_CXX_OBJC | D_CXXWARN },
   { "char",		RID_CHAR,	0 },
+  { "символ",		RID_CHAR,	0 },
   { "char8_t",		RID_CHAR8,	D_CXX_CHAR8_T_FLAGS | D_CXXWARN },
+  { "симв8_t",		RID_CHAR8,	D_CXX_CHAR8_T_FLAGS | D_CXXWARN },
   { "char16_t",		RID_CHAR16,	D_CXXONLY | D_CXX11 | D_CXXWARN },
+  { "симв16_t",		RID_CHAR16,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "char32_t",		RID_CHAR32,	D_CXXONLY | D_CXX11 | D_CXXWARN },
+  { "симв32_t",		RID_CHAR32,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "class",		RID_CLASS,	D_CXX_OBJC | D_CXXWARN },
+  { "класс",		RID_CLASS,	D_CXX_OBJC | D_CXXWARN },
+  { "__конст",		RID_CONST,	0 }, 
   { "consteval",	RID_CONSTEVAL,	D_CXXONLY | D_CXX20 | D_CXXWARN },
+  { "конст_вычисл",	RID_CONSTEVAL,	D_CXXONLY | D_CXX20 | D_CXXWARN },
   { "constexpr",	RID_CONSTEXPR,	D_C23 | D_CXX11 | D_CXXWARN },
+  { "конст_выраж",	RID_CONSTEXPR,	D_C23 | D_CXX11 | D_CXXWARN },
   { "constinit",	RID_CONSTINIT,	D_CXXONLY | D_CXX20 | D_CXXWARN },
+  { "конст_иниц",	RID_CONSTINIT,	D_CXXONLY | D_CXX20 | D_CXXWARN },
   { "const_cast",	RID_CONSTCAST,	D_CXXONLY | D_CXXWARN },
+  { "конст_преобр",	RID_CONSTCAST,	D_CXXONLY | D_CXXWARN },
   { "continue",		RID_CONTINUE,	0 },
+  { "продолжи",		RID_CONTINUE,	0 },
   { "decltype",         RID_DECLTYPE,   D_CXXONLY | D_CXX11 | D_CXXWARN },
+  { "тип_выраж",        RID_DECLTYPE,   D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "default",		RID_DEFAULT,	0 },
+  { "умолч",		RID_DEFAULT,	0 },
   { "delete",		RID_DELETE,	D_CXXONLY | D_CXXWARN },
+  { "удалить",		RID_DELETE,	D_CXXONLY | D_CXXWARN },
   { "do",		RID_DO,		0 },
+  { "делай",		RID_DO,		0 },
   { "double",		RID_DOUBLE,	0 },
+  { "двойн",		RID_DOUBLE,	0 },
   { "dynamic_cast",	RID_DYNCAST,	D_CXXONLY | D_CXXWARN },
+  { "динам_преобр",	RID_DYNCAST,	D_CXXONLY | D_CXXWARN },
   { "else",		RID_ELSE,	0 },
+  { "иначе",		RID_ELSE,	0 },
   { "enum",		RID_ENUM,	0 },
+  { "переч",		RID_ENUM,	0 },
   { "explicit",		RID_EXPLICIT,	D_CXXONLY | D_CXXWARN },
+  { "явный",		RID_EXPLICIT,	D_CXXONLY | D_CXXWARN },
   { "export",		RID_EXPORT,	D_CXXONLY | D_CXXWARN },
+  { "экспорт",		RID_EXPORT,	D_CXXONLY | D_CXXWARN },
   { "extern",		RID_EXTERN,	0 },
+  { "внеш",		RID_EXTERN,	0 },
   { "false",		RID_FALSE,	D_C23 | D_CXXWARN },
+  { "ложь",		RID_FALSE,	0 },
   { "float",		RID_FLOAT,	0 },
+  { "плав",		RID_FLOAT,	0 },
   { "for",		RID_FOR,	0 },
+  { "для",		RID_FOR,	0 },
   { "friend",		RID_FRIEND,	D_CXXONLY | D_CXXWARN },
+  { "друг",		RID_FRIEND,	D_CXXONLY | D_CXXWARN },
   { "goto",		RID_GOTO,	0 },
+  { "перейти",		RID_GOTO,	0 },
   { "if",		RID_IF,		0 },
+  { "если",		RID_IF,		0 },
   { "inline",		RID_INLINE,	D_EXT89 },
+  { "инлайн",		RID_INLINE,	D_EXT89 },
   { "int",		RID_INT,	0 },
+  { "цел",		RID_INT_RU,	0 },                                             
   { "long",		RID_LONG,	0 },
+  { "длин",		RID_LONG,	0 },
   { "mutable",		RID_MUTABLE,	D_CXXONLY | D_CXXWARN },
+  { "измен",		RID_MUTABLE,	D_CXXONLY | D_CXXWARN },
   { "namespace",	RID_NAMESPACE,	D_CXXONLY | D_CXXWARN },
+  { "пространство",	RID_NAMESPACE,	D_CXXONLY | D_CXXWARN },
   { "new",		RID_NEW,	D_CXXONLY | D_CXXWARN },
+  { "новый",		RID_NEW,	D_CXXONLY | D_CXXWARN },
   { "noexcept",		RID_NOEXCEPT,	D_CXXONLY | D_CXX11 | D_CXXWARN },
+  { "без_искл",		RID_NOEXCEPT,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "nullptr",		RID_NULLPTR,	D_C23 | D_CXX11 | D_CXXWARN },
+  { "пуст_указ",	RID_NULLPTR,	D_C23 | D_CXX11 | D_CXXWARN },
   { "operator",		RID_OPERATOR,	D_CXXONLY | D_CXXWARN },
+  { "оператор",		RID_OPERATOR,	D_CXXONLY | D_CXXWARN },
   { "private",		RID_PRIVATE,	D_CXX_OBJC | D_CXXWARN },
+  { "закрыт",		RID_PRIVATE,	D_CXX_OBJC | D_CXXWARN },
   { "protected",	RID_PROTECTED,	D_CXX_OBJC | D_CXXWARN },
+  { "защищ",	        RID_PROTECTED,	D_CXX_OBJC | D_CXXWARN },
   { "public",		RID_PUBLIC,	D_CXX_OBJC | D_CXXWARN },
+  { "открыт",		RID_PUBLIC,	D_CXX_OBJC | D_CXXWARN },
   { "register",		RID_REGISTER,	0 },
+  { "регистр",		RID_REGISTER,	0 },
   { "reinterpret_cast",	RID_REINTCAST,	D_CXXONLY | D_CXXWARN },
+  { "переинт_преобр",	RID_REINTCAST,	D_CXXONLY | D_CXXWARN },
   { "restrict",		RID_RESTRICT,	D_CONLY | D_C99 },
+  { "огранич",		RID_RESTRICT,	D_CONLY | D_C99 },
   { "return",		RID_RETURN,	0 },
+  { "возврат",		RID_RETURN,	0 },
   { "short",		RID_SHORT,	0 },
+  { "корот",		RID_SHORT,	0 },
   { "signed",		RID_SIGNED,	0 },
+  { "знак",		RID_SIGNED,	0 },
   { "sizeof",		RID_SIZEOF,	0 },
+  { "размер",		RID_SIZEOF,	0 },
   { "static",		RID_STATIC,	0 },
+  { "стат",		RID_STATIC,	0 },
   { "static_assert",    RID_STATIC_ASSERT, D_C23 | D_CXX11 | D_CXXWARN },
+  { "стат_проверка",    RID_STATIC_ASSERT, D_C23 | D_CXX11 | D_CXXWARN },
   { "static_cast",	RID_STATCAST,	D_CXXONLY | D_CXXWARN },
+  { "стат_преобр",	RID_STATCAST,	D_CXXONLY | D_CXXWARN },
   { "struct",		RID_STRUCT,	0 },
+  { "структ",		RID_STRUCT,	0 },
   { "switch",		RID_SWITCH,	0 },
+  { "выбор",		RID_SWITCH,	0 },
   { "template",		RID_TEMPLATE,	D_CXXONLY | D_CXXWARN },
+  { "шаблон",		RID_TEMPLATE,	D_CXXONLY | D_CXXWARN },
   { "this",		RID_THIS,	D_CXXONLY | D_CXXWARN },
+  { "этот",		RID_THIS,	D_CXXONLY | D_CXXWARN },
   { "thread_local",	RID_THREAD,	D_C23 | D_CXX11 | D_CXXWARN },
+  { "_Поток_лок",	RID_THREAD,	D_C23 | D_CXX11 | D_CXXWARN },
   { "throw",		RID_THROW,	D_CXX_OBJC | D_CXXWARN },
+  { "бросить",		RID_THROW,	D_CXX_OBJC | D_CXXWARN },
   { "true",		RID_TRUE,	D_C23 | D_CXXWARN },
+  { "истина",		RID_TRUE,	0 },
   { "try",		RID_TRY,	D_CXX_OBJC | D_CXXWARN },
+  { "попытка",		RID_TRY,	D_CXX_OBJC | D_CXXWARN },
   { "typedef",		RID_TYPEDEF,	0 },
+  { "типдеф",		RID_TYPEDEF,	0 },
   { "typename",		RID_TYPENAME,	D_CXXONLY | D_CXXWARN },
+  { "имя_типа",		RID_TYPENAME,	D_CXXONLY | D_CXXWARN },
   { "typeid",		RID_TYPEID,	D_CXXONLY | D_CXXWARN },
+  { "ид_типа",		RID_TYPEID,	D_CXXONLY | D_CXXWARN },
   { "typeof",		RID_TYPEOF,	D_EXT11 },
+  { "типоф",		RID_TYPEOF,	D_EXT11 },
   { "typeof_unqual",	RID_TYPEOF_UNQUAL,	D_CONLY | D_C23 },
+  { "тип_от_без_квал",	RID_TYPEOF_UNQUAL,	D_CONLY | D_C23 },
   { "union",		RID_UNION,	0 },
+  { "объед",		RID_UNION,	0 },
   { "unsigned",		RID_UNSIGNED,	0 },
+  { "беззнак",		RID_UNSIGNED,	0 },
   { "using",		RID_USING,	D_CXXONLY | D_CXXWARN },
+  { "используя",	RID_USING,	D_CXXONLY | D_CXXWARN },
   { "virtual",		RID_VIRTUAL,	D_CXXONLY | D_CXXWARN },
+  { "вирт",		RID_VIRTUAL,	D_CXXONLY | D_CXXWARN },
   { "void",		RID_VOID,	0 },
+  { "пусто",		RID_VOID,	0 },
   { "volatile",		RID_VOLATILE,	0 },
+  { "летуч",		RID_VOLATILE,	0 },
   { "wchar_t",		RID_WCHAR,	D_CXXONLY },
+  { "ш_симв",		RID_WCHAR,	D_CXXONLY },
   { "while",		RID_WHILE,	0 },
+  { "пока",		RID_WHILE,	0 },
 
   /* C++ transactional memory.  */
   { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
+  { "синхрон",	        RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
   { "atomic_noexcept",	RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
+  { "атомарн_без_искл",	RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
   { "atomic_cancel",	RID_ATOMIC_CANCEL, D_CXXONLY | D_TRANSMEM },
+  { "атомарн_отмена",	RID_ATOMIC_CANCEL, D_CXXONLY | D_TRANSMEM },
   { "atomic_commit",	RID_TRANSACTION_ATOMIC, D_CXXONLY | D_TRANSMEM },
+  { "атомарн_фиксация",	RID_TRANSACTION_ATOMIC, D_CXXONLY | D_TRANSMEM },
 
   /* Concepts-related keywords */
   { "concept",		RID_CONCEPT,	D_CXX_CONCEPTS_FLAGS | D_CXXWARN },
+  { "концепт",		RID_CONCEPT,	D_CXX_CONCEPTS_FLAGS | D_CXXWARN },
   { "requires", 	RID_REQUIRES,	D_CXX_CONCEPTS_FLAGS | D_CXXWARN },
+  { "требует", 	        RID_REQUIRES,	D_CXX_CONCEPTS_FLAGS | D_CXXWARN },
 
   /* Modules-related keywords, these are internal unspellable tokens,
      created by the preprocessor.  */
   { "module ",		RID__MODULE,	D_CXX_MODULES_FLAGS | D_CXXWARN },
+  { "модуль ",		RID__MODULE,	D_CXX_MODULES_FLAGS | D_CXXWARN },
   { "import ",		RID__IMPORT,	D_CXX_MODULES_FLAGS | D_CXXWARN },
+  { "импорт ",		RID__IMPORT,	D_CXX_MODULES_FLAGS | D_CXXWARN },
   { "export ",		RID__EXPORT,	D_CXX_MODULES_FLAGS | D_CXXWARN },
+  { "экспорт ",		RID__EXPORT,	D_CXX_MODULES_FLAGS | D_CXXWARN },
 
   /* Coroutines-related keywords */
   { "co_await",		RID_CO_AWAIT,	D_CXX_COROUTINES_FLAGS | D_CXXWARN },
+  { "со_ждать",		RID_CO_AWAIT,	D_CXX_COROUTINES_FLAGS | D_CXXWARN },
   { "co_yield",		RID_CO_YIELD,	D_CXX_COROUTINES_FLAGS | D_CXXWARN },
+  { "со_уступить",	RID_CO_YIELD,	D_CXX_COROUTINES_FLAGS | D_CXXWARN },
   { "co_return", 	RID_CO_RETURN,	D_CXX_COROUTINES_FLAGS | D_CXXWARN },
+  { "со_возврат", 	RID_CO_RETURN,	D_CXX_COROUTINES_FLAGS | D_CXXWARN },
 
   /* These Objective-C keywords are recognized only immediately after
      an '@'.  */
   { "compatibility_alias", RID_AT_ALIAS,	D_OBJC },
+  { "совместим_псевдоним", RID_AT_ALIAS,	D_OBJC },
   { "defs",		RID_AT_DEFS,		D_OBJC },
+  { "описания",		RID_AT_DEFS,		D_OBJC },
   { "encode",		RID_AT_ENCODE,		D_OBJC },
+  { "кодировать",	RID_AT_ENCODE,		D_OBJC },
   { "end",		RID_AT_END,		D_OBJC },
+  { "конец",		RID_AT_END,		D_OBJC },
   { "implementation",	RID_AT_IMPLEMENTATION,	D_OBJC },
+  { "реализация",	RID_AT_IMPLEMENTATION,	D_OBJC },
   { "interface",	RID_AT_INTERFACE,	D_OBJC },
+  { "интерфейс",	RID_AT_INTERFACE,	D_OBJC },
   { "protocol",		RID_AT_PROTOCOL,	D_OBJC },
+  { "протокол",		RID_AT_PROTOCOL,	D_OBJC },
   { "selector",		RID_AT_SELECTOR,	D_OBJC },
+  { "селектор",		RID_AT_SELECTOR,	D_OBJC },
   { "finally",		RID_AT_FINALLY,		D_OBJC },
+  { "наконец",		RID_AT_FINALLY,		D_OBJC },
   { "optional",		RID_AT_OPTIONAL,	D_OBJC },
+  { "необязат",		RID_AT_OPTIONAL,	D_OBJC },
   { "required",		RID_AT_REQUIRED,	D_OBJC },
+  { "обязат",		RID_AT_REQUIRED,	D_OBJC },
   { "property",		RID_AT_PROPERTY,	D_OBJC },
+  { "свойство",		RID_AT_PROPERTY,	D_OBJC },
   { "package",		RID_AT_PACKAGE,		D_OBJC },
+  { "пакет",		RID_AT_PACKAGE,		D_OBJC },
   { "synthesize",	RID_AT_SYNTHESIZE,	D_OBJC },
+  { "синтез",	        RID_AT_SYNTHESIZE,	D_OBJC },
   { "dynamic",		RID_AT_DYNAMIC,		D_OBJC },
+  { "динам",		RID_AT_DYNAMIC,		D_OBJC },
   /* These are recognized only in protocol-qualifier context
      (see above) */
   { "bycopy",		RID_BYCOPY,		D_OBJC },
+  { "копировать",	RID_BYCOPY,		D_OBJC },
   { "byref",		RID_BYREF,		D_OBJC },
+  { "по_ссылке",	RID_BYREF,		D_OBJC },
   { "in",		RID_IN,			D_OBJC },
+  { "вход",		RID_IN,			D_OBJC },
   { "inout",		RID_INOUT,		D_OBJC },
+  { "вход_выход",	RID_INOUT,		D_OBJC },
   { "oneway",		RID_ONEWAY,		D_OBJC },
+  { "однонапр",		RID_ONEWAY,		D_OBJC },
   { "out",		RID_OUT,		D_OBJC },
+  { "выход",		RID_OUT,		D_OBJC },
   /* These are recognized inside a property attribute list */
   { "assign",		RID_ASSIGN,		D_OBJC },
+  { "присвоить",	RID_ASSIGN,		D_OBJC },
   { "atomic",		RID_PROPATOMIC,		D_OBJC },
+  { "атомарн",		RID_PROPATOMIC,		D_OBJC },
   { "copy",		RID_COPY,		D_OBJC },
+  { "копия",		RID_COPY,		D_OBJC },
   { "getter",		RID_GETTER,		D_OBJC },
+  { "получатель",	RID_GETTER,		D_OBJC },
   { "nonatomic",	RID_NONATOMIC,		D_OBJC },
+  { "не_атомарн",	RID_NONATOMIC,		D_OBJC },
   { "readonly",		RID_READONLY,		D_OBJC },
+  { "только_чтение",	RID_READONLY,		D_OBJC },
   { "readwrite",	RID_READWRITE,		D_OBJC },
+  { "чтение_запись",	RID_READWRITE,		D_OBJC },
   { "retain",		RID_RETAIN,		D_OBJC },
+  { "удержать",		RID_RETAIN,		D_OBJC },
   { "setter",		RID_SETTER,		D_OBJC },
+  { "установщик",	RID_SETTER,		D_OBJC },
   /* These are Objective C implementation of nullability, accepted only in
      specific contexts.  */
   { "null_unspecified", RID_NULL_UNSPECIFIED,	D_OBJC },
+  { "нуль_не_указан",   RID_NULL_UNSPECIFIED,	D_OBJC },
   { "nullable",		RID_NULLABLE,		D_OBJC },
+  { "может_быть_нуль",	RID_NULLABLE,		D_OBJC },
   { "nonnull",		RID_NONNULL,		D_OBJC },
+  { "не_нуль",		RID_NONNULL,		D_OBJC },
   { "null_resettable",	RID_NULL_RESETTABLE,	D_OBJC },
+  { "нуль_сбрасываемый",RID_NULL_RESETTABLE,	D_OBJC },
 };
 
 const unsigned int num_c_common_reswords = ARRAY_SIZE (c_common_reswords);
@@ -4792,6 +5012,7 @@ c_common_nodes_and_builtins (void)
   c_define_builtins (va_list_ref_type_node, va_list_arg_type_node);
 
   main_identifier_node = get_identifier ("main");
+  main_ru_identifier_node = get_identifier ("главн");
 
   /* Create the built-in __null node.  It is important that this is
      not shared.  */
@@ -8802,6 +9023,7 @@ keyword_begins_type_specifier (enum rid keyword)
     {
     case RID_AUTO_TYPE:
     case RID_INT:
+    case RID_INT_RU:  // ДОБАВИТЬ ЗДЕСЬ!
     case RID_CHAR:
     case RID_FLOAT:
     case RID_DOUBLE:
@@ -8847,6 +9069,7 @@ keyword_is_type_qualifier (enum rid keyword)
   switch (keyword)
     {
     case RID_CONST:
+    //case RID_CONST_RU:  // ДОБАВИТЬ ЗДЕСЬ!
     case RID_VOLATILE:
     case RID_RESTRICT:
     case RID_ATOMIC:
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 2d5f5399885..d94ebf3fe89 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -260,7 +260,11 @@ enum rid
   RID_FIRST_PQ = RID_IN,
   RID_LAST_PQ = RID_ONEWAY,
   RID_FIRST_PATTR = RID_GETTER,
-  RID_LAST_PATTR = RID_NULL_RESETTABLE
+  RID_LAST_PATTR = RID_NULL_RESETTABLE,
+
+  RID_INT_RU,
+  RID_CONST_RU,
+  RID_MAIN_RU
 };
 
 #define OBJC_IS_AT_KEYWORD(rid) \
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 0e52f217618..cbb738b142b 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -10502,6 +10502,14 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
 			  &attributes, &expr, NULL, DEPRECATED_NORMAL);
   invoke_plugin_callbacks (PLUGIN_START_PARSE_FUNCTION, decl1);
 
+  /* === ДОБАВЛЕНО: замена "главн" на "main" === */
+  if (decl1 != NULL_TREE && TREE_CODE (decl1) == FUNCTION_DECL)
+    {
+      if (DECL_NAME (decl1) == main_ru_identifier_node)
+        DECL_NAME (decl1) = main_identifier_node;
+    }
+  /* === КОНЕЦ ДОБАВЛЕННОГО БЛОКА === */
+
   /* If the declarator is not suitable for a function definition,
      cause a syntax error.  */
   if (decl1 == NULL_TREE
@@ -12466,6 +12474,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
 		}
 	      return specs;
 	    case RID_INT:
+		case RID_INT_RU:  // ДОБАВИТЬ ЗДЕСЬ!
 	      if (specs->saturating_p)
 		error_at (loc,
 			  ("both %<_Sat%> and %<int%> in "
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 5fcfff7134a..1e1a68eb1b8 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -588,6 +588,7 @@ c_keyword_starts_typename (enum rid keyword)
     case RID_SIGNED:
     case RID_COMPLEX:
     case RID_INT:
+case RID_INT_RU:  // ДОБАВИТЬ ЗДЕСЬ!
     case RID_CHAR:
     case RID_FLOAT:
     case RID_DOUBLE:
@@ -792,6 +793,7 @@ c_token_starts_declspecs (c_token *token)
 	case RID_SIGNED:
 	case RID_COMPLEX:
 	case RID_INT:
+case RID_INT_RU:  // ДОБАВИТЬ ЗДЕСЬ!
 	case RID_CHAR:
 	case RID_FLOAT:
 	case RID_DOUBLE:
@@ -3446,6 +3448,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 	case RID_SIGNED:
 	case RID_COMPLEX:
 	case RID_INT:
+case RID_INT_RU:  // ДОБАВИТЬ ЗДЕСЬ!
 	case RID_CHAR:
 	case RID_FLOAT:
 	case RID_DOUBLE:
@@ -5173,6 +5176,7 @@ c_parser_gnu_attribute_any_word (c_parser *parser)
 	case RID_COMPLEX:
 	case RID_THREAD:
 	case RID_INT:
+case RID_INT_RU:  // ДОБАВИТЬ ЗДЕСЬ!
 	case RID_CHAR:
 	case RID_FLOAT:
 	case RID_DOUBLE:
@@ -13901,6 +13905,7 @@ c_parser_objc_selector (c_parser *parser)
     case RID_BYREF:
     case RID_ONEWAY:
     case RID_INT:
+case RID_INT_RU:  // ДОБАВИТЬ ЗДЕСЬ!
     case RID_CHAR:
     case RID_FLOAT:
     case RID_DOUBLE:
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 1110db7f8d0..d29f5c20100 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -262,17 +262,33 @@ init_reswords (void)
   /* The Objective-C keywords are all context-dependent.  */
   mask |= D_OBJC;
 
-  ridpointers = ggc_cleared_vec_alloc<tree> ((int) RID_MAX);
-  for (i = 0; i < num_c_common_reswords; i++)
-    {
-      if (c_common_reswords[i].disable & D_CONLY)
-	continue;
-      id = get_identifier (c_common_reswords[i].word);
-      C_SET_RID_CODE (id, c_common_reswords[i].rid);
-      ridpointers [(int) c_common_reswords[i].rid] = id;
-      if (! (c_common_reswords[i].disable & mask))
-	set_identifier_kind (id, cik_keyword);
-    }
+// В gcc/cp/lex.cc (или gcc/c-family/c-common.cc для C)
+// Добавить специальную обработку после основного цикла
+
+ridpointers = ggc_cleared_vec_alloc<tree> ((int) RID_MAX);
+for (i = 0; i < num_c_common_reswords; i++)
+{
+    if (c_common_reswords[i].disable & D_CONLY)
+        continue;
+    id = get_identifier (c_common_reswords[i].word);
+    C_SET_RID_CODE (id, c_common_reswords[i].rid);
+    ridpointers [(int) c_common_reswords[i].rid] = id;
+    if (! (c_common_reswords[i].disable & mask))
+        set_identifier_kind (id, cik_keyword);
+}
+
+// ✅ ДОБАВИТЬ: сделать RID_INT_RU и RID_INT эквивалентными
+// Делаем так, чтобы оба ключевых слова указывали на ОДИН идентификатор
+if (ridpointers[RID_INT] && ridpointers[RID_INT_RU])
+{
+    // Вариант 1: переиспользовать идентификатор RID_INT для RID_INT_RU
+    ridpointers[RID_INT_RU] = ridpointers[RID_INT];
+    
+    // ИЛИ вариант 2: сделать оба указателя на идентификатор "цел"
+    // ridpointers[RID_INT] = ridpointers[RID_INT_RU];
+}
+
+
 
   for (i = 0; i < NUM_INT_N_ENTS; i++)
     {
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 9fa74342919..a5be6ec6955 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -754,6 +754,7 @@ enum tree_index {
   TI_VOID_LIST_NODE,
 
   TI_MAIN_IDENTIFIER,
+  TI_MAIN_RU_IDENTIFIER,
 
   TI_SAT_SFRACT_TYPE,
   TI_SAT_FRACT_TYPE,
diff --git a/gcc/tree.h b/gcc/tree.h
index ee2aae332a4..b3336250935 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4606,9 +4606,11 @@ tree_strip_any_location_wrapper (tree exp)
 #define void_list_node                  global_trees[TI_VOID_LIST_NODE]
 
 #define main_identifier_node		global_trees[TI_MAIN_IDENTIFIER]
+#define main_ru_identifier_node global_trees[TI_MAIN_RU_IDENTIFIER]
 #define MAIN_NAME_P(NODE) \
   (IDENTIFIER_NODE_CHECK (NODE) == main_identifier_node)
-
+#define MAIN_RU_NAME_P(NODE) \
+  (IDENTIFIER_NODE_CHECK (NODE) == main_ru_identifier_node)  // ← ДОБАВИТЬ
 /* Optimization options (OPTIMIZATION_NODE) to use for default and current
    functions.  */
 #define optimization_default_node	global_trees[TI_OPTIMIZATION_DEFAULT]
diff --git a/libcpp/directives.cc b/libcpp/directives.cc
index 479f8c716e8..aed62174ab0 100644
--- a/libcpp/directives.cc
+++ b/libcpp/directives.cc
@@ -190,6 +190,23 @@ enum
 static const directive dtable[] =
 {
 DIRECTIVE_TABLE
+
+  /* Русские синонимы для директив */
+  { do_define,   UC"определить",   sizeof "определить" - 1, KANDR, IN_I },
+  { do_include,  UC"включить",     sizeof "включить" - 1,   KANDR, INCL | EXPAND },
+  { do_if,       UC"если",         sizeof "если" - 1,       KANDR, COND | IF_COND | EXPAND },
+  { do_ifdef,    UC"еслиопр",      sizeof "еслиопр" - 1, KANDR, COND | IF_COND },
+  { do_ifndef,   UC"еслинеопр", sizeof "еслинеопр" - 1, KANDR, COND | IF_COND },
+  { do_elif,     UC"иначеесли",    sizeof "иначеесли" - 1, STDC89, COND | EXPAND },
+  { do_else,     UC"иначе",        sizeof "иначе" - 1,      KANDR, COND },
+  { do_endif,    UC"конецесли",    sizeof "конецесли" - 1, KANDR, COND },
+  { do_undef,    UC"отменить",     sizeof "отменить" - 1,   KANDR, IN_I },
+  { do_error,    UC"ошибка",       sizeof "ошибка" - 1,     STDC89, 0 },
+  { do_warning,  UC"предупреждение", sizeof "предупреждение" - 1, STDC23, 0 },
+  { do_pragma,   UC"прагма",       sizeof "прагма" - 1,     STDC89, IN_I },
+  { do_line,     UC"строка",       sizeof "строка" - 1,     KANDR, EXPAND },
+  { do_include_next, UC"включить_след", sizeof "включить_след" - 1, EXTENSION, INCL | EXPAND },
+  { do_import,   UC"импорт",       sizeof "импорт" - 1,     EXTENSION, INCL | EXPAND },
 };
 #undef D
 
@@ -197,7 +214,25 @@ DIRECTIVE_TABLE
    when suggesting corrections for misspelled directives.  */
 #define D(name, t, origin, flags) #name,
 static const char * const directive_names[] = {
-DIRECTIVE_TABLE
+  DIRECTIVE_TABLE
+
+  /* Русские синонимы для подсказок */
+  "определить",
+  "включить",
+  "если",
+  "если_определен",
+  "если_не_определен",
+  "иначе_если",
+  "иначе",
+  "конец_если",
+  "отменить",
+  "ошибка",
+  "предупреждение",
+  "прагма",
+  "строка",
+  "включить_след",
+  "импорт",
+
   NULL
 };
 #undef D
@@ -459,6 +494,7 @@ _cpp_handle_directive (cpp_reader *pfile, bool indented)
 
   if (dname->type == CPP_NAME)
     {
+      /* Сначала проверяем стандартные директивы по is_directive.  */
       if (dname->val.node.node->is_directive)
 	{
 	  dir = &dtable[dname->val.node.node->directive_index];
@@ -469,6 +505,31 @@ _cpp_handle_directive (cpp_reader *pfile, bool indented)
 	      && CPP_OPTION (pfile, std))
 	    dir = 0;
 	}
+else
+  {
+    /* Если не нашли по is_directive, ищем русский синоним в dtable.  */
+    const uchar *name = NODE_NAME (dname->val.node.node);
+    size_t len = NODE_LEN (dname->val.node.node);
+    
+    /* ОТЛАДКА: выводим имя и длину искомой директивы */
+    fprintf (stderr, "DEBUG: Looking for directive '%.*s' (len=%zu)\n",
+             (int)len, name, len);
+    
+    for (unsigned int i = 0; i < ARRAY_SIZE (dtable); i++)
+      {
+        /* ОТЛАДКА: выводим каждую запись в dtable */
+        fprintf (stderr, "DEBUG: dtable[%u] = '%.*s' (len=%hu)\n",
+                 i, (int)dtable[i].length, dtable[i].name, dtable[i].length);
+        
+        if (dtable[i].length == len
+            && memcmp (dtable[i].name, name, len) == 0)
+          {
+            fprintf (stderr, "DEBUG: FOUND! i=%u\n", i);
+            dir = &dtable[i];
+            break;
+          }
+      }
+  }
     }
   /* We do not recognize the # followed by a number extension in
      assembler code.  */
@@ -2171,8 +2232,9 @@ do_elif (cpp_reader *pfile)
 	}
       else
 	{
-	  if (pfile->directive == &dtable[T_ELIF])
-	    pfile->state.skipping = !_cpp_parse_expr (pfile, false);
+	  if (pfile->directive == &dtable[T_ELIF]
+      || pfile->directive->handler == do_elif)
+      pfile->state.skipping = !_cpp_parse_expr (pfile, false);
 	  else
 	    {
 	      cpp_hashnode *node = lex_macro_node (pfile, false);
@@ -2813,6 +2875,16 @@ _cpp_init_directives (cpp_reader *pfile)
       node->is_directive = 1;
       node->directive_index = i;
     }
+
+  /* Добавляем русские синонимы в хеш-таблицу.
+     Они не должны иметь is_directive, потому что мы будем
+     искать их напрямую в dtable[] по имени.  */
+  const char *russian_aliases[] = {
+    "определить", "включить", "если", "если_определен",
+    "если_не_определен", "иначе_если", "иначе",
+    "конец_если", "отменить", "ошибка", "предупреждение",
+    "прагма", "строка", "включить_след", "импорт"
+  };
 }
 
 /* Extract header file from a bracket include. Parsing starts after '<'.
diff --git a/libcpp/expr.cc b/libcpp/expr.cc
index 815eb137a99..4008d222560 100644
--- a/libcpp/expr.cc
+++ b/libcpp/expr.cc
@@ -1174,6 +1174,16 @@ parse_defined (cpp_reader *pfile)
   return result;
 }
 
+/* Handle meeting "определено" in a preprocessor expression (Russian synonym).  */
+static cpp_num
+parse_defined_ru (cpp_reader *pfile)
+{
+  /* Просто вызываем parse_defined, так как логика обработки идентична.
+     Разница только в имени оператора, которое используется только в
+     сообщениях об ошибках, поэтому переиспользуем существующую функцию.  */
+  return parse_defined (pfile);
+}
+
 /* Convert a token into a CPP_NUMBER (an interpreted preprocessing
    number or character constant, or the result of the "defined" or "#"
    operators).  */
@@ -1241,6 +1251,9 @@ eval_token (cpp_reader *pfile, const cpp_token *token,
     case CPP_NAME:
       if (token->val.node.node == pfile->spec_nodes.n_defined)
 	return parse_defined (pfile);
+      /* Русский синоним "определено" */
+      else if (token->val.node.node == pfile->spec_nodes.n_defined_ru)
+	return parse_defined (pfile);
       else if (CPP_OPTION (pfile, true_false)
 	       && (token->val.node.node == pfile->spec_nodes.n_true
 		   || token->val.node.node == pfile->spec_nodes.n_false))
diff --git a/libcpp/init.cc b/libcpp/init.cc
index 54fc9236d38..ea647e5b544 100644
--- a/libcpp/init.cc
+++ b/libcpp/init.cc
@@ -309,6 +309,9 @@ cpp_create_reader (enum c_lang lang, cpp_hash_table *table,
 
   _cpp_init_hashtable (pfile, table, extra_table);
 
+  pfile->spec_nodes.n_defined_ru = cpp_lookup (pfile, UC"определено", 
+                                                sizeof "определено" - 1);
+
   return pfile;
 }
 
@@ -418,14 +421,22 @@ struct builtin_macro
 static const struct builtin_macro builtin_array[] =
 {
   B("__TIMESTAMP__",	 BT_TIMESTAMP,     false),
+  B("__ВРЕМЯ_ФАЙЛА__",	 BT_TIMESTAMP,     false),
   B("__TIME__",		 BT_TIME,          false),
+  B("__ВРЕМЯ__",		 BT_TIME,          false),
   B("__DATE__",		 BT_DATE,          false),
+  B("__ДАТА__",		 BT_DATE,          false),
   B("__FILE__",		 BT_FILE,          false),
+  B("__ФАЙЛ__",		 BT_FILE,          false),
   B("__FILE_NAME__",	 BT_FILE_NAME,     false),
   B("__BASE_FILE__",	 BT_BASE_FILE,     false),
+  B("__БАЗОВЫЙ_ФАЙЛ__",	 BT_BASE_FILE,     false),
   B("__LINE__",		 BT_SPECLINE,      true),
+  B("__ЛИНИЯ__",		 BT_SPECLINE,      true),
   B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL, true),
   B("__COUNTER__",	 BT_COUNTER,       true),
+  B("__СЧЁТЧИК__",	 BT_COUNTER,       true),
+  B("__СЧЕТЧИК__",	 BT_COUNTER,       true),
   /* Make sure to update the list of built-in
      function-like macros in traditional.cc:
      fun_like_macro() when adding more following */
diff --git a/libcpp/internal.h b/libcpp/internal.h
index a20215c5709..538013d980f 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -297,6 +297,7 @@ struct lexer_state
 struct spec_nodes
 {
   cpp_hashnode *n_defined;		/* defined operator */
+  cpp_hashnode *n_defined_ru;	/* русский синоним "определено" */
   cpp_hashnode *n_true;			/* C++ keyword true */
   cpp_hashnode *n_false;		/* C++ keyword false */
   cpp_hashnode *n__VA_ARGS__;		/* C99 vararg macros */
diff --git a/libcpp/lex.cc b/libcpp/lex.cc
index c9e44e6cccc..e6743393116 100644
--- a/libcpp/lex.cc
+++ b/libcpp/lex.cc
@@ -2085,6 +2085,40 @@ forms_identifier_p (cpp_reader *pfile, int first,
       return true;
     }
 
+  /* ================================================================
+     ДОБАВЛЕНО: Проверка на русские буквы в UTF-8
+     ================================================================ */
+  if (*buffer->cur == 0xD0 || *buffer->cur == 0xD1)
+    {
+      unsigned char first = *buffer->cur;
+      unsigned char second = *(buffer->cur + 1);
+
+      /* Диапазоны русских букв в UTF-8:
+         А-Я: D0 90 - D0 AF
+         а-я: D1 80 - D1 8F
+         Ё:   D0 81
+         ё:   D1 91
+      */
+      if (first == 0xD0 && second >= 0x90 && second <= 0xBF)
+	{
+	  buffer->cur += 2;
+	  return true;
+	}
+      if (first == 0xD1 && second >= 0x80 && second <= 0x8F)
+	{
+	  buffer->cur += 2;
+	  return true;
+	}
+      if (first == 0xD0 && (second == 0x81 || second == 0x91))
+	{
+	  buffer->cur += 2;
+	  return true;
+	}
+    }
+  /* ================================================================
+     КОНЕЦ ДОБАВЛЕННОГО БЛОКА
+     ================================================================ */
+
   /* Is this a syntactically valid UCN or a valid UTF-8 char?  */
   if (CPP_OPTION (pfile, extended_identifiers))
     {
? Дизассемблированные привет мир
me@me-Aspire-5742G:~/Документы/rusi/rusi$ objdump -d привет_chibicc 

привет_chibicc:     формат файла elf64-x86-64


Дизассемблирование раздела .init:

0000000000401000 <_init>:
  401000:	f3 0f 1e fa          	endbr64
  401004:	48 83 ec 08          	sub    $0x8,%rsp
  401008:	48 8b 05 d1 2f 00 00 	mov    0x2fd1(%rip),%rax        # 403fe0 <__gmon_start__>
  40100f:	48 85 c0             	test   %rax,%rax
  401012:	74 02                	je     401016 <_init+0x16>
  401014:	ff d0                	call   *%rax
  401016:	48 83 c4 08          	add    $0x8,%rsp
  40101a:	c3                   	ret

Дизассемблирование раздела .text:

0000000000401020 <_start>:
  401020:	f3 0f 1e fa          	endbr64
  401024:	31 ed                	xor    %ebp,%ebp
  401026:	49 89 d1             	mov    %rdx,%r9
  401029:	5e                   	pop    %rsi
  40102a:	48 89 e2             	mov    %rsp,%rdx
  40102d:	48 83 e4 f0          	and    $0xfffffffffffffff0,%rsp
  401031:	50                   	push   %rax
  401032:	54                   	push   %rsp
  401033:	45 31 c0             	xor    %r8d,%r8d
  401036:	31 c9                	xor    %ecx,%ecx
  401038:	48 c7 c7 06 11 40 00 	mov    $0x401106,%rdi
  40103f:	ff 15 8b 2f 00 00    	call   *0x2f8b(%rip)        # 403fd0 <__libc_start_main@GLIBC_2.34>
  401045:	f4                   	hlt
  401046:	66 2e 0f 1f 84 00 00 	cs nopw 0x0(%rax,%rax,1)
  40104d:	00 00 00 

0000000000401050 <_dl_relocate_static_pie>:
  401050:	f3 0f 1e fa          	endbr64
  401054:	c3                   	ret
  401055:	66 2e 0f 1f 84 00 00 	cs nopw 0x0(%rax,%rax,1)
  40105c:	00 00 00 
  40105f: 90                   	nop

0000000000401060 <deregister_tm_clones>:
  401060:	b8 d8 41 40 00       	mov    $0x4041d8,%eax
  401065:	48 3d d8 41 40 00    	cmp    $0x4041d8,%rax
  40106b:	74 13                	je     401080 <deregister_tm_clones+0x20>
  40106d:	b8 00 00 00 00       	mov    $0x0,%eax
  401072:	48 85 c0             	test   %rax,%rax
  401075:	74 09                	je     401080 <deregister_tm_clones+0x20>
  401077:	bf d8 41 40 00       	mov    $0x4041d8,%edi
  40107c:	ff e0                	jmp    *%rax
  40107e:	66 90                	xchg   %ax,%ax
  401080:	c3                   	ret
  401081:	0f 1f 40 00          	nopl   0x0(%rax)
  401085:	66 66 2e 0f 1f 84 00 	data16 cs nopw 0x0(%rax,%rax,1)
  40108c:	00 00 00 00 

0000000000401090 <register_tm_clones>:
  401090:	be d8 41 40 00       	mov    $0x4041d8,%esi
  401095:	48 81 ee d8 41 40 00 	sub    $0x4041d8,%rsi
  40109c:	48 89 f0             	mov    %rsi,%rax
  40109f:	48 c1 ee 3f          	shr    $0x3f,%rsi
  4010a3:	48 c1 f8 03          	sar    $0x3,%rax
  4010a7:	48 01 c6             	add    %rax,%rsi
  4010aa: 48 d1 fe             	sar    $1,%rsi
  4010ad:	74 11                	je     4010c0 <register_tm_clones+0x30>
  4010af:	b8 00 00 00 00       	mov    $0x0,%eax
  4010b4:	48 85 c0             	test   %rax,%rax
  4010b7:	74 07                	je     4010c0 <register_tm_clones+0x30>
  4010b9:	bf d8 41 40 00       	mov    $0x4041d8,%edi
  4010be:	ff e0                	jmp    *%rax
  4010c0:	c3                   	ret
  4010c1:	0f 1f 40 00          	nopl   0x0(%rax)
  4010c5:	66 66 2e 0f 1f 84 00 	data16 cs nopw 0x0(%rax,%rax,1)
  4010cc:	00 00 00 00 

00000000004010d0 <__do_global_dtors_aux>:
  4010d0:	f3 0f 1e fa          	endbr64
  4010d4:	80 3d fa 30 00 00 00 	cmpb   $0x0,0x30fa(%rip)        # 4041d5 <completed.0>
  4010db:	75 13                	jne    4010f0 <__do_global_dtors_aux+0x20>
  4010dd:	55                   	push   %rbp
  4010de:	48 89 e5             	mov    %rsp,%rbp
  4010e1:	e8 7a ff ff ff       	call   401060 <deregister_tm_clones>
  4010e6:	c6 05 e8 30 00 00 01 	movb   $0x1,0x30e8(%rip)        # 4041d5 <completed.0>
  4010ed:	5d                   	pop    %rbp
  4010ee:	c3                   	ret
  4010ef:	90                   	nop
  4010f0:	c3                   	ret
  4010f1:	0f 1f 40 00          	nopl   0x0(%rax)
  4010f5:	66 66 2e 0f 1f 84 00 	data16 cs nopw 0x0(%rax,%rax,1)
  4010fc:	00 00 00 00 

0000000000401100 <frame_dummy>:
  401100:	f3 0f 1e fa          	endbr64
  401104:	eb 8a                	jmp    401090 <register_tm_clones>

0000000000401106 <главн>:
  401106:	55                   	push   %rbp
  401107:	48 89 e5             	mov    %rsp,%rbp
  40110a:	48 83 ec 10          	sub    $0x10,%rsp
  40110e:	48 89 65 f8          	mov    %rsp,-0x8(%rbp)
  401112:	48 8d 05 f7 2e 00 00 	lea    0x2ef7(%rip),%rax        # 404010 <__dso_handle+0x8>
  401119:	50                   	push   %rax
  40111a:	48 8b 05 b7 2e 00 00 	mov    0x2eb7(%rip),%rax        # 403fd8 <printf@GLIBC_2.2.5>
  401121:	5f                   	pop    %rdi
  401122:	49 89 c2             	mov    %rax,%r10
  401125:	48 c7 c0 00 00 00 00 	mov    $0x0,%rax
  40112c:	41 ff d2             	call   *%r10
  40112f:	48 83 c4 00          	add    $0x0,%rsp
  401133:	48 c7 c0 00 00 00 00 	mov    $0x0,%rax
  40113a:	eb 07                	jmp    401143 <главн+0x3d>
  40113c:	48 c7 c0 00 00 00 00 	mov    $0x0,%rax
  401143:	48 89 ec             	mov    %rbp,%rsp
  401146:	5d                   	pop    %rbp
  401147:	c3                   	ret

0000000000401148 <__va_read_from_fp>:
  401148:	55                   	push   %rbp
  401149:	48 89 e5             	mov    %rsp,%rbp
  40114c:	48 83 ec 30          	sub    $0x30,%rsp
  401150:	48 89 65 e8          	mov    %rsp,-0x18(%rbp)
  401154:	48 89 7d e0          	mov    %rdi,-0x20(%rbp)
  401158:	89 75 dc             	mov    %esi,-0x24(%rbp)
  40115b:	89 55 d8             	mov    %edx,-0x28(%rbp)
  40115e:	48 8d 45 e0          	lea    -0x20(%rbp),%rax
  401162:	48 8b 00             	mov    (%rax),%rax
  401165:	48 83 c0 04          	add    $0x4,%rax
  401169:	48 63 00             	movslq (%rax),%rax
  40116c:	50                   	push   %rax
  40116d:	48 c7 c0 70 00 00 00 	mov    $0x70,%rax
  401174:	5f                   	pop    %rdi
  401175:	39 f8                	cmp    %edi,%eax
  401177:	0f 96 c0             	setbe  %al
  40117a:	48 0f b6 c0          	movzbq %al,%rax
  40117e:	83 f8 00             	cmp    $0x0,%eax
  401181:	74 3a                	je     4011bd <__va_read_from_fp+0x75>
  401183:	48 8d 45 d8          	lea    -0x28(%rbp),%rax
  401187:	48 63 00             	movslq (%rax),%rax
  40118a:	50                   	push   %rax
  40118b:	48 8d 45 dc          	lea    -0x24(%rbp),%rax
  40118f:	48 63 00             	movslq (%rax),%rax
  401192:	50                   	push   %rax
  401193:	48 8d 45 e0          	lea    -0x20(%rbp),%rax
  401197:	48 8b 00             	mov    (%rax),%rax
  40119a:	50                   	push   %rax
  40119b:	48 8d 05 ac 01 00 00 	lea    0x1ac(%rip),%rax        # 40134e <__va_read_from_stack>
  4011a2:	5f                   	pop    %rdi
  4011a3:	5e                   	pop    %rsi
  4011a4:	5a                   	pop    %rdx
  4011a5:	49 89 c2             	mov    %rax,%r10
  4011a8:	48 c7 c0 00 00 00 00 	mov    $0x0,%rax
  4011af:	41 ff d2             	call   *%r10
  4011b2:	48 83 c4 00          	add    $0x0,%rsp
  4011b6:	e9 8b 00 00 00       	jmp    401246 <__va_read_from_fp+0xfe>
  4011bb:	eb 00                	jmp    4011bd <__va_read_from_fp+0x75>
  4011bd:	48 c7 c1 08 00 00 00 	mov    $0x8,%rcx
  4011c4:	48 8d 7d f0          	lea    -0x10(%rbp),%rdi
  4011c8:	b0 00                	mov    $0x0,%al
  4011ca:	f3 aa                	rep stos %al,(%rdi)
  4011cc:	48 8d 45 f0          	lea    -0x10(%rbp),%rax
  4011d0:	50                   	push   %rax
  4011d1:	48 c7 c0 01 00 00 00 	mov    $0x1,%rax
  4011d8:	50                   	push   %rax
  4011d9: 48 8d 45 e0          	lea    -0x20(%rbp),%rax
  4011dd:	48 8b 00             	mov    (%rax),%rax
  4011e0: 48 83 c0 04          	add    $0x4,%rax
  4011e4: 48 63 00             	movslq (%rax),%rax
  4011e7: 89 c0                	mov    %eax,%eax
  4011e9: 5f                   	pop    %rdi
  4011ea: 48 0f af c7          	imul   %rdi,%rax
  4011ee: 50                   	push   %rax
  4011ef: 48 8d 45 e0          	lea    -0x20(%rbp),%rax
  4011f3: 48 8b 00             	mov    (%rax),%rax
  4011f6: 48 83 c0 10          	add    $0x10,%rax
  4011fa: 48 8b 00             	mov    (%rax),%rax
  4011fd: 5f                   	pop    %rdi
  4011fe: 48 01 f8             	add    %rdi,%rax
  401201:	5f                   	pop    %rdi
  401202:	48 89 07             	mov    %rax,(%rdi)
  401205: 48 8d 45 f8          	lea    -0x8(%rbp),%rax
  401209:	50                   	push   %rax
  40120a: 48 8d 45 e0          	lea    -0x20(%rbp),%rax
  40120e:	48 8b 00             	mov    (%rax),%rax
  401211:	5f                   	pop    %rdi
  401212:	48 89 07             	mov    %rax,(%rdi)
  401215: 48 8d 45 f8          	lea    -0x8(%rbp),%rax
  401219:	48 8b 00             	mov    (%rax),%rax
  40121c:	48 83 c0 04          	add    $0x4,%rax
  401220:	50                   	push   %rax
  401221: 48 c7 c0 08 00 00 00 	mov    $0x8,%rax
  401228:	50                   	push   %rax
  401229: 48 8d 45 f8          	lea    -0x8(%rbp),%rax
  40122d: 48 8b 00             	mov    (%rax),%rax
  401230: 48 83 c0 04          	add    $0x4,%rax
  401234: 48 63 00             	movslq (%rax),%rax
  401237:	5f                   	pop    %rdi
  401238:	01 f8                	add    %edi,%eax
  40123a:	5f                   	pop    %rdi
  40123b:	89 07                	mov    %eax,(%rdi)
  40123d: 48 8d 45 f0          	lea    -0x10(%rbp),%rax
  401241: 48 8b 00             	mov    (%rax),%rax
  401244:	eb 00                	jmp    401246 <__va_read_from_fp+0xfe>
  401246:	48 89 ec             	mov    %rbp,%rsp
  401249:	5d                   	pop    %rbp
  40124a:	c3                   	ret

000000000040124b <__va_read_from_gp>:
  40124b:	55                   	push   %rbp
  40124c:	48 89 e5             	mov    %rsp,%rbp
  40124f:	48 83 ec 30          	sub    $0x30,%rsp
  401253:	48 89 65 e8          	mov    %rsp,-0x18(%rbp)
  401257:	48 89 7d e0          	mov    %rdi,-0x20(%rbp)
  40125b:	89 75 dc             	mov    %esi,-0x24(%rbp)
  40125e:	89 55 d8             	mov    %edx,-0x28(%rbp)
  401261:	48 8d 45 e0          	lea    -0x20(%rbp),%rax
  401265:	48 8b 00             	mov    (%rax),%rax
  401268:	48 83 c0 00          	add    $0x0,%rax
  40126c:	48 63 00             	movslq (%rax),%rax
  40126f:	50                   	push   %rax
  401270: 48 c7 c0 30 00 00 00 	mov    $0x30,%rax
  401277: 5f                   	pop    %rdi
  401278:	39 f8                	cmp    %edi,%eax
  40127a:	0f 96 c0             	setbe  %al
  40127d: 48 0f b6 c0          	movzbq %al,%rax
  401281:	83 f8 00             	cmp    $0x0,%eax
  401284: 74 3a                	je     4012c0 <__va_read_from_gp+0x75>
  401286: 48 8d 45 d8          	lea    -0x28(%rbp),%rax
  40128a: 48 63 00             	movslq (%rax),%rax
  40128d:	50                   	push   %rax
  40128e: 48 8d 45 dc          	lea    -0x24(%rbp),%rax
  401292: 48 63 00             	movslq (%rax),%rax
  401295:	50                   	push   %rax
  401296: 48 8d 45 e0          	lea    -0x20(%rbp),%rax
  40129a: 48 8b 00             	mov    (%rax),%rax
  40129d:	50                   	push   %rax
  40129e: 48 8d 05 a9 00 00 00 	lea    0xa9(%rip),%rax        # 40134e <__va_read_from_stack>
  4012a5: 5f                   	pop    %rdi
  4012a6: 5e                   	pop    %rsi
  4012a7: 5a                   	pop    %rdx
  4012a8: 49 89 c2             	mov    %rax,%r10
  4012ab: 48 c7 c0 00 00 00 00 	mov    $0x0,%rax
  4012b2: 41 ff d2             	call   *%r10
  4012b5: 48 83 c4 00          	add    $0x0,%rsp
  4012b9: e9 8b 00 00 00       	jmp    401349 <__va_read_from_gp+0xfe>
  4012be: eb 00                	jmp    4012c0 <__va_read_from_gp+0x75>
  4012c0: 48 c7 c1 08 00 00 00 	mov    $0x8,%rcx
  4012c7: 48 8d 7d f0          	lea    -0x10(%rbp),%rdi
  4012cb: b0 00                	mov    $0x0,%al
  4012cd: f3 aa                	rep stos %al,(%rdi)
  4012cf: 48 8d 45 f0          	lea    -0x10(%rbp),%rax
  4012d3: 50                   	push   %rax
  4012d4: 48 c7 c0 01 00 00 00 	mov    $0x1,%rax
  4012db: 50                   	push   %rax
  4012dc: 48 8d 45 e0          	lea    -0x20(%rbp),%rax
  4012e0: 48 8b 00             	mov    (%rax),%rax
  4012e3: 48 83 c0 00          	add    $0x0,%rax
  4012e7: 48 63 00             	movslq (%rax),%rax
  4012ea: 89 c0                	mov    %eax,%eax
  4012ec: 5f                   	pop    %rdi
  4012ed: 48 0f af c7          	imul   %rdi,%rax
  4012f1: 50                   	push   %rax
  4012f2: 48 8d 45 e0          	lea    -0x20(%rbp),%rax
  4012f6: 48 8b 00             	mov    (%rax),%rax
  4012f9: 48 83 c0 10          	add    $0x10,%rax
  4012fd: 48 8b 00             	mov    (%rax),%rax
  401300: 5f                   	pop    %rdi
  401301: 48 01 f8             	add    %rdi,%rax
  401304: 5f                   	pop    %rdi
  401305: 48 89 07             	mov    %rax,(%rdi)
  401308: 48 8d 45 f8          	lea    -0x8(%rbp),%rax
  40130c: 50                   	push   %rax
  40130d: 48 8d 45 e0          	lea    -0x20(%rbp),%rax
  401311: 48 8b 00             	mov    (%rax),%rax
  401314: 5f                   	pop    %rdi
  401315: 48 89 07             	mov    %rax,(%rdi)
  401318: 48 8d 45 f8          	lea    -0x8(%rbp),%rax
  40131c: 48 8b 00             	mov    (%rax),%rax
  40131f: 48 83 c0 00          	add    $0x0,%rax
  401323: 50                   	push   %rax
  401324: 48 c7 c0 08 00 00 00 	mov    $0x8,%rax
  40132b: 50                   	push   %rax
  40132c: 48 8d 45 f8          	lea    -0x8(%rbp),%rax
  401330: 48 8b 00             	mov    (%rax),%rax
  401333: 48 83 c0 00          	add    $0x0,%rax
  401337: 48 63 00             	movslq (%rax),%rax
  40133a: 5f                   	pop    %rdi
  40133b: 01 f8                	add    %edi,%eax
  40133d: 5f                   	pop    %rdi
  40133e: 89 07                	mov    %eax,(%rdi)
  401340: 48 8d 45 f0          	lea    -0x10(%rbp),%rax
  401344: 48 8b 00             	mov    (%rax),%rax
  401347: eb 00                	jmp    401349 <__va_read_from_gp+0xfe>
  401349: 48 89 ec             	mov    %rbp,%rsp
  40134c: 5d                   	pop    %rbp
  40134d:	c3                   	ret

000000000040134e <__va_read_from_stack>:
  40134e: 55                   	push   %rbp
  40134f: 48 89 e5             	mov    %rsp,%rbp
  401352: 48 83 ec 20          	sub    $0x20,%rsp
  401356: 48 89 65 f0          	mov    %rsp,-0x10(%rbp)
  40135a: 48 89 7d e8          	mov    %rdi,-0x18(%rbp)
  40135e: 89 75 e4             	mov    %esi,-0x1c(%rbp)
  401361: 89 55 e0             	mov    %edx,-0x20(%rbp)
  401364: 48 c7 c1 08 00 00 00 	mov    $0x8,%rcx
  40136b: 48 8d 7d f8          	lea    -0x8(%rbp),%rdi
  40136f: b0 00                	mov    $0x0,%al
  401371: f3 aa                	rep stos %al,(%rdi)
  401373: 48 8d 45 f8          	lea    -0x8(%rbp),%rax
  401377: 50                   	push   %rax
  401378: 48 8d 45 e8          	lea    -0x18(%rbp),%rax
  40137c: 48 8b 00             	mov    (%rax),%rax
  40137f: 48 83 c0 08          	add    $0x8,%rax
  401383: 48 8b 00             	mov    (%rax),%rax
  401386: 5f                   	pop    %rdi
  401387: 48 89 07             	mov    %rax,(%rdi)
  40138a: 48 8d 45 e0          	lea    -0x20(%rbp),%rax
  40138e: 48 63 00             	movslq (%rax),%rax
  401391: 50                   	push   %rax
  401392: 48 c7 c0 08 00 00 00 	mov    $0x8,%rax
  401399: 5f                   	pop    %rdi
  40139a: 39 f8                	cmp    %edi,%eax
  40139c: 0f 9c c0             	setl   %al
  40139f: 48 0f b6 c0          	movzbq %al,%rax
  4013a3: 83 f8 00             	cmp    $0x0,%eax
  4013a6: 74 54                	je     4013fc <__va_read_from_stack+0xae>
  4013a8: 48 8d 45 f8          	lea    -0x8(%rbp),%rax
  4013ac: 50                   	push   %rax
  4013ad: 48 c7 c0 10 00 00 00 	mov    $0x10,%rax
  4013b4: 48 63 c0             	movslq %eax,%rax
  4013b7: 50                   	push   %rax
  4013b8: 48 c7 c0 10 00 00 00 	mov    $0x10,%rax
  4013bf: 48 63 c0             	movslq %eax,%rax
  4013c2: 50                   	push   %rax
  4013c3: 48 c7 c0 01 00 00 00 	mov    $0x1,%rax
  4013ca: 50                   	push   %rax
  4013cb: 48 c7 c0 0f 00 00 00 	mov    $0xf,%rax
  4013d2: 48 63 c0             	movslq %eax,%rax
  4013d5: 5f                   	pop    %rdi
  4013d6: 48 0f af c7          	imul   %rdi,%rax
  4013da: 50                   	push   %rax
  4013db: 48 8d 45 f8          	lea    -0x8(%rbp),%rax
  4013df: 48 8b 00             	mov    (%rax),%rax
  4013e2: 5f                   	pop    %rdi
  4013e3: 48 01 f8             	add    %rdi,%rax
  4013e6: 5f                   	pop    %rdi
  4013e7: 48 c7 c2 00 00 00 00 	mov    $0x0,%rdx
  4013ee: 48 f7 f7             	div    %rdi
  4013f1: 5f                   	pop    %rdi
  4013f2: 48 0f af c7          	imul   %rdi,%rax
  4013f6: 5f                   	pop    %rdi
  4013f7: 48 89 07             	mov    %rax,(%rdi)
  4013fa: eb 00                	jmp    4013fc <__va_read_from_stack+0xae>
  4013fc: 48 8d 45 e8          	lea    -0x18(%rbp),%rax
  401400: 48 8b 00             	mov    (%rax),%rax
  401403: 48 83 c0 08          	add    $0x8,%rax
  401407: 50                   	push   %rax
  401408: 48 c7 c0 08 00 00 00 	mov    $0x8,%rax
  40140f: 48 63 c0             	movslq %eax,%rax
  401412: 50                   	push   %rax
  401413: 48 c7 c0 08 00 00 00 	mov    $0x8,%rax
  40141a: 48 63 c0             	movslq %eax,%rax
  40141d: 50                   	push   %rax
  40141e: 48 c7 c0 07 00 00 00 	mov    $0x7,%rax
  401425: 48 63 c0             	movslq %eax,%rax
  401428: 50                   	push   %rax
  401429: 48 8d 45 e4          	lea    -0x1c(%rbp),%rax
  40142d: 48 63 00             	movslq (%rax),%rax
  401430: 48 63 c0             	movslq %eax,%rax
  401433: 50                   	push   %rax
  401434: 48 8d 45 f8          	lea    -0x8(%rbp),%rax
  401438: 48 8b 00             	mov    (%rax),%rax
  40143b: 5f                   	pop    %rdi
  40143c: 48 01 f8             	add    %rdi,%rax
  40143f: 5f                   	pop    %rdi
  401440: 48 01 f8             	add    %rdi,%rax
  401443: 5f                   	pop    %rdi
  401444: 48 c7 c2 00 00 00 00 	mov    $0x0,%rdx
  40144b: 48 f7 f7              div    %rdi
  40144e: 5f                   	pop    %rdi
  40144f: 48 0f af c7          	imul   %rdi,%rax
  401453: 5f                   	pop    %rdi
  401454: 48 89 07             	mov    %rax,(%rdi)
  401457: 48 8d 45 f8          	lea    -0x8(%rbp),%rax
  40145b: 48 8b 00             	mov    (%rax),%rax
  40145e: eb 00                	jmp    401460 <__va_read_from_stack+0x112>
  401460: 48 89 ec             	mov    %rbp,%rsp
  401463: 5d                   	pop    %rbp
  401464: c3                   	ret

Дизассемблирование раздела .fini:

0000000000401468 <_fini>:
  401468: f3 0f 1e fa          	endbr64
  40146c: 48 83 ec 08          	sub    $0x8,%rsp
  401470: 48 83 c4 08          	add    $0x8,%rsp
  401474: c3                   	ret
me@me-Aspire-5742G:~/Документы/rusi/rusi$ 
me@me-Aspire-5742G:~/Документы/rusi/rusi$ objdump -d привет_gcc

привет_gcc:     формат файла elf64-x86-64


Дизассемблирование раздела .init:

0000000000401000 <_init>:
  401000: f3 0f 1e fa          	endbr64
  401004: 48 83 ec 08          	sub    $0x8,%rsp
  401008: 48 8b 05 d1 2f 00 00 	mov    0x2fd1(%rip),%rax        # 403fe0 <__gmon_start__>
  40100f: 48 85 c0             	test   %rax,%rax
  401012: 74 02                	je     401016 <_init+0x16>
  401014: ff d0                	call   *%rax
  401016: 48 83 c4 08          	add    $0x8,%rsp
  40101a: c3                   	ret

Дизассемблирование раздела .plt:

0000000000401020 <puts@plt-0x10>:
  401020: ff 35 ca 2f 00 00    	push   0x2fca(%rip)        # 403ff0 <_GLOBAL_OFFSET_TABLE_+0x8>
  401026: ff 25 cc 2f 00 00    	jmp    *0x2fcc(%rip)        # 403ff8 <_GLOBAL_OFFSET_TABLE_+0x10>
  40102c: 0f 1f 40 00          	nopl   0x0(%rax)

0000000000401030 <puts@plt>:
  401030: ff 25 ca 2f 00 00    	jmp    *0x2fca(%rip)        # 404000 <puts@GLIBC_2.2.5>
  401036: 68 00 00 00 00       	push   $0x0
  40103b: e9 e0 ff ff ff       	jmp    401020 <_init+0x20>

Дизассемблирование раздела .text:

0000000000401040 <main>:
  401040: 48 83 ec 08          	sub    $0x8,%rsp
  401044: bf 04 20 40 00       	mov    $0x402004,%edi
  401049: e8 e2 ff ff ff       	call   401030 <puts@plt>
  40104e: 31 c0                	xor    %eax,%eax
  401050: 48 83 c4 08          	add    $0x8,%rsp
  401054: c3                   	ret
  401055: 66 2e 0f 1f 84 00 00 	cs nopw 0x0(%rax,%rax,1)
  40105c: 00 00 00 
  40105f: 90                   	nop

0000000000401060 <_start>:
  401060: f3 0f 1e fa          	endbr64
  401064: 31 ed                	xor    %ebp,%ebp
  401066: 49 89 d1             	mov    %rdx,%r9
  401069: 5e                   	pop    %rsi
  40106a: 48 89 e2             	mov    %rsp,%rdx
  40106d: 48 83 e4 f0          	and    $0xfffffffffffffff0,%rsp
  401071: 50                   	push   %rax
  401072: 54                   	push   %rsp
  401073: 45 31 c0             	xor    %r8d,%r8d
  401076: 31 c9                	xor    %ecx,%ecx
  401078: 48 c7 c7 40 10 40 00 	mov    $0x401040,%rdi
  40107f: ff 15 53 2f 00 00    	call   *0x2f53(%rip)        # 403fd8 <__libc_start_main@GLIBC_2.34>
  401085: f4                   	hlt
  401086: 66 2e 0f 1f 84 00 00 	cs nopw 0x0(%rax,%rax,1)
  40108d: 00 00 00 

0000000000401090 <_dl_relocate_static_pie>:
  401090: f3 0f 1e fa          	endbr64
  401094: c3                   	ret
  401095: 66 2e 0f 1f 84 00 00 	cs nopw 0x0(%rax,%rax,1)
  40109c: 00 00 00 
  40109f: 90                   	nop

00000000004010a0 <deregister_tm_clones>:
  4010a0: b8 18 40 40 00       	mov    $0x404018,%eax
  4010a5: 48 3d 18 40 40 00    	cmp    $0x404018,%rax
  4010ab: 74 13                	je     4010c0 <deregister_tm_clones+0x20>
  4010ad: b8 00 00 00 00       	mov    $0x0,%eax
  4010b2: 48 85 c0             	test   %rax,%rax
  4010b5: 74 09                	je     4010c0 <deregister_tm_clones+0x20>
  4010b7: bf 18 40 40 00       	mov    $0x404018,%edi
  4010bc: ff e0                	jmp    *%rax
  4010be: 66 90                	xchg   %ax,%ax
  4010c0: c3                   	ret
  4010c1: 0f 1f 40 00          	nopl   0x0(%rax)
  4010c5: 66 66 2e 0f 1f 84 00 	data16 cs nopw 0x0(%rax,%rax,1)
  4010cc: 00 00 00 00 

00000000004010d0 <register_tm_clones>:
  4010d0: be 18 40 40 00       	mov    $0x404018,%esi
  4010d5: 48 81 ee 18 40 40 00 	sub    $0x404018,%rsi
  4010dc: 48 89 f0             	mov    %rsi,%rax
  4010df: 48 c1 ee 3f          	shr    $0x3f,%rsi
  4010e3: 48 c1 f8 03          	sar    $0x3,%rax
  4010e7: 48 01 c6             	add    %rax,%rsi
  4010ea: 48 d1 fe             	sar    $1,%rsi
  4010ed: 74 11                	je     401100 <register_tm_clones+0x30>
  4010ef: b8 00 00 00 00       	mov    $0x0,%eax
  4010f4: 48 85 c0             	test   %rax,%rax
  4010f7: 74 07                	je     401100 <register_tm_clones+0x30>
  4010f9: bf 18 40 40 00       	mov    $0x404018,%edi
  4010fe: ff e0                	jmp    *%rax
  401100: c3                   	ret
  401101: 0f 1f 40 00          	nopl   0x0(%rax)
  401105: 66 66 2e 0f 1f 84 00 	data16 cs nopw 0x0(%rax,%rax,1)
  40110c: 00 00 00 00 

0000000000401110 <__do_global_dtors_aux>:
  401110: f3 0f 1e fa          	endbr64
  401114: 80 3d fd 2e 00 00 00 	cmpb   $0x0,0x2efd(%rip)        # 404018 <__TMC_END__>
  40111b: 75 13                	jne    401130 <__do_global_dtors_aux+0x20>
  40111d: 55                   	push   %rbp
  40111e: 48 89 e5             	mov    %rsp,%rbp
  401121: e8 7a ff ff ff       	call   4010a0 <deregister_tm_clones>
  401126: c6 05 eb 2e 00 00 01 	movb   $0x1,0x2eeb(%rip)        # 404018 <__TMC_END__>
  40112d: 5d                   	pop    %rbp
  40112e: c3                   	ret
  40112f: 90                   	nop
  401130: c3                   	ret
  401131: 0f 1f 40 00          	nopl   0x0(%rax)
  401135: 66 66 2e 0f 1f 84 00 	data16 cs nopw 0x0(%rax,%rax,1)
  40113c: 00 00 00 00 

0000000000401140 <frame_dummy>:
  401140: f3 0f 1e fa          	endbr64
  401144: eb 8a                	jmp    4010d0 <register_tm_clones>

Дизассемблирование раздела .fini:

0000000000401148 <_fini>:
  401148: f3 0f 1e fa          	endbr64
  40114c: 48 83 ec 08          	sub    $0x8,%rsp
  401150: 48 83 c4 08          	add    $0x8,%rsp
  401154: c3                   	ret
me@me-Aspire-5742G:~/Документы/rusi/rusi$
? Еще один тестовый пример на плюсах
класс Фигура {
открыт:
    вирт пусто описать() {
        std::cout << "Фигура" << std::endl;
    }
    вирт ~Фигура() {}
};

класс Круг : открыт Фигура {
открыт:
    двойн радиус;
    Круг(двойн р) : радиус(р) {}
    пусто описать() override {
        std::cout << "Круг радиусом " << радиус << std::endl;
    }
};

шаблон<имя_типа T>
T удвоить(T значение) {
    возврат значение * 2;
}

цел главн() {
    Круг к(5.0);
    к.описать();

    std::cout << "Удвоенное 21 = " << удвоить(21) << std::endl;
    std::cout << "Удвоенное 1.5 = " << удвоить(1.5) << std::endl;

    возврат 0;
}
me@me-Aspire-5742G:/usr/local/gcc-rus/bin/g++ -std=c++20 /tmp/руси_плюс_плюс.cpp -o /tmp/руси_плюс_плюс 2>&1 | head -30
me@me-Aspire-5742G:~/RUSI-build/rgcc/тесты$ /tmp/руси_плюс_плюс
Круг радиусом 5
Удвоенное 21 = 42
Удвоенное 1.5 = 3

Промпты для анализа статьи

Тем, кто хочет извлечь дополнительную информацию для размышлений или почерпнуть филосовских и технических взглядов на проект. Загружаем текст статьи в контекст и просим:

Оценку с позиции кибернетики.
Анализ с позиции ТРИЗ.
Провести анализ текста с позиций эвристики.
Анализ написанного с позиции теории систем.
Оценить написанное с позиции философии open source.
Оценка с позиций аналитической философии техники.

Послесловие

Этот проект начинался как спортивный интерес. «Смогу ли я одолеть GCC?» Смог, получилось, заработало. И результат радует.

Из нишевого форка chibicc выросли три оригинальных синтаксиса: Руси (Си), Руси++ (C++), Объектный-Руси (Objective-C). Все три - промышленного уровня, на базе GCC 14.2.

Это не «русский язык программирования с нуля». Это теперь двойной Си. Это билингвальный интерфейс к существующему языку. Не «вместо», а «вместе».

Комментарии (105)


  1. Kotofay
    17.10.2026 18:30

    наместе двояко провѣрятичегоглаголют молчаливо
    кагбе
    		ѣжѣли получалка.сломалася молчаливо тогдауж 
    		кагбе 
    			молвити "Не лепо молвишь, барин!" аминь1
    			возвѣрнути нуль спасихоспади1
    		ага
    		возвѣрнути один аминь1
    ага

    https://habr.com/ru/articles/1003246/comments/#comment_29579650


    1. randomsimplenumber
      17.10.2026 18:30

      Так проще ;)


    1. Yukr
      17.10.2026 18:30

      "Ключница синтаксис делала.."(с)


      1. Chemist_modeler
        17.10.2026 18:30

        Ну да, только с первой "Г".


      1. Kotofay
        17.10.2026 18:30

        .


    1. artrades Автор
      17.10.2026 18:30

      Дефайны не интересно


      1. randomsimplenumber
        17.10.2026 18:30

        Если нет разницы.. (ц)



    1. qngdjas
      17.10.2026 18:30

      Кто ещё пропел?


  1. SilverTrouse
    17.10.2026 18:30

    а есть поддержка модулей? там "имортировать модудль РУС;" и "экспортировать модудль РУС;" ?


    1. artrades Автор
      17.10.2026 18:30

      #включить "config.h"
      #include "system.h"


  1. serafims
    17.10.2026 18:30

    Грустно выглядит, за счёт сокращений типа "цел" (что мешает писать "целое") слов теряется стройность, которая для англоговорящих получается.


    1. serafims
      17.10.2026 18:30

      С применением спец клавиатур, спец символов по мне так было бы интересно интегрировать специальные иероглифы в код, чтобы сократить визуальный мусор от служебных слов и сделать акцент на логике кода.


      1. vadimr
        17.10.2026 18:30

        Язык APL был уже давно.

        Но некоторая правда тут в том, что всякие там состояния конечных автоматов и прочие абстрактные символы бывает красиво обозначать китайскими иероглифами. Хотя и не очень человеколюбиво.

        Русский же язык с его флективностью объективно плохо подходит для лексической базы языков программирования.


        1. randomsimplenumber
          17.10.2026 18:30

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

          Красивое

          не очень человеколюбиво

          Китайцы будут недовольны ;)


    1. artrades Автор
      17.10.2026 18:30

      int - сокращённый integer

      у англоговорящего аналогичное сокращение


    1. Blacpaul57
      17.10.2026 18:30

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


    1. trilirium
      17.10.2026 18:30

      Вообще-то, int -- тоже сокращение от integer. )))


  1. spacediver
    17.10.2026 18:30

    Прикольно, не ново, но, кажется, уже окончательно поздняк.

    Исходными кодами на «языках программирования высокого уровня» теперь будут заниматься LLM БЯМ-ки, а им лучше жевать то, на чём написан колоссальный массив, на котором они были обучены, массив, написанный в уходящую эпоху, когда исходные программы ещё писались руками…


    1. Wesha
      17.10.2026 18:30

      в уходящую эпоху, когда исходные программы ещё писались руками…

      (Меланхолично:) Не знаю, кто как — а я вот программы пишу головой.

      Руками я переношу их из головы в компьютер.


  1. IvaYan
    17.10.2026 18:30

    Честно говоря, не очень ясен практический смысл в этой "русификации". Ну то есть, какую задачу это решает. Если цель в том, чтобы просто развлечься и посмотреть, как в GCC переименовать ключевые слова, то окей, вопросов нет, но в остальном, я смысла не вижу, если честно.

    Для профессиональных программистов это не имеет смысла, они о смысле ключевых слов в языке-оригинале вряд ли задумываются. А при обучении программированию, незнание смысла слова void вряд ли является основным препятствием.

    Такой стандарт может быть принят для использования в … - везде, где требуется русскоязычная документация и код.

    А где требуется русскоязычный код? Вот именно прям чтобы требуется и без этого нельзя. И что мешает иметь русскоязычную документацию если код использует латиницу?

    Отрасли

    • Приборостроение - уникальные приборы, измерительная техника

    • Робототехника - управление роботами

    • Системы связи - телекоммуникационное оборудование

    • Транспорт - встроенные системы автомобилей, поездов, самолётов

    Как эти отрасли выиграют от перевода ключевых слов ПРОМПТом?


    1. randomsimplenumber
      17.10.2026 18:30

      незнание смысла слова void

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


      1. IvaYan
        17.10.2026 18:30

        А зачем знать смысл? Ключевые слова не используются как слова английского языка, а программа - не текст на английском. 

        Я ровно об этом и говорю. При обучении программированию проблема вовсе не в том, что человек не знает значения слова void, а значит замена на слово "пустота" этой проблемы не решит. Поэтому замена ключевых слов другими словами, но написанными кириллицей даже для учебных целей сомнительна. Более того, может быть даже вредна. Пока код написан "другими" буквами на "другом" языке, можно абстрагироваться от реального смысла слова float и оперировать тем смыслом, который это слово обозначает в коде, а не в нашем мире.


    1. gbeam
      17.10.2026 18:30

      @Честно говоря, не очень ясен практический смысл в этой "русификации".

      Может, например, чтобы раскладку постоянно туда-сюда не переключать, в том случае если в коде много комментариев и текстовых строк на кириллице (как это сделано в 1C)?


    1. artrades Автор
      17.10.2026 18:30

      Проанализировав 9,14 миллиарда обсуждений на GitHub и более 62 500 патчей кода с 2015 по май 2025 года, мы показываем, что участие многоязычных пользователей неуклонно растет, особенно на корейском, китайском и русском языках.

      ...

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

      ...

      https://arxiv.org/html/2602.19446


      1. randomsimplenumber
        17.10.2026 18:30

        Если бы esp-idf было бы на китайском, я б наверно помер.


    1. Popadanec
      17.10.2026 18:30

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


      1. randomsimplenumber
        17.10.2026 18:30

        Не поможет. Он же, паршивец, все равно выучит бесовские if.


        1. Serge78rus
          17.10.2026 18:30

          Поможет. Если обучать на "суверенных языках программирования", то обучаемый скорее всего он еще в процессе обучения возненавидит программирование, а значит не станет программистом и никуда не уедет.


          1. Blacpaul57
            17.10.2026 18:30

            Опасность тут скорее в иллюзии простоты для начинающих. Человек заучивает русские ключевые слова, а потом открывает документацию к любому внешнему SDK и садится в лужу. Приходится переучиваться с нуля, проклиная добрых методистов


        1. Popadanec
          17.10.2026 18:30

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


          1. randomsimplenumber
            17.10.2026 18:30

            Все равно придется смотреть документацию, примеры, тонны уже написанного кода. А там - упсь. if.


    1. Blacpaul57
      17.10.2026 18:30

      Смысл просто пет-проектный: поковырять AST компилятора и понять, как работает лексер на живом коде)


    1. bio_bot
      17.10.2026 18:30

      Я вот для себя нашел практический смысл в "руссификации" языков программирования. Если быть более точным, то для сына. Написали с ним свой DSL над Python, назвали это дело как полагается в честь нашего кота. Причесали все это иишаком не самым модным, и теперь ребенка не оторвать.

      Суть не сделать из ребенка программиста, а просто научить думать алгоритмически. С чем моя подделка справляется на ура (для нас по крайней мере). Ребенку банально просто понимать все это дело в своей языковой среде. Но это мой частный случай.

      Скорее всего вот такие вещи и будут решать задачи именно обучения.


      1. vadimr
        17.10.2026 18:30

        Да, для DSL родной язык хорошо заходит.


  1. dkfbm
    17.10.2026 18:30


    1. Yarus23
      17.10.2026 18:30

      только хотел написать что надо новый завет переписать на Руси


    1. Wesha
      17.10.2026 18:30

      А красивые в этой программе иконки!


  1. Chemist_modeler
    17.10.2026 18:30

    Друзья, не спешите минусовать автора! Мне тоже не очень нравится задача, всем понятно, почему она имеет шанс ноль целых ноль десятых на что-то практическое. Но автор честно написал, что не это для него главное.

    Не всем дано стать мертвым страусом...Автору удачи в своих начинаниях и в выборе тем, а нам всем чуточку больше снисхождения к чужим хотелкам, даже если они нам не нравятся.


    1. Serge78rus
      17.10.2026 18:30

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


      1. randomsimplenumber
        17.10.2026 18:30

        От Кумира еще никто не умер.


        1. Serge78rus
          17.10.2026 18:30

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


  1. LimTroev
    17.10.2026 18:30

    Ну да, пусть белорусы пишут на белорусском, китайцы на китайском, японцы на японском и т.д. Надо же как то хлебушек в эпоху ИИ теперь зарабатывать кому то. А то что универсальность теряется это ничего... Потом еще придумаем переводчик китайских программ на русские и т.п. Даешь изучение традиционно-ценностного РУСИ, РУГО, РУПИ, РУБЭ во всех образовательных учреждениях! ))))


  1. RAprogramm
    17.10.2026 18:30

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

    https://github.com/RAprogramm/rusem

    Идея закодировать правила и логику языка


    1. Belarus
      17.10.2026 18:30

      Где про это можно почитать? Ничево не найду.


    1. vadimr
      17.10.2026 18:30

      Этим много занимались в прошлом веке, результаты были не очень.


  1. checkpoint
    17.10.2026 18:30

    Эх, плохо что KPI программиста исчисляют в строках кода, а не в байтах. Так бы поможно было повысить производительность труда сразу в три раза! ;-)

    А если серьезно, на опасную тропу Вы вышли с этим вот Вашим двояко-выпуклом языком. Соверешнно случайно эта статья может попасть на глаза какому нибудь чиновнуку из Минобрнауки и уже через год мы все тут начем говорить на двояком.


    1. Serge78rus
      17.10.2026 18:30

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


      1. vadimr
        17.10.2026 18:30

        В 80-90-е годы большинство школьников в СССР начинало изучать программирование с русскоязычных алгоритмического языка, Рапиры, Лого и т.п., и никакой трагедии в этом не было. Скорее полезно. Другое дело, что в Си вообще со словами напряг, и выглядит это уродливо.


        1. randomsimplenumber
          17.10.2026 18:30

          Скорее полезно

          Даже в изучении отченаш есть польза.


        1. Serge78rus
          17.10.2026 18:30

          Аккуратней используйте слово "большинство". Мой сын как раз в конце 80-х - 90-х учился в школе. У них информатика преподавалась на турбо Паскале (естественно, ворованном). У детей друзей примерно в то же время было так же. Возможно, у кого-то и преподавали Рапиры, Лого и т.п., но точно не у большинства, либо это было уже позже означенного Вами периода.


          1. vadimr
            17.10.2026 18:30

            В конце 80-х Турбо Паскаль в школе мог появиться только благодаря редчайшему стечению обстоятельств, так как вообще IBM PC до 90-х был в СССР редкостью. Единый советский учебник информатики Ершова использовал русский алгоритмический язык, а большинство (действительно большинство) школьников в то время изучало программирование без компьютеров вообще. А если и были компьютеры в школах, то в основном до 1990 года отечественные или изредка болгарские.

            Сам я начал изучать программирование в спецшколе с 7 класса с русского Лого. И очень завидовал школьникам, которые начинали со 2 класса с того же самого русского Лого. Понятно, что никакого английского языка второклассники в школах с техническим уклоном не знали.

            Изучая программирование на очень продвинутом для школьника уровне, я IBM PC впервые увидел живьём в жизни в 1989 или 1990 году, а в учебном процессе (наряду с другими машинами) – в 1992 году в институте. (В тот период, кстати, я считал вычислительные машины, потребляющие меньше 100 кВт мощности, не очень достойными внимания – хотя я и начинал с персоналок).


            1. Serge78rus
              17.10.2026 18:30

              Боюсь ошибиться, но по моему у них было что-то типа Искры-1030 или ЕС-1840. Еще вспомнил, что примерно в то же время в школах было поделие под названием КУВТ (если не ошибся с аббревиатурой) - специальный учебный класс, по мотивам ДВК, БК-шки и т.д. Там в составе базового ПО был Бейсик.


  1. apevzner
    17.10.2026 18:30

    Гипотетически: каким бы был полноценный продакшеновый русский Си?

    Ну, наверное, он не был бы продакшеновым :)


  1. Daddy_Cool
    17.10.2026 18:30

    Так вот ты какая, деглобализация!
    Вашему вниманию предлагается классическая программа на языке С "Hello, wold!" на тамильском языке.

    #உள்ளடக்கு <நிலையான உள்ளீட்டு/வெளியீட்டுத் தலைப்பு>

    முழுஎண் பிரதானசார்பு(வெறுமை)

    {

    அச்சிடு("வணக்கம், உலகமே\n");

    திருப்பு 0;

    }

    -----------
    По-моему это красиво...

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


    1. Chemist_modeler
      17.10.2026 18:30

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


      1. Wesha
        17.10.2026 18:30

        по-английски в нашей стране не сильно шпрехают даже преподаватели русского языка

        Так в том-то и хохма: читать код на ЯВУ как текст — это боль. Я вот языкеи всегда воспринимал как «этот „глиф“ означает цикл, этот — условие, этот — целое число» и тому подобное. Под словом «глиф» в данном случае понимается комбинация буковков (while, if, int...) И тот факт что буковки латинские, помогало не читать слово, а воспринимать его как набор закорючек.


      1. peschex0d
        17.10.2026 18:30

        в русском экселе я просто не могу запомнить большинство названий функций, при этом и "цел" в Си для меня выглядит опечаткой, а код вида

        цел й = ы

        как кот прошёл по клавиатуре


    1. ulisma
      17.10.2026 18:30

      в русифицированном Экселе ввод названий функций по-русски бесит

      Это точно)


    1. trilirium
      17.10.2026 18:30

      "நிலையான உள்ளீட்டு/வெளியீட்டுத் தலைப்பு" -- это "stdio.h"?

      Почему так длинно? )))


      1. Daddy_Cool
        17.10.2026 18:30

        "стандартный ввод вывод" как сократить я не додумался ).


  1. sergeym69
    17.10.2026 18:30

    "цел" это как то слишком кратко, лучше "целка"


    1. Wesha
      17.10.2026 18:30

      "цел" это как то слишком кратко, лучше "целка"

      «Цел» — это когда выпал из окна второго этажа, отряхнулся и домой пошёл.


      1. Serge78rus
        17.10.2026 18:30

        А float - это когда выпал с десятого?


        1. randomsimplenumber
          17.10.2026 18:30

          А struct когда по частям ;)


        1. Int_13h
          17.10.2026 18:30

          с приблизительно 10.0- го


        1. Daddy_Cool
          17.10.2026 18:30

          кода упал в бассейн ;)


  1. Elbrus128
    17.10.2026 18:30

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

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

    Более того, это полезно, т. к. несёт единственный смысл. У кого русский родной — понимает сразу и однозначно, что принтер — это периферийное устройство компьютера для получения аналоговой твëрдой копии документа.

    У кого родной английский — уже возможны варианты...

    В этом сила правила заимствования иностранных слов в русском языке.

    Принтер — пример правильного и полезного заимствования. Лайфхак — пример мусорного и бесполезного заимствования.

    P. S.: Можете понижать карму дальше. )) Если дискутировать это мне и не позволяет, то раз в неделю я всё равно могу писать вам сюда. )))


    1. Chemist_modeler
      17.10.2026 18:30

      Я в целом придерживаюсь Вашей логики, детали есть, но не суть. По существу Вас поддерживаю. А вот по форме не совсем. Чуток поболее уважения к коллегам, и, глядишь, минусить в карму перестанут.

      Удачи!


      1. Daddy_Cool
        17.10.2026 18:30

        Уважения недостаточно. Чтобы получить минус в карму нужно всего лишь высказать мнение конфликтное на уровне ценностей. И как бы его вежливо ни высказал... ))) Конфликтные ценности делают человека врагом, потому что ценности потенциально определяют его действия.


    1. randomsimplenumber
      17.10.2026 18:30

      Лайфхак — пример мусорного и бесполезного заимствования.

      Бесполезных заимствований не бывает. Раз словом пользуются - значит оно полезное


    1. WLMike
      17.10.2026 18:30

      Про Лайфхак очень сомнительно - мусорное умирает, в том числе изначально русские слова, полезное живет


    1. ulisma
      17.10.2026 18:30

      Спасибо за мнение. Карму поднял)))


    1. zatim
      17.10.2026 18:30

      Тоже не люблю вату и либерду. Поставил +.


  1. saag
    17.10.2026 18:30

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


  1. Roman_Cherkasov
    17.10.2026 18:30

    Начал изучать программирование со школы, не зная английского языка вообще. Начал понятно с паскаля и учебников, которые давали в школе. Не шло. Было очень интересно но с тех пор терпеть не могу конструкции вроде - "Сделай так, получите это", без объяснений.
    Потом стало интересно, на чем пишут "настоящие" программы. Мне учитель намекнул на C# и .net Framework. И выдал 2 диска. Один с Visual Studio и SDK, а второй с MSDN на русском. И вот нормальная документация на русском языке мне тогда помогла очень сильно. Да, у меня были названия классов и функций транслитом, но вот с ключевыми словами вообще не возникало проблем. Так что грамотно переведенный CPP Reference, разумеется, был бы сильно полезнее. Но на это, конечно, надо время потратить.


  1. Riedl
    17.10.2026 18:30

    Это полный бред, бредятина, фиаско. Не знаю откуда столько свободного времени взяли на эту чушь. Ладно бы какой то там ЦЕрковный Си++(ЦЕСИ++) или СОборный Си++ (СОСИ++)


  1. vasisulay
    17.10.2026 18:30

    Ну да, а то вдруг английский случайно изучат.


  1. Blacpaul57
    17.10.2026 18:30

    Код на Си и без того перегружен макросами и указателями, а тут еще и русские синонимы вперемешку с английской libc. Если не переводить заголовки стандартной библиотеки, получается жуткая каша из printf и если. В итоге разработчик тратит половину сил не на логику, а на переключение контекста в голове


  1. Tomasina
    17.10.2026 18:30

    Нафига? Чтобы иной народ не смог разобраться в коде программы?

    И да, сомневаюсь что такой код пройдет верификацию при регистрации ПО в реестре отечественного ПО.


    1. randomsimplenumber
      17.10.2026 18:30

      Чтобы иной народ не смог разобраться в коде программы?

      Ллм в помощь.


  1. ross-s
    17.10.2026 18:30

    Теперь нужно как-то интегрировать падежи и уменьшительно-ласкательные


  1. trilirium
    17.10.2026 18:30

    Переменная с именем "твёрдый знак" -- это же конь-цептуально!

    Ради одного этого -- язык имело смысл создавать!! )))


  1. GrimAnEye
    17.10.2026 18:30


  1. jooher
    17.10.2026 18:30

    2026 год - самое время для си с нескучными обоями


  1. virst
    17.10.2026 18:30

    Мы уже видели до чедо довел фанатизм по поводу суверенного интернета. Суверенное программирование это шаг в туже сторону.


    1. peschex0d
      17.10.2026 18:30

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


  1. KonstantinTokar
    17.10.2026 18:30

    Хуже даже чем за или против "ё"


  1. Diacut
    17.10.2026 18:30

    В очередной раз перепутали синтаксис с лексикой. Синтаксис си останется синтаксисом си, неважно "if" там или "если".

    Бессмысленная работа.


  1. peschex0d
    17.10.2026 18:30

    На рубеже 2000 я пару лет вёл информатику в лицее и ФМШ на базе УКНЦ с Бейсиком и ibm pc с продуктами Борланд. Русифицированные среды в формате "черепашки" видел, но не использовал, поскольку plot/draw всё то же самое делает. У знакомых, связанных с системой образования, отношение к русскоязычным средам было от равнодушного до брезгливого, поскольку возможности совместной разработки, создания библиотек и больших проектов отсутствовали и все "черепашку" ощущали как обязательную пустую трату времени перед началом изучения Паскаля и си.

    Десткий мозг гибкий и не зная языка, дети вполне считывают if else как логический блок, а не рассказ на английском, как и остальные ключевые слова. Ломать это восприятие, превращая программу в повесть, дикую смесь комментариев, отдельных букв в роли имени переменных и слов русского языка, которые наделены особыми правами в рамках синтаксиса, это насилие над разумом. Как пресловутое ВычСрЗнач в Экселе для бальзаковского возраста бухгалтерш, которые иное просто органически не осилят или не захотят.

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

    Жаль, конечно, что не русский язык стал основным для MSDN, хехе, но причина явно не в отсутствии компилятора с "если" и "иначе".


    1. vadimr
      17.10.2026 18:30

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

      В детском курсе информатики не зря бывает много псевдокода для "программирования" людей. Зачем вводить искусственную разницу между черепашкой, которая понимает "DRAW", и соседом по парте, который понимает "НАРИСУЙ"?


      1. randomsimplenumber
        17.10.2026 18:30

        Зачем вводить искусственную разницу между черепашкой, которая понимает "DRAW", и соседом по парте, который понимает "НАРИСУЙ"?

        Одно из них умеет понимать естественного языка, другое нет. Человеков программируют не так как роботов.


      1. peschex0d
        17.10.2026 18:30

        На развитии логики синтаксис не сказывается вообще никак.

        При этом четверть века назад информатика в школе использовалась именно для воспроизводства программистов, учитывая CTR в 1% это не грозило их избытком )

        Это позже мы расслабились, уверовали в то, что MS Office навсегда и давайте штамповать уверенных пользователей ПК.

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

        В обсуждаемом форке gcc можно было бы добавить ещё условно полсотни синонимов для void как пример, но программист будет всё равно натыкаться на invalid keyword ошибки при попытке своими словами написать код и всё равно требуется знать подмножество естественного языка, которое применять можно.

        Поэтому зачем плодить сущности?

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


        1. vadimr
          17.10.2026 18:30

          Информатику в школе учит каждый, а программистов мало. Даже из нашего программистского школьного класса (а мы изучали по специальной учебной программе именно программирование вдобавок к дисциплине всеобщего среднего образования – информатике) в итоге вышло два с половиной программиста. Так что, думаю, вероятностью обучить программиста на уроках информатики можно пренебречь, также как пренебрегают вероятностью обучить переводчика с арабского на уроках английского языка.


          1. peschex0d
            17.10.2026 18:30

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

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


          1. peschex0d
            17.10.2026 18:30

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

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

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


            1. randomsimplenumber
              17.10.2026 18:30

              страны и общества в целом это было бы губительно

              Какая польза для общества от безработных программистов?

              когда и где тогда учить программистов, если не в школе

              После школы

              Профессии раньше учили в ПТУ.


              1. peschex0d
                17.10.2026 18:30

                в ПТУ раньше шли отбросы, прошу прощения, неспособные осилить программу старших классов. Из них делать программистов, мне кажется, такое себе. Вот слесарей для АвтоВАЗа самое то.

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

                Какая польза для общества от безработных программистов?

                от любых безработных есть польза стартапам при найме соответствующих специалистов, хоть сварщиков, хоть юристов.

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

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

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

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

                или шокирует?

                После школы

                Профессии раньше учили в ПТУ

                Я согласен с тем, когда плотника или слесаря учат в ПТУ, потому что для ряда профессий ученик банально должен обладать физической силой и мозгами, чтобы например не тыкать электродом сварочного аппарата себе в глаз.

                при этом логическое мышление развивается тем успешнее, чем раньше начато развитие и условно возраст 6-7 лет для начала информатики - самое то, чтобы ребенка не перегружать и более сложные вещи он успел осилить до условно периода "год топтания плаца сапогами"

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

                у меня лично информатики в школе не было, перфокарты, СМ4 и ДВК я увидел впервые учась в вузе, БК0010 и его ассемблер осваивал дома примерно в те же годы, но будь у меня лет пять запаса времени, то есть, начни я ковыряться еще в школе, скорее всего был бы только рад.


                1. randomsimplenumber
                  17.10.2026 18:30

                  Прикиньте, вам в школе прогать было интересно. А остальным? Конечно, китайский метод - пусть учат все, из миллиона выберем 10 способных - хорош, если есть в запасе 1 000 000 000 китайцев.

                  Программирование - рабочая профессия. В ПТУ ей нормально. Только ПТУ не для сварщиков а для программистов.


  1. the_homeless_god
    17.10.2026 18:30

    Вообще писал недавно о решении, с любой семантикой тут https://habr.com/ru/articles/1095038/

    Для нетерпеливых https://github.com/digitable-lol/flang


  1. DmitrySolomennikov
    17.10.2026 18:30

    Просто оставлю это здесь

    https://github.com/andrey-terekhov/RuC

    Разработка Андрея Николаевича Терехова


  1. igorek_tm
    17.10.2026 18:30

    есть конструктивная мысль: Т.к. основная проблема (мне) видится в размерах русских аналогов названий операторов - сравним "if" и "если" - двукратное увеличение слова, какой ужас начнется с switch - case, или конструкциями типа exception просто не хочется и думать. А если использовать обсценную лексику? Такого рода слова гораздо короче и в силу некоторой неопределенности значения могли бы быть использованы в "русском Си". Длинные слова-операторы continue, return, break а то и goto (!!) прекрасно заменились бы гораздо более короткими, причем читаемость кода, на мой взгляд, только улучшилась бы.


    1. randomsimplenumber
      17.10.2026 18:30

      А если использовать обсценную лексику?

      -- Плохой человек?

      -- редиска

      -- unsigned long long int ?

      -- забыл..


  1. perebour
    17.10.2026 18:30

    Кто пустил одинэсника в тред?

    Ужасная скреподуховная импортозамешенная суверенная мешанина на месте того, что признано международным стандартом


  1. Desvor
    17.10.2026 18:30

    Ни в коем случае не хочу обидеть автора, сли он писал это сам, но что-то мне напоминает текст ИИшный. Это не плохо, но мне интересно: у меня шиза, или есть место быть?