Предисловие

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

Книга следует проверенной структуре «Языка программирования C», чтобы читатель, знакомый с C, мог быстро освоить T, а новичок получил систематическое введение в троичное программирование.

Предисловие к первому изданию

Язык T родился из экспериментов с троичной машиной «Сетунь» и современных исследований в области многозначной логики. Мы стремились создать инструмент, который позволяет программисту работать с тритами так же естественно, как C позволяет работать с битами. Основные отличия — трёхзначная логика, тринарные операторы и сбалансированное представление чисел — дают новые выразительные возможности, сохраняя низкоуровневый контроль над аппаратурой.

Введение

T — это язык системного программирования, в котором основной единицей информации является трит (трёхзначный разряд), а машинным словом — трайт (9 тритов). Все целые типы кратны трайту, используется исключительно сбалансированная система (-, 0, +). Логика трёхзначная, с состояниями «истина», «ложь» и «может быть». Синтаксис заимствован у C и расширен русскими ключевыми словами.

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

1. Обзор языка

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

1.1. Начнём, пожалуй

Первая программа — троичное приветствие:

#include <tio.h>

tint main() {
    print("Привет, троичный мир!\n");
    return 0t;
}

С русскими ключевыми словами:

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

тцел главная() {
    печать("Привет, троичный мир!\n");
    возврат 0t;
}

Функция main (главная) — точка входа. print (печать) выводит строку, завершённую нулевым трайтом 0t. Тип tint (тцел) — стандартное целое (трайт). Литерал 0t — десятичный ноль с суффиксом t, обозначающим тип tint. return (возврат) завершает функцию и возвращает значение.

1.2. Переменные и арифметические выражения

В языке T определён ряд базовых типов: tint (тцел), tryte (трайт, синоним tint), tlong (тдлин), tfloat (твещ), tdouble (тдвойн). Переменные объявляются так же, как в C, но с использованием троичных типов.

#include <tio.h>

tint main() {
    tryte a = 0t+-0_0+0;   // троичный сбалансированный литерал
    tryte b = 50t;         // десятичный литерал
    tryte sum = a + b;
    printtryte(sum);       // выводит десятичное значение
    return 0t;
}

С русскими ключевыми словами:

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

тцел главная() {
    трайт a = 0t+-0_0+0;   // троичный сбалансированный литерал
    трайт b = 50t;         // десятичный литерал
    трайт sum = a + b;
    печатьтрайт(sum);      // выводит десятичное значение
    возврат 0t;
}

Арифметика сбалансированная: +, -, , /, %. Деление целочисленное с округлением к –∞. Например, -5t / 3t даёт -2t, так как -5t = (-2t)3t + 1t.

1.3. Инструкция for

Цикл for (для) работает как в C, но условие может быть трёхзначным. Тело выполняется, пока условие равно true (истина). Если условие принимает значение maybe (может) — цикл прерывается.

#include <tio.h>

tint main() {
    for (tryte i = 0t; i < 10t; i = i + 1t)
        printbal(i);
    return 0t;
}

С русскими ключевыми словами:

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

тцел главная() {
    для (трайт i = 0t; i < 10t; i = i + 1t)
        печатьбал(i);
    возврат 0t;
}

Эта программа выведет сбалансированные представления чисел от 0 до 9: 0, +, +-, ++, +--, +-0, +-+, ++-, ++0, +++.

1.4. Именованные константы

Именованные константы задаются двумя способами. Первый — директива препроцессора #define (#определить):

#define MAX 100t

С русскими ключевыми словами:

#определить MAX 100t

Второй — константная переменная:

const tryte MAX = 100t;

С русскими ключевыми словами:

конст трайт MAX = 100t;

Также есть встроенные константы истинности: true (истина), false (ложь), maybe (может). Они имеют тип tril (трил) и используются в трёхзначной логике.

1.5. Ввод-вывод символов

Символ в языке T — это tryte (трайт), хранящий код символа. Ввод-вывод осуществляется через функции из библиотеки <tio.h>: getchar() (получитьсимв) читает символ, putchar(c) (положитьсимв) записывает. Конец файла обозначается нулевым трайтом 0t.

1.5.1. Копирование файла

Простейшая программа-копировщик читает символы со стандартного ввода и выводит их на стандартный вывод:

#include <tio.h>

tint main() {
    tryte c;
    while ((c = getchar()) != 0t)   // 0t — конец файла
        putchar(c);
    return 0t;
}

С русскими ключевыми словами:

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

тцел главная() {
    трайт c;
    пока ((c = получитьсимв()) != 0t)   // 0t — конец файла
        положитьсимв(c);
    возврат 0t;
}

1.5.2. Подсчёт символов

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

#include <tio.h>

tint main() {
    tlong count = 0tl;
    while (getchar() != 0t)
        count = count + 1tl;
    printtlong(count);
    return 0t;
}

С русскими ключевыми словами:

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

тцел главная() {
    тдлин count = 0tl;
    пока (получитьсимв() != 0t)
        count = count + 1tl;
    печатьтдлин(count);
    возврат 0t;
}

Обратите внимание на суффикс tl — он обозначает тип tlong (тдлин, 18 тритов). Переменная count имеет тип tlong, чтобы можно было подсчитать большее количество символов, чем помещается в tint.

1.5.3. Подсчёт строк

Следующая программа подсчитывает количество строк во входном потоке. Символ новой строки имеет троичный код, который в десятичном представлении равен 10 (как и в ASCII).

#include <tio.h>

tint main() {
    tryte c;
    tlong lines = 0tl;
    while ((c = getchar()) != 0t) {
        if (c == 10t)      // 10t — код новой строки
            lines = lines + 1tl;
    }
    printtlong(lines);
    return 0t;
}

С русскими ключевыми словами:

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

тцел главная() {
    трайт c;
    тдлин lines = 0tl;
    пока ((c = получитьсимв()) != 0t) {
        если (c == 10t)      // 10t — код новой строки
            lines = lines + 1tl;
    }
    печатьтдлин(lines);
    возврат 0t;
}

1.5.4. Подсчёт слов

Программа подсчитывает количество слов, понимая слово как последовательность непробельных символов. Используется флаг inword, который принимает значение true (истина), когда мы находимся внутри слова.

#include <tio.h>

tint main() {
    tryte c;
    tlong words = 0tl;
    tril inword = false;

    while ((c = getchar()) != 0t) {
        if (c == 10t || c == 32t || c == 9t) {  // \n, пробел, табуляция
            inword = false;
        } else if (!inword) {
            inword = true;
            words = words + 1tl;
        }
    }
    printtlong(words);
    return 0t;
}

С русскими ключевыми словами:

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

тцел главная() {
    трайт c;
    тдлин words = 0tl;
    трил inword = ложь;

    пока ((c = получитьсимв()) != 0t) {
        если (c == 10t || c == 32t || c == 9t) {  // \n, пробел, табуляция
            inword = ложь;
        } иначе если (!inword) {
            inword = истина;
            words = words + 1tl;
        }
    }
    печатьтдлин(words);
    возврат 0t;
}

1.6. Массивы

Массивы в T объявляются так же, как в C: тип имя[размер]. Индексация начинается с нуля.

#include <tio.h>

tint main() {
    tryte digits[10];
    for (tryte i = 0t; i < 10t; i = i + 1t)
        digits[i] = i;
    return 0t;
}

С русскими ключевыми словами:

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

тцел главная() {
    трайт digits[10];
    для (трайт i = 0t; i < 10t; i = i + 1t)
        digits[i] = i;
    возврат 0t;
}

Размер массива должен быть константным выражением. Имя массива является указателем на его первый элемент (подробнее в главе 5).

1.7. Функции

Функции в T определяются так же, как в C. Тип возврата может быть любым: tint (тцел), tril (трил), tfloat (твещ), void (пусто) и т.д. Если тип не указан, по умолчанию подразумевается tint.

tryte add(tryte x, tryte y) {
    return x + y;
}

С русскими ключевыми словами:

трайт сложить(трайт x, трайт y) {
    возврат x + y;
}

Функция может быть объявлена до её использования (прототип):

tryte add(tryte x, tryte y);   // прототип

tint main() {
    tryte s = add(3t, 4t);
    return 0t;
}

tryte add(tryte x, tryte y) {
    return x + y;
}

С русскими ключевыми словами:

трайт сложить(трайт x, трайт y);   // прототип

тцел главная() {
    трайт s = сложить(3t, 4t);
    возврат 0t;
}

трайт сложить(трайт x, трайт y) {
    возврат x + y;
}

1.8. Аргументы. Вызов по значению

Все аргументы в T передаются по значению: функция получает копию значения, и изменения параметра внутри функции не влияют на переменную вызывающей стороны. Чтобы изменить переменную, нужно передать указатель (см. главу 5).

void increment(tryte *p) {
    *p = *p + 1t;
}

С русскими ключевыми словами:

пусто увеличить(трайт *p) {
    *p = *p + 1t;
}

1.9. Символьные массивы

Строки в T — это массивы tryte (трайт), заканчивающиеся нулевым трайтом 0t. Стандартные функции для работы со строками находятся в <tstring.h>.

#include <tstring.h>
#include <tio.h>

tint main() {
    tryte str[] = "Здравствуй, T!";
    tlong len = tstrlen(str);
    printtlong(len);
    return 0t;
}

С русскими ключевыми словами:

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

тцел главная() {
    трайт str[] = "Здравствуй, T!";
    тдлин len = тдлинастр(str);
    печатьтдлин(len);
    возврат 0t;
}

1.10. Внешние переменные и область видимости

Глобальные переменные объявляются вне функций и видимы во всём файле после точки объявления. Ключевое слово extern (внеш) даёт доступ к переменной, определённой в другом файле.

// file1.t
tint global_counter = 0t;

// file2.t
extern tint global_counter;

С русскими ключевыми словами:

// file1.t
тцел global_counter = 0t;

// file2.t
внеш тцел global_counter;

Статические глобальные переменные (с ключевым словом static / статич) видны только в пределах одного файла.

2. Типы, операторы и выражения

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

2.1. Имена переменных

Идентификаторы (имена переменных и функций) состоят из букв, цифр и знака подчёркивания . Первым символом должна быть буква или . Допускаются как латинские (AZ, az), так и кириллические (АЯ, ая, Ё, ё) буквы. Регистр различается.

Примеры допустимых имён:

счётчик    myVar    _trit    temp_value    ДлинаСтроки

2.2. Типы и размеры данных

В языке T определена следующая иерархия типов:

Тип

Тритов

Трайтов

Диапазон (сбалансированный)

trit

1

–1, 0, +1

tryte, tint

9

1

–9 841 … +9 841

tlong

18

2

–193 710 244 … +193 710 244

tlong long

27

3

–3 812 798 742 493 … +3 812 798 742 493

tfloat

18

2

6 тритов порядка, 12 мантиссы

tdouble

36

4

8 тритов порядка, 28 мантиссы

tril

1

true, maybe, false

  • trit — одиночный трит (–1, 0, +1). В выражениях автоматически повышается до tint.

  • tryte и tint — синонимы, оба обозначают машинное слово в 9 тритов.

  • tfloat — троичная плавающая точка (2 трайта), tdouble — повышенная точность (4 трайта).

  • tril — логический трит для трёхзначной логики.

Оператор sizeof (размер) возвращает размер в трайтах:

sizeof(tryte)   == 1
sizeof(tlong)   == 2
sizeof(tdouble) == 4

С русскими ключевыми словами:

размер(трайт)   == 1
размер(тдлин)   == 2
размер(тдвойн)  == 4

2.3. Константы

В языке T четыре вида констант: целые, вещественные, символьные и строковые.

Целочисленные константы бывают трёх форм:

  1. Десятичные — последовательность десятичных цифр с обязательным суффиксом размера:

    • ttint (9 тритов): 42t, -100t, 0t

    • tltlong (18 тритов): 1000tl, -500000tl

    • tlltlong long (27 тритов): 1000000tll

  2. Сбалансированные троичные — префикс 0t, затем троичные цифры -, 0, +:

    • 0t+-0_+-0 — 9 тритов с группировкой через _

    • 0t+++_+++_+++ — максимальное положительное значение tint (+9841)

    • 0t---_---_--- — минимальное отрицательное значение tint (–9841)

    • 0t0 — явный троичный ноль типа tint

  3. 27-ричные (tryx) — префикс 0y, затем 3, 6 или 9 цифр 09, AQ:

    • 0yDDD — ноль

    • 0yQQQ — максимальное значение tint (+9841)

    • 0y000 — минимальное значение tint (–9841)

