Page 5 of 9

Re: Компилятор Oberon-07

Posted: Sun Apr 15, 2018 8:44 pm
by 0CodErr
akron1 wrote:Не подсвечиваются шестнадцатиричные константы и вложенные комментарии. Конечное END считается ошибкой, если в процедуре нет BEGIN, а такое возможно
Некоторые вещи пофиксил.
Теперь список процедур должен отображаться правильно в выпадающем списке:
Spoiler:
drop_down_list.PNG
drop_down_list.PNG (60.1 KiB)
Viewed 13508 times
Процелурные типы

Code: Select all

TYPE ProcName = PROCEDURE...
и переменные процедурных типов

Code: Select all

Var ProcName : PROCEDURE...
тоже попадают в этот список.
Если это лишнее — убрать не долго, нужно отредактировать секцию <LABELS>...</LABELS> в файле ob07_spec.xml — убрать ненужные <Label.../>.

Комментарии сейчас могут быть дважды вложенными, то есть, например, так:

Code: Select all

(* 
   (*
    *
    *  (* *** *)
    *
    *)
*)
Я просто не знаю, как это правильно реализовать, сделал, как смог
Spoiler:comment2 может находится в контейнере comment1, который может находится в контейнере comment:

Code: Select all

<Style id="comment"...
  <Blocks>
    <Block open="//" close="\n"/>
    <Block open="(*" close="*)"/>
  </Blocks>
</Style>
<Style id="comment1"...
  <Containers>
    <Open id="comment"/>
    <Close id="comment"/>
  </Containers>
  <Blocks>
    <Block open="(*" close="*)"/>
  </Blocks>
</Style>
<Style id="comment2"...
  <Containers>
    <Open id="comment1"/>
    <Close id="comment1"/>
  </Containers>
  <Blocks>
    <Block open="(*" close="*)"/>
  </Blocks>
Редактор HippoEDIT позволяет настроить выполнение той или иной программы(команды, bat, и т.п.) в зависимости от расширения открытого файла.
Вполне удобно иметь возможность компилировать и запускать скомпилированный файл прямо из редактора.

Для этого выбираем меню->Tools->Manage Tools
У меня в данный момент уже открыта вкладка с файлом с расширением .ob07, поэтому в меню отображается Manage Tools(Oberon-07)
Spoiler:
menu.PNG
menu.PNG (22.62 KiB)
Viewed 13508 times
После открытия диалога Manage Tools(см. скриншот под спойлером ниже) выбираем в нём нажатием мыши значок Oberon-07.
Кнопкой Add добавляем новый пункт.
Указываем название(будет отображаться в меню Tools). Я назвал Ob-07 Compiler.
Указываем путь к исполняемому файлу компилятора.
Для сборки консольного приложения под Windows компилятору нужно указать опцию 'con', пишем в аргументах:

Code: Select all

%MainFile% con  
Указываем Initial directory:

Code: Select all

%FileDir%
Можно определить горячую клавишу, по нажатию которой будет запускаться нужная программа(или bat-файл).

Для того, чтобы запускать скомпилированный файл, создадим ещё один пункт.
Я назвал его Run.
В поле Command нужно ввести:

Code: Select all

%MainFileDir%\%FileNameWOExt%.exe
Spoiler:
ob07+run.PNG
ob07+run.PNG (65.89 KiB)
Viewed 13508 times
Теперь когда активная вкладка будет содержать открытый файл с расширением .ob07, то в меню Tools должны появиться два пункта: Ob-07 Compiler и Run.
Ob07_.7z (2.53 KiB)
Downloaded 399 times

Re: Компилятор Oberon-07

Posted: Mon Apr 16, 2018 8:54 pm
by akron1
0CodErr wrote:Процедурные типы и переменные процедурных типов тоже попадают в этот список.
Если это лишнее — убрать не долго
Да, это конечно, лишнее.
0CodErr wrote: Комментарии сейчас могут быть дважды вложенными
Нормально, на практике бОльшая глубина не требуется.

