        Компилятор языка программирования Oberon-07/16 для x86_64
                Windows/Linux
------------------------------------------------------------------------------

        Параметры командной строки

  Вход - текстовые файлы модулей с расширением ".ob07", кодировка ANSI или
UTF-8 с BOM-сигнатурой.
  Выход - испоняемый файл формата PE32+ или ELF64.
  Параметры:
  1) имя главного модуля
  2) тип приложения
      "win64con" - Windows64 console
      "win64gui" - Windows64 GUI
      "win64dll" - Windows64 DLL
      "linux64exe" - Linux ELF64-EXEC
      "linux64so" - Linux ELF64-SO

  3) необязательные параметры-ключи
      -out <file_name> имя результирующего файла; по умолчанию,
      совпадает с именем главного модуля, но с другим расширением
      (соответствует типу исполняемого файла)
      -stk <size> размер стэка в мегабайтах (по умолчанию 2 Мб,
       допустимо от 1 до 32 Мб)
      -nochk <"ptibcwra"> отключить проверки при выполнении
      -lower разрешить ключевые слова и встроенные идентификаторы в
      нижнем регистре
      -def <имя> задать символ условной компиляции

      параметр -nochk задается в виде строки из символов:
      "p" - указатели
      "t" - типы
      "i" - индексы
      "b" - неявное приведение INTEGER к BYTE
      "c" - диапазон аргумента функции CHR
      "w" - диапазон аргумента функции WCHR
      "r" - эквивалентно "bcw"
      "a" - все проверки

      Порядок символов может быть любым. Наличие в строке того или иного
      символа отключает соответствующую проверку.

      Например: -nochk it - отключить проверку индексов и охрану типа.
      -nochk a - отключить все отключаемые проверки.

  Например:

  Compiler.exe "C:\example.ob07" win64con -out "C:\example.exe" -stk 1
  Compiler.exe "C:\example.ob07" win64dll -out "C:\example.dll" -nochk pti
  Compiler "source/Compiler.ob07" linux64exe -out "source/Compiler" -nochk a

  В случае успешной компиляции, компилятор передает код завершения 0, иначе 1.

------------------------------------------------------------------------------
        Отличия от оригинала

1.      Расширен псевдомодуль SYSTEM
2.      В идентификаторах допускается символ "_"
3.      Добавлены системные флаги
4.      Усовершенствован оператор CASE (добавлены константные выражения в
        метках вариантов и необязательная ветка ELSE)
5.      Расширен набор стандартных процедур
6.      Семантика охраны/проверки типа уточнена для нулевого указателя
7.      Добавлены однострочные комментарии (начинаются с пары символов "//")
8.      Разрешено наследование от типа-указателя
9.      Добавлен синтаксис для импорта процедур из внешних библиотек
10.     "Строки" можно заключать также в одиночные кавычки: 'строка'
11.     Добавлен тип WCHAR
12.     Добавлена операция конкатенации строковых и символьных констант
13.     Возможен импорт модулей с указанием пути и имени файла
14.     Добавлен специальный синтаксис для условной компиляции (см. CC.txt)
15.     Имя процедуры в конце объявления (после END) необязательно

------------------------------------------------------------------------------
        Особенности реализации

1.      Основные типы

          Тип              Диапазон значений                      Размер, байт

        INTEGER       -9223372036854775808 .. 9223372036854775807       8
        REAL          4.94E-324 .. 1.70E+308                            8
        CHAR          символ ASCII (0X .. 0FFX)                         1
        BOOLEAN       FALSE, TRUE                                       1
        SET           множество из целых чисел {0 .. 63}                8
        BYTE          0 .. 255                                          1
        WCHAR         символ юникода (0X .. 0FFFFX)                     2

