Этот пост — небольшая обучалка по m4. Как мне кажется, приведённый ниже пример
хорошо иллюстрирует некоторые базовые принципы использования m4.
Я весьма часто пишу тексты, и для разметки приходится использовать довольно разный
синтаксис: то html, то LaTex, то google wiki, то bbCode (upd ещё vkontakte разметку бывает
приходится использовать). Даже html бывает разного вида (например, некоторые блоги
сами вставляют тег br в конце каждой строки).
Запомнить и набить руку на все эти варианты быстро не получается, да и не особо
хочется, поэтому приходится постоянно лезть в документации и вспоминать как
что-то делается. А хочется иметь какой-то единый синтаксис на все случаи
жизни. Во-первых, тогда можно будет изучить только его. А, во-вторых, написанный
текст можно будет конвертировать сразу в несколько выходных форматов.
Для обеспечения единого синтаксиса я решил воспользоваться m4, а именно:
текст будет писаться с использованием макросов, а в зависимости от того
какой выходной файл нужно будет получить, эти макросы будут по разному
раскрываться.
Рассмотрим это на примере HTML и LaTeX. Я создал два файла: html.m4 и tex.m4.
Когда требуется из файла изготовить текст на HTML, то следует вызывать
m4 html.m4 file.m4 > file.html
Если же требуется получить LaTeX, то нужно вызывать
m4 tex.m4 file.m4 > file.tex
Этот вызов сначала выполнит html.m4 или tex.m4, потом file.m4, сольёт результат вместе и
запишет в file.out. При этом в файлах html.m4 и tex.m4 находится исключительно служебная
информация, и мы не хотим, чтобы из них что-то печаталось. Поэтому в начало
каждого такого файла добавляется строка
divert(-1)
которая весь дальнейший вывод выбрасывает, а в конце файла пишем
divert
после чего вывод будет происходить нормально.
Приступим, наконец, к написанию макросов. Самое простое — перевод строки.
html.m4:
define(`BR', `<BR>')
tex.m4:
define(`BR',`\\')
Я решил, что все макросы будут писаться большими буквами, чтобы было по-меньше
конфликтов имён.
Перейдём к более сложному макросу: жирный шрифт. Использование такого макроса
будет выглядеть примерно так: BOLD(жирный шрифт). Для реализации нужно
в теле макроса написать $* — вместо него будет подставлено всё, что находится
между скобочек:
html.m4:
define(`BOLD', `<strong>$*</strong>')
tex.m4:
define(`BOLD', `\textbf{$*}')
Далее, запись списков. Я выбрал такой синтаксис:
LIST(
ITEM(Ананас)
ITEM(Манго)
ITEM(Кокос)
)
Оно создаст соответствующий нумерованный список. Реализация:
html.m4:
define(`LIST',`<OL>$*</OL>')
define(`ITEM',`<LI>$*</LI>')
tex.m4:
define('LIST', `\begin{enumerate}$*\end{enumerate}')
define('ITEM', `\item $*')
Перейдём к более сложному примеру: ссылки. Ссылки уже требуют двух параметров:
куда ссылается и что отображается. Для получения отдельных параметров вместо $*
следует использовать $1, $2, и т.д. Поэтому реализацию ссылки можно бы было
записать так:
define(`LINK', `<a href="$1">$2</a>')
Но эта конструкция имеет проблему: если написать
LINK(google.com, Используй гугл перед тем, как задать вопрос, пожалуйста)
то m4 будет думать, что тут четыре параметра, и второй — «Используй гугл перед тем»,
а не вся фраза целиком. Для решения проблемы следует использовать макрос «shift»:
он возвращает все свои параметры, кроме первого.
html.m4
define(`LINK', `<a href="$1">shift($*)</a>')
tex.m4
define(`LINK', `\href{shift($*)}{$1}')
Теперь указанный выше пример сработает корректно.
Далее — дело техники, уже перечисленного достаточно для реализации многого.
В случае, если при наборе какого-то текста критично то, что макросы для разметки слишком длинные, то легко можно вставить где-то в тексте строки вида:
define(`B',`BOLD')
и использовать краткие варианты макросов, ничего при этом не потеряв.
Вот мои файлы: html.m4 и tex.m4. Пока что они не полные и скорее полигон для экспериментов, чем что-то, что я использую в боевых условиях, но со временем эти файлы будут пополняться и совершенствоваться.
Комментариев нет:
Отправить комментарий