Вещественные константы также бывают двух форм:

  1. Десятичная запись — целая и дробная часть через точку, опционально экспонента e:

    • 3.14 (тип tdouble), -0.001f (тип tfloat), 1.0e+2d

  2. Троичная запись — префикс 0t, мантисса с точкой, порядок после e:

    • 0t+.-0+0e+0ftfloat

    • 0t-.0++_---e-+dtdouble

Символьные константы заключаются в одиночные кавычки:

  • '+', '0', '-' имеют тип trit и значения +1, 0, –1 соответственно.

  • Любой другой символ (например, 'A') имеет тип tint и хранит его код.

Строковые константы — последовательность символов в двойных кавычках, завершаемая нулевым трайтом 0t:

"текст"

Логические константыtrue (истина), false (ложь), maybe (может). Имеют тип tril.

2.4. Объявления

Переменная объявляется указанием типа и имени. Инициализация может быть выполнена в объявлении:

tint a;
tril flag = true;
tfloat pi = 3.14f;
tryte name[] = "T";

С русскими ключевыми словами:

тцел a;
трил flag = истина;
твещ pi = 3.14f;
трайт name[] = "T";

Множественные объявления одного типа:

tint x, y, z;
tlong big = 1000tl, small = -1tl;

С русскими ключевыми словами:

тцел x, y, z;
тдлин big = 1000tl, small = -1tl;

2.5. Арифметические операторы

Базовые арифметические операторы: +, -, *, /, %. Они работают как с целыми, так и с вещественными типами (кроме %, который определён только для целых).

Целочисленное деление округляется вниз (к –∞). Например:

 5t / 3t  ==  1t    //  5 = 1*3 + 2
-5t / 3t  == -2t    // -5 = -2*3 + 1
 5t / -3t == -2t    //  5 = -2*(-3) + (-1)
-5t / -3t ==  1t    // -5 = 1*(-3) + (-2)

Остаток всегда удовлетворяет равенству (a/b)*b + a%b == a.

2.6. Операторы отношения и логические операторы

Операторы отношения (<, >, <=, >=, ==, !=) сравнивают числа и возвращают результат типа tril:

  • true (+1) — если отношение истинно

  • false (–1) — если отношение ложно

  • maybe (0) — не возникает при сравнении чисел, но может появиться при сравнении значений tril

Логические операторы && (И) и || (ИЛИ) реализуют трёхзначную логику:

  • a && b — минимум: true && maybe == maybe, true && false == false

  • a b — максимум: false maybe == maybe, false || true == true

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

2.7. Преобразования типов

Неявные преобразования:

  • trit автоматически повышается до tint в выражениях.

  • В операциях с разными целыми типами меньший тип повышается до большего: tinttlongtlong long.

  • Целые типы преобразуются в вещественные при смешанных операциях: tinttfloattdouble.

  • tril неявно преобразуется в trit и наоборот.

Явные преобразования (приведение типа):

tfloat f = (tfloat) a;   // tint → tfloat
tint x = (tint) 3.14;    // tdouble → tint (отбрасывание дробной части)

С русскими ключевыми словами:

твещ f = (твещ) a;   // тцел → твещ
тцел x = (тцел) 3.14;    // тдвойн → тцел (отбрасывание дробной части)

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

2.8. Операторы инкремента и декремента

Префиксные и постфиксные формы ++ и -- работают как в C:

tint x = 5t;
tint y = x++;   // y = 5, x = 6
tint z = ++x;   // z = 7, x = 7

С русскими ключевыми словами:

тцел x = 5t;
тцел y = x++;   // y = 5, x = 6
тцел z = ++x;   // z = 7, x = 7

Для указателей инкремент/декремент сдвигает адрес на размер объекта в трайтах.

2.9. Потритовые операторы

Потритовые операторы работают с каждым тритом числа независимо:

  • & — потритовый минимум: каждый трит результата равен минимуму соответствующих тритов операндов.

    + & 0 = 0    + & - = -    0 & - = -
    
  • | — потритовый максимум: каждый трит результата равен максимуму.

    + | 0 = +    + | - = +    0 | - = 0
    
  • ^ — потритовая сумма по модулю 3 без переноса:

    + ^ + = -    (1 + 1 = 2 → -1)
    - ^ - = +    (-1 + -1 = -2 → +1)
    + ^ 0 = +    + ^ - = 0
    
  • ~ — потритовое отрицание: каждый трит меняет знак.

    ~+ = -    ~- = +    ~0 = 0
    

Эти операторы применимы только к целым типам.

2.10. Операторы и выражения присваивания

Простое присваивание: a = b. Составные операторы присваивания:

a += b    // a = a + b
a -= b    // a = a - b
a *= b    // a = a * b
a /= b    // a = a / b
a %= b    // a = a % b
a <<= b   // a = a << b
a >>= b   // a = a >> b
a &= b    // a = a & b
a |= b    // a = a | b
a ^= b    // a = a ^ b

2.11. Условные выражения

Тринарный условный оператор — одно из ключевых отличий T от C. Он позволяет выбрать одну из трёх ветвей в зависимости от трёхзначного условия:

условие ?? выраж_истина :? выраж_может :! выраж_ложь

Пример:

tril flag = maybe;
tryte x = (flag == true) ?? 10t :? 0t :! -10t;

С русскими ключевыми словами:

трил flag = может;
трайт x = (flag == истина) ?? 10t :? 0t :! -10t;

Все три выражения вычисляются. Тип результата — общий тип трёх выражений. Опустить ветвь нельзя.

2.12. Приоритет и очередность вычислений

В следующей таблице операторы перечислены в порядке убывания приоритета (высший — первый):

Приоритет

Операторы

Ассоциативность

1

++ -- (постфиксные) () [] . ->

→ (слева направо)

2

++ -- (префиксные) + - ! ~ * & sizeof

← (справа налево)

3

* / %

4

+ -

5

<< >>

6

< > <= >=

7

== !=

8

& (потритовый минимум)

9

^ (потритовая сумма)

10

| (потритовый максимум)

11

&&

12

||

13

?? :? :! (тринарный)

14

= += -= *= /= %= <<= >>= &= ^= |=

Выражения с одинаковым приоритетом вычисляются в соответствии с ассоциативностью. Порядок вычисления операндов внутри выражения не определён (за исключением операторов &&, ||, ??:?:! и ,, которые гарантируют последовательное вычисление слева направо).

3. Управление

Порядок выполнения инструкций в программе на T определяется управляющими конструкциями: условными операторами, циклами и переходами. В этой главе рассматриваются все конструкции управления, включая трёхзначные расширения, отличающие T от C.

3.1. Инструкции и блоки

Инструкция — это либо выражение, завершённое точкой с запятой, либо управляющая конструкция. Блок — последовательность инструкций (и, возможно, объявлений), заключённая в фигурные скобки { }. Блок рассматривается как единая инструкция.

{
    tint x = 5t;
    x = x + 1t;
    printtryte(x);
}

С русскими ключевыми словами:

{
    тцел x = 5t;
    x = x + 1t;
    печатьтрайт(x);
}

3.2. Конструкция if-else

Классический if-else работает как в C:

if (a > b)
    print("больше\n");
else
    print("не больше\n");

С русскими ключевыми словами:

если (a > b)
    печать("больше\n");
иначе
    печать("не больше\n");

В T ветвь maybe может быть добавлена в любом порядке относительно else:

if (condition)
    print("истина\n");
maybe
    print("может быть\n");
else
    print("ложь\n");

С русскими ключевыми словами:

если (condition)
    печать("истина\n");
может
    печать("может быть\n");
иначе
    печать("ложь\n");

или:

if (condition)
    print("истина\n");
else
    print("ложь\n");
maybe
    print("может быть\n");

С русскими ключевыми словами:

если (condition)
    печать("истина\n");
иначе
    печать("ложь\n");
может
    печать("может быть\n");

Если ветвь maybe опущена, то при значении условия maybe управление переходит к следующей после if инструкции (ничего не выполняется).

3.3. Конструкция else-if

Цепочки else-if позволяют реализовать многоступенчатый выбор:

tint score = 75t;

if (score >= 90t)
    print("отлично\n");
else if (score >= 70t)
    print("хорошо\n");
else if (score >= 50t)
    print("удовлетворительно\n");
else
    print("неудовлетворительно\n");

С русскими ключевыми словами:

тцел score = 75t;

если (score >= 90t)
    печать("отлично\n");
иначе если (score >= 70t)
    печать("хорошо\n");
иначе если (score >= 50t)
    печать("удовлетворительно\n");
иначе
    печать("неудовлетворительно\n");

С maybe:

tril flag = maybe;

if (flag == true)
    print("да\n");
else if (flag == maybe)
    print("неизвестно\n");
else
    print("нет\n");

С русскими ключевыми словами:

трил flag = может;

если (flag == истина)
    печать("да\n");
иначе если (flag == может)
    печать("неизвестно\n");
иначе
    печать("нет\n");

3.4. Переключатель switch

switch работает как в C. Условие должно быть целочисленным выражением (типа tint, tlong и т.д.). Метки case — целочисленные константы.

switch (trit_value) {
    case -1: print("-"); break;
    case 0:  print("0"); break;
    case 1:  print("+"); break;
    default: print("?");
}

С русскими ключевыми словами:

переключатель (trit_value) {
    случай -1: печать("-"); прервать;
    случай 0:  печать("0"); прервать;
    случай 1:  печать("+"); прервать;
    поумолчанию: печать("?");
}

Тип tril не может быть использован непосредственно в switch — его нужно явно преобразовать в целое.

3.5. Циклы while и for

Цикл while повторяет тело, пока условие равно true. При maybe или false цикл прерывается.

tint i = 0t;
while (i < 10t) {
    printbal(i);
    i = i + 1t;
}

С русскими ключевыми словами:

тцел i = 0t;
пока (i < 10t) {
    печатьбал(i);
    i = i + 1t;
}

Цикл for — компактная форма:

for (tint i = 0t; i < 10t; i = i + 1t)
    printbal(i);

С русскими ключевыми словами:

для (тцел i = 0t; i < 10t; i = i + 1t)
    печатьбал(i);

Любая из трёх частей for может быть опущена. Бесконечный цикл:

for (;;)
    ...

С русскими ключевыми словами:

для (;;)
    ...

3.6. Цикл do-while

Цикл do-while гарантирует хотя бы одно выполнение тела:

tint i = 0t;
do {
    printbal(i);
    i = i + 1t;
} while (i < 10t);

С русскими ключевыми словами:

тцел i = 0t;
делать {
    печатьбал(i);
    i = i + 1t;
} пока (i < 10t);

3.7. Инструкции break и continue

break немедленно завершает выполнение цикла или switch. continue переходит к следующей итерации цикла, пропуская оставшиеся инструкции тела.

for (tint i = 0t; i < 100t; i = i + 1t) {
    if (i == 50t)
        break;       // завершаем цикл на 50
    if (i % 3t == 0t)
        continue;    // пропускаем чётные (в троичном смысле)
    printbal(i);
}

С русскими ключевыми словами:

для (тцел i = 0t; i < 100t; i = i + 1t) {
    если (i == 50t)
        прервать;       // завершаем цикл на 50
    если (i % 3t == 0t)
        продолжить;     // пропускаем чётные (в троичном смысле)
    печатьбал(i);
}

3.8. Инструкция goto и метки

goto и метки поддерживаются, но не рекомендуются к использованию. Метка — это идентификатор, за которым следует двоеточие.

tint i = 0t;
loop:
    if (i >= 10t) goto end;
    printbal(i);
    i = i + 1t;
    goto loop;
end:
    return 0t;

С русскими ключевыми словами:

тцел i = 0t;
метка:
    если (i >= 10t) перейти конец;
    печатьбал(i);
    i = i + 1t;
    перейти метка;
конец:
    возврат 0t;

4. Функции и структура программы

Функции — основной способ структурирования программы на T. В этой главе рассматриваются определение и использование функций, области видимости, классы памяти и препроцессор.

4.1. Основные сведения о функциях

Функция в T определяется указанием типа возврата, имени, списка параметров и тела:

tint square(tint x) {
    return x * x;
}

С русскими ключевыми словами:

тцел квадрат(тцел x) {
    возврат x * x;
}

Если функция не возвращает значения, используется тип void (пусто):

void print_hello() {
    print("Здравствуй, T!\n");
}

С русскими ключевыми словами:

