Макроязыки (2024)

Стрим на YouTube

(Про что не будет разговора)

Программирование, обусловленное средой — изначально среда представлена готовым набором объектов и команд над ними

Контекстно обусловленная обработка данных — как правило, текстов, или domain-specific:

Принцип макроподстановки

Задача: параметризовать текст.

Свойства области применения:

Все? А алгоритмическая полнота?

  1. Аллегирование
    • Данные: по связыванию (как в ФП)
      • Параметризация определения и подстановки

    • Контекст: имена макросов
  2. Действия, определяемые свойствами данных
    • Пустой/непустой контекст, сравнение двух контекстов, …
  3. …в том числе возможность итерации
    • Проверка на наличие нетерминалов в макроподстановке ⇒ рекурсия!

Что может ещё потребоваться:

Практические элементы:

Немного истории

General-purpose macro processor и Macro_(computer_science).

Самый популярный вариант — препроцессор Си и другие макронадстройки над языками, однако это DSL (и таких бездна).

Более общий вариант — маркосы в Lisp, но и там макроподстановка не замещает функциональную парадигму и служит в первую очередь повышению читаемости.

M4

Чуть ли не единственный из известных.

Принцип:

Вот этот текст разумный http://mbreen.com/m4.html

Примеры просьба прощёлкивать! Если нет linux под рукой — можно воспользоваться любым online linux-окружением, например http://repl.it. При открытии редактора там в правой части запускается натуральная linux-консоль.

В ней можно запустить m4, но лучше что-нибудь вроде cat > o; echo "===="; m4 < o, чтобы ввод и вывод не перемешивались. Ввод заканчивается новой строкой и Ctrl+D для обозначения конца файла.

Если в вашем дистрибутиве есть команда rlwrap, можно получить более полноценный REPL (с историей, подсказкой, поиском и т. п.) примерно так:

rlwrap -S "m4> " m4

или даже

rlwrap -A -S "`tput smul`m4`tput rmul`> " m4

Макроопределение и макроподстановка

define(AUTHOR, W. Shakespeare)
`AUTHOR' is AUTHOR

define(AUTHOR, Me)
define(AUTHOR, A. Maclean)
`AUTHOR' is AUTHOR or Me?

И это не заработает:

define(AUTHOR, W. Shakespeare)
define(AUTHOR, A. Maclean)
`AUTHOR' is AUTHOR or W. Shakespeare?

Так что лучше брать макрос в кавычки всегда, и обмазывать dnl от лишних переводов строки

define(`AUTHOR', Me)dnl
define(`AUTHOR', A. Maclean)dnl
`AUTHOR' is  A. Maclean or Me? Answer: AUTHOR!

Откуда переводы строки?

А кто просил их удалять? ☺

Специальный макро: delete up to new line:

qwe
qwe dnl
define(`a', b)
define(`a', b) dnl

Вложенность

Кавычки раскрываются по одной паре за подстановку:

define(`definenum', `define(`num', `99')')
num
definenum
num

define(`definenum', define(`num', `99'))
num

Тройное раскрытие:

define(`definenum', `define(`num', `define(`deep', 100500)'99)')
deep num
definenum
deep num
deep num

Условные операторы

На пространство имён

define(`macro', `--$1--')dnl
ifdef(`macro', QQ, QKRQ)
QQ
undefine(`macro')dnl
ifdef(`macro', QQ, QKRQ)
QKRQ

Только на сопоставление

define(`a', b)dnl
ifelse(a, b, c, d)
ifelse(a, w, c, d)
ifelse(a, w, c)

Многоместные: проверяется первая тройка параметров, если нет, она отбрасывается, и процесс повторяется

ifelse(a, `a', 1, a, `b', 2, 3)
define(`a', `b')
ifelse(a, `a', 1, a, `b', 2, 3)
define(`a', `c')
ifelse(a, `a', 1, a, `b', 2, 3)

Типы данных

translit(`Highgest leet of all', `etl', 371)

Параметрические макросы и циклы

Параметры — это просто $№ в теле макроподствновки

Цикл == рекурсия!

define(`len',`ifelse($1,,0,`eval(1+len(substr($1,1)))')')dnl
len(qw qw)
len()
len

Цикл по параметрам (shift):

shift(1, 2, 3, 4)
define(`reverse', `ifelse(`$#', `0', , `$#', `1', ``$1'', `reverse(shift($@)), `$1'')')

Остальные циклы (forloop, foreach cмоделированы в соотв. библиотеках)

Управление пространством имён и контексты

GNU m4:

Потоки вывода

Часть текста можно перенаправить в синтетический поток, по окончании работы M4 они припишутся в конец в порядке нумерации (0 — основной поток)

one
divert(3)dnl
two
three
divert(1)dnl
four
five
divert(0)dnl
six
seven

Поток -1 не направляется никуда (а определённые макросы остаются!), а ещё поток можно закрыть и вставить по месту с помощью undivert()

divert(-1)
Здесь можно писать что угодно
значение имеют только макроопределения
define(`c', `divnum'> $1)
divert(2)
М. Ю. Лермонтов
divert(0)dnl
c(выхожу один)
divert(1)dnl
c(сквозь туман)
divert(0)dnl
c(я на дорогу)
undivert(1)dnl
c(кремнистый путь блестит)

Если успеем

Макровзрыв

Д/З

  1. Прощёлкать примеры из лекции и какую-нибудь методичку (например, эту) по M4; иметь под рукой учебник (его тоже можно при желании прочитать и прощёлкать)

  2. Скачать генератор домашнего задания formgen.m4 и запустить его так ($RANDOM выдаст случайный номер, также можно выбрать любой номер, кроме 1337, самому):

    m4 -DSEED=$RANDOM formgen.m4
    • По выбранному номеру будет сгенерирован текст задания. В задании требуется обработать с помощью m4 текстовый файл с произвольными параметрическими формулами (с использованием стандартной математической библиотеки), чтобы он превратился в программу на Си или на Паскале, которая их вычисляет. Программа, конечно, должна быть работающая ☺.

    • Задания бывают разной сложности — от 4 до 6 баллов.
    • В заданиях требуется сгенерировать программу любо на Си, либо на Паскале.
  3. Решение — программа на m4

    • Присылать на почту uneexlectures@cs.msu.ru

    • В виде приложенного файла с расширением .m4

    • С обязательным приложением полного текста задания с номером варианта

    • В поле «Subject» должно присутствовать словосочетание «ПП2024»

    • Крайний срок сдачи — 12/XII 2024

LecturesCMC/AL/2024_12_02 (последним исправлял пользователь FrBrGeorge 2024-12-23 17:07:11)