При беглом осмотре нашел только один недочет: кроме суффикса "H" (INTEGER), шестнадцатиричные константы могут иметь суффикс "X" (CHAR), последние не подсвечиваются, но должны подсвечиваться как "строки".

В остальном -- отлично!

Сейчас пишу транслятор промежуточного байт-кода в ассемблер FASM, заодно и опробую HyppoEdit.
Байт-код не сложный, но обширный -- около 180 инструкций. Пока обработано только 30. Первые результаты несколько неоднозначные.
Такой код:

Code: Select all

PROCEDURE test (n: INTEGER);
VAR
    a: INTEGER;
BEGIN
    WHILE n > 0 DO
        a := 7FFFFFFFH;
        WHILE a > 0 DO
            a := a - 1
        END;
        n := n - 1
    END
END test;
выполняется в 3 раза быстрее, чем скомпилированный текущим (старым) компилятором, но в 6-7 раз медленнее, чем Delphi7. Но тут понятно, Delphi хорошо оптимизирует: процедура-лист, две переменные -- два регистра. Мои компиляторы честно загружают и сохраняют переменные при каждом обращении. В более сложных случаях разрыв, наверно, будет меньше. Сделать полноценное распределение регистров, конечно, сложно, но можно будет попробовать выявить в программе места, в которых распределить регистры сравнительно просто (вроде этой процедуры), и транслировать такие процедуры по особым правилам.

Re: Компилятор Oberon-07

Posted: Mon Apr 16, 2018 10:45 pm
by 0CodErr
akron1 wrote:выполняется в 3 раза быстрее, чем скомпилированный текущим (старым) компилятором, но в 6-7 раз медленнее, чем Delphi7
Ну прогресс ведь уже есть — это главное!
Какое, кстати, внутреннее соглашение вызова(если не указано явно [stdcall] | [winapi]| [cdecl])?
akron1 wrote:шестнадцатиричные константы могут иметь суффикс "X" (CHAR), последние не подсвечиваются, но должны подсвечиваться как "строки".
Пробовал такой регуляркой:

Code: Select all

<Regexp text="[0-9][0-9A-F]*X" lead="[^\w]"/>
Вот здесь:

Code: Select all

      <Style id="char" name="Char" text="1" bold="0" italic="0" underline="0" clr="Strings" bkclr="#FFFFFFFF">
        <Blocks>
          <Block open=""" close="""/>
          <Regexp text="[0-9][0-9A-F]*X" lead="[^\w]"/>
        </Blocks>
      </Style>
Проверял её в https://regex101.com/ и она там рабочая.
Но в HippoEDIT она не заработала. Вообще у меня не самая новая версия программы, может просто ещё тег Regexp не поддерживался.
Ни в одной синтаксической схеме, поставляемой с моей версией, не присутствует ни один тег Regexp.
В то же время в файлах отсюда https://www.hippoedit.com/syntax_files.php?lang=ru такой тег присутствует во многих местах, в частности в asm_arm_spec.xml:

Code: Select all

      <Style id="number" extend="true">
        <Blocks>
          <!--  0xFFFF -->
          <Regexp text="0x[0-9A-Fa-f]+\>" lead="[^\w]"/>
          <!-- Binary: 0b1010 -->
          <Regexp text="0b[01]+\>" lead="[^\w]"/>
          <!-- Octal: 01234567 -->
          <Regexp text="0[0-7]\>" lead="[^\w]"/>
          <!-- Decimal  are built-in -->
        </Blocks>
      </Style>
0CodErr wrote:Вставка шаблонов кода Code templates по Ctrl+Enter.
Как оказалось, клавишу Ctrl нажимать не всегда обязательно, в большинстве случаев достаточно Enter.
Есть ещё Ctrl+Пробелautocomplete(автоподстановка по первым введённым буквам).

