O p t i o n s - C o m p i l e r

Eine C-Funktion übernimmt die ganzheitliche Verarbeitung und Prüfung aller Optionsargumente von Kommandos und setzt sie in eine Gebrauchsform um.




extern int compilo(int, char**, char*, char*, int(*)(int,char*,int));

int main(int argc, char **argv)
{
   register int n;
   n= compilo(argc, argv, "options_syntax", oflags, ofunc);
   if (n<0)  /* ...ERROR... */ ;
   argc-=n, argv+=n;
   //...
   return (0);
}


Options-Syntax von compilo():
  bgrep   "c,l,v,f{},F{},e{}"
  bgrep1  "c,l,v,[f|F|e]{}"
  bgrep2  "c,l,v,{f|F|e}{}"
  DIR     "<^/,[:,l>,p,w,s,b,l,[ch|c],a[h|-h][s|-s][d|-d][a|-a][r|-r]"
  tar     "<^>#({c|r|u|x|t}[l,v,m,n,o,p,e,f!,b!,k!])"
  ar      "<^>,#{r|x|d|tv|t}{}"
  dd      "<^,{>,if={},of={},bs={},count={},skip={}"
  dd1     "<^,{=>,if{},of{},bs{},count{},skip{}"
  cc      "c,S,s,J,o{},O[0|1|2|3],K{frame,space,nolu}"
usw.,usw.,...


Der Quellkode compilo.c wird hier nicht gezeigt.




:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Beschreibender Artikel
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

# Anm.:  Ich unterscheide nachfolgend 'Listing' und 'Liste' !



O p t i o n s  -  C o m p i l e r



HELMUT SCHELLONG

Eine C-Funktion übernimmt die ganzheitliche Verarbeitung und Prüfung
aller Optionsargumente von Kommandos und setzt sie in eine
Gebrauchsform um.



Nahezu jedes ausführbare Programm ist ein Kommando, das nach seinem
Namen weitere Argumente berücksichtigt oder deren Angabe verlangt.
Bei Kennzeichnung, Anordnung, Ausgestaltung und sonstigen Festlegungen
von Optionen und ihren Werten gibt es einen großen Variantenreichtum,
wenngleich hier auch betriebssystemzugeordnete Schwerpunkte erkennbar
sind.
Die in diesem Artikel beschriebene und abgedruckte C-Funktion
'compilo()' kann innerhalb von Kommandos deren gesamte Argumentliste
einschließlich aller Werte und Wertkonstanten verarbeiten, prüfen und
umsetzen und den damit verbundenen, stets wiederkehrenden
Programmieraufwand fast vollkommen überflüssig machen.
Desweiteren verbessert sie -ganz unwillkürlich- die Einheitlichkeit
und Vollständigkeit von Kommandos.
Zusätzliche Wertschöpfungen werden möglich oder erleichtert, wenn
man mit Hilfe dieser Funktion beispielsweise verschiedene
Hilfsprogramme, die im Rahmen größerer Projekte für Test- und Analyse=
zwecke entstanden waren, nachträglich aufmöbelt und zu eigenen
Standard-Kommandos erhebt.

Der Auslöser zur Entwicklung von 'compilo' war dadurch begründet,
daß die Argumenteverarbeitung, wie übrigens auch die Programmierung
von ordentlichen Fehlermeldungs-Funktionen, durchaus von erheblichem
Aufwand sein kann und zudem häufig als sehr lästig empfunden
und (daher) mit schwankender Qualität uneinheitlich fertiggestellt
wurde.
Es ist nun mal spannender, den eigentlichen Kern von Programmen
zu entwickeln, als immer wieder gleiches und dann doch nicht gleiches
in Angriff zu nehmen!


