Spec-Zone.ru › Haskell 8

15. Другие программы-утилиты Haskell

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

15.1. “Yacc для Haskell”: happy

Энди Гиль и Саймон Марлоу написали генератор парсеров для Haskell под названием happy. Happy для Haskell то же, что Yacc для C.

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

Happy лучше всего работает, когда компилируется GHC.

15.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-заголовок» — его заголовочный файл.

15.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-программу.

15.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.

#def ⟨C_definition⟩

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

#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; эта конструкция не выводит само определение типа.

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

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

C-шаблон должен определить макрос или функцию с префиксом hsc_ , которая обрабатывает конструкцию, выводя расширение в стандартный вывод. См. template-hsc.h для примеров.

END_OF_DOCUMENT_MARKER

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

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

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

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

  • #{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/8.10.2/docs/html/users_guide/utils.html

Spec-Zone.ru

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