Забыл сказать, что если выбрать опцию 'Capture output', тогда то, что компилятор выводит обычно в консоль, будет выведено прямо в редакторе в панель Output.
Потом его ещё вроде можно регулярками распарсить(Output Pattern).
Spoiler:
capture_output_hippo_edit.PNG
capture_output_hippo_edit.PNG (76.13 KiB)
Viewed 13462 times

Re: Компилятор Oberon-07

Posted: Mon Apr 16, 2018 11:58 pm
by akron1
0CodErr wrote:Какое, кстати, внутреннее соглашение вызова(если не указано явно [stdcall] | [winapi]| [cdecl])?
По умолчанию stdcall.
Есть нюансы: массивы и записи всегда передаются по ссылке, но если перед формальным параметром-записью указано VAR, то на самом деле там будет передан не один параметр, а два: тип записи и адрес:

Code: Select all

PROCEDURE (VAR r: REC);
procedure (typeof(r), adr(r)); stdcall
Если формальный параметр -- открытый массив (VAR или нет -- не важно), то кроме адреса передаются длины по всем измерениям:

Code: Select all

PROCEDURE (a: ARRAY OF ... );
procedure (adr(a), len(a, 0), len(a, 1)...); stdcall
В новом компиляторе я изменил порядок передачи адреса и длин:

Code: Select all

PROCEDURE (a: ARRAY OF ... );
procedure (len(a, 0), len(a, 1)..., adr(a)); stdcall
Это оказалось удобнее для индексации массива и передачи в другую процедуру. Не знаю, почему я сразу так не сделал... Наверно, долго не обдумавал и просто взял первое что пришло.

Re: Компилятор Oberon-07

Posted: Tue Apr 17, 2018 10:07 am
by Siemargl
Может лучше уж опционально транслировать в LLVM ?

В FASM-никакой выгоды, на 1й взгляд.

Re: Компилятор Oberon-07

Posted: Tue Apr 17, 2018 1:39 pm
by akron1
Новый компилятор отличается от старого не только "более лучшим" качеством результирующего кода, а также исходного (в последнее время я пишу значительно лучше). Отличается архитектура: есть четкое разделение на фронт-энд (исходный код -> промежуточное представление) и бэк-энд (промежуточное представление -> целевой код). Разделение настолько четкое, что сейчас это физически две отдельные программы. Предполагается, что таких бэк-эндов будет несколько, в принципе, можно будет сделать бэк-энд LLVM. Но пока я транслирую в FASM. Часто говорят, что трансляция ЯВУ в ассемблер не имеет никаких преимуществ. Но я с этим не согласен: это позволяет легко контролировать правильность трансляции, первое время не заниматься опкодами и вычислением меток, а потом можно без проблем заменить ассемблерный код на машинный. Как это и было в первый раз. Может быть, LLVM выдаст более эффективный машинный код, но ассемблер x86 -- это единственный низкоуровневый язык который я кое-как знаю. Всё остальное мне нужно сначала прочитать, осмыслить и только потом приступать к трансляции. В общем, пока цель -- FASM, потом FASM -> машинный код, а потом посмотрим...

Re: Компилятор Oberon-07

Posted: Tue Apr 17, 2018 2:59 pm
by mkostoevr
akron1 wrote:Байт-код не сложный, но обширный -- около 180 инструкций.
А можно, если это не секрет, узнать, почему так много?

Re: Компилятор Oberon-07

Posted: Tue Apr 17, 2018 3:29 pm
by akron1
На самом деле, многие инструкции очень похожи, отличаются знаком операции, порядком и типом операндов.
Например, операции сравнения: их шесть ">", "<", ">=", "<=", "=", "#". Вроде немного...

Но во-первых, они могуть применяться к разным типам операндов: целым, вещественным и строковым. Для каждого типа нужна своя операция сравнения. Таким образом, ужЕ получается 18 операций.