Aufruf genügt:
--------------
Als erstes übergibt man der Funktion 'argc' und 'argv', so wie sie
in der Parameterliste der Hauptfunktion 'main' stehen (Listing 1).
Es folgt ein Zeichenketten-Parameter, der die Options-Syntax enthält,
mit der man die gewünschten Options-Worte und -Werte detailliert
und mit unterschiedlicher Restriktivität definieren kann.
Die letzten beiden Parameter sind Adressen von Objekten, die von der
Funktion beschrieben bzw. aufgerufen werden. Hier kann jeweils eine
Nulladresse (0) übergeben werden, um die Verwendung auszuschließen.
'oflags' zeigt auf ein char-Array, in das Options-Flags und
ab 'oflags+128' strukturierte Informationen abgelegt werden.
'ofu' zeigt auf eine Protokoll-Funktion, die von 'compilo' zu jedem
Vorgang mit drei Parametern aufgerufen wird. Mittels dieser Funktion
wird man gegebenenfalls besser informiert als nur mit den Daten aus
dem Protokoll-Array.
Der Rückgabewert von 'compilo' ist die Anzahl der von ihr bearbeiteten
Kommandoargumente, oder aber eine Fehlernummer, falls negativ.


Kann oder Muß:
--------------
Vorrang bei der Konzeption der Syntax hatte eine besonders einfache
Schreibweise für die Definition der meistgebrauchten Optionsvarianten.
Außerdem wurde darauf geachtet, möglichst umfassend eine bereits
bekannte Symbolik zu verwenden.
Wichtig war auch, einen guten und praxisorientierten Kompromiß
zwischen Syntax-Komplexität, dargebotenen Möglichkeiten und Code-Größe
der Funktion zu finden.
Zur Beschreibung von Kommandos und von Programmiersprachen wird
meistens eine bestimmte Syntax ergänzend verwendet, eine Syntax also,
mit der man eine andere Syntax beschreibt. Hieraus dürfte zumindest
die Optionalklammerung [] weithin bekannt sein.
Die Syntax von 'compilo' enthält viele Elemente daraus,
beispielsweise gibt es Kann-Klammern [] und Muß-Klammern {}.
Wer sich mal eine mächtige Anwendung dieser Syntax in allerbester
Ausführung anschauen möchte, der sei auf das Buch zur
Programmiersprache PEARL von Werum/Windauer, Vieweg Verlag, verwiesen.
Die Options-Syntax von 'compilo' wird schwerpunktmäßig mit Hilfe
dieser Beschreibungssyntax (Liste 1) und mittels vieler Beispiele
erklärt. Die Darstellungen in Liste 1 sind aus praktischen Gründen
stellenweise vereinfacht und damit leicht unpräzise.

Nachfolgend ein einführendes Anwendungsbeispiel anhand des
hypothetischen Kommandos 'bgrep', das drei Flag-Optionen  -c,-l,-v
und drei Optionen mit Wert  -e,-f,-F berücksichtigt. (Listing 1)
Im Kopfteil einer Handbuch-Beschreibung würde dann wohl folgende
Aufrufvorschrift (usage) zu sehen sein:

     bgrep  [-clv] { {-f|-F} sm_datei | [-e] sm }  [datei ...]

Die zugehörige compilo-Syntax ergibt sich folgendermaßen:

     "c,l,v,f{},F{},e{}"   oder   "c,l,v,[f|F|e]{}"
      1 2 3  4   5   6             1 2 3  4 5 6  7

Die Nummern werden von 'compilo' vergeben, zur identifizierenden
Verwendung in 'ofu' und 'oflags'.
Für das Anwendungsbeispiel in Listing 1 wurde diejenige Syntax mit
der größten resultierenden Flexibilität ausgewählt, die andererseits
jedoch einige Anweisungen zusätzlich erfordert.
Dies soll darauf aufmerksam machen, daß hier mehrere Optionen dem
selben Endzweck dienen und somit gegenseitig verriegelt werden müssen,
und daß Optionen im Regelfall mehrmals angegeben werden können.
Einfache Flag-Optionen dürfen untereinander in beliebiger Reihenfolge,
Häufigkeit und Kombination gesetzt werden.
'compilo' folgt dieser Praxis, kann aber mit unterschiedlichem Grad
restriktiv eingestellt werden, wovon der Aufwand abhängig ist, mit
dem man diese Funktion unterstützen muß.
Die zweite Syntax-Variante erzwingt, daß nur eine der Wert-Optionen
gegeben werden darf und spart etwas Aufwand, jedoch ein Wert kann
nicht mehr bündig (z.B. -Fdatei) angegeben werden.
Der minimalste Aufruf von 'bgrep' ist 'bgrep  sm',
woran man erkennt, daß dieser Aufruf ohne jede Option erfolgt
und zumindest in diesem Zusammenhang nicht von 'compilo' allein
bearbeitet werden kann.
Wenn Option -e oben nicht optional wäre, entstünde die Möglichkeit
zu einer weiteren Definition der Options-Syntax:
     "c,l,v,{f|F|e}{}"