2.      Максимальная длина идентификаторов - 255 символов
3.      Максимальная длина строковых констант - 511 символов (UTF-8)
4.      Максимальная размерность открытых массивов - 5
5.      Процедура NEW заполняет нулями выделенный блок памяти
6.      Глобальные и локальные переменные инициализируются нулями
7.      В отличие от многих Oberon-реализаций, сборщик мусора и динамическая
        модульность отсутствуют
8.      Тип BYTE в выражениях всегда приводится к INTEGER
9.      Контроль переполнения значений выражений не производится
10.     Ошибки времени выполнения:

 1       ASSERT(x), при x = FALSE
 2       разыменование нулевого указателя
 3       целочисленное деление на неположительное число
 4       вызов процедуры через процедурную переменную с нулевым значением
 5       ошибка охраны типа
 6       нарушение границ массива
 7       непредусмотренное значение выражения в операторе CASE
 8       ошибка копирования массивов v := x, если LEN(v) < LEN(x)
 9       CHR(x), если (x < 0) OR (x > 255)
10       WCHR(x), если (x < 0) OR (x > 65535)
11       неявное приведение x:INTEGER к v:BYTE, если (x < 0) OR (x > 255)

------------------------------------------------------------------------------
        Псевдомодуль SYSTEM

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

        PROCEDURE ADR(v: любой тип): INTEGER
                v - переменная или процедура;
                возвращает адрес v

        PROCEDURE SADR(x: строковая константа (CHAR UTF-8)): INTEGER
                возвращает адрес x

        PROCEDURE WSADR(x: строковая константа (WCHAR)): INTEGER
                возвращает адрес x

        PROCEDURE SIZE(T): INTEGER
                возвращает размер типа T

        PROCEDURE TYPEID(T): INTEGER
                T - тип-запись или тип-указатель,
                возвращает номер типа в таблице типов-записей

        PROCEDURE INF(): REAL
                возвращает специальное вещественное значение "бесконечность"

        PROCEDURE MOVE(Source, Dest, n: INTEGER)
                Копирует n байт памяти из Source в Dest,
                области Source и Dest не могут перекрываться

        PROCEDURE GET(a: INTEGER;
                VAR v: любой основной тип, PROCEDURE, POINTER)
                v := Память[a]

        PROCEDURE GET8(a: INTEGER;
                       VAR x: INTEGER, SET, BYTE, CHAR, WCHAR, SYSTEM.CARD32)
                Эквивалентно
                SYSTEM.MOVE(a, SYSTEM.ADR(x), 1)

        PROCEDURE GET16(a: INTEGER;
                        VAR x: INTEGER, SET, WCHAR, SYSTEM.CARD32)
                Эквивалентно
                SYSTEM.MOVE(a, SYSTEM.ADR(x), 2)

        PROCEDURE GET32(a: INTEGER; VAR x: INTEGER, SET, SYSTEM.CARD32)
                Эквивалентно
                SYSTEM.MOVE(a, SYSTEM.ADR(x), 4)

        PROCEDURE PUT(a: INTEGER; x: любой основной тип, PROCEDURE, POINTER)
                Память[a] := x;
                Если x: BYTE или x: WCHAR, то значение x будет расширено
                до 64 бит, для записи байтов использовать SYSTEM.PUT8,
                для WCHAR -- SYSTEM.PUT16

        PROCEDURE PUT8(a: INTEGER;
                       x: INTEGER, SET, BYTE, CHAR, WCHAR, SYSTEM.CARD32)
                Память[a] := младшие 8 бит (x)

        PROCEDURE PUT16(a: INTEGER;
                        x: INTEGER, SET, BYTE, CHAR, WCHAR, SYSTEM.CARD32)
                Память[a] := младшие 16 бит (x)

        PROCEDURE PUT32(a: INTEGER;
                        x: INTEGER, SET, BYTE, CHAR, WCHAR, SYSTEM.CARD32)
                Память[a] := младшие 32 бит (x)

        PROCEDURE COPY(VAR Source: любой тип; VAR Dest: любой тип; n: INTEGER)
                Копирует n байт памяти из Source в Dest.
                Эквивалентно
                SYSTEM.MOVE(SYSTEM.ADR(Source), SYSTEM.ADR(Dest), n)

        PROCEDURE CODE(byte1, byte2,... : BYTE)
                Вставка машинного кода,
                byte1, byte2 ... - константы в диапазоне 0..255,
                например:

                SYSTEM.CODE(048H,08BH,045H,010H) (* mov rax,qword[rbp+16] *)

  Также, в модуле SYSTEM определен тип CARD32 (4 байта). Для типа CARD32 не
