my_title
ID: 3637954 • Letter: M
Question
Define an interesting macro in m4---------------------------------
Define and test a non-trivial macro, using the m4 macro processor.
"Non-trivial" should be read as "not as simple as 'factorial'".
Here are some possibilities to choose from. Any additions to the list
would be most welcome.
1. hanoi( N, `A', `B', `C' ) (where N is some integer) would be
expanded to a recipe for solving the problem of Towers of Hanoi
for N disks which should be moved from peg A to peg C, using B as
an auxiliary peg.
2. fib( N ) (where N is some integer) would be expanded to the N'th
Fibonacci number.
3. ... (Your own ideas.)
Your solution should be a file that contains the macro
definition and some example calls. It should be ready to run
on m4. In the head comment (use "dnl" for that) specify the version of m4 that you were using.
------------------------------------------------------------------------
Explanation / Answer
m4 is a great tool to boost your productivity. Have a lot of fun writing m4 scripts. This page will learn you the most essential parts, enough to start writing great scripts. Introduction to the m4 macro processor The m4 macro processor has been in use on Unix systems for a long time. The main purpose of m4 is to generate files. Initially m4 was created as a pre-processor for Fortran program code. This was about 30 years ago. Today m4 is used as a tool to generate configuration files, and is most famous as a generator of the sendmail.cf file. m4 is still very useful today. I use m4 mostly to generate xhtml files. The combination of awk, m4 and make provide a powerful tool and together they are a good replacement for a content management system. The combination of awk, m4 and make builds xhtml-files with good working links in menus. So it works like some kind of templating system. Also m4 helps me to separate content from (xhtml-)code I keep all the xhtml-code in one file, the content for each page in a separate content-file per page and have put the m4 scripts in a few files on their own. There is one single configuration file which contains a list of files to generate, with the page-titles, menu definitions etc. Output is generated by running make. The result of this: Change of xhtml-code requires only the editing of one file. Running make will build the new version of all the web pages through a single command. Adding a web page to the site is trivial. A line is added to the configuration file, telling the name of the new file, its title and if and how it should be adopted in the different menus of the site. The content of the new page is put in its own file in the content sub-directory. Running make will build the new web page and build new versions of the pages that have altered menus. Updating the content of a web page only requires the editing of the specific content file in the sub-directory and running make to build the new version of the web page. I have build a number of websites this way and have maintained them this way for some years now. And I am still happy with this solution :) Because all the scripts as well as the content are ordinary text files, it is very easy to keep them in a CVS repository. This allows not only for reversibility of changes but also provides a very good mechanism to keep everything neatly organized. As a bonus the CVS repository simplifies the backup procedures. Below follows a small introduction in the basic usage of m4. First steps in m4 The standard syntax of a macro definition in m4 is: define(`keyword',`replacement') Notice the back tick (`) and the single quote ('), these are the standard delimiters. Here we use it in an example: define(`yoo',`Hello World!') I say this: yoo Put this line into a file, called my_first_m4_program and run it with m4: m4 my_first_m4_program I say this: Hello World! Redirect the output of m4 to a file Because m4 transfers its output to stdout, it is very simple to redirect the output of m4 to a file: m4 my_first_m4_program > test_file cat test_file I say this: Hello World! We simply put " > filename" behind the m4 command. m4 macro definition A simple macro just replaces some part of the text on the input. Although this is a simple mechanism it lead to powerful m4 scripts. Literal text is placed between text-delimiters (standard: ` and '), variables not. The statement can be broken into several lines: define(`yoo', `Hello World!' ) I say this: yoo This will result in some extra white lines in the output, though. Also it is possible to let the second part of the statement be text that is several lines: define(`htmlheader', ` my_title ') Parameter list to mimic function-like calls A M4-definition can be enhanced with a parameter list: define(`my_value',`$1_file') my_value(`test') This last command (my_value(`test') returns the output test_file. The first parameter is addressed with $1, the second with $2, etc. Conditional statements in m4 Conditional statements enhances the usefulness of our scripts. This is the syntax: ifelse(`first_text',`second_text',`true_action',`false_action') ifelse: the m4 command first_text: this is the first parameter second_text: this is the second parameter true_action: this is the output if first parameter and second parameter are equal false_action: this is the output if first parameter and second parameter are not equal An example in real life usage: ifelse(my_filename,`index.html',`Home',`Home') This is a part of a m4 macro that creates the menu in a web page. If the current page has the filename "index.html" (which is fed to the macro in the variable my_filename) then the output is a line with just the word "Home", otherwise the output is a hyperlink to the homepage. Nesting macros m4 macros can be nested. This means that one macro uses the output of another macro to modify that. When combined with conditional statements this results in a very strong mechanism. define(`my_sidebar',`include(content/$1_sidebar)') Another, more complex example: define(`my_menu',`Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.