пусто печать_привет() {
    печать("Здравствуй, T!\n");
}

Прототип функции позволяет использовать её до определения:

tint square(tint x);   // прототип

tint main() {
    return square(5t);
}

tint square(tint x) {
    return x * x;
}

С русскими ключевыми словами:

тцел квадрат(тцел x);   // прототип

тцел главная() {
    возврат квадрат(5t);
}

тцел квадрат(тцел x) {
    возврат x * x;
}

4.2. Функции, возвращающие нецелые значения

Функция может возвращать любой тип: tfloat (твещ), tdouble (тдвойн), tril (трил), void (пусто) и т.д.

tril is_positive(tint x) {
    if (x > 0t) return true;
    else if (x < 0t) return false;
    else return maybe;
}

tdouble average(tfloat a, tfloat b) {
    return (a + b) / 2.0f;
}

С русскими ключевыми словами:

трил положительное(тцел x) {
    если (x > 0t) возврат истина;
    иначе если (x < 0t) возврат ложь;
    иначе возврат может;
}

тдвойн среднее(твещ a, твещ b) {
    возврат (a + b) / 2.0f;
}

4.3. Внешние переменные

Глобальные переменные, объявленные вне функций, видны во всех функциях файла после точки объявления. Для доступа к глобальной переменной из другого файла используется ключевое слово extern (внеш):

// file1.t
tint global_count = 0t;

// file2.t
extern tint global_count;

С русскими ключевыми словами:

// file1.t
тцел global_count = 0t;

// file2.t
внеш тцел global_count;

4.4. Области видимости

  • Локальные переменные — объявлены внутри функции или блока, видны только в нём.

  • Глобальные переменные — объявлены вне функций, видны во всём файле.

  • Статические глобальные — с ключевым словом static (статич), видны только в пределах одного файла.

  • Параметры функций — локальны для функции.

tint global = 10t;          // глобальная
static tint file_local;     // видна только в этом файле

void func() {
    tint local = 5t;        // локальная
    {
        tint inner = 3t;    // видна только внутри блока
    }
}

С русскими ключевыми словами:

тцел global = 10t;            // глобальная
статич тцел file_local;       // видна только в этом файле

пусто func() {
    тцел local = 5t;          // локальная
    {
        тцел inner = 3t;      // видна только внутри блока
    }
}

4.5. Заголовочные файлы

Заголовочные файлы содержат объявления функций, типов и макросов, общих для нескольких файлов. Подключаются через #include (#включить):

#include "myheader.h"   // кавычки — поиск в текущем каталоге
#include <tio.h>        // угловые скобки — поиск в системном каталоге

С русскими ключевыми словами:

#включить "myheader.h"   // кавычки — поиск в текущем каталоге
#включить <tio.h>        // угловые скобки — поиск в системном каталоге

Пример заголовочного файла utils.h:

// utils.h
#ifndef UTILS_H
#define UTILS_H

tint max(tint a, tint b);
tint min(tint a, tint b);
#define ABS(x) ((x) < 0t ? -(x) : (x))

#endif

С русскими ключевыми словами:

// utils.h
#еслинеопределено UTILS_H
#определить UTILS_H

тцел макс(тцел a, тцел b);
тцел мин(тцел a, тцел b);
#определить ABS(x) ((x) < 0t ? -(x) : (x))

#кончить

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

#include "utils.h"

tint main() {
    tint m = max(10t, 20t);
    return 0t;
}

С русскими ключевыми словами:

#включить "utils.h"

тцел главная() {
    тцел m = макс(10t, 20t);
    возврат 0t;
}

4.6. Статические переменные

Ключевое слово static (статич) имеет два значения:

  1. Для глобальных переменных и функций — ограничивает область видимости текущим файлом.

  2. Для локальных переменных — сохраняет значение между вызовами функции.

void counter() {
    static tint calls = 0t;   // инициализируется один раз
    calls = calls + 1t;
    printtryte(calls);
}

С русскими ключевыми словами:

пусто счётчик() {
    статич тцел calls = 0t;   // инициализируется один раз
    calls = calls + 1t;
    печатьтрайт(calls);
}

4.7. Регистровые переменные

Ключевое слово register (регистр) — подсказка компилятору разместить переменную в троичном регистре процессора. Компилятор может проигнорировать эту подсказку.

void fast_sum(tint n) {
    register tint acc = 0t;
    for (register tint i = 0t; i < n; i = i + 1t)
        acc = acc + i;
}

С русскими ключевыми словами:

пусто быстрая_сумма(тцел n) {
    регистр тцел acc = 0t;
    для (регистр тцел i = 0t; i < n; i = i + 1t)
        acc = acc + i;
}

4.8. Блочная структура

Переменные могут быть объявлены в любом блоке. Внутренний блок может перекрывать имена внешних переменных:

tint x = 10t;
{
    tint x = 20t;        // перекрывает внешнюю x
    printtryte(x);       // выведет 20
}
printtryte(x);           // выведет 10

С русскими ключевыми словами:

тцел x = 10t;
{
    тцел x = 20t;        // перекрывает внешнюю x
    печатьтрайт(x);      // выведет 20
}
печатьтрайт(x);          // выведет 10

4.9. Инициализация

Глобальные и статические переменные инициализируются нулём (0t), если явно не заданы. Локальные переменные не инициализируются автоматически — их начальное значение неопределено.

tint global;             // 0t
static tint s;           // 0t

void func() {
    tint local;          // неопределённое значение!
    tint init = 5t;      // явная инициализация
}

С русскими ключевыми словами:

тцел global;               // 0t
статич тцел s;             // 0t

пусто func() {
    тцел local;            // неопределённое значение!
    тцел init = 5t;        // явная инициализация
}

4.10. Рекурсия

Функции могут вызывать себя. Классический пример — вычисление факториала:

tint factorial(tint n) {
    if (n <= 1t)
        return 1t;
    else
        return n * factorial(n - 1t);
}

С русскими ключевыми словами:

тцел факториал(тцел n) {
    если (n <= 1t)
        возврат 1t;
    иначе
        возврат n * факториал(n - 1t);
}

4.11. Препроцессор языка T

Препроцессор T аналогичен препроцессору C. Он обрабатывает директивы, начинающиеся с символа #, до начала основной компиляции. Все директивы препроцессора имеют русские эквиваленты.

4.11.1. Включение файла

Директива #include (#включить) вставляет содержимое указанного файла:

#include <tio.h>      // системный заголовок
#include "myheader.h" // пользовательский заголовок

С русскими ключевыми словами:

#включить <tio.h>      // системный заголовок
#включить "myheader.h" // пользовательский заголовок

Поиск файла в угловых скобках выполняется в системных каталогах, в кавычках — начиная с каталога текущего файла.

4.11.2. Макроподстановка

Директива #define (#определить) определяет макрос. Простой макрос:

#define MAX 100t

С русскими ключевыми словами:

#определить MAX 100t

Макрос с параметрами:

#define MAX(A,B) ((A) | (B))   // потритовый максимум
#define MIN(A,B) ((A) & (B))   // потритовый минимум
#define SQUARE(X) ((X)*(X))

С русскими ключевыми словами:

#определить MAX(A,B) ((A) | (B))   // потритовый максимум
#определить MIN(A,B) ((A) & (B))   // потритовый минимум
#определить КВАДРАТ(X) ((X)*(X))

Оператор # преобразует параметр в строку, ## склеивает токены:

#define STR(X) #X
#define CONCAT(A,B) A ## B

С русскими ключевыми словами:

#определить СТР(X) #X
#определить СЦЕПИТЬ(A,B) A ## B

4.11.3. Условная компиляция

Директивы условной компиляции: #if (#если), #ifdef (#еслиопределено), #ifndef (#еслинеопределено), #else (#иначе), #elif (#илиесли), #endif (#кончить).

#define T_VERSION 1t

#if T_VERSION >= 2t
    // код для версии 2 и выше
#elif T_VERSION == 1t
    // код для версии 1
#else
    // код для старых версий
#endif

#ifdef DEBUG
    print("отладочный вывод\n");
#endif

С русскими ключевыми словами:

#определить T_VERSION 1t

#если T_VERSION >= 2t
    // код для версии 2 и выше
#илиесли T_VERSION == 1t
    // код для версии 1
#иначе
    // код для старых версий
#кончить

#еслиопределено DEBUG
    печать("отладочный вывод\n");
#кончить

В выражениях #if константа true равна 1, false равна 0. Константа maybe не разрешена в #if — требуется явное приведение к целому.

Предопределённые макросы:

  • __T_LINE__ — номер текущей строки

  • __T_FILE__ — имя текущего файла

  • __T_VERSION__ — версия компилятора T

4.12. Встраиваемые функции (inline)

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

inline tint max(tint a, tint b) {
    return (a > b) ? a : b;
}

С русскими ключевыми словами:

встроен тцел макс(тцел a, тцел b) {
    возврат (a > b) ? a : b;
}

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

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

// В файле utils.h
#ifndef UTILS_H
#define UTILS_H

inline tint abs(tint x) {
    return (x < 0t) ? -x : x;
}

#endif

С русскими ключевыми словами:

// В файле utils.h
#еслинеопределено UTILS_H
#определить UTILS_H

встроен тцел модуль(тцел x) {
    возврат (x < 0t) ? -x : x;
}

#кончить

5. Указатели и массивы

Указатели — фундаментальная концепция языка T, обеспечивающая низкоуровневый доступ к памяти. В троичной системе указатели работают с трайтами как минимальными адресуемыми единицами.

5.1. Указатели и адреса

Указатель хранит адрес трайта в памяти. Типизированный указатель объявляется с помощью *:

tryte *p;    // указатель на tryte
tint *q;     // указатель на tint

Оператор & берёт адрес переменной, * разыменовывает указатель (обращается к значению по адресу):

tint x = 42t;
tint *p = &x;
printtryte(*p);   // выведет 42
*p = 100t;        // теперь x == 100t

Указатель void * — универсальный указатель, может хранить адрес любого типа:

void *ptr = &x;

С русскими ключевыми словами:

тцел x = 42t;
тцел *p = &x;
печатьтрайт(*p);   // выведет 42
*p = 100t;         // теперь x == 100t

5.2. Указатели и аргументы функций

Передача по указателю позволяет функции изменять переменные вызывающей стороны:

void swap(tryte *a, tryte *b) {
    tryte temp = *a;
    *a = *b;
    *b = temp;
}

tint main() {
    tryte x = 5t, y = 10t;
    swap(&x, &y);
    // теперь x == 10t, y == 5t
    return 0t;
}

С русскими ключевыми словами:

пусто обмен(трайт *a, трайт *b) {
    трайт temp = *a;
    *a = *b;
    *b = temp;
}

тцел главная() {
    трайт x = 5t, y = 10t;
    обмен(&x, &y);
    // теперь x == 10t, y == 5t
    возврат 0t;
}

5.3. Указатели и массивы

Имя массива является указателем на его первый элемент. Индексация arr[i] эквивалентна *(arr + i):

tryte arr[5];
tryte *p = arr;      // p указывает на arr[0]
*p = 10t;            // arr[0] = 10
*(p + 1t) = 20t;     // arr[1] = 20
arr[2] = 30t;        // эквивалентно *(arr + 2) = 30

С русскими ключевыми словами:

трайт arr[5];
трайт *p = arr;
*p = 10t;
*(p + 1t) = 20t;
arr[2] = 30t;

5.4. Адресная арифметика

Прибавление целого числа к указателю сдвигает адрес на n * sizeof(тип) трайтов:

tryte arr[10];
tryte *p = arr;
p = p + 1t;    // сдвиг на sizeof(tryte) = 1 трайт

tlong *q;
q = q + 1t;    // сдвиг на sizeof(tlong) = 2 трайта

Вычитание указателей даёт количество элементов между ними:

tryte *start = &arr[0];
tryte *end = &arr[5];
tlong diff = end - start;   // 5t

С русскими ключевыми словами:

трайт *начало = &arr[0];
трайт *конец = &arr[5];
тдлин разность = конец - начало;   // 5t

5.5. Символьные указатели и функции

Строковые литералы — массивы tryte, завершающиеся 0t. Указатель на строку:

tryte *s = "Привет, T!";

Функция, принимающая строку:

void print_upper(tryte *s) {
    for (tint i = 0t; s[i] != 0t; i = i + 1t)
        putchar(s[i]);
}

С русскими ключевыми словами:

пусто печать_верх(трайт *s) {
    для (тцел i = 0t; s[i] != 0t; i = i + 1t)
        putchar(s[i]);
}