Damit könnte man in Listing 1 den Aufwand noch weiter reduzieren,
indem nur noch Pointer-Zuweisungen nötig wären und nur noch auf
einen negativen Rückgabewert von 'compilo' reagiert werden müßte.

Die bisher gezeigten Syntax-Strings benutzen Voreinstellungen
bezüglich Options-Vorzeichen und Wert-Folgeart.
Es kann aber auch eine Kommando-Klammer <kommandos> hinzugefügt
werden, die diese und andere Einstellungen explizit angibt.
Die Listen 1 und 2 informieren hierüber.
Gar keins bis maximal drei einschaltende und maximal zwei abschaltende
Options-Vorzeichen können zugelassen werden.
Eine die Abarbeitung der Argumentliste abbrechende Zeichenkette, die
auch leer sein darf (-'') und in der Praxis zumeist -'-' ist, kann
angegeben werden.
Um bei mehreren Vorzeichen eine gemischte Angabe innerhalb eines
Kommandoaufrufs zuzulassen, muß 'vorzeichen-mix' gewählt werden.
Andernfalls wird das erste erkannte Vorzeichen festgeschrieben.
Flag-Optionen (Ein-Zeichen-Optionen ohne Wert) dürfen standardmäßig
untereinander hinter einem Vorzeichen kombiniert werden.
Um dies zu unterbinden, muß 'einzeln' gesetzt werden.
Kommando 'kommandoname' verhindert das Überspringen des Argumentes
'argv[0]', das durch diese Maßnahme ebenfalls prüfbar wird.
Kommando <l> bewirkt, daß Wert-Listen als Ein-Buchstaben-Listen
interpretiert werden, ohne das standardmäßige Komma (,) als
Trennzeichen zu erwarten. (s.u. dir-Beispiel)



Dann macht man's einfach:
-------------------------
Nachfolgend werden einige von UNIX und DOS her bekannte Kommandos
gezeigt, mit zugehöriger compilo-Syntax und Ident-Nummern, allerdings
nicht mit Angabe sämtlicher Original-Optionen.
Die Ident-Nummer beginnt mit 1 und wird hochgezählt nach jedem Namen
und jedem leeren Klammerpaar. Die einzige Ausnahme bildet eine
Standard-Wertoption (z.B. uvw{}), bei der Options-Name und
Beliebig-Wert (oder n-Zeichen-Wert) mit der gleichen Nummer belegt
und gleichzeitig an 'ofu' übergeben werden.

     tar  cruxt[vlmnopefbk]  [file] [blocking] [size]  [file...]
     "<^>,#({c|r|u|x|t}[v,l,m,n,o,p,e,f!,b!,k!])"
             1 2 3 4 5  6 7 8 9 10 .. 13 14 15

