Компилятор языка программирования Oberon-07/16 для микроконтроллеров STM32 Cortex-M3. ------------------------------------------------------------------------------ Параметры командной строки Вход - текстовые файлы модулей с расширением ".ob07", кодировка ANSI или UTF-8 с BOM-сигнатурой. Выход - hex-файл прошивки. Параметры: 1) имя главного модуля 2) "stm32cm3" 3) необязательные параметры-ключи -out имя результирующего файла; по умолчанию, совпадает с именем главного модуля, но с расширением ".hex" -ram размер ОЗУ в килобайтах (4 - 65536) по умолчанию 4 -rom размер ПЗУ в килобайтах (16 - 65536) по умолчанию 16 -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" stm32cm3 -ram 32 -rom 256 -nochk pti Compiler.exe "C:\example.ob07" stm32cm3 -out "C:\Ex1.hex" -ram 8 -rom 32 В случае успешной компиляции, компилятор передает код завершения 0, иначе 1. При работе компилятора в KolibriOS, код завершения не передается. ------------------------------------------------------------------------------ Отличия от оригинала 1. Расширен псевдомодуль SYSTEM 2. В идентификаторах допускается символ "_" 3. Усовершенствован оператор CASE (добавлены константные выражения в метках вариантов и необязательная ветка ELSE) 4. Расширен набор стандартных процедур 5. Семантика охраны/проверки типа уточнена для нулевого указателя 6. Добавлены однострочные комментарии (начинаются с пары символов "//") 7. Разрешено наследование от типа-указателя 8. "Строки" можно заключать также в одиночные кавычки: 'строка' 9. Добавлен тип WCHAR 10. Добавлена операция конкатенации строковых и символьных констант 11. Добавлены кодовые процедуры ------------------------------------------------------------------------------ Особенности реализации 1. Основные типы Тип Диапазон значений Размер, байт INTEGER -2147483648 .. 2147483647 4 REAL 1.17E-38 .. 3.40E+38 4 CHAR символ ASCII (0X .. 0FFX) 1 BOOLEAN FALSE, TRUE 1 SET множество из целых чисел {0 .. 31} 4 BYTE 0 .. 255 1 WCHAR символ юникода (0X .. 0FFFFX) 2 2. Максимальная длина идентификаторов - 1024 символов 3. Максимальная длина строковых констант - 1024 символов (UTF-8) 4. Максимальная размерность открытых массивов - 5 5. Процедура NEW заполняет нулями выделенный блок памяти 6. Локальные переменные инициализируются нулями 7. В отличие от многих Oberon-реализаций, сборщик мусора и динамическая модульность отсутствуют 8. Тип BYTE в выражениях всегда приводится к INTEGER 9. Контроль переполнения значений выражений не производится ------------------------------------------------------------------------------ Псевдомодуль 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 будет расширено до 32 бит, для записи байтов использовать 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 CODE(hword1, hword2,... : INTEGER) Вставка машинного кода, hword1, hword2 ... - константы в диапазоне 0..65535, например: SYSTEM.CODE(0BF30H) (* wfi *) Также, в модуле SYSTEM определен тип CARD32 (4 байта). Для типа CARD32 не допускаются никакие явные операции, за исключением присваивания. Функции псевдомодуля SYSTEM нельзя использовать в константных выражениях. ------------------------------------------------------------------------------ Оператор CASE Синтаксис оператора CASE: CaseStatement = CASE Expression OF Сase {"|" Сase} [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 c BOM. ------------------------------------------------------------------------------ Конкатенация строковых и символьных констант Допускается конкатенация ("+") константных строк и символов типа CHAR: str = CHR(39) + "string" + CHR(39); (* str = "'string'" *) newline = 0DX + 0AX; ------------------------------------------------------------------------------ Проверка и охрана типа нулевого указателя Оригинальное сообщение о языке не определяет поведение программы при выполнении охраны p(T) и проверки типа p IS T при p = NIL. Во многих Oberon-реализациях выполнение такой операции приводит к ошибке времени выполнения. В данной реализации охрана типа нулевого указателя не приводит к ошибке, а проверка типа дает результат FALSE. В ряде случаев это позволяет значительно сократить частоту применения охраны типа. ------------------------------------------------------------------------------ Дополнительные стандартные процедуры 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 ------------------------------------------------------------------------------ Использование регистров общего назначения R0 - R12 R0 - R3: регистровый стэк (промежуточные значения выражений) R4 - R12: не используются ------------------------------------------------------------------------------ Вызов процедур и кадр стэка Правила вызова похожи на соглашение cdecl (x86): - параметры передаются через стэк справа налево - результат, если есть, передается через регистр R0 - вызывающая процедура очищает стэк Состояние стэка при выполнении процедуры: меньшие адреса <- |var3|var2|var1|LR|arg1|arg2|arg3| -> бОльшие адреса LR - сохраненный регистр LR (адрес возврата) argX - параметры в порядке объявления (слева направо) varX - локальные переменные в порядке использования в процедуре Размер каждого элемента в стэке (кроме локальных переменных структурных типов) - 1 машинное слово (4 байта). Структурные переменные (массивы и записи) занимают место в стэке в соответствии с их размером (с учетом выравнивания). Размещение локальных переменных зависит от их размеров и порядка использования, и в общем случае неопределенно. Если переменная не используется явно, то компилятор не выделяет для нее место в стэке. ------------------------------------------------------------------------------ Скрытые параметры процедур Некоторые процедуры могут иметь скрытые параметры, они отсутствуют в списке формальных параметров, но учитываются компилятором при трансляции вызовов. Это возможно в следующих случаях: 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)) ------------------------------------------------------------------------------ Кодовые процедуры Компилятор поддерживает процедуры, написаные в машинных кодах. Синтаксис: PROCEDURE "[code]" имя [ (параметры): ТипРезультата ] МашКом, МашКом,... МашКом; ";" после заголовка и END "имя" в конце процедуры не ставятся. МашКом - целочисленная константа [0..65535] (в том числе и константное выражение). Например: PROCEDURE [code] WFI 0BF30H; (* wfi *) Компилятор автоматически добавляет к такой процедуре команду возврата (bx LR). Способ передачи параметров и результата не изменяется. Регистр LR, при входе в процедуру не сохраняется. Чтобы использовать кодовые процедуры, необходимо импортировать псевдомодуль SYSTEM. ------------------------------------------------------------------------------ Обработка прерываний При возникновении прерывания, будет вызван обработчик (если он объявлен). Объявление обработчика: PROCEDURE handler_name [iv]; (* процедура без параметров *) iv - целочисленная константа (константное выражение), номер вектора прерывания в таблице векторов, iv >= 2: 0 начальное значение SP 1 сброс ... 15 SysTick ... 59 TIM6 60 TIM7 ... например: (* обработчик прерываний от TIM6 *) PROCEDURE tim6 [59]; BEGIN (* код обработки *) END tim6; Также, можно объявить общий обработчик (iv = 0), который будет вызван, если не назначен индивидуальный. Общий обработчик получает параметр - номер вектора прерывания. По значению этого параметра, обработчик должен определить источник прерывания и выполнить соответствующие действия: PROCEDURE handler (iv: INTEGER) [0]; BEGIN IF iv = 59 THEN (* TIM6 *) ELSIF iv = 60 THEN (* TIM7 *) ELSIF .... .... END END handler; В конец программы компилятор добавляет команду ожидания прерывания. ------------------------------------------------------------------------------ Обработка ошибок В случае возникновения ошибки при выполнении программы, будет вызван пользовательский обработчик (если он объявлен). Объявление обработчика ошибок: PROCEDURE trap (modNum, modName, err, line: INTEGER) [1]; BEGIN END trap; где, modNum - номер модуля (в отчете о компиляции: compiling (modNum) "modName" ) modName - адрес имени модуля err - код ошибки line - номер строки Коды ошибок: 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) После возврата из обработчика программа будет перезапущена. ------------------------------------------------------------------------------