допускаются никакие явные операции, за исключением присваивания.

  Функции псевдомодуля SYSTEM нельзя использовать в константных выражениях.

------------------------------------------------------------------------------
        Системные флаги

  При объявлении процедурных типов и глобальных процедур, после ключевого
слова PROCEDURE может быть указан флаг соглашения о вызове:
[win64], [systemv], [windows], [linux], [oberon], [ccall].
Например:

        PROCEDURE [win64] MyProc (x, y, z: INTEGER): INTEGER;

  Флаг [windows] - синоним для [win64], [linux] - синоним для [systemv].
  Флаг [ccall] - синоним для [win64] или [systemv] (зависит от целевой ОС).
  Знак "-" после имени флага ([win64-], [linux-], ...) означает, что
результат процедуры можно игнорировать (не допускается для типа REAL).
  Если флаг не указан или указан флаг [oberon], то принимается внутреннее
соглашение о вызове. [win64] и [systemv] используются для связи с
операционной системой и внешними приложениями.

  При объявлении типов-записей, после ключевого слова RECORD может быть
указан флаг [noalign]. Флаг [noalign] означает отсутствие выравнивания полей
записи. Записи с системным флагом не могут иметь базовый тип и не могут быть
базовыми типами для других записей.
  Для использования системных флагов, требуется импортировать SYSTEM.

------------------------------------------------------------------------------
        Оператор CASE

  Синтаксис оператора CASE:

        CaseStatement =
                CASE Expression OF Case {"|" Case}
                        [ELSE StatementSequence] END.
        Case = [CaseLabelList ":" StatementSequence].
        CaseLabelList = CaseLabels {"," CaseLabels}.
        CaseLabels = ConstExpression [".." ConstExpression].

  Например:

        CASE x OF
        |-1:    DoSomething1
        | 1:    DoSomething2
        | 0:    DoSomething3
        ELSE
                DoSomething4
        END

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

------------------------------------------------------------------------------
        Тип WCHAR

  Тип WCHAR добавлен в язык для удобной поддежки юникода. Для типов WCHAR и
ARRAY OF WCHAR допускаются все те же операции, как для типов CHAR и
ARRAY OF CHAR, за исключением встроенной процедуры CHR, которая возвращает
только тип CHAR. Для получения значения типа WCHAR, следует использовать
процедуру WCHR вместо CHR. Для правильной работы с типом, необходимо сохранять
исходный код в кодировке UTF-8 с BOM.

------------------------------------------------------------------------------
        Конкатенация строковых и символьных констант

  Допускается конкатенация ("+") константных строк и символов типа CHAR:

  str = CHR(39) + "string" + CHR(39); (* str = "'string'" *)

  newline = 0DX + 0AX;

------------------------------------------------------------------------------
        Проверка и охрана типа нулевого указателя

  Оригинальное сообщение о языке не определяет поведение программы при
выполнении охраны p(T) и проверки типа p IS T при p = NIL. Во многих
Oberon-реализациях выполнение такой операции приводит к ошибке времени
выполнения. В данной реализации охрана типа нулевого указателя не приводит к
ошибке, а проверка типа дает результат FALSE. В ряде случаев это позволяет
значительно сократить частоту применения охраны типа.