5.6. Массивы указателей, указатели на указатели

Массив указателей:

tryte *lines[100];   // массив из 100 указателей на tryte

Указатель на указатель:

tryte **pp;          // указатель на указатель на tryte

Используется для передачи многомерных структур:

void sort_lines(tryte **lines, tint n) {
    // сортировка строк
}

С русскими ключевыми словами:

пусто сортировать_строки(трайт **строки, тцел n) {
    // сортировка строк
}

5.7. Многомерные массивы

Двумерный массив объявляется как тип имя[строки][столбцы]:

tryte matrix[10][20];   // 10 строк по 20 элементов

Доступ к элементу: matrix[i][j]. В памяти элементы хранятся по строкам (row-major order).

5.8. Инициализация массивов указателей

Массив указателей можно инициализировать списком строк:

tryte *months[] = {
    "январь", "февраль", "март",
    "апрель", "май", "июнь",
    "июль", "август", "сентябрь",
    "октябрь", "ноябрь", "декабрь"
};

tint main() {
    for (tint i = 0t; i < 12t; i = i + 1t)
        print(months[i]);
    return 0t;
}

С русскими ключевыми словами:

трайт *месяцы[] = {
    "январь", "февраль", "март",
    "апрель", "май", "июнь",
    "июль", "август", "сентябрь",
    "октябрь", "ноябрь", "декабрь"
};

тцел главная() {
    для (тцел i = 0t; i < 12t; i = i + 1t)
        печать(месяцы[i]);
    возврат 0t;
}

5.9. Указатели против многомерных массивов

Разница между tryte *p[10] (массив указателей) и tryte p[10][20] (двумерный массив) существенна:

  • tryte *p[10] — 10 указателей, каждый может указывать на строку произвольной длины.

  • tryte p[10][20] — непрерывная область 10×20 трайтов, все строки фиксированной длины.

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

5.10. Аргументы командной строки

Функция main может принимать аргументы командной строки:

tint main(tint argc, tryte *argv[]) {
    for (tint i = 0t; i < argc; i = i + 1t) {
        print(argv[i]);
        print("\n");
    }
    return 0t;
}
  • argc — количество аргументов (включая имя программы).

  • argv[0] — имя программы.

  • argv[argc] — нулевой указатель.

С русскими ключевыми словами:

тцел главная(тцел argc, трайт *argv[]) {
    для (тцел i = 0t; i < argc; i = i + 1t) {
        печать(argv[i]);
        печать("\n");
    }
    возврат 0t;
}

5.11. Указатели на функции

Указатель на функцию хранит адрес функции и позволяет вызывать её косвенно:

tryte (*func)(tryte, tryte);   // указатель на функцию

tryte add(tryte a, tryte b) { return a + b; }
tryte sub(tryte a, tryte b) { return a - b; }

tint main() {
    func = add;
    printtryte(func(5t, 3t));   // 8
    func = sub;
    printtryte(func(5t, 3t));   // 2
    return 0t;
}

С русскими ключевыми словами:

трайт (*операция)(трайт, трайт);

трайт сложить(трайт a, трайт b) { возврат a + b; }
трайт вычесть(трайт a, трайт b) { возврат a - b; }

тцел главная() {
    операция = сложить;
    печатьтрайт(операция(5t, 3t));   // 8
    операция = вычесть;
    печатьтрайт(операция(5t, 3t));   // 2
    возврат 0t;
}

Указатели на функции часто используются для таблиц переходов и callback-функций.

5.12. Сложные объявления

В T, как и в C, объявления могут быть сложными. Правило чтения: «от имени наружу».

tryte *(*fp)(tryte *);   // fp — указатель на функцию,
                          // принимающую tryte* и возвращающую tryte*

tint (*arr[10])(tlong);  // arr — массив из 10 указателей на функции,
                          // принимающие tlong и возвращающие tint

tint (*(*f)(tint))[5];   // f — указатель на функцию, принимающую tint
                          // и возвращающую указатель на массив из 5 tint

Для упрощения сложных объявлений используйте typedef:

typedef tint (*func_t)(tint, tint);
func_t operations[10];

С русскими ключевыми словами:

типрег тцел (*функция_т)(тцел, тцел);
функция_т операции[10];

6. Структуры

Структуры в T позволяют группировать связанные данные разных типов под одним именем. Это основной механизм для создания составных типов данных.

6.1. Основные сведения о структурах

Структура объявляется ключевым словом struct (структура):

struct point {
    tryte x;
    tryte y;
};

После объявления можно создавать переменные этого типа:

struct point p1;
struct point p2 = { 10t, 20t };

Доступ к полям — через точку .:

p1.x = 5t;
p1.y = 15t;
printtryte(p1.x + p1.y);

С русскими ключевыми словами:

структура точка {
    трайт x;
    трайт y;
};

структура точка p1;
структура точка p2 = { 10t, 20t };

p1.x = 5t;
p1.y = 15t;
печатьтрайт(p1.x + p1.y);

6.2. Структуры и функции

Структуры можно передавать в функции по значению и возвращать из функций:

struct point make_point(tryte x, tryte y) {
    struct point p;
    p.x = x;
    p.y = y;
    return p;
}

void print_point(struct point p) {
    printbal(p.x);
    print(" ");
    printbal(p.y);
    print("\n");
}

Для больших структур эффективнее передавать указатель:

void move_point(struct point *p, tryte dx, tryte dy) {
    p->x = p->x + dx;
    p->y = p->y + dy;
}

С русскими ключевыми словами:

структура точка создать_точку(трайт x, трайт y) {
    структура точка p;
    p.x = x;
    p.y = y;
    возврат p;
}

пусто печать_точка(структура точка p) {
    печатьбал(p.x);
    печать(" ");
    печатьбал(p.y);
    печать("\n");
}

пусто сдвинуть_точку(структура точка *p, трайт dx, трайт dy) {
    p->x = p->x + dx;
    p->y = p->y + dy;
}

6.3. Массивы структур

Массив структур объявляется как любой другой массив:

struct point points[100];

// инициализация
struct point polygon[] = {
    { 0t, 0t },
    { 10t, 0t },
    { 10t, 10t },
    { 0t, 10t }
};

Доступ к элементам:

for (tint i = 0t; i < 4t; i = i + 1t)
    print_point(polygon[i]);

С русскими ключевыми словами:

структура точка точки[100];

структура точка многоугольник[] = {
    { 0t, 0t },
    { 10t, 0t },
    { 10t, 10t },
    { 0t, 10t }
};

для (тцел i = 0t; i < 4t; i = i + 1t)
    печать_точка(многоугольник[i]);

6.4. Указатели на структуры

Указатель на структуру объявляется как обычно. Для доступа к полям через указатель используется оператор ->:

struct point *pp = &p1;
pp->x = 30t;              // эквивалентно (*pp).x = 30
printtryte(pp->y);

С русскими ключевыми словами:

структура точка *pp = &p1;
pp->x = 30t;
печатьтрайт(pp->y);

6.5. Структуры со ссылками на себя

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

struct node {
    tryte data;
    struct node *next;
};

Пример создания простого списка:

tint main() {
    struct node n1, n2, n3;
    n1.data = 1t; n1.next = &n2;
    n2.data = 2t; n2.next = &n3;
    n3.data = 3t; n3.next = 0t;   // нулевой указатель — конец списка

    // обход списка
    for (struct node *p = &n1; p != 0t; p = p->next)
        printtryte(p->data);
    return 0t;
}

С русскими ключевыми словами:

структура узел {
    трайт данные;
    структура узел *следующий;
};

тцел главная() {
    структура узел n1, n2, n3;
    n1.данные = 1t; n1.следующий = &n2;
    n2.данные = 2t; n2.следующий = &n3;
    n3.данные = 3t; n3.следующий = 0t;

    для (структура узел *p = &n1; p != 0t; p = p->следующий)
        печатьтрайт(p->данные);
    возврат 0t;
}

6.6. Просмотр таблиц

Структуры часто используются для реализации таблиц поиска. Пример — таблица соответствия троичных цифр и их названий:

struct trit_entry {
    tryte value;
    tryte *name;
};

struct trit_entry trit_table[] = {
    { -1, "минус" },
    { 0,  "ноль" },
    { 1,  "плюс" }
};

tryte *trit_name(tryte val) {
    for (tint i = 0t; i < 3t; i = i + 1t) {
        if (trit_table[i].value == val)
            return trit_table[i].name;
    }
    return "неизвестно";
}

С русскими ключевыми словами:

структура запись_трита {
    трайт значение;
    трайт *имя;
};

структура запись_трита таблица_тритов[] = {
    { -1, "минус" },
    { 0,  "ноль" },
    { 1,  "плюс" }
};

трайт *имя_трита(трайт val) {
    для (тцел i = 0t; i < 3t; i = i + 1t) {
        если (таблица_тритов[i].значение == val)
            возврат таблица_тритов[i].имя;
    }
    возврат "неизвестно";
}

6.7. Средство typedef

typedef создаёт синоним для существующего типа:

typedef tryte трит_массив[3];
typedef struct point Point;
typedef struct node *NodePtr;

После объявления:

Point p1;              // то же, что struct point p1
трит_массив arr;       // то же, что tryte arr[3]
NodePtr list_head;     // то же, что struct node *list_head

typedef особенно полезен для сложных объявлений:

typedef tint (*CompareFunc)(const tryte *, const tryte *);

С русскими ключевыми словами:

типрег трайт массив_тритов[3];
типрег структура точка Точка;
типрег структура узел *УказательУзла;

6.8. Объединения

Объединение (union / объединение) позволяет хранить разные типы данных в одной области памяти. Размер объединения равен размеру наибольшего поля.

union data {
    tint i;
    tfloat f;
    tryte *s;
};

union data d;
d.i = 42t;          // храним tint
printtryte(d.i);
d.f = 3.14f;        // теперь там tfloat (предыдущее значение перезаписано)
printfloat(d.f);

С русскими ключевыми словами:

объединение данные {
    тцел i;
    твещ f;
    трайт *s;
};

объединение данные d;
d.i = 42t;
печатьтрайт(d.i);
d.f = 3.14f;
печатьвещ(d.f);

6.9. Тритовые поля (аналог битовых полей)

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

struct {
    tryte x : 3;   // 3 трита (диапазон -13..+13)
    tryte y : 3;   // 3 трита
    tryte z : 3;   // 3 трита — всего 9 тритов = 1 трайт
} packed;

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

packed.x = 5t;
packed.y = -3t;
packed.z = 0t;

С русскими ключевыми словами:

структура {
    трайт x : 3;
    трайт y : 3;
    трайт z : 3;
} упаковано;

упаковано.x = 5t;
упаковано.y = -3t;
упаковано.z = 0t;

7. Ввод и вывод

В языке T нет встроенных средств ввода-вывода — они реализованы в стандартной библиотеке <tio.h>. Эта глава описывает основные функции для работы с вводом и выводом.

7.1. Стандартный ввод-вывод

Библиотека <tio.h> предоставляет функции для работы со стандартными потоками:

  • getchar() — читает один символ (тип tryte) со стандартного ввода. Возвращает 0t при достижении конца файла.

  • putchar(c) — записывает символ c на стандартный вывод.

  • print(s) — выводит строку.

  • printtryte(x) — выводит целое число в десятичном виде.

  • printbal(x) — выводит целое число в сбалансированной троичной форме (+, 0, -).

  • printtril(b) — выводит логическое значение как true, maybe или false.

  • printfloat(f) — выводит tfloat в десятичном виде.

  • printdouble(d) — выводит tdouble в десятичном виде.

Пример:

#include <tio.h>

tint main() {
    tryte c;
    while ((c = getchar()) != 0t)
        putchar(c);
    return 0t;
}

С русскими ключевыми словами:

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

тцел главная() {
    трайт c;
    пока ((c = getchar()) != 0t)
        putchar(c);
    возврат 0t;
}

7.2. Форматный вывод (printf)

Функция tprintf (или printf) выводит форматированный текст с троичными спецификаторами:

tprintf("целое: %T, баланс: %B, tril: %R\n", a, a, flag);

Спецификаторы формата:

Спецификатор

Описание

%T

Десятичный вывод tryte / tint

%L

Вывод tlong в десятичном виде

%LL

Вывод tlong long в десятичном виде

%B

Сбалансированный троичный вывод (+, 0, -)

%R

Вывод tril (true / maybe / false)

%F

Вывод tfloat

%D

Вывод tdouble

%S

