Страницы

среда, 26 июня 2019 г.

Связка с кодом на других высокоуровневых языках

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

В трансляторе "Востока" сейчас применён более простой модульный подход. Входной язык не содержит никаких расширений, а для связывания используется подмена кода на входном языке на код на выходном языке. То есть, интерфейсный модуль на Обероне с, возможно, пустыми типами и процедурами во время полной трансляции заменяется соответствующим файлом-"модулем" на С, Java или JavaScript, заполненным нужным функционалом.

Этот способ связки имеет важные преимущества:

  1. Отсутствует рваный стиль исходного модуля, сшитого из разнородных языков - каждый файл написан на одном языке. Нет необходимости представлять, как входной язык должен отображаться на выходные языки
  2. Выходные языки можно использовать по полной программе, лишь соблюдая возможность корректного связывания. Нет необходимости втискиваться в рамки предоставленного расширениями транслятора, но требуется соблюдать осторожность
  3. Заставляет программиста тщательней разделять связочные модули и основную логику, улучшая архитектуру. Расширенный же язык позволяет втискивать обращение к выходному языку куда угодно, размазывая внешние зависимости по программе
  4. Программа можеть быть собрана любым совместимым транслятором входного языка, ничего не знающим о несовместимых расширениях. Хотя, конечно, не любая такая программа может быть исполнена корректно без доработки
Недостатки тоже есть:
  1. Может потребоваться писать больше кода на выходном языке
  2. Несколько мест для изменений одной сущности
  3. Сложней вносить изменения, соблюдая целостность, в связку существующего модуля на входном языке и сопроводительные файлы на выходных, чем в единый модуль, написанном на расширении входного языка

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

  1. Создание интерфейсного модуля на Обероне, например, Print.mod:
    MODULE Print;
     PROCEDURE Do*(str: ARRAY OF CHAR);
     BEGIN
       ASSERT(FALSE)
     END Do; 
    END Print.
  2. Трансляция модуля, лежащего в текущем каталоге, в код на Си сюда же:
    $ ost to-c Print . -m .
    На выходе получаем Print.h:
    #if !defined HEADER_GUARD_Print
    #    define  HEADER_GUARD_Print 1
    
    extern void Print_Do(o7_int_t str_len0, o7_char str[/*len0*/]);
    
    O7_INLINE void Print_init(void) { ; }
    #endif
    и Print.c:
    #include <o7.h>
    #include "Print.h"
    
    extern void Print_Do(o7_int_t str_len0, o7_char str[/*len0*/]) {
     O7_ASSERT((0 > 1));
    }
    
  3. Дополнение Си-файла нужными объявлениями и действиями:
    #include <o7.h>
    #include "Print.h"
    
    #include <stdio.h>
    
    extern void Print_Do(o7_int_t str_len0, o7_char str[/*len0*/]) {
     printf("%s\n", str);
    }
  4. Запуск привязки. Указываем, что интерфейсный модуль (-i) и соответствующие файлы на Си (-c) лежат в текущем каталоге:
    $ ost run 'Print.Do("Проба микрофона")' -i . -c .
  5. Можно поместить файлы привязки в общий каталог print
    $ mkdir -p print/singularity/definition print/singularity/implementation
    $ mv Print.mod print/singularity/definition/ && mv Print.[hc] print/singularity/implementation/
    $ ost run 'Print.Do("Или так")' -infr print 

Аналогичным образом пишутся привязки для Java:

$ mkdir -p print/singularity/implementation.java
$ ost to-java Print print/singularity/implementation.java/ -m print/singularity/definition
$ editor print/singularity/implementation.java/Print.java 
$ ost run-java 'Print.Do("Запуск через Java")' -infr print
и для JavaScript:
$ mkdir -p print/singularity/implementation.js
$ ost to-js Print print/singularity/implementation.js/ -m print/singularity/definition
$ editor print/singularity/implementation.js/Print.js
$ ost run-js 'Print.Do("Запуск через JavaScript")' -infr print

Комментариев нет:

Отправить комментарий

Обработка ошибок

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