Spec-Zone.ru › Haskell 9

12. Другие вспомогательные программы Haskell

В этом разделе описаны другие программы, которые мы распространяем и которые помогают в решении масштабной задачи программирования на Haskell.

12.1. «Yacc для Haskell»: happy

Andy Gill и Simon Marlow написали генератор синтаксических анализаторов для Haskell под названием happy. Happy для Haskell — то же, что Yacc для C.

Вы можете получить happy на главной странице Happy.

Happy раскрывает свои лучшие качества при компиляции с помощью GHC.

12.2. Создание интерфейсов Haskell для кода C: hsc2hs

Команду hsc2hs можно использовать для автоматизации некоторых этапов создания привязок Haskell к коду C. Она читает исходный файл, почти соответствующий синтаксису Haskell и содержащий специальные встроенные конструкции, а затем выводит настоящий файл Haskell, в котором эти конструкции обработаны на основе сведений из заголовочных файлов C. Дополнительные конструкции предназначены для доступа к данным C из Haskell.

Она также может вывести файл C с дополнительными функциями C, которые будут скомпонованы с программой, и заголовочный файл C, включаемый в код C, в который будет скомпилирован модуль Haskell (при компиляции через C), а также в сам файл C. Эти два файла создаются при использовании конструкции #def (см. ниже).

На самом деле hsc2hs не выводит файл Haskell напрямую. Она создаёт программу C, включающую заголовочные файлы, которая автоматически компилируется и запускается. Эта программа выводит код Haskell.

Далее под «файлом Haskell» подразумевается основной выходной файл (обычно файл .hs), под «скомпилированным файлом Haskell» — файл Haskell после того, как ghc скомпилировала его в C (то есть файл .hc), под «программой C» — программа, выводящая файл Haskell, под «файлом C» — необязательный создаваемый файл C, а под «заголовочным файлом C» — его заголовочный файл.

12.2.1. Синтаксис командной строки

hsc2hs принимает входные файлы в качестве аргументов, а также флаги, изменяющие её поведение:

-o FILE, --output=FILE

Имя файла Haskell.

-t FILE, --template=FILE

Файл шаблона (см. ниже).

-c PROG, --cc=PROG

Используемый компилятор C (по умолчанию: gcc)

-l PROG, --ld=PROG

Используемый компоновщик (по умолчанию: gcc).

-C FLAG, --cflag=FLAG

Дополнительный флаг, передаваемый компилятору C.

-I DIR

Передаётся компилятору C.

-L FLAG, --lflag=FLAG

Дополнительный флаг, передаваемый компоновщику.

-i FILE, --include=FILE

Эквивалентно размещению в исходном файле соответствующей директивы #include.

-D NAME[=VALUE], --define=NAME[=VALUE]

Эквивалентно размещению в исходном файле соответствующей директивы #define.

--no-compile

Остановиться после записи промежуточной программы C на диск. Имя файла промежуточной программы C образуется из имени входного файла заменой .hsc на _hsc_make.c.

-k, --keep-files

Продолжить обычную работу, но не удалять промежуточные файлы.

-x, --cross-compile

Включить режим кросс-компиляции (см. раздел Кросс-компиляция).

--cross-safe

Ограничить набор директив .hsc теми, которые поддерживаются в режиме --cross-compile (см. раздел Кросс-компиляция). Это полезно, если ваши файлы .hsc необходимо безопасно кросс-компилировать и вы хотите не допустить появления в них конструкций, несовместимых с кросс-компиляцией.

-?, --help

Вывести сводку доступных флагов и завершить работу без ошибки.

-V, --version

Вывести сведения о версии и завершить работу без ошибки.

Имя входного файла должно иметь окончание .hsc (файл должен содержать только обычный исходный код Haskell; поддержка литерального Haskell пока отсутствует). По умолчанию имена выходных файлов формируются заменой суффикса .hsc:

.hs

Файл Haskell

_hsc.h

Заголовочный файл C

_hsc.c

Файл C

Программа C компилируется с помощью компилятора Haskell. Благодаря этому предоставляется путь поиска включаемых файлов для HsFFI.h, который автоматически включается в программу C.

12.2.2. Синтаксис входных данных

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

После # могут следовать необязательные пробелы и табуляции, алфавитно-цифровое ключевое слово, описывающее тип обработки, и его аргументы. Аргументы записываются как выражения C, разделённые запятыми (без круглых скобок). Они продолжаются до ближайшей незакрытой ), ] или } либо до конца строки, если символ встречается вне любых () [] {} '' "" /**/ и перед ним нет обратной косой черты. Пары «обратная косая черта — перевод строки» удаляются.

Кроме того, #{stuff} эквивалентно #stuff, за исключением того, что оно имеет собственные ограничители и поэтому его не нужно размещать в конце строки или в скобках.

Значения ключевых слов:

#include <file.h>, #include "file.h"

Указанный файл включается в программу C, скомпилированный файл Haskell и заголовочный файл C. <HsFFI.h> включается автоматически.

#define ⟨name⟩, #define ⟨name ⟨value⟩, #undef ⟨name⟩

Аналогично #include. Обратите внимание, что #includes и #defines могут дважды размещаться в одном файле, поэтому они не должны полагаться на обратное.