Вывод строки (tryte *)

%C

Вывод символа

7.3. Списки аргументов переменной длины

Библиотека <tstdarg.h> предоставляет средства для работы с функциями переменного числа аргументов:

#include <tstdarg.h>
#include <tio.h>

tint sum(tint count, ...) {
    tva_list args;
    tva_start(args, count);
    tint total = 0t;
    for (tint i = 0t; i < count; i = i + 1t)
        total = total + tva_arg(args, tint);
    tva_end(args);
    return total;
}

tint main() {
    tint s = sum(4t, 1t, 2t, 3t, 4t);
    printtryte(s);   // 10
    return 0t;
}

С русскими ключевыми словами:

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

тцел сумма(тцел count, ...) {
    tva_list args;
    tva_start(args, count);
    тцел всего = 0t;
    для (тцел i = 0t; i < count; i = i + 1t)
        всего = всего + tva_arg(args, тцел);
    tva_end(args);
    возврат всего;
}

тцел главная() {
    тцел s = сумма(4t, 1t, 2t, 3t, 4t);
    печатьтрайт(s);   // 10
    возврат 0t;
}

7.4. Форматный ввод (tscanf)

Функция tscanf (или scanf) читает форматированный ввод:

tint x;
tscanf("%T", &x);

Спецификаторы формата для ввода те же, что и для вывода: %T, %L, %F, %D, %S.

7.5. Доступ к файлам

Для работы с файлами используются функции:

  • tFILE tfopen(const tryte path, const tryte *mode) — открывает файл.

  • tint tgetc(tFILE *stream) — читает символ из файла.

  • tint tputc(tint c, tFILE *stream) — записывает символ в файл.

  • tint tfclose(tFILE *stream) — закрывает файл.

Режимы открытия: "r" (чтение), "w" (запись), "a" (добавление), "r+", "w+", "a+".

#include <tio.h>

tint main() {
    tFILE *f = tfopen("пример.т", "r");
    if (f == 0t) {
        print("ошибка открытия файла\n");
        return 1t;
    }

    tryte c;
    while ((c = tgetc(f)) != 0t)
        putchar(c);

    tfclose(f);
    return 0t;
}

С русскими ключевыми словами:

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

тцел главная() {
    tFILE *f = tfopen("пример.т", "r");
    если (f == 0t) {
        печать("ошибка открытия файла\n");
        возврат 1t;
    }

    трайт c;
    пока ((c = tgetc(f)) != 0t)
        putchar(c);

    tfclose(f);
    возврат 0t;
}

7.6. Управление ошибками (stderr и exit)

Стандартный поток ошибок — tstderr. Функция texit(code) немедленно завершает программу с кодом возврата:

#include <tio.h>

tint main() {
    tFILE *f = tfopen("несущ.т", "r");
    if (f == 0t) {
        tprintf("ошибка: файл не найден\n");
        texit(1t);
    }
    tfclose(f);
    return 0t;
}

7.7. Ввод-вывод строк

Функции tgets и tputs работают со строками:

  • tryte tgets(tryte s, tint n, tFILE *stream) — читает строку (до n-1 символов или до конца строки).

  • tint tputs(const tryte s, tFILE stream) — записывает строку.

#include <tio.h>

tint main() {
    tryte buf[100];
    while (tgets(buf, 100, tstdin) != 0t)
        tputs(buf, tstdout);
    return 0t;
}

7.8. Другие библиотечные функции

7.8.1. Операции со строками

Библиотека <tstring.h> предоставляет функции для работы со строками:

  • tstrlen(s) — длина строки.

  • tstrcpy(dst, src) — копирование строки.

  • tstrcat(dst, src) — конкатенация строк.

  • tstrcmp(s1, s2) — лексикографическое сравнение (возвращает –1, 0, +1).

#include <tstring.h>
#include <tio.h>

tint main() {
    tryte s1[] = "троичный";
    tryte s2[] = "троичный";
    if (tstrcmp(s1, s2) == 0t)
        print("строки равны\n");
    return 0t;
}

7.8.2. Анализ класса символов и преобразование

Библиотека <tctype.h> предоставляет функции проверки символов:

  • tisdigit(c) — проверка на десятичную цифру.

  • tisspace(c) — проверка на пробельный символ.

  • tistrit(c) — проверка на троичную цифру (-, 0, +).

  • tisalpha(c) — проверка на букву.

  • toupper(c), tolower(c) — преобразование регистра.

7.8.3. Функция ungetc

tungetc(c, stream) возвращает символ обратно в поток. Гарантируется не менее одного символа возврата.

tryte c = tgetc(f);
if (tisdigit(c))
    tungetc(c, f);   // вернули цифру обратно

7.8.4. Исполнение команд операционной системы

tsystem(command) выполняет команду операционной системы:

tsystem("троичный_компилятор программа.т");

7.8.5. Управление памятью

Функции для работы с динамической памятью:

  • void *tmalloc(n) — выделяет n трайтов.

  • void tfree(p) — освобождает память.

  • void *trealloc(p, n) — изменяет размер блока.

  • void *tcalloc(n, size) — выделяет и обнуляет память.

#include <tstdlib.h>
#include <tio.h>

tint main() {
    tryte *buf = (tryte *) tmalloc(100t);
    if (buf == 0t) {
        print("не удалось выделить память\n");
        return 1t;
    }
    // работа с buf
    tfree(buf);
    return 0t;
}

7.8.6. Математические функции

Библиотека <tmath.h> предоставляет математические функции:

  • tsin(x), tcos(x) — тригонометрические функции.

  • tsqrt(x) — квадратный корень.

  • tabs(x) — абсолютное значение для целых.

  • tfabs(x) — абсолютное значение для вещественных.

  • tmin(x, y), tmax(x, y) — минимум и максимум.

  • tfloor(x), tceil(x) — округление вниз и вверх.

#include <tmath.h>
#include <tio.h>

tint main() {
    tdouble x = 2.0;
    tdouble r = tsqrt(x);
    printdouble(r);
    return 0t;
}

7.8.7. Генератор случайных чисел

trand() возвращает псевдослучайное значение типа tint в диапазоне от –9841 до +9841:

#include <tstdlib.h>
#include <tio.h>

tint main() {
    for (tint i = 0t; i < 10t; i = i + 1t)
        printtryte(trand());
    return 0t;
}

8. Интерфейс с системой UNIX (троичная эмуляция)

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

8.1. Дескрипторы файлов

Дескриптор файла — это целое число типа tint, идентифицирующее открытый файл в операционной системе. Стандартные дескрипторы:

  • 0t — стандартный ввод (stdin)

  • 1t — стандартный вывод (stdout)

  • 2t — стандартный вывод ошибок (stderr)

8.2. Нижний уровень ввода-вывода (read и write)

Системные вызовы tread и twrite работают с дескрипторами файлов:

tint n = tread(fd, buf, ntraits);
tint m = twrite(fd, buf, ntraits);
  • fd — дескриптор файла.

  • buf — указатель на буфер (тип void *).

  • ntraits — количество трайтов для чтения/записи.

  • Возвращают количество прочитанных/записанных трайтов или -1t при ошибке.

Пример — копирование с использованием низкоуровневого ввода-вывода:

#include <tio.h>

#define BUFSIZE 512t

tint main() {
    tryte buf[BUFSIZE];
    tint n;
    while ((n = tread(0t, buf, BUFSIZE)) > 0t)
        twrite(1t, buf, n);
    return 0t;
}

С русскими ключевыми словами:

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

#определить РАЗМЕРБУФА 512t

тцел главная() {
    трайт буф[РАЗМЕРБУФА];
    тцел n;
    пока ((n = tread(0t, буф, РАЗМЕРБУФА)) > 0t)
        twrite(1t, буф, n);
    возврат 0t;
}

8.3. Системные вызовы open, creat, close, unlink

  • tint topen(const tryte *path, tint flags) — открывает файл. Флаги: 0t (только чтение), 1t (только запись), 2t (чтение и запись).

  • tint tcreat(const tryte *path, tint mode) — создаёт файл.

  • tint tclose(tint fd) — закрывает файл.

  • tint tunlink(const tryte *path) — удаляет файл.

#include <tio.h>

tint main() {
    tint fd = topen("данные.т", 0t);   // открыть на чтение
    if (fd < 0t) {
        print("ошибка открытия\n");
        return 1t;
    }

    tryte buf[100];
    tint n = tread(fd, buf, 100);
    twrite(1t, buf, n);

    tclose(fd);
    return 0t;
}

С русскими ключевыми словами:

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

тцел главная() {
    тцел fd = topen("данные.т", 0t);
    если (fd < 0t) {
        печать("ошибка открытия\n");
        возврат 1t;
    }

    трайт буф[100];
    тцел n = tread(fd, буф, 100);
    twrite(1t, буф, n);

    tclose(fd);
    возврат 0t;
}

8.4. Произвольный доступ (tlseek)

tlseek(fd, offset, whence) — перемещает позицию в файле. Смещение задаётся в трайтах.

  • whence = 0t — от начала файла.

  • whence = 1t — от текущей позиции.

  • whence = 2t — от конца файла.

tlseek(fd, 0t, 0t);     // переход в начало файла
tlseek(fd, 100t, 1t);   // на 100 трайтов вперёд от текущей позиции
tlseek(fd, 0t, 2t);     // переход в конец файла

8.5. Пример. Реализация функций tfopen и tgetc

Покажем, как можно реализовать буферизованный ввод-вывод поверх системных вызовов:

#include <tio.h>
#include <tstdlib.h>
#include <tstring.h>

#define BUFSIZE 512t

struct tFILE {
    tint fd;                // дескриптор файла
    tryte buf[BUFSIZE];     // буфер
    tint pos;               // текущая позиция в буфере
    tint end;               // конец данных в буфере
    tint flags;             // флаги: 0 — чтение, 1 — запись
};

tFILE *tfopen(const tryte *path, const tryte *mode) {
    tFILE *fp = (tFILE *) tmalloc(sizeof(tFILE));
    if (fp == 0t)
        return 0t;

    tint flags;
    if (mode[0] == 'r')
        flags = 0t;        // только чтение
    else if (mode[0] == 'w')
        flags = 1t;        // только запись
    else
        flags = 2t;        // чтение и запись

    fp->fd = topen(path, flags);
    if (fp->fd < 0t) {
        tfree(fp);
        return 0t;
    }

    fp->pos = 0t;
    fp->end = 0t;
    fp->flags = 0t;
    return fp;
}

tint tgetc(tFILE *fp) {
    if (fp->pos >= fp->end) {
        // буфер пуст — читаем новую порцию
        fp->end = tread(fp->fd, fp->buf, BUFSIZE);
        if (fp->end <= 0t)
            return 0t;     // конец файла или ошибка
        fp->pos = 0t;
    }
    return fp->buf[fp->pos++];
}

tint tfclose(tFILE *fp) {
    tint result = tclose(fp->fd);
    tfree(fp);
    return result;
}

8.6. Пример. Печать каталогов

Рекурсивный обход троичной файловой системы:

#include <tio.h>
#include <tstdlib.h>
#include <tstring.h>

struct t_dirent {
    tint inode;
    tryte name[256];
};

tint topendir(const tryte *path);
tint tclosedir(tint fd);
tint treaddir(tint fd, struct t_dirent *entry);

void print_directory(const tryte *path, tint depth) {
    tint fd = topendir(path);
    if (fd < 0t)
        return;

    struct t_dirent entry;
    while (treaddir(fd, &entry) > 0t) {
        // отступ для вложенности
        for (tint i = 0t; i < depth; i = i + 1t)
            print("  ");

        print(entry.name);
        print("\n");

        // если это каталог (inode == 1t), рекурсивно обходим
        if (entry.inode == 1t && entry.name[0] != '.') {
            tryte fullpath[512];
            tstrcpy(fullpath, path);
            tstrcat(fullpath, "/");
            tstrcat(fullpath, entry.name);
            print_directory(fullpath, depth + 1t);
        }
    }
    tclosedir(fd);
}

tint main() {
    print_directory(".", 0t);
    return 0t;
}

8.7. Пример. Распределитель памяти

Упрощённый менеджер кучи, работающий с трайтами:

#include <tio.h>
#include <tstdlib.h>

#define HEAP_SIZE 4096t
#define ALIGNMENT 1t     // выравнивание в трайтах

static tryte heap[HEAP_SIZE];
static tint heap_free = 0t;   // начало свободной области

