|
Персональные инструменты |
|||
|
|
M4Материал из CustisWikiВерсия от 06:47, 7 июля 2006; BenderBot (обсуждение | вклад) (реплицировано из внутренней CustisWiki) Макропроцессор m4, разработанный в 1977 году, легендарными программистами - Брайаном Керниганом (Brian Kernighan) и Денисом Ричи (Dennis Ritchie) предназначен для макрогенерации на предварительном проходе в различных языках. Макрогенерация означает копирование входного символьного потока в выходной, с подстановкой макросов, по мере их появления. Макросы могут быть встроенными или определенными пользователями, и принимать произвольное число аргументов. Имеется множество встроенных функций для включения файлов, запуска внешних команд, выполнения целочисленной арифметики, манипуляции строками. m4 может быть полезен везде:
СодержаниеОбучениеРазумно сначала использовать m4 для решения простых задач, и лишь затем, переходить к все более и более сложным, походу дела изучая, как писать сложные блоки макросов. Далее, мы приведем описание макропроцессора m4, включая формат вызова, синтаксис использования, встроенные макрокоманды. Мы будем описывать версию GNU m4, отличающаяся от стандартного макропроцессора m4, входящего в поставку большинства UNIX-систем, наличием большого числа функциональных расширений, открытостью и переносимостью кода (доступен под любые платформы). Основные принципы препроцессированияВ данной главе описаны основные принципы препроцессирования m4. Также описаны базовые встроенные макросы. Работа препроцессора m4 состоит в поиске в текстах входных файлов макровызовов с целью их подстановки. Макровызовы имеют следующий вид: имя (арг1, арг2, ... аргn) Левая скобка должна следовать непосредственно за именем макроса. Если за именем определенного макроса не следует «(», то полагается, что макрос вызван без аргументов. Имя макроса может состоять из букв, цифр и символов подчеркивания, причем первым символом не может быть цифра. На самом деле можно именовать макросы и с нарушением этих правил, но тогда придется вызывать эти макросы с помощью встроенного макроса indir. В процессе сбора аргументов m4 игнорирует не заключенные в кавычки начальные пробелы, табуляции и символы перевода строки. Для того, чтобы запретить интерпретацию цепочки символов, их заключают между правой и левой одинарными кавычками: `эта цепочка не интерпретируется' Значение цепочки символов, заключенной в кавычки, равно самой этой цепочке без внешних кавычек. Заметим, что символы используемые для обозначения внешних кавычек, можно менять с помощью встроенного макроса changequote. Зачастую это очень удобно по соображениям либо эстетического, либо синтаксического (конфликт с синтаксисом «постпроцессирующего» компилятора) характера. Когда имя макроса распознано, его аргументы собираются путем поиска парной правой скобки. Если аргументов оказалось меньше, чем используется в определении макроса, то последним аргументам будут даны пустые значения. В процессе сбора аргументов продолжается макрообработка и все не взятые в кавычки запятые и правые скобки, которые образовались в результате вложенных макровызовов, действуют так же, как будто они встретились в исходном тексте. После сбора аргументов значение макроса сканируется повторно, так как если бы оно было в исходном тексте. m4 предоставляет следующие встроенные макросы, которые могут быть переопределены, но в этом случае их первоначальный смысл теряется. Значения встроенных макросов, если не оговорено противное, равны пустой цепочке.
m4wrap(`cleanup()')
define(`$internal$macro', `Internal macro (name `$0')') => $internal$macro =>$internal$macro indir(`$internal$macro') =>Internal macro (name $internal$macro) Формат и опции командной строкиСинтаксис вызова: m4 [опции...] [макроопределения...] [входные файлы...] Все файлы-аргументы обрабатываются по очереди. Если файлы не указаны, или в качестве имени файла задан «-», то читается стандартный ввод. Обработанный текст записывается на стандартный вывод. Все опции начинаются с «-», если используется короткая (как правило однобуквенная) запись опции, или «--» если используется длинная запись. Заметим, что необязательно писать полностью длинное название опции, достаточно написать однозначно определяющий ее префикс.
--version печатает версию программы и немедленно выходит; -G, --traditional подавляет обработку всех дополнений по сравнению со стандартом System V; -E, --fatal-warnings прекратить обработку после первой ошибки; -Iкаталог, --include=каталог указывает каталог для поиска включаемых файлов, ненайденных в текущем каталоге; -s, --synclines генерация синхронизирующих директив вида #line linenum «filename»; -Dимя, -Dимя=значение, --define=имя, --define=имя=значение определение макроса до начала компиляции; если значение не задано, оно считается пустой строкой; -Uимя, --undefine=имя удаление определения ранее предопределенного в командной строке имени.
Уроки-примеры генерации кодаПриведем начальное обучение базовым навыкам использования препроцессора m4 для генерации кода 3GL и 4GL языков путем разбора примеров. В приведенных в разделе примерах символы используемые для обозначения внешних кавычек, будут заменены на фигурные скобки. Это делается с помощью встроенного макроса changequote: changequote({,}) Подразумевается, что перед чтением данной главы читатель уже ознакомился с разделом #Основные принципы препроцессирования. m4 предоставляет удобные возможности для работы со списками. Использование списков в свою очередь, позволяет легко масштабировать программный код. Список определяется, как обычный макрос. Например, это список колонок в таблице. define({parameter_field_list}, {"ID_CONFIG","ID_OBJECT","MONIKER","NAME","VALUE","COMMENTS","SYS_LEVEL","KIND"}) С помощью приведенного ниже макроса, мы будем иметь возможность брать произвольный элемент ранее определенного списка. define({Nth}, {pushdef({_n},{$}$1)_n($2){}popdef({_n})})dnl Внимательно присмотритесь к телу этого макроса. Это хороший пример как можно играться с раскрытием экранирующих кавычек-скобок. Внутри данного макроса определяется «внутренний» макрос _n возвращающий один из своих параметров (номер параметра определяется первым параметром исходного макроса), затем этот макрос вызывается, причем на вход ему подается список — второй параметр исходного макроса. Таким образом подставляется требуемый элемент списка. Затем определение макроса _n уничтожается. По рефлексируйте над этим макросом, представляйте, как происходят подстановки. Вспомним, что при каждой подстановке часть выражения не «защищенного» экранирующими скобками раскрывается, а в части защищенном этими скобками крайние скобки «сьедаются». Nth(2,{parameter_field_list}) ----------- "ID_OBJECT" Процесс подстановки:
Убедитесь, что в описанном процессе все понятно — далее комментарии будут менее подробные. Следующее, что необходимо для эффективной кодо- или просто тексто- генерации — это итерации. Их (через рекурсию) реализует следующие макросы: define({forloop}, { pushdef({$1},$2) $4{}ifelse($2, $3, , { pushdef({$1_next}, incr($2))forloop({$1}, {$1_next}, {$3}, {$4})popdef({$1_next})})popdef({$1})}) Формально синтаксис вызова этого макроса следующий: forloop(имя переменной, стартовое значение, конечное значение, тело цикла) Введя еще макрос для получения длины списка, мы сразу получим возможность реализовывать мощные, масштабируемые конструкции. define({$size},{$#}) define({Size}, {ifelse($#,1,{indir({$size},$1)})}) Итак, используя перечисленные «базовые» макросы, начнем разрабатывать прикладные: введем макрос для добавления префикса к элементам списка, являющимися колонками (заключенным в кавычки). define({add_prefix_to_list},{ifelse($#,2,{forloop({j}, 1, Size({$1}),{ifelse(j(),1,,{,})patsubst(Nth({j},{$1}),{^[^"]*"},$2")})})}) Введем макрос, который для элементов списка, являющихся колонками формируется синтаксическая конструкция вида колонка_из_списка1_i = колонка_из_списка2_i, .... где i — порядковый номер колонки в списке (UPDATE SET CLAUSE). define({update_set2},{forloop({j},1,Size({$1}),{ifelse(eval(index(Nth({j},{$1}),{"})>=0),1,{ ifdef({ok},{,})}Nth({j},{$1}){ifdef({ok},,{pushdef({ok},1)})}=Nth({j},{$2}))})popdef({ok})}) Итак, используя вышеприведенное определение для parameter_field_list, мы можем легко написать следующую «пре»-SQL-конструкцию: UPDATE t_parameter SET update_set2({parameter_field_list},{add_prefix_to_list({parameter_field_list},{:NEW.})}) WHERE id_parameter=123; после препроцессирования получим: UPDATE t_parameter SET «ID_CONFIG»=:NEW."ID_CONFIG" ,"ID_OBJECT"=:NEW."ID_OBJECT" ,"MONIKER"=:NEW."MONIKER" ,"NAME"=:NEW."NAME" ,"VALUE"=:NEW."VALUE" ,"COMMENTS"=:NEW."COMMENTS" ,"SYS_LEVEL"=:NEW."SYS_LEVEL" ,"KIND"=:NEW."KIND" WHERE id_parameter=123; На этом начальное введение в m4 можно считать завершенным. Опыт написания объемных программных текстов с помощью m4 показал, что для этого достаточно знания основных встроенных макросов и использования описанных выше стандартных макросов для работы со списками и для реализации итераций. Тогда можно писать программные тексты произвольной масштабируемости — вводить с помощью списков декларативное описание структур и вперед!
СсылкиОригинальная документация на английском языке находится здесь. Базовый справочник и самоучитель (на русском языке), написанный разработчиками компании, находится [mk:@MSITStore:I:\docs\html\lib-book-tech\lib-book-tech.chm::/lib-m4.htm здесь].
Любые правки этой статьи будут перезаписаны при следующем сеансе репликации. Если у вас есть серьезное замечание по тексту статьи, запишите его в раздел «discussion». Репликация: База Знаний «Заказных Информ Систем» → «M4» |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||