Препроцессинг, условная компиляция, настройка
Сразу после лексического анализа и перед синтаксическим анализом каждый модуль Фикус проходит предварительную обработку. На данном этапе возможна вставка, исключение и модификация любых частей модуля, включая директивы import и другие, основываясь на текущих условиях среды и желаемой конфигурации. Определение символов препроцессора
Во-первых, существует опция -D компилятора Фикус, используемая для задания определённых символов препроцессора. Она выглядит следующим образом:
-D символ_имени или
-D символ_имени=значение
где значение может быть:
- логическое значение:
true(синонимыTRUE,ON,on),false(синонимыFALSE,OFF,off); - целое число;
- строка текста.
Отсутствующее значение заменяется на true.
Определяемые символы размещаются в начале каждого компилируемого модуля в следующем виде:
@define символ значение
Можно задать свои определения:
@define символ выражение_препроцессора
где выражение_препроцессора это арифметическое выражение, включающее литералы, ранее определённые символы и встроенные функции и операции:
abs(x)– абсолютное значениеint(x)– преобразование строки или логического значения в числоstring(x)– преобразование логического значения или числа в строкуdefined(x)–true, если символxопределенf"..."– интерполяция строки, см. раздел Строковые выражения.
Обратная операция
@undef символ
удаляет определение, так что последующий вызов defined(символ) возвращает false, пока символ снова не будет объявлен.
Условная компиляция
При компиляции можно включать или исключать части компилируемого модуля с помощью директив условной компиляции, аналогичных директивам C:
@if выражение_препроцессора
...
[@elif другое_выражение_препроцессора
...] // необязательные ветви else_if
[@else
...] // необязательная ветвь else
@endif // соответствующая закрывающая директива для @if
Также можно использовать и сокращенные формы:
@ifdef символ // эквивалентно @if defined(символ)
...
@ifndef символ // эквивалентно @if !defined(символ)
...
Отчёт о проблемах
также аналогичен препроцессору C:
// выводит
// '<локализация>: предупреждение: <результат_выражения>'
// и продолжает компиляцию
@warning выражение_препроцессора
// выводит
// '<локализация>: ошибка: <результат_выражения>'
// и прерывает компиляцию
@error выражение_препроцессора
Аргументfvb выражений @error и @warning должны быть строковыми выражениями или выражениями, результатом которых является строка.
Приведем умозрительный пример.
Допустим, у нас есть модуль win32_ui.fx:
// win32_ui.fx: Backend интерфейса пользователя Win32, зависит от Windows API
...
и модуль linux_ui.fx:
// linux_ui.fx: Интерфейс пользователя на основе GTK+ с аналогичным API, как у Win32 UI
...
Теперь кросс-платформенный код может выглядеть так:
// my_app.fx
@if Platform == "Win32"
import win32_ui as ui
@elif Platform == "Linux"
import linux_ui as ui
@else
@error "Неподдерживаемая платформа"
@endif
ui.make_button("Нажмите меня!", fun() {println("Привет!")})
ui.run()
Этот код можно собрать на разных платформах с помощью команды:
ficus -app -D Platform=<целевая_платформа> my_app.fx
Подмена результата
Помимо условной компиляции, значения выражений препроцессора можно вставить непосредственно в итоговый код с помощью специальной директивы @{выражение_препроцессора}, например:
// myexample.fx
...
@define x 5
@define y x + opt
val x = @{y*y}
println(x)
При сборке с аргументом ficus -D opt=1 myexample.fx пример выше выведет 36.
Обратите внимание, что символы препроцессора существуют исключительно на стадии предварительной обработки. Их имена не конфликтуют и не могут конфликтовать с обычными именами (например, с именами значений, функций, типов, исключений, интерфейсов и т.п.), определенными в программе.