tar:
Hier sind gleich mehrere besondere Bestandteile der Syntax zu sehen.
Es gibt kein Vorzeichen <^>. Es wird eine Wort-Namen-Liste gebildet,
durch Angabe einer Muß-Oder- gefolgt von einer Kann-UndOder-Klammer.
Die beiden Klammerpaare werden durch runde Klammern ({}[]) eingefaßt,
damit auch die zweite Klammer als Options-Wort und nicht schon als Wert
interpretiert wird. Eine solche Option besteht aus mehreren Wort-Namen,
die in ein einziges Kommando-Argument gezwungen werden.
Das vordere Zeichen # erzwingt zusätzlich die erste Options-Position
und macht eigentlich erst Sinn, wenn zwei oder mehr Optionen
(option,option) im Syntax-String enthalten sind. Jedes Zeichen #
erhöht diesen Wert um 1. Das Zeichen ! ist eine Argument-Anforderung,
gekoppelt an das Vorkommen des zugehörigen Namens, die bewirkt, daß
(zuvor) unmittelbar das nächste Kommando-Argument als Wert gemeinsam
mit der Wort/Wert-Name-ID an 'ofu' weitergegeben wird. Normal-Werte
werden gegebenenfalls anschließend berücksichtigt. Pro Name können
mehrere Zeichen ! angegeben werden, erkannt wird es nur innerhalb von
Klammern. Auch Wort-Namen dürfen mehr als ein Zeichen enthalten,
solange Eindeutigkeit erhalten wird.

     ar  rxdt[v]  file.a  [name...]
     "<^>,#{r|x|d|tv|t}{}"  oder  "<^>,#({r|x|d|t}[v]){}"
            1 2 3 4  5  6                 1 2 3 4  5   6

