M4 - very short intro (Deutsch)
Einleitung
Die offizielle Doku gibt es hier: http://www.gnu.org/software/m4/manual/index.html Hier noch ein ganze kurze Einführung:
Von der Idee her, ist es mit dem C-Präprocessor vergleichbar, der ebenfalls Macro-Ersetzungen durchführt und das Ergebnis an den C-Compiler weiterleitet. Bei m4 ist das Ergebnisse lediglich der Text, den die Macro-Ersetzungen ergeben.
Wie es genau funktioniert, aber unbedingt nachlesen, da es manchmal auch auf die Feinheiten ankommt.
Kommentare werden mit # wie in C gekennzeichnet.
Es gibt keinen "Befehlsterminator" wie z.B. ein Semikolon.
Ersetzungen werden aber ähnlich wie ein Funktionen in einer Programmiersprache aufgerufen.
Wichtig ist auch die Quotierung mit ` und ' , die das Verhalten bei der Macro-Expandierung entscheidend beeinflusst. siehe hier und folgende http://www.gnu.org/software/m4/manual/m4.html#Quoting-Arguments
Macro definieren
Im Gegensatz zum C-Präprocessor wird hier ein sogenanntes "builtin" benutzt:
define(name, [expansion])
Zu beachten: werden die Argumente nicht quotiert, kann hier schon die Macro-Erweiterung zuschlagen, was dann zu unerwünschten Ergebnissen führen kann.
Mit den "Pseudo-Variablen" $1, $2, etc. kann man die Argumente des Macros in der Expansion referenzieren. Im Gegensatz zum C-Präprozessor, der überwiegend mit benannten Parametern arbeitet.
- $* - alle Argumente
- $@ - alle Argumente quotiert - Im Gegensatz zur vorhergehenden Variante werden die Argumente nicht weiter expandiert.
- $# - Anzahl der Argumente
Kontrol-Strukturen
Hiermit sind bedingte Ausführung und Schleifen gemeint.
- ifdef(name, string1, [string2])
- - wenn name definiert ist, dann ist das Ergebnis string1, sonst string2
- ifelse(string1, string2, equal1, string3, string4, equal2, ..., [not_equal])
- - wenn string1 = string2, dann equal1, sonst if string3 = string4, dann equal2, sonst ..., sonst not_equal
- join oder joinall([separator], [args....])
- - args zusammenfügen, Separator dazwischen setzen. Bei joinall wird immer der Separator gesetzt - auch wenn ein Argument leer ist.
- Rekursive Macro-Definitionen sind auch möglich - hilfreich dabei die shift Funktion, die jeweils das erste Argument abschneidet.
- forloop (iterator, start, end, text)
- - iterator muss ein gültiger Macroname sein, Start und Ende ganze Zahlen, der Text wird gemäß der Schleifendurchläufe ersetzt.
- foreach (iterator, paren-list, text) / foreachq (iterator, paren-list, text)
- - jedes Argument der parent-list wird an den Iterator gebunden und dann eine Ersetzung für Text ausgeführt.
divert
Da dieses Konstrukt häufig in Ethersex eingesetzt wird, hier noch ein paar Extra-Bemerkungen: Mit divert(<ausgabeidx>) wird ein Text-Abschnitt begonnen, der an der durch <ausgabeindex> definierten Stelle in die Ausgabe-Text eingefügt wird. <ausgabeidx> ist eine ganze, positive Zahl. Abschnitt 1 wird vor 2, 2 wird vor 3, usw. ausgegeben. Dabei spielt es keine Rolle, in welcher Reiehnfolge die Abschnitt in der m4-Quelldatei definiert werden.
Der Textabschnitt wird durch ein weiteres "divert" beendet, wobei "divert(-1)" dafür sorgt, dass kein neuer Abschnitt beginnt.
Sind mehrer Abschnitte mit dem gleichen <ausgabeidx> definiert, so werden sie mit der Reihenfolge ihrer Defnition ausgegeben.
Beispiel:
divert(3)dnl Das ist Abschnitt 3 divert(2)dnl Das ist Abschnitt 2a divert(1)dnl Das ist Abschnitt 1 divert(2)dnl Das ist Abschnitt 2b divert(-1)dnl
Die Ausgabe sind dann wie folgt aus:
Das ist Abschnitt 1 Das ist Abschnitt 2a Das ist Abschnitt 2b Das ist Abschnitt 3
Bemerkung: die Sprache ist sehr mächtig und man kann "Wildes" konstruieren, dass man nach 2 Tagen selber nicht mehr versteht ;-)
Wichtiges
- dnl - "Discard to next line" - Schließt die Zeile ab - alles nachfolgende wird ignoriert.
- changecom(<newcomment-start>) - ändert das Kommentarzeichen auf die angegebene Zeichenfolge (Defualt: #)