#let ⟨name⟩ ⟨parameters⟩ = "⟨definition⟩"

Определяет макрос, применяемый к исходному коду Haskell. Имена параметров разделяются запятыми и не заключаются в скобки. Такой макрос вызывается, как и другие конструкции #, начиная с #name. Определение помещается в программу C в скобках в качестве аргументов printf. Чтобы обратиться к параметру, закройте кавычку, укажите имя параметра и снова откройте кавычку — так литералы C будут объединены. Либо используйте директивы форматирования printf. Значения аргументов должны быть строками, если только сам макрос не преобразует их в строки с помощью синтаксиса #parameter препроцессора C.

#def ⟨C_definition⟩

Определение (функции, переменной, структуры или typedef) записывается в файл C, а его прототип или объявление extern — в заголовочный файл C. Встроенные функции обрабатываются корректно. Определения структур и typedef также записываются в программу C. Ключевое слово inline, struct или typedef должно идти непосредственно после def.

#if ⟨condition⟩, #ifdef ⟨name⟩, #ifndef ⟨name⟩, #elif ⟨condition⟩, #else, #endif, #error ⟨message⟩, #warning ⟨message⟩

Директивы условной компиляции без изменений передаются программе C, файлу C и заголовочному файлу C. Их размещение в программе C позволяет пропускать соответствующие части файла Haskell.

#const ⟨C_expression⟩

Выражение должно преобразовываться в long или unsigned long. Будет выведено его значение (литерал или литерал с отрицательным знаком).

#const_str ⟨C_expression⟩

Выражение должно преобразовываться в указатель на const char. Будет выведено его значение (строковый литерал).

#type ⟨C_type⟩

Будет выведен эквивалент числового типа C в Haskell. Это будет один из типов {Int,Word}{8,16,32,64}, Float, Double, LDouble.

#peek ⟨struct_type⟩, ⟨field⟩

Будет выведена функция для чтения поля структуры C. Её тип — Storable b => Ptr a -> IO b. Предполагается, что #peek и #poke можно использовать для реализации операций класса Storable для заданной структуры C (см. модуль Foreign.Storable в документации библиотеки).

#poke ⟨struct_type⟩, ⟨field⟩

Аналогично для записи значения (poke). Тип функции — Storable b => Ptr a -> b -> IO ().

#ptr ⟨struct_type⟩, ⟨field⟩

Создаёт указатель на поле структуры. Его тип — Ptr a -> Ptr b.

#offset ⟨struct_type⟩, ⟨field⟩

Вычисляет смещение в байтах field в struct_type. Тип результата — Int.

#size ⟨struct_type⟩

Вычисляет размер struct_type в байтах. Тип результата — Int.

#alignment ⟨struct_type⟩

Вычисляет выравнивание struct_type в байтах. Тип результата — Int.

#enum ⟨type⟩, ⟨constructor⟩, ⟨value⟩, ⟨value⟩, ...

Сокращённая запись для нескольких определений, использующих #const. Каждый value — это имя целочисленной константы C, например значения перечисления. Имя преобразуется в Haskell: первая буква после подчёркивания становится заглавной, остальные буквы переводятся в нижний регистр, а подчёркивания удаляются. Можно задать другое преобразование, указав hs_name = c_value вместо value; в этом случае c_value может быть произвольным выражением. hs_name будет определён с указанным type. Его определение — указанное constructor (которое на самом деле может быть выражением или быть пустым), применённое к соответствующему целочисленному значению. Можно задать несколько определений #enum с одинаковым type; эта конструкция сама по себе не выводит определение типа.

12.2.3. Пользовательские конструкции

#const, #type, #peek, #poke и #ptr не встроены непосредственно в hsc2hs, а определяются в шаблоне C, который включается в программу C: template-hsc.h. Можно также использовать пользовательские конструкции и шаблоны. Предполагается, что любую конструкцию # с неизвестным ключом обработает шаблон C.

В шаблоне C следует определить макрос или функцию с именем, начинающимся с hsc_, которая обрабатывает конструкцию, выводя результат раскрытия в stdout. Примеры см. в template-hsc.h.

Такие макросы можно также определять непосредственно в исходном файле. Они полезны для создания макроса, подобного #let, раскрытие которого использует другие макросы #let. Обычный #let добавляет hsc_ в начало имени макроса и оборачивает определение вызовом printf.

12.2.4. Кросс-компиляция

Обычно hsc2hs создаёт программу C, компилирует и запускает её. Такой подход не работает при кросс-компиляции: в этом случае компилятор C создаёт код для целевой машины, а не для хост-машины. Для этой ситуации предусмотрен специальный режим hsc2hs --cross-compile, который может создавать файл .hs, извлекая сведения только из результатов компиляции — в частности, выясняя, завершается ли компиляция ошибкой.

В --cross-compile поддерживается только подмножество синтаксиса .hsc. Не поддерживаются следующие конструкции:

  • #{const_str}
  • #{let}
  • #{def}
  • Пользовательские конструкции

© 2002–2007 The University Court of the University of Glasgow. All rights reserved.
Licensed under the Glasgow Haskell Compiler License.
https://downloads.haskell.org/~ghc/9.14.1/docs/users_guide/utils.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API