Во-вторых, операнды могут быть константами и переменными (выражениями). Возможны три случая:
1) оба операнда переменные (выражения)
2) левый операнд переменная, правый -- константа
3) правый операнд переменная, левый -- константа
Если оба операнда -- константы, то это вычисляется при компиляции и код не генерируется. Каждый из этих случаев транслируется в машинный код по своим правилам.

18*3 = 54

То же самое можно сказать про арифметические операции: "+", "-" и т. д. А еще есть встроенные в язык процедуры: INC, ODD, LSL ... Вот так и получается ~180.

Конечно, некоторые инструкции полностью совпадают:

a > 5: больше(выраж, конст)
5 < a: меньше(конст, выраж)

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

Re: Компилятор Oberon-07

Posted: Tue Apr 17, 2018 5:50 pm
by mkostoevr
akron1 wrote:...
Ага, теперь всё понял. Благодарю за развёрнутый ответ.

Re: Компилятор Oberon-07

Posted: Tue Apr 17, 2018 7:21 pm
by Siemargl
akron1 wrote:Новый компилятор отличается от старого не только "более лучшим" качеством результирующего кода, а также исходного (в последнее время я пишу значительно лучше). Отличается архитектура: есть четкое разделение на фронт-энд (исходный код -> промежуточное представление) и бэк-энд (промежуточное представление -> целевой код). Разделение настолько четкое, что сейчас это физически две отдельные программы. Предполагается, что таких бэк-эндов будет несколько, в принципе, можно будет сделать бэк-энд LLVM. Но пока я транслирую в FASM. Часто говорят, что трансляция ЯВУ в ассемблер не имеет никаких преимуществ. Но я с этим не согласен: это позволяет легко контролировать правильность трансляции, первое время не заниматься опкодами и вычислением меток, а потом можно без проблем заменить ассемблерный код на машинный. Как это и было в первый раз. Может быть, LLVM выдаст более эффективный машинный код, но ассемблер x86 -- это единственный низкоуровневый язык который я кое-как знаю. Всё остальное мне нужно сначала прочитать, осмыслить и только потом приступать к трансляции. В общем, пока цель -- FASM, потом FASM -> машинный код, а потом посмотрим...
Возможно, если почитать и осмыслить чужой байт код - не только LLVM, есть же JVM, .net bc, hhvm итп, то найдутся удачные решения и для своего ?

Re: Компилятор Oberon-07

Posted: Tue Apr 17, 2018 10:35 pm
by akron1
Siemargl wrote:Возможно, если почитать и осмыслить чужой байт код - не только LLVM, есть же JVM, .net bc, hhvm итп, то найдутся удачные решения и для своего ?
Возможно, но на переправе я ничего уже менять не буду. Вот сделаю, тогда и посмотрю, что и как можно улучшить.

Re: Компилятор Oberon-07

Posted: Tue Apr 17, 2018 11:12 pm
by 0CodErr
akron1 wrote:
0CodErr wrote:Процедурные типы и переменные процедурных типов тоже попадают в этот список.
Если это лишнее — убрать не долго
Да, это конечно, лишнее.
Убрал процедурные типы и переменные процедурного типа из выпадающего списка.
akron1 wrote:При беглом осмотре нашел только один недочет: кроме суффикса "H" (INTEGER), шестнадцатиричные константы могут иметь суффикс "X" (CHAR), последние не подсвечиваются, но должны подсвечиваться как "строки".
Добавил для строковых шестнадцатеричных констант

Code: Select all

<Regexp text="[0-9][0-9A-F]*X" lead="[^\w]"/> 
может в новой версии это заработает(у меня не самая новая).
Сейчас вместо stdcall|winapi|cdecl также допустимо писать какой-нибудь my_call, то есть, так:

Code: Select all

    PROCEDURE [my_call] MyProcedure(Param1: INTEGER);