typedef struct header {
    tint size;              // размер блока в трайтах
    tint used;              // 0 — свободен, 1 — занят
    struct header *next;    // следующий блок
} Header;

static Header *free_list = 0t;

void *tmalloc(tint n) {
    // выравнивание
    n = (n + ALIGNMENT - 1t) / ALIGNMENT * ALIGNMENT;

    // поиск свободного блока
    Header *prev = 0t;
    Header *curr = free_list;

    while (curr != 0t) {
        if (!curr->used && curr->size >= n) {
            // нашли подходящий блок
            curr->used = 1t;
            return (void *)(curr + 1t);
        }
        prev = curr;
        curr = curr->next;
    }

    // нет подходящего блока — выделяем из кучи
    if (heap_free + n + sizeof(Header) > HEAP_SIZE)
        return 0t;   // не хватает памяти

    Header *new_block = (Header *) &heap[heap_free];
    new_block->size = n;
    new_block->used = 1t;
    new_block->next = 0t;

    if (prev != 0t)
        prev->next = new_block;
    else
        free_list = new_block;

    heap_free = heap_free + n + sizeof(Header);
    return (void *)(new_block + 1t);
}

void tfree(void *ptr) {
    if (ptr == 0t)
        return;

    Header *block = (Header *)ptr - 1t;
    block->used = 0t;

    // слияние соседних свободных блоков
    Header *curr = free_list;
    while (curr != 0t) {
        if (!curr->used && curr->next != 0t && !curr->next->used) {
            curr->size = curr->size + sizeof(Header) + curr->next->size;
            curr->next = curr->next->next;
        } else {
            curr = curr->next;
        }
    }
}

А. Справочное руководство

Данное приложение является формальным справочным руководством по языку T. Оно описывает лексику, синтаксис и семантику языка в том же стиле, что и Приложение A в книге K&R.

А.1. Введение

Язык T — низкоуровневый троичный аналог языка C. Основу составляют трит (трёхзначный разряд) и трайт (9-тритное машинное слово). Используется исключительно сбалансированная троичная система счисления с цифрами - (–1), 0, + (+1). Логика трёхзначная; синтаксис близок к C, но расширен тринарными операторами и трёхветвевыми конструкциями.

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

А.2. Соглашения о лексике

Программа на T состоит из токенов, разделённых пробельными символами (пробел, табуляция, перевод строки). Комментарии: /* ... */ (многострочные) и // ... (до конца строки).

Токены:

  1. Идентификаторы — последовательность букв (латиница AZ, az и кириллица АЯ, ая, Ё, ё), цифр (09) и знака подчёркивания . Первый символ — буква или . Регистр различается.

  2. Ключевые слова — имеют английские и русские варианты:

    Английское

    Русское

    Категория

    if

    если

    Условие

    maybe

    может

    Ветвь / константа

    else

    иначе

    Условие

    switch

    выбор

    Выбор

    case

    случай

    Метка выбора

    default

    умолчание

    Метка выбора

    while

    пока

    Цикл

    do

    делать

    Цикл

    for

    для

    Цикл

    break

    прервать

    Переход

    continue

    продолжить

    Переход

    return

    возврат

    Переход

    goto

    перейти

    Переход

    struct

    структура

    Тип

    union

    объединение

    Тип

    enum

    перечисление

    Тип

    typedef

    типрег

    Объявление типа

    const

    конст

    Квалификатор

    volatile

    изменч

    Квалификатор

    signed

    знак

    Спецификатор

    unsigned

    беззнак

    Спецификатор

    void

    пусто

    Тип

    tint

    тцел

    Целый тип

    tryte

    трайт

    Целый тип (синоним tint)

    tlong

    тдлин

    Целый тип

    tlong long

    тдлиндлин

    Целый тип

    tfloat

    твещ

    Вещественный тип

    tdouble

    тдвойн

    Вещественный тип

    trit

    трит

    Тип трита

    tril

    трил

    Логический тип

    true

    истина

    Константа

    false

    ложь

    Константа

    maybe

    может

    Константа

    sizeof

    размер

    Оператор

    extern

    внеш

    Класс хранения

    static

    статич

    Класс хранения

    auto

    авто

    Класс хранения

    register

    регистр

    Класс хранения

    inline

    встроен

    Спецификатор функции

    Зарезервированные, но не используемые слова: short (коротк), char (симв), int (цел), long (длин), float (плав), double (двойн).

  3. Константы:

    • Целые десятичные: последовательность цифр с суффиксом t (tint), tl (tlong), tll (tlong long). Примеры: 42t, -100tl, 0t.

    • Целые сбалансированные троичные: префикс 0t, затем цифры -, 0, +. Примеры: 0t+-0_+-0, 0t0.

    • Целые 27-ричные (tryx): префикс 0y, затем 3/6/9 цифр 09, AQ. Примеры: 0yDDD, 0yQQQ.

    • Вещественные десятичные: целая и дробная часть через точку, опционально e с показателем. Суффикс f (tfloat) или d (tdouble). Примеры: 3.14, -0.001f, 1.0e+2d.

    • Вещественные троичные: префикс 0t, мантисса с точкой, e, порядок. Суффикс f или d обязателен. Примеры: 0t+.-0+0e+0f.

    • Символьные: '+', '0', '-' (тип trit); остальные символы — тип tint.

    • Строковые: последовательность символов в двойных кавычках, завершается 0t.

    • Логические: true (истина), false (ложь), maybe (может).

  4. Строковые литералы — последовательность символов в двойных кавычках, завершаемая нулевым трайтом 0t. Тип — tryte *. Соседние строковые литералы конкатенируются на этапе трансляции.

A.3. Нотация синтаксиса

Грамматика языка T описывается в EBNF (Extended Backus-Naur Form):

  • = — определение

  • , — последовательность

  • | — альтернатива

  • [ ... ] — опционально (0 или 1 раз)

  • { ... } — повторение (0 или более раз)

  • ( ... ) — группировка

  • "..." — терминальный символ

  • (* ... *) — комментарий

Пример:

identifier = ( letter | "_" ) { letter | digit | "_" } .

А.4. Что обозначают идентификаторы

Идентификатор обозначает объект (переменную), функцию, тип, метку или член структуры/объединения.

Классы памяти:

  • auto (авто) — локальная переменная (по умолчанию).

  • extern (внеш) — внешнее связывание, переменная определена в другом файле.

  • static (статич) — внутреннее связывание (файл) или сохраняемая локальная переменная.

  • register (регистр) — подсказка разместить в регистре.

Базовые типы:

Тип

Описание

Размер

trit

Одиночный трит (–1, 0, +1)

1 трит

tryte / tint

Целое (синонимы)

9 тритов (1 трайт)

tlong

Длинное целое

18 тритов (2 трайта)

tlong long

Сверхдлинное целое

27 тритов (3 трайта)

tfloat

Вещественное

18 тритов (2 трайта)

tdouble

Вещественное двойной точности

36 тритов (4 трайта)

tril

Логический трит

1 трит

void

Пустой тип

Производные типы: указатели, массивы, функции, структуры, объединения, перечисления.

Квалификаторы: const (конст) — значение не может быть изменено; volatile (изменч) — значение может изменяться внешними факторами.

А.5. Объекты и Lvalues

Объект — область памяти, содержимое которой можно интерпретировать как значение определённого типа.

Lvalue — выражение, обозначающее объект (имеет адрес). К lvalue относятся: имена переменных, элементы массивов (a[i]), поля структур (s.m, p->m), разыменованные указатели (*p).

Модифицируемое lvalue — lvalue, не имеющее квалификатора const и не являющееся массивом. Только модифицируемое lvalue может стоять слева от присваивания.

А.6. Преобразования

Неявные преобразования:

  1. Повышение trit: trit автоматически повышается до tint в выражениях.

  2. Целочисленные преобразования: меньший целый тип повышается до большего: tinttlongtlong long.

  3. Целые → вещественные: целые преобразуются в tfloat или tdouble при смешанных операциях.

  4. Вещественные: tfloat повышается до tdouble при необходимости.

  5. triltrit: взаимно обратимые неявные преобразования.

Явные преобразования (приведение):

(tfloat) a    // tint → tfloat
(tint) 3.14   // tdouble → tint (отбрасывание дробной части)

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

Преобразование вещественного в целый: отбрасывание дробной части (округление к нулю).

А.7. Выражения

Приоритет операций (от высшего к низшему):

Приоритет

Операторы

Ассоциативность

1

++ -- (постфиксные) () [] . ->

2

++ -- (префиксные) + - ! ~ * & sizeof

3

* / %

4

+ -

5

<< >>

6

< > <= >=

7

== !=

8

& (потритовый минимум)

9

^ (потритовая сумма)

10

| (потритовый максимум)

11

&&

12

||

13

?? :? :! (тринарный)

14

= += -= *= /= %= <<= >>= &= ^= |=

А.7.1. Первичные выражения: идентификатор, константа, строковый литерал, ( выражение ).

А.7.2. Постфиксные операторы:

  • expr[expr] — индексация массива (эквивалентно *(expr + expr))

  • expr(args) — вызов функции

  • expr.member — доступ к полю структуры/объединения

  • expr->member — доступ к полю через указатель (эквивалентно (*expr).member)

  • expr++, expr-- — постфиксный инкремент/декремент

А.7.3. Унарные операторы:

  • ++expr, --expr — префиксный инкремент/декремент

  • +expr — унарный плюс

  • -expr — арифметическое отрицание

  • !expr — логическое отрицание (меняет + на -, - на +, 0 остаётся 0; возвращает tril)

  • ~expr — потритовое отрицание (каждый трит меняет знак)

  • *expr — разыменование указателя

  • &expr — взятие адреса

  • sizeof expr или sizeof(type) — размер в трайтах

А.7.4. Мультипликативные: *, /, %. Деление округляется к –∞.

А.7.5. Аддитивные: +, -.

А.7.6. Сдвиги: << — умножение на 3ⁿ; >> — арифметический сдвиг вправо (деление на 3ⁿ с округлением вниз).

А.7.7. Отношения: <, >, <=, >= — возвращают tril.

А.7.8. Равенства: ==, != — возвращают tril.

А.7.9. Потритовые операторы:

  • & — потритовый минимум

  • ^ — потритовая сумма по модулю 3 без переноса

  • | — потритовый максимум

