д) в программу на Planning C вместо обращения к макромодулю вставляется код, содержащий префиксную строку (которая может быть пустой) и результирующий текст модуля, обрамленный фигурными скобками.
Необходимо детализировать возможные типы параметров . Каждый параметр (после выполнения всех макроподстановок и подстановок значений констант, определенных в программе с помощью ключевого слова const) должен быть константным выражением, содержащим только неименованные константы . Такое выражение может быть числом/числовым выражением, или строкой (заключенной в апострофы), или списком, который может содержать числа, строки и другие списки. Числовые выражения вычисляются, применительно к результирующим значениям действуют следующие простые правила:
– целые числа так и считаются целыми;
– близкие к нулю вещественные константы считаются целочисленными нулями;
– близкие к целым вещественные значения считаются соответствующими целыми (с округлением);
– прочие значения считаются вещественными.
Развернутый в константное выражение параметр распознается по следующим правилам :
а) если он начинается с « [», то это список , который передается в макромодуль без изменения вплоть до» ]» с учетом сбалансированности по вложенным парам квадратных скобок;
б) если он начинается с « '», то это строка, которая передается без изменения вплоть до закрывающего апострофа « '» с учетом наличия в строке возможных пар апострофов, представляющих апостроф, являющийся одним из символов строки;
в) иначе делается попытка распознать параметр как число/числовое выражение.
Определение макромодуля может содержать обращения к иным макромодулям, записанным в той же форме «имя_модуля (параметры);». Таким образом, реализованы вложенные макромодули, с помощью которых можно (в некоторых случаях) сократить общий объем модулей и повысить гибкость их применения.
2.1.2. Расширение базовой семантики макромодуля: порождающее программирование
Приведем общую схему порожденного макромодулем фрагмента, которая, в ранних версиях языка, предназначалась почти исключительно для генерации описателей вычислительных топологий:
префиксная_строка « {» сгенерированный_макромодулем_код» }»
Уже очевидно, что возможно применение макромодулей для параметризованной генерации синтаксических конструкций, включающих префиксованный блок (П-блок) в фигурных скобках: деклараций структур, классов, уний, функций. Очевидно, что если ввести синтаксические средства, позволяющие убрать префиксную строку (возможность ее изменения заложена в макромодуль изначально) и обрамляющие скобки, то задача порождения принципиально произвольного Planning C-кода будет решена. Соответственно, определим два специальных предиката, управляющих порождением кода :
– prefix_off, выключающий префиксную строку,
– brackets_off, выключающий обрамляющие фигурные скобки.
Эти предикаты имеют глобальный для всего макромодуля эффект, соответственно они могут быть вызваны в любом из предикатов/целей модуля.
Таким образом, реализовано полноценное логическое порождающее программирование , которое может быть применено для решения сложных, интеллектуальных задач:
а) дедуктивного анализа фактов, представляющих, в частности, разобранную входную программу, с выработкой фактов, указывающих на необходимость применения распараллеливающих конструкций;
б) генерации кода на основании исходных и полученных фактов.
2.1.3. Некоторые простые примеры логического порождающего программирования на базе макромодулей
1. Пусть макромодуль генерирует серию заголовков цикла – в этом случае используется П-блок с опущенными префиксом и скобками. Далее приведен пример, содержащий соответствующий макромодуль big_loop, который вызывается для генерации тройного вложенного цикла (i = 0..2, j = 0..3, k = 0..4).
#include
using namespace std;
#def_module () big_loop (Vars, Lows, Highs) {
@goal:-brackets_off.
@loop ([], [], []):-!.
@loop ([V|VT], [L|LT], [H|HT]):-
write (’for (int»),write (V),write (»=»),write (L),write (»;»),
write (V),write (»<=»),write (H),write (»;»),
write (V),write (»++)»),
loop (VT, LT, HT).
@goal:-loop (Vars, Lows, Highs).
};
int main () {
big_loop ([’i’,’j’,’k’], [0,0,0], [2,3,4])
cout <<���«1»;
cout <
return 0;
}
2. Рассмотрим применение макромодуля tree_nodeдля формирования декларацию типа элемента n-арного дерева (n> = 2).
Читать дальше