ar:
Hierher kann man das zuvor Erklärte weitgehend übernehmen.
Ein Muß-Wert wurde definiert; Werte können bei Kombi-Optionen niemals
bündig sein, auch wenn das mittels <{> verlangt wurde.
Gemäß der zweiten Syntax-Variante kann 'v' auch ohne 't' vorkommen
und an beliebiger Position stehen.

    dir [/pwsbl/c[h]] [/a[[:]{[-]hsdar}]]  [datei]
    "<^/,[:,l>,p,w,s,b,l,[ch|c],a[h|-h][s|-s][d|-d][a|-a][r|-r]"
               1 2 3 4 5  6  7  8 9 10  11 12 13 14 15 16 17 18
    "<^/,[:,l>,p,w,s,b,l,ch,c,a[h,s,d,a,r,-h,-s,-d,-a,-r]"

dir:
Hier ist erstmals eine Namen-Kombination im Wert-Bereich zu sehen,
die als Wert-Liste keine runden Klammern ([][]) benötigt.
Die zweite Variante ist weniger restriktiv.
Folgenden DOS-typischen Aufruf kann 'compilo' nicht verarbeiten:
     dir/p \dos/a/oe/s
Das wäre einfach zu speziell und ist auch gar nicht nötig, denn unter
DOS kann man auch mit Zwischenraumzeichen eingeben. Zudem ermöglicht
'compilo' die Kombination von Flag-Optionen.
Wer das trotzdem realisiert haben möchte, muß 'argv' transformieren.
Umwandlung in Großbuchstaben ist möglich, indem man 'memcmp()' durch
eine entsprechende eigene Version ersetzt.

     dd  [if=inp_file] [of=outp_file] [bs=n] [count=n] [skip=n]
     "<^,{>,if={},of={},bs={},count={},skip={}"
              1     2     3        4       5
     "<^,{=>,if{},of{},bs{},count{},skip{}"

dd:
Auch hier ist die erste Variante etwas einengender, da die zweite
zuläßt, daß ein leerer String als Wert gegeben wird ('opt=').
Bei Definitionen ohne Vorzeichen darf eine mehrfach angegebene Option
unter Umständen nicht die letzte beim Kommando-Aufruf sein.
Das hängt mit der hier geltenden Abbruchbedingung für 'compilo'
zusammen.
Bei diesem Beispiel wird beendet, wenn kein Argument mehr da ist
oder 5 Optionen verarbeitet wurden. Falls jedoch rechtzeitig eine
Doppelangabe erkannt ist, wird das Maximum auf 6 erhöht.

     cc  [-cSsJ] [-o exefile] [-O[0123]] [-K frame,space,nolu]
     "c,S,s,J,o{},O[0|1|2|3],K{frame,space,nolu}"
      1 2 3 4  5  6 7 8 9 10 11  12   13    14
     "c,S,s,J,o{},O[?],K{frame,space,nolu}"
      1 2 3 4  5   6   7   8     9    10

cc:
Bei diesem Compiler-Kommando sind Standard-Wertlisten definiert.
Wertlisten werden zuvor gelöscht, damit sich bei mehrfacher Angabe
Namen nicht aufsummieren, was bei Oder-Klammern Fehlermeldungen gäbe.
Beim realen Kommando cc schließen sich -c,-S,-o gegenseitig aus,
-s macht bei -S und -c keinen Sinn, und so weiter.
Solche speziellen Abhängigkeiten müssen weitgehend außerhalb von
'compilo' behandelt werden.

     vi  [-RLl] [+cmd|-c cmd] [-w#] [-t tag] [-r file]  [file...]
     "<0,^-+,?>,#{view|vi|vedit},R,L,l,c{},w{},t{},r{},-{}"
                   1   2    3    4 5 6  7   8   9  10  11

vi:
Dieses Beispiel zeigt, wie ein Kommandoname kontrolliert wird.
Wegen '+cmd' ==> (-+,?  -{}) ist überdurchschnittlich viel
Zusatzaufwand nötig.
Nicht ohne Grund wird in Kommando-Beschreibungen darauf hingewiesen,
daß so manche traditionelle Schreibweise in Zukunft nicht mehr
implementiert sein könnte. Bestrebungen allerdings, daß zukünftig eine
Options-Syntax sich in "abc:d" erschöpfen soll, Werte (:) nur noch
nichtbündig sind, es nur noch Ein-Buchstaben-Optionen gibt, unbedingt
mit einem bestimmten Vorzeichen, gehen doch unverständlich weit.
Wie wollte man dann 'skip' und 'seek' des dd-Kommandos darstellen?



Protokoll komplett:
-------------------
Die Protokoll-Funktion 'ofu' wird für gegebene Optionen mit den
jeweils zugehörigen Ident-Nummern mindestens einmal aufgerufen
und gestattet eine genaue Kontrolle über alle Vorgänge.
Insbesondere kann die Reihenfolge des Eingangs der Optionen
berücksichtigt werden.
Bei Erstanwendungen wird empfohlen, die gesamte Arbeitsweise mittels
Ausgabe durch einen printf()-Aufruf zu begutachten.
Ein NULL-Pointer in 'wert' fordert auf, den entsprechenden Wert zu
löschen, falls einer definiert wurde. Das ist bei Mehrfachangaben
wichtig, besonders bei Wert-Listen. Generell zeigt ein NULL-Pointer
an, daß zur Ident-Nummer kein Wert erlangt werden konnte oder sollte.
Das gegebene Vorzeichen kann man hier zurückgewinnen, indem ein
positiver Wert von 'ovz' bereits das Einschalt-Vorzeichen
und ein negierter negativer Wert das Ausschalt-Vorzeichen ist.
Wenn 'compilo' einen Fehler feststellt, wird 'ofu' mit einer negativen
ID aufgerufen, die die Fehlernummer darstellt. Danach wird 'compilo'
verlassen - ebenfalls mit dieser Nummer.
Standardmäßig verläßt man die Protokoll-Funktion mit return=0,
jedoch bei Werten kleiner Null verhält sich 'compilo' so wie bei
internen Fehlern, mit der Ausnahme, daß dann vor Schluß nicht noch
'ofu' aufgerufen wird. Bei return>1 wird 'compilo' sofort beendet,
während bei return=1 erst noch die aktuelle Option abgearbeitet wird,
allerdings ohne 'ofu' aufzurufen.


Protokoll einfach:
------------------
Im Array 'oflags' werden Vorkommnisse von Ein-Zeichen-Optionen
aufaddiert. Eine Abfrage wäre beispielsweise 'if (O['a']) ;'.
Ab Adresse 'oflags+128' werden strukturierte Daten abgelegt:
     #pragma pack(1)
     struct { uchar nvk, *wert; };
     #pragma pack()
Abgefragt werden kann per Pointer-Konversion oder Struktur-Pointer,
wobei die Ident-Nummern als Index verwendet werden müssen.
nvk=0 ist Löschzustand und 'wert' hat dann keine Bedeutung.
Dieses Array sollte mindestens 200 Byte enthalten und muß mit Null
initialisiert sein. Letzteres ist bei global-Definition automatisch
der Fall.



Logisch:
--------
Die Syntax nach Liste 1 läßt logische Unkorrektheiten zu.
Einige Einschränkungen müssen daher aufgezählt werden.
Kann-Werte (o[]) sind implizit bündig. Bei mehreren Werten (o{}{})
kann nur der erste bündig sein, alle müssen Muß-Werte sein, und
bei 'o{}{}' werden drei ID vergeben - nicht zwei.
Ein Kombi-Optionswort darf nur einmal vorkommen. Ein bündiger Wert
dahinter ist nicht möglich. <Kommandos> werden hier übertrumpft.
Eine Wertliste besteht aus einer ununterbrochenen Reihe von Namen
und wird argumentmäßig als ein einziger Wert betrachtet.
Ein Beliebig-Wert ({}) säße unterbrechend zwischen zwei Listen
und besetzte ein separates Kommando-Argument.
Längere Wort- und Wertnamen sollten vor kürzeren stehen, falls
Eindeutigkeit bei vorderen Zeichen nicht vorliegt.
     "<^-+,?>,a{}{},-{}"
Alles, was nicht mit 'a' beginnt, ist ein Wert für die zweite Option.
Nach Positionswechsel finge sie auch 'a' als Wert ab.
Ein Trick besteht darin, einen Namen doppelt anzugeben, um dadurch
eine Wort-Namen-Liste zu erzeugen:
     "...,[dop|dop],..."
Namen dürfen hier nämlich nur innerhalb eines Argumentes erneut
auftauchen, was eine nutzbare Restriktion darstellt.


Schaltwerk compilo:
-------------------
Eine programmiermäßige Erklärung zur Funktion erfolgt in diesem
Artikel nicht. Sie ist von der Intention her als Library-Funktion
konzipiert, daher sehr kompakt und abschnittweise unübersichtlich
programmiert und in diesem Sinne als Vorführobjekt ungeeignet.
Deshalb nur ein paar kurze Hinweise:
In der ersten Schleife wird der Syntax-String in eine Datentabelle
umgesetzt. Weitere Tabellenspalten werden in den beiden darauf
folgenden Schleifen gefüllt. Danach wird die Argumentliste (C,*A)
unter Berücksichtigung der Tabelle abgearbeitet. In der beendenden
Schleife werden weitere Fehlersituationen geprüft.
Zwei Größen-Limits gibt es, und zwar beim Struktur-Array und beim
internen Syntax-String. Die Größenangaben brauchen nur an den
Definitionsstellen geändert werden, falls dafür Bedarf entsteht.

Der Code-Umfang liegt je nach Compiler und dessen Einstellungen
bei ungefähr 4000 Byte.
Wer eine Objekt-Datei (*.o) erzeugen will, muß zuvor die
Speicherklasse 'static' entfernen!
Angesichts des Quelltextes könnte man meinen, 'compilo' wäre langsam.
Dem ist aber nicht so! Die Funktion läuft durchschnittlich in
etwa hundert Mikrosekunden bzw. 6000 Pentium-Takten durch.



AUTOR:
Copyright (c) 1996  Helmut Schellong
Tiefer Grund 12
32108 Bad Salzuflen
schellong@t-online.de
http://home.t-online.de/home/schellong



Listing 1:
------------------------------------------------------------------------
// Anwendungs-Beispiel  compilo():

static char oflags[200], *Sm;

static int ofu(int id, char *wert, int ovz)
{
   //printf("%d, '%s', %d\n", id, wert, ovz);
   if (id<0)  Err(-id, wert);
   if (id==4)  Sm=wert, oflags['F']=oflags['e']=0;
   if (id==5)  Sm=wert, oflags['f']=oflags['e']=0;
   if (id==6)  Sm=wert, oflags['f']=oflags['F']=0;
   return (0);
}

int main(int argc, char **argv)
{
   register int n;
   n= compilo(argc, argv, "c,l,v,f{},F{},e{}", oflags, ofu);
   argc-=n; argv+=n;
   if (!Sm)  if (argc<1)  Err(E_ARGLST, "Suchmuster fehlt");
             else         Sm=*argv++, --argc;
   //. . .
   return (n);
}
------------------------------------------------------------------------


# Hinweis:
# Beide Syntaxformen verwenden | [] {}
# Deshalb:
# compilo-Syntax:     |  [ ]  { }
# Beschr.-Syntax:     ¦ ^[^] ^{^}
# Ideal wäre es, bei letzterer größer und dünner darzustellen,
# und natürlich dann ^ wegfallen zu lassen.
Liste 1:
------------------------------------------------------------------------
options-syntax :=  ^[<kdo^[,kdo^]...>,^]option^[,option^]...
        option :=  kann-option ¦ muß-option ¦ mußn-option
   kann-option :=  kann-wort^[wert^]
    muß-option :=   muß-wort^[wert^]
   mußn-option :=  #muß-wort^[wert^]
     kann-wort :=  name ¦ [liste] ¦ ([liste]...) ¦ - ¦ []
      muß-wort :=  {liste} ¦ ({liste}^[{liste}¦[liste]^]...) ¦ {}
     leer-wort :=  - ¦ [] ¦ {}
          wert :=  kann-wert ¦ muß-wert
     kann-wert :=  ^{ []¦[liste] ^}...
      muß-wert :=  ^{ {}¦{liste} ^}^[ {}¦[]¦{liste}¦[liste] ^]...
 beliebig-wert :=  [] ¦ {}
         liste :=  name^[ ^{|¦,^}name ^]...
          name :=  zeichen... ¦ n-zeichen-wert
n-zeichen-wert :=  ?...
  wert-anford. :=  !...name ¦ name!...            (innerh. []{})
      kommando :=  on-vorzeichen ¦ off-vorzeichen ¦ abbruch
                   wertfolgeart ¦ vorzeichen-mix ¦ einzeln
                   kommandoname ¦ 1-buchst-liste
 on-vorzeichen :=  ^ccc ¦ ^cc ¦ ^c ¦ ^                      (^-)
off-vorzeichen :=  ~cc ¦ ~c ¦ ~
       abbruch :=  $ccc ¦ $cc ¦ $c ¦ $
  wertfolgeart :=  [¦{¦[c¦{c¦[ ¦{ ¦[ c¦{ c                  ([ )
vorzeichen-mix :=  ?
       einzeln :=  e
  kommandoname :=  0
1-buchst-liste :=  l            (-o ^{^[!a-zA-Z^]...a-zA-Z^}...)
 std-wertliste :=               (-o name^[,name^]...)
maskierzeichen :=  %
------------------------------------------------------------------------


Liste 2:
------------------------------------------------------------------------
Wert-Folgearten:
   "<[>"     bündig
   "<{>"     bündig

   "<[:>"    bündig | bündig:
   "<{:>"    bündig:
   "<[ >"    bündig | nächstes arg
   "<{ >"    nächstes arg
   "<[ :>"   bündig | bündig: | nächstes arg
   "<[: >"   bündig | bündig: | nächstes arg
   "<{ :>"   bündig: | nächstes arg
   "<{: >"   bündig: | nächstes arg

Fehler-Nummern:
   -1     Syntax-Fehler  (compilo-Anwendung)
   -2     Unbekannte Option
   -3     Vorzeitiges Ende der Argumentliste
   -4     Falsche Options-Position
   -5     Unbekannter Wertname
   -6     Falsche Wertlänge bei ?...
   -7     Zuviel oder zuwenig Vorkommnisse von Namen bzw. Werten
   -8     Verteiltes Kombi-Optionswort
 <=-10    Selbstdefiniert:  ofu(){return <=-1;}
------------------------------------------------------------------------



Listing 2:
------------------------------------------------------------------------
# Siehe Datei compilo.c
------------------------------------------------------------------------