------------------------------------------------------------------------------
        Дополнительные стандартные процедуры

        DISPOSE (VAR v: любой_указатель)
                Освобождает память, выделенную процедурой NEW для
                динамической переменной v^, и присваивает переменной v
                значение NIL.

        COPY (x: ARRAY OF CHAR/WCHAR; VAR v: ARRAY OF CHAR/WCHAR);
                v := x;
                Если LEN(v) < LEN(x), то строка x будет скопирована
                не полностью

        LSR (x, n: INTEGER): INTEGER
                Логический сдвиг x на n бит вправо.

        MIN (a, b: INTEGER): INTEGER
                Минимум из двух значений.

        MAX (a, b: INTEGER): INTEGER
                Максимум из двух значений.

        BITS (x: INTEGER): SET
                Интерпретирует x как значение типа SET.
                Выполняется на этапе компиляции.

        LENGTH (s: ARRAY OF CHAR/WCHAR): INTEGER
                Длина 0X-завершенной строки s, без учета символа 0X.
                Если символ 0X отсутствует, функция возвращает длину
                массива s. s не может быть константой.

        WCHR (n: INTEGER): WCHAR
                Преобразование типа, аналогично CHR(n: INTEGER): CHAR

------------------------------------------------------------------------------
        Импорт модулей с указанием пути и имени файла

Примеры:

    IMPORT Math IN "./lib/math.ob07"; (* относительно текущего модуля *)

    IMPORT M1 IN "C:\lib\math.ob07"; (* абсолютный путь *)

------------------------------------------------------------------------------
        Импортированные процедуры

  Синтаксис импорта:

  PROCEDURE [callconv, library, function] proc_name (FormalParam): Type;

  - callconv -- соглашение о вызове
  - library -- имя файла динамической библиотеки (строковая константа)
  - function -- имя импортируемой процедуры (строковая константа), если
  указана пустая строка, то имя процедуры = proc_name

  например:

  PROCEDURE [windows, "kernel32.dll", "ExitProcess"] exit (code: INTEGER);

  PROCEDURE [windows, "kernel32.dll", ""] GetTickCount (): INTEGER;

  В конце объявления может быть добавлено (необязательно) "END proc_name;"

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

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

  VAR
      ExitProcess: PROCEDURE [windows] (code: INTEGER);

  Для Linux, импортированные процедуры не реализованы.

------------------------------------------------------------------------------
        Скрытые параметры процедур

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

1.      Процедура имеет формальный параметр открытый массив:
                PROCEDURE Proc (x: ARRAY OF ARRAY OF REAL);
        Вызов транслируется так:
                Proc(LEN(x), LEN(x[0]), SYSTEM.ADR(x))
2.      Процедура имеет формальный параметр-переменную типа RECORD:
                PROCEDURE Proc (VAR x: Rec);
        Вызов транслируется так:
                Proc(SYSTEM.TYPEID(Rec), SYSTEM.ADR(x))

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

------------------------------------------------------------------------------
        Модуль RTL

  Все программы неявно используют модуль RTL. Компилятор транслирует
некоторые операции (проверка и охрана типа, сравнение строк, сообщения об
ошибках времени выполнения и др.) как вызовы процедур этого модуля. Не
следует вызывать эти процедуры явно.
  Сообщения об ошибках времени выполнения выводятся в диалоговых окнах
(Windows), в терминал (Linux).

------------------------------------------------------------------------------
        Модуль API

  Существуют несколько реализаций модуля API (для различных ОС).
  Как и модуль RTL, модуль API не предназначен для прямого использования.
Он обеспечивает связь RTL с ОС.

------------------------------------------------------------------------------
        Генерация исполняемых файлов DLL

  Разрешается экспортировать только процедуры. Для этого, процедура должна
находиться в главном модуле программы, ее имя должно быть отмечено символом
экспорта ("*") и должно быть указано соглашение о вызове. Нельзя
экспортировать процедуры, которые импортированы из других dll-библиотек.