M4 - very short intro (Deutsch)

From Ethersex_Wiki
Jump to: navigation, search

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 (Default: #)