Ob07_.7z (2.23 KiB)
Downloaded 367 times

Re: Компилятор Oberon-07

Posted: Tue May 01, 2018 3:57 am
by akron1
Осталась необработана только одна инструкция промежуточного кода. Она довольно сложная, и сходу я не придумал, как её эффективно транслировать в ассемблер. Это новая операция, в старой версии языка её нет и в уже написанных программах естесственно тоже, поэтому пока я отложил её реализацию, но на днях, конечно сделаю. Компилятор успешно транслирует свой собственный код, а также после небольших модификаций удалось скомпилировать и Editor.
Антивирусы не ругаются на GUI-приложения и я выяснил одну из причин, почему есть такая проблема со старым компилятором. Остается еще много мелких недоработок: не доделан рантайм, нет поддержки KolibriOS, не очень информативные сообщения об ошибках компиляции, нет удаления неиспользуемых процедур, ненадежная работа с плавающей точкой, возможно, что-то еще.
Новый компилятор создает чуть более компактный код, но код при этом более разнообразный и поэтому хуже сжимается. Похоже, что размер сжатого кода будет всё же чуть больше, чем у старого компилятора. Но зато по скорости большое преимущество.

Провел ряд тестов на скорость между новым, старым компилятором и tcc.
1. задача размытия изображения (blur)
2. рекурсивное вычисление чисел Фибоначчи (fib)
3. задача о ферзях (queens)
4. сортировка "пузырьком" целочисленного массива (фиксированной длины и нефиксированной (открытый массив)) (bubble, bubbleOA)

Результат сравнения со старым компилятором (во сколько раз новый быстрее)

queens 1.85
fib 2.52
blur 5.01 (!)
bubble 2.20
bubbleOA 9.20 (!)

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

Результат сравнения с tcc

queens 1.28
fib 1.02
blur 1.01

Как видно, качество кодогенерации в целом не уступает tcc.
При этом, в задаче blur идет интенсивная работа с массивами, а Оберон традиционно проверяет индексы при выполнении.
В задаче fib некоторый оверхед вносит синтаксис Оберона: из-за невозможности возврата из середины процедуры, выполняются лишние действия.
В задаче queens нет возвратов из середины и работа с массивами менее интенсивная, поэтому здесь tcc остался позади.

Сортировку на tcc не тестировал, потому что язык C позволяет выполнить ручную оптимизацию: заменить индексацию массива на инкремент указателя, что должно быть гораздо эффективнее.

Превзойти tcc, это, конечно не великое достижение, но в сравнении с тем, что было, весьма неплохо.

Re: Компилятор Oberon-07

Posted: Tue May 01, 2018 9:59 am
by 0CodErr
Ну, прогресс уже есть — это здорово!
Было бы ещё интересно сравнить результаты с другими реализациями Oberon(или Modula).
akron1 wrote:Превзойти tcc, это, конечно не великое достижение, но в сравнении с тем, что было, весьма неплохо.
Конечно, неплохо! Может можно ещё добиться скорости за счёт оптимизированных стандартных модулей? Тогда меньше пришлось бы париться из-за качества кодогенерации.

Re: Компилятор Oberon-07

Posted: Tue May 01, 2018 1:33 pm
by akron1
Компилятор XDS хоть и устаревший, но оптимизирующий, с ним сравнивать неинтересно и он еще имеет настройки оптимизации, вроде отключения проверок.
Можно будет сравнить с Black Box, он похоже один из лучших среди неоптимизирующих.

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

Впрочем, не все возможности исчерпаны: можно сделать табличный CASE, счетчики FOR хранить в регистрах. Вообще, компилятор использует только регистры eax, ecx и edx для хранения промежуточных значений выражений. Регистры ebx, esi, edi не используются и можно попробовать задействовать их для хранения часто используемых переменных, но для этого надо делать второй проход и серьезно изменить промежуточное представление.

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

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