А.7.10. Логические операторы:

  • && — трёхзначное И (минимум)

  • || — трёхзначное ИЛИ (максимум)

  • Оба операнда вычисляются всегда.

    А.7.11. Тринарный условный оператор:

    условие ?? выраж1 :? выраж2 :! выраж3
    

    Если условие true → выраж1, maybe → выраж2, false → выраж3.

    А.7.12. Присваивание: =, +=, -=, *=, /=, %=, <<=, >>=, &=, |=, ^=.

    А.7.13. Константные выражения: могут быть вычислены на этапе компиляции. Используются в case, размерах массивов, инициализаторах статических переменных.

    А.8. Объявления

    Объявление имеет вид:

    declaration-specifiers init-declarator-list ;
    

    Спецификаторы класса памяти: auto, extern, static, register, typedef. Не более одного класса памяти в объявлении.

    Спецификаторы типа: void, tint/tryte, tlong, tlong long, trit, tril, tfloat, tdouble, signed, unsigned, struct/union-спецификатор, enum-спецификатор, typedef-имя.

    Квалификаторы: const, volatile.

    Объявители: идентификатор с возможными модификаторами:

    • * — указатель

    • [n] — массив

    • (params) — функция

    Инициализация:

    • Скаляры: = выражение

    • Агрегаты: = { список }

    • Строки: = "строка"

    Имена типов: синтаксис объявителя без идентификатора, используется в приведениях и sizeof.

    typedef: создаёт синоним типа. Не вводит новый тип, только псевдоним.

    Эквивалентность типов: структурная — два типа эквивалентны, если они имеют одинаковую структуру (для typedef — по имени).

    А.9. Инструкции

    Помеченные инструкции:

    case константа : инструкция
    default : инструкция
    метка : инструкция
    

    Инструкция-выражение: выражение ;

    Составная инструкция (блок): { объявления? инструкции? }

    Инструкция выбора:

    if (выражение) инструкция
    [maybe инструкция]
    [else инструкция]
    

    Ветви maybe и else опциональны и могут следовать в любом порядке.

    switch (выражение) инструкция
    

    Инструкции цикла:

    while (выражение) инструкция
    do инструкция while (выражение) ;
    for (выражение? ; выражение? ; выражение?) инструкция
    

    Инструкции перехода:

    break ;
    continue ;
    return выражение? ;
    goto идентификатор ;
    

    А.10. Внешние объявления

    Единица трансляции состоит из последовательности внешних определений:

    translation-unit = { external-definition }
    external-definition = function-definition | declaration
    

    Определение функции:

    declaration-specifiers declarator declaration-list? compound-statement
    

    Если тип возврата не указан, по умолчанию tint.

    Внешние объявления переменных: объявления на верхнем уровне с классом памяти extern или без класса памяти.

    А.11. Область видимости и связи

    Область видимости (scope):

    • Файловая (глобальная): от точки объявления до конца файла.

    • Блочная (локальная): от точки объявления до конца блока.

    • Прототипная: в списке параметров прототипа функции.

    • Функциональная: для меток goto.

    Связи (linkage):

    • Внешняя (extern): идентификатор может быть доступен из других файлов.

    • Внутренняя (static): идентификатор доступен только в пределах одного файла.

    • Пустая: локальные переменные, параметры функций, typedef.

    А.12. Препроцессирование

    Препроцессор T обрабатывает директивы, начинающиеся с # в первой позиции строки. Все директивы имеют русские эквиваленты.

    Директивы:

    • #include <файл> / #включить <файл> — включение системного заголовка

    • #include "файл" / #включить "файл" — включение пользовательского заголовка

    • #define имя текст / #определить имя текст — определение макроса без параметров

    • #define имя(парам) текст / #определить имя(парам) текст — определение макроса с параметрами

    • #undef имя / #отменить имя — отмена определения макроса

    • #if выражение / #если выражение — условная компиляция

    • #ifdef имя / #еслиопределено имя — проверка определённости макроса

    • #ifndef имя / #еслинеопределено имя — проверка неопределённости макроса

    • #else / #иначе — альтернативная ветвь

    • #elif выражение / #илиесли выражение — цепочка условий

    • #endif / #кончить — завершение условной компиляции

    • #error сообщение / #ошибка сообщение — генерация ошибки

    • #line число "файл" / #строка число "файл" — изменение нумерации строк

    Операторы макросов:

    • # — строкизация параметра

    • ## — склейка токенов

    Предопределённые макросы:

    • __T_LINE__ — номер текущей строки

    • __T_FILE__ — имя текущего файла

    • __T_VERSION__ — версия компилятора T

    В выражениях #if константа true равна 1, false равна 0. Константа maybe не разрешена — требуется явное приведение к целому.

    А.13. Грамматика

    Ниже приведена полная EBNF-грамматика языка T.

    (* ============================================================
       Полная EBNF-грамматика языка T
       ============================================================ *)
    
    (* --- Лексическая структура --- *)
    trit_digit         = "-" | "0" | "+" .
    
    identifier         = ( letter | "_" ) { letter | digit | "_" } .
    letter             = latin_letter | cyrillic_letter .
    latin_letter       = "A".."Z" | "a".."z" .
    cyrillic_letter    = "А".."Я" | "а".."я" | "Ё" | "ё" .
    digit              = "0".."9" .
    
    decimal_suffix     = "t" | "tl" | "tll" .
    decimal_literal    = [ "+" | "-" ] digit { digit } decimal_suffix .
    balanced_prefix    = "0t" .
    balanced_digits    = trit_digit { trit_digit } [ "_" trit_digit ] .
    balanced_literal   = balanced_prefix balanced_digits .
    tryx_prefix        = "0y" .
    tryx_digit         = digit | "A".."Q" | "a".."q" .
    tryx_literal       = tryx_prefix tryx_digit { tryx_digit } .
    integer_literal    = decimal_literal | balanced_literal | tryx_literal .
    
    float_suffix       = "f" | "d" .
    decimal_float      = [ "+" | "-" ] digit { digit } "." digit { digit }
                         [ "e" [ "+" | "-" ] digit { digit } ] [ float_suffix ] .
    balanced_float     = balanced_prefix mantissa_part "e" exponent_part float_suffix .
    mantissa_part      = trit_digit { trit_digit } [ "_" trit_digit ]
                         "." trit_digit { trit_digit } .
    exponent_part      = trit_digit { trit_digit } .
    float_literal      = decimal_float | balanced_float .
    
    char_literal       = "'" ( trit_digit | any_character ) "'" .
    string_literal     = '"' { any_character } '"' .
    
    true_const         = "true" | "истина" .
    false_const        = "false" | "ложь" .
    maybe_const        = "maybe" | "может" .
    constant           = integer_literal | float_literal | char_literal
                       | string_literal | true_const | false_const | maybe_const .
    
    (* --- Выражения --- *)
    primary_expr       = identifier | constant | "(" expression ")" .
    postfix_expr       = primary_expr
                       | postfix_expr "[" expression "]"
                       | postfix_expr "(" [ argument_list ] ")"
                       | postfix_expr "." identifier
                       | postfix_expr "->" identifier
                       | postfix_expr "++"
                       | postfix_expr "--" .
    argument_list      = expression { "," expression } .
    
    unary_expr         = postfix_expr
                       | "++" unary_expr
                       | "--" unary_expr
                       | unary_operator unary_expr .
    unary_operator     = "+" | "-" | "!" | "~" | "*" | "&"
                       | "sizeof" | "размер" .
    
    multiplicative_expr = unary_expr { ( "*" | "/" | "%" ) unary_expr } .
    additive_expr      = multiplicative_expr { ( "+" | "-" ) multiplicative_expr } .
    shift_expr         = additive_expr { ( "<<" | ">>" ) additive_expr } .
    relational_expr    = shift_expr { ( "<" | ">" | "<=" | ">=" ) shift_expr } .
    equality_expr      = relational_expr { ( "==" | "!=" ) relational_expr } .
    
    bitwise_and_expr   = equality_expr { "&" equality_expr } .
    bitwise_xor_expr   = bitwise_and_expr { "^" bitwise_and_expr } .
    bitwise_or_expr    = bitwise_xor_expr { "|" bitwise_xor_expr } .
    logical_and_expr   = bitwise_or_expr { "&&" bitwise_or_expr } .
    logical_or_expr    = logical_and_expr { "||" logical_and_expr } .
    
    ternary_expr       = logical_or_expr
                         "??" expression ":?" expression ":!" expression .
    assignment_expr    = ternary_expr
                       | unary_expr assignment_operator assignment_expr .
    assignment_operator = "=" | "+=" | "-=" | "*=" | "/=" | "%="
                         | "<<=" | ">>=" | "&=" | "|=" | "^=" .
    expression         = assignment_expr .
    
    (* --- Объявления --- *)
    void_type          = "void" | "пусто" .
    tint_type          = "tint" | "тцел" .
    tlong_type         = "tlong" | "тдлин" .
    tlong_long_type    = "tlong" "long" | "тдлиндлин" .
    tryte_type         = "tryte" | "трайт" .
    trit_type          = "trit" | "трит" .
    tril_type          = "tril" | "трил" .
    tfloat_type        = "tfloat" | "твещ" .
    tdouble_type       = "tdouble" | "тдвойн" .
    signed_spec        = "signed" | "знак" .
    unsigned_spec      = "unsigned" | "беззнак" .
    
    type_specifier     = void_type | tint_type | tlong_type | tlong_long_type
                       | tryte_type | trit_type | tril_type
                       | tfloat_type | tdouble_type
                       | signed_spec | unsigned_spec
                       | struct_or_union_specifier | enum_specifier
                       | typedef_name .
    
    struct_or_union    = "struct" | "структура" | "union" | "объединение" .
    struct_or_union_specifier = struct_or_union [ identifier ] "{" { struct_declaration } "}"
                             | struct_or_union identifier .
    struct_declaration = type_specifier struct_declarator_list ";" .
    struct_declarator_list = struct_declarator { "," struct_declarator } .
    struct_declarator  = declarator | [ declarator ] ":" expression .
    
    enum_kw            = "enum" | "перечисление" .
    enum_specifier     = enum_kw [ identifier ] "{" enumerator_list "}"
                       | enum_kw identifier .
    enumerator_list    = enumerator { "," enumerator } .
    enumerator         = identifier [ "=" expression ] .
    
    type_qualifier     = "const" | "конст" | "volatile" | "изменч" .
    
    declaration_specifiers = ( type_specifier | type_qualifier )
                             { type_specifier | type_qualifier } .
    declarator         = pointer_decl direct_declarator | direct_declarator .
    direct_declarator  = identifier
                       | "(" declarator ")"
                       | direct_declarator "[" [ expression ] "]"
                       | direct_declarator "(" parameter_list ")"
                       | direct_declarator "(" ")" .
    pointer_decl       = "*" [ type_qualifier { type_qualifier } ] [ pointer_decl ] .
    parameter_list     = parameter_declaration { "," parameter_declaration } .
    parameter_declaration = declaration_specifiers [ declarator | abstract_declarator ] .
    abstract_declarator = pointer_decl [ direct_abstract_declarator ]
                        | direct_abstract_declarator .
    direct_abstract_declarator = "(" abstract_declarator ")"
                               | "[" [ expression "]"
                               | "(" [ parameter_list ] ")" .
    initializer        = expression | "{" initializer_list [ "," ] "}" .
    initializer_list   = initializer { "," initializer } .
    declaration        = declaration_specifiers [ init_declarator_list ] ";" .
    init_declarator_list = init_declarator { "," init_declarator } .
    init_declarator    = declarator [ "=" initializer ] .
    
    (* --- Операторы --- *)
    if_kw              = "if" | "если" .
    maybe_kw           = "maybe" | "может" .
    else_kw            = "else" | "иначе" .
    switch_kw          = "switch" | "выбор" .
    case_kw            = "case" | "случай" .
    default_kw         = "default" | "умолчание" .
    while_kw           = "while" | "пока" .
    do_kw              = "do" | "делать" .
    for_kw             = "for" | "для" .
    continue_kw        = "continue" | "продолжить" .
    break_kw           = "break" | "прервать" .
    return_kw          = "return" | "возврат" .
    goto_kw            = "goto" | "перейти" .
    
    statement          = expression_statement
                       | compound_statement
                       | selection_statement
                       | switch_statement
                       | labeled_statement
                       | iteration_statement
                       | jump_statement .
    expression_statement = [ expression ] ";" .
    compound_statement   = "{" { declaration | statement } "}" .
    selection_statement  = if_kw "(" expression ")" statement
                           ( [ maybe_kw statement ] [ else_kw statement ]
                           | [ else_kw statement ] [ maybe_kw statement ] ) .
    switch_statement     = switch_kw "(" expression ")" statement .
    case_label           = case_kw expression ":" .
    default_label        = default_kw ":" .
    labeled_statement    = case_label statement | default_label statement .
    iteration_statement  = while_kw "(" expression ")" statement
                         | do_kw statement while_kw "(" expression ")" ";"
                         | for_kw "(" [ expression ] ";" [ expression ] ";"
                                   [ expression ] ")" statement .
    jump_statement       = continue_kw ";"
                         | break_kw ";"
                         | return_kw [ expression ] ";"
                         | goto_kw identifier ";" .
    
    (* --- Внешние определения --- *)
    extern_kw          = "extern" | "внеш" .
    static_kw          = "static" | "статич" .
    auto_kw            = "auto" | "авто" .
    register_kw        = "register" | "регистр" .
    inline_kw          = "inline" | "встроен" .
    typedef_kw         = "typedef" | "типрег" .
    
    translation_unit   = { external_definition } .
    external_definition = function_definition | declaration .
    function_definition  = declaration_specifiers declarator
                          [ declaration_list ] compound_statement .
    declaration_list    = { declaration } .
    

    B. Стандартная библиотека

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

    B.1. Ввод-вывод:

    Заголовочный файл <tio.h> объявляет функции и типы для ввода-вывода.

    Типы:

    • tFILE — структура для управления потоком ввода-вывода (аналог FILE).

    Функции:

    tFILE *tfopen(const tryte *path, const tryte *mode);
    

    Открывает файл. path — путь к файлу, mode — режим: "r" (чтение), "w" (запись), "a" (добавление), "r+", "w+", "a+". Возвращает указатель на tFILE или 0t при ошибке.

    tint tfclose(tFILE *stream);
    

    Закрывает файл. Возвращает 0t при успехе или -1t при ошибке.

    tint tgetc(tFILE *stream);
    

    Читает один символ из потока. Возвращает прочитанный символ (тип tint) или 0t при достижении конца файла.

    tint tputc(tint c, tFILE *stream);
    

    Записывает символ c в поток. Возвращает записанный символ или -1t при ошибке.

    tint tprintf(const tryte *format, ...);
    

    Форматный вывод. Спецификаторы: %T (tint), %L (tlong), %LL (tlong long), %B (сбалансированный), %F (tfloat), %D (tdouble), %S (строка), %C (символ), %R (tril).

    tint tscanf(const tryte *format, ...);
    

    Форматный ввод. Спецификаторы те же, что и для tprintf.

    void printbal(tryte x);
    

    Выводит целое число в сбалансированной троичной форме (+, 0, -).

    void printtryte(tryte x);
    

    Выводит целое число в десятичном виде.

    void printtril(tril b);
    

    Выводит логическое значение: true, maybe или false (или русские эквиваленты).

    void printfloat(tfloat f);
    

    Выводит tfloat в десятичном виде.

    void printdouble(tdouble d);
    

    Выводит tdouble в десятичном виде.

    tryte scant();
    

    Читает десятичное число со стандартного ввода. Возвращает значение типа tryte.

    tfloat scanf();
    

    Читает вещественное число типа tfloat со стандартного ввода.

    tdouble scand();
    

    Читает вещественное число типа tdouble со стандартного ввода.

    Стандартные потоки:

    • tstdin — стандартный ввод (дескриптор 0t)

    • tstdout — стандартный вывод (дескриптор 1t)

    • tstderr — стандартный вывод ошибок (дескриптор 2t)

    B.2. Проверки класса символа:

    Заголовочный файл <tctype.h> объявляет функции для классификации и преобразования символов.

    tint tisdigit(tryte c);
    

    Проверяет, является ли символ десятичной цифрой (09).

    tint tisspace(tryte c);
    

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

    tint tistrit(tryte c);
    

    Проверяет, является ли символ троичной цифрой (-, 0, +).

    tint tisalpha(tryte c);
    

    Проверяет, является ли символ буквой (латинской или кириллической).

    tint tisalnum(tryte c);
    

    Проверяет, является ли символ буквой или десятичной цифрой.

    tint tisupper(tryte c);
    

    Проверяет, является ли символ заглавной буквой.

    tint tislower(tryte c);
    

    Проверяет, является ли символ строчной буквой.

    tryte toupper(tryte c);
    

    Преобразует символ в заглавный (если применимо).

    tryte tolower(tryte c);
    

    Преобразует символ в строчный (если применимо).

    B.3. Функции, оперирующие со строками:

    Заголовочный файл <tstring.h> объявляет функции для работы со строками (массивами tryte, завершающимися 0t).

    tint tstrlen(const tryte *s);
    

    Возвращает длину строки (количество символов до завершающего 0t).

    tryte *tstrcpy(tryte *dst, const tryte *src);
    

    Копирует строку src в dst, включая завершающий 0t. Возвращает dst.

    tryte *tstrcat(tryte *dst, const tryte *src);
    

    Дописывает строку src в конец dst. Возвращает dst.

    tint tstrcmp(const tryte *s1, const tryte *s2);
    

    Лексикографическое сравнение строк. Возвращает:

    • -1t — если s1 < s2

    • 0t — если s1 == s2

    • +1t — если s1 > s2

    Сравнение учитывает троичный порядок: - < 0 < +.

    tryte *tstrchr(const tryte *s, tryte c);
    

    Ищет первое вхождение символа c в строке s. Возвращает указатель на найденный символ или 0t, если символ не найден.

    B.4. Математические функции:

    Заголовочный файл <tmath.h> объявляет математические функции.

    tdouble tsin(tdouble x);
    

    Синус угла x (в радианах).

    tdouble tcos(tdouble x);
    

    Косинус угла x (в радианах).

    tdouble tsqrt(tdouble x);
    

    Квадратный корень из x. Для отрицательных аргументов возвращает NaN.

    tdouble tfloor(tdouble x);
    

    Округление вниз (к –∞).

    tdouble tceil(tdouble x);
    

    Округление вверх (к +∞).

    tint tabs(tint x);
    

    Абсолютное значение для целого числа.

    tfloat tfabs(tfloat x);
    

    Абсолютное значение для вещественного числа.

    tint tmin(tint x, tint y);
    

    Минимум двух целых чисел.

    tint tmax(tint x, tint y);
    

    Максимум двух целых чисел.

    tfloat tfmin(tfloat x, tfloat y);
    

    Минимум двух вещественных чисел.

    tfloat tfmax(tfloat x, tfloat y);
    

    Максимум двух вещественных чисел.

    B.5. Функции общего назначения:

    Заголовочный файл <tstdlib.h> объявляет функции для управления памятью, выполнения программ и генерации случайных чисел.

    void *tmalloc(tint n);
    

    Выделяет n трайтов памяти. Возвращает указатель на выделенную память или 0t при ошибке.

    void tfree(void *ptr);
    

    Освобождает память, ранее выделенную tmalloc, trealloc или tcalloc.

    void *trealloc(void *ptr, tint n);
    

    Изменяет размер блока памяти до n трайтов. Содержимое сохраняется до меньшего из размеров. Возвращает указатель на новый блок или 0t при ошибке.

    void *tcalloc(tint n, tint size);
    

    Выделяет память для массива из n элементов по size трайтов каждый. Память обнуляется. Возвращает указатель или 0t при ошибке.

    void texit(tint status);
    

    Завершает программу с кодом возврата status. Выполняет очистку (закрытие файлов и т.д.).

    tint trand(void);
    

    Возвращает псевдослучайное число типа tint в диапазоне от –9841 до +9841.

    tint tsystem(const tryte *command);
    

    Выполняет команду операционной системы. Возвращает код завершения команды.

    B.6. Диагностика:

    Заголовочный файл <tassert.h> определяет макрос tassert.

    void tassert(tint expression);
    

    Если expression равно false (0), макрос выводит диагностическое сообщение (имя файла, номер строки, текст выражения) и вызывает texit. Если expression истинно, макрос не выполняет никаких действий.

    Макрос отключается, если перед включением <tassert.h> определён макрос TNDEBUG:

    #define TNDEBUG
    #include <tassert.h>
    

    B.7. Списки аргументов переменной длины:

    Заголовочный файл <tstdarg.h> предоставляет средства для работы с функциями, принимающими переменное число аргументов.

    Типы:

    • tva_list — тип для хранения информации о списке аргументов.

    Макросы:

    void tva_start(tva_list ap, last_named);
    

    Инициализирует ap для обхода аргументов. last_named — последний именованный параметр функции.

    type tva_arg(tva_list ap, type);
    

    Возвращает очередной аргумент типа type и продвигает указатель.

    void tva_end(tva_list ap);
    

    Завершает обход списка аргументов.

    B.8. Дальние переходы:

    Заголовочный файл <tsetjmp.h> предоставляет механизм нелокальных переходов.

    Типы:

    • tjmp_buf — тип для хранения состояния выполнения.

    Функции:

    tint tsetjmp(tjmp_buf env);
    

    Сохраняет текущее состояние выполнения в env. Возвращает 0t при прямом вызове и ненулевое значение при возврате из tlongjmp.

    void tlongjmp(tjmp_buf env, tint val);
    

    Восстанавливает состояние, сохранённое в env. Управление передаётся так, как если бы tsetjmp вернула val.

    B.9. Сигналы:

    Заголовочный файл <tsignal.h> предоставляет средства обработки сигналов (прерываний).

    Типы:

    • tsig_atomic_t — целый тип, который может быть атомарно прочитан или записан в обработчике сигнала.

    • void (*tsighandler_t)(tint) — тип указателя на функцию-обработчик сигнала.

    Константы:

    • TSIG_ERR — код ошибки.

    • TSIG_DFL — обработка по умолчанию.

    • TSIG_IGN — игнорирование сигнала.

    Сигналы:

    • TSIGABRT — аварийное завершение.

    • TSIGFPE — ошибка плавающей арифметики.

    • TSIGINT — прерывание (Ctrl+C).

    • TSIGSEGV — ошибка доступа к памяти.

    • TSIGTERM — запрос завершения.

    Функции:

    tsighandler_t tsignal(tint sig, tsighandler_t handler);
    

    Устанавливает обработчик сигнала sig. Возвращает предыдущий обработчик или TSIG_ERR при ошибке.

    int traise(tint sig);
    

    Генерирует сигнал sig. Возвращает 0t при успехе.

    B.10. Функции даты и времени:

    Заголовочный файл <ttime.h> объявляет функции для работы с датой и временем.

    Типы:

    • ttime_t — целый тип (обычно tlong long) для хранения времени.

    • tclock_t — целый тип для хранения процессорного времени.

    Функции:

    ttime_t ttime(ttime_t *t);
    

    Возвращает текущее календарное время. Если t не 0t, значение также сохраняется по указателю.

    tclock_t tclock(void);
    

    Возвращает процессорное время, затраченное программой.

    tdouble tdifftime(ttime_t t1, ttime_t t0);
    

    Возвращает разницу t1 - t0 в секундах как tdouble.

    B.11. Зависящие от реализации пределы: и

    Заголовочный файл <tlimits.h> определяет макросы с пределами целых типов:

    Макрос

    Значение

    Описание

    TINT_MIN

    –9 841

    Минимальное значение tint

    TINT_MAX

    +9 841

    Максимальное значение tint

    TLONG_MIN

    –193 710 244

    Минимальное значение tlong

    TLONG_MAX

    +193 710 244

    Максимальное значение tlong

    TLLONG_MIN

    –3 812 798 742 493

    Минимальное значение tlong long

    TLLONG_MAX

    +3 812 798 742 493

    Максимальное значение tlong long

    Заголовочный файл <tfloat.h> определяет макросы с параметрами вещественных типов:

    Макрос

    Описание

    TFLT_MANT_DIG

    Количество тритов мантиссы tfloat (12)

    TFLT_EPSILON

    Наименьшее число, такое что 1.0 + epsilon != 1.0

    TFLT_MIN

    Минимальное положительное нормализованное число

    TFLT_MAX

    Максимальное конечное число

    TDBL_MANT_DIG

    Количество тритов мантиссы tdouble (28)

    TDBL_EPSILON

    Машинный эпсилон для tdouble

    TDBL_MIN

    Минимальное положительное нормализованное число

    TDBL_MAX

    Максимальное конечное число

    C. Перечень изменений

    По сравнению с классическим языком C, язык T вносит следующие ключевые изменения:

    1. Троичная основа. Все данные хранятся в сбалансированной троичной системе счисления. Биты заменены тритами, байты — трайтами (9 тритов).

    2. Типы данных. Базовые типы: trit, tryte (синоним tint), tlong (18 тритов), tlong long (27 тритов), tfloat (18 тритов), tdouble (36 тритов), tril (логический трит). Типы short, char, int, long в их классическом виде отсутствуют.

    3. Логический тип tril. Трёхзначная логика: true (+1), false (–1), maybe (0). Логические операции &&, || определены как min и max, оба операнда вычисляются всегда.

    4. Тринарный условный оператор. ?? :? :! позволяет выбрать одну из трёх ветвей.

    5. Условный оператор if. К традиционным if и else добавлена опциональная ветвь maybe, идущая в любом порядке. Если maybe отсутствует, соответствующее состояние игнорируется.

    6. Потритовые операторы. &, |, ^ теперь выполняют троичные операции минимума, максимума и суммы по модулю 3 без переноса.

    7. Сдвиги. << и >> — умножение и деление на 3ⁿ.

    8. Литералы. Десятичные литералы требуют суффикса размера (t, tl, tll). Введены троичные сбалансированные литералы с префиксом 0t и 27-ричные с префиксом 0y. Вещественные литералы имеют сбалансированную форму записи порядка и мантиссы.

    9. Русские ключевые слова. Все ключевые слова имеют русские синонимы (например, если, иначе, может, для, пока, возврат), что позволяет писать программы на русском без макросов.

    10. Стандартная библиотека. Адаптирована для троичных типов: <tio.h>, <tstring.h>, <tmath.h>, <tstdlib.h> и т.д. Функции ввода-вывода работают с троичными представлениями чисел и строк.

    11. Препроцессор. В целом совместим с C, но #if и #ifdef работают с целыми; константа maybe не разрешена без явного приведения.

    12. Отсутствие беззнаковых типов. Только сбалансированное представление, нет unsigned.

    13. Адресация памяти. Минимальная единица — трайт (9 тритов). Указатели инкрементируются на размер объекта в трайтах. sizeof возвращает размер в трайтах.

    14. Структуры и объединения. Поддерживают тритовые поля (упаковка тритов внутри трайта).

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