#ifndef SML3__FORMEL_H_
#define SML3__FORMEL_H_

/* ++++++++++++++++++++
 * +++ Beschreibung +++
 * ++++++++++++++++++++

  SML3_formel_rechne() berechnet eine Formel und gibt sie im letzten Arg zurueck.
  Die Kommastellenanzahl der einzelnen Zahlenwerte in der Formel kann angegeben
  werden, wobei je Wert gerundet wird: "2" z.B. bedeutet 2 Nachkommastellen.

  SML3_formel_expandvar() ermittelt einen Variablenamen und gibt das zugehoerige
  Hash-Element zurueck.

  SML3_formel_expandvalue() ermittelt einen Variablenwert und gibt ihn zurueck.

  SML3_formel_expandstring() ermittelt einen String (loest Variablen auf).

  SML3_formel_booltest() testet einen Bool-Ausdruck (Formel oder String).

  Mit den Funktionen SML3_formel_ebene_*() koennen SubCalls
  mit lokalen Variablen simuliert werden.


  Variablen:
  ----------
  - Der Variablenname darf nur aus [A-Za-z0-9_] bestehen
  - Der Variablenname eines Feldes beginnt mit '@',
    z.B. @A1 oder @B[X]
  - Den Wert einer Variablen erhaelt man mit vorangestelltem '$'
    (ohne '@' bei Feldern),
    z.B. $VAR oder $A1[1] oder $B[X][1]
  - Ein Feld kann beliebig viele Dimensionen haben mit '[...]',
    z.B. VAR1[Dim1][Dim2]
  - In den Dimensionen koennen alle Zeichen (ausser \0) verwendet werden
  - In den Dimensionen koennen Variablenwerte vorkommen, die aber die
    Dimension nicht ueberschreiten koennen,
    z.B. gesetzt ist: A="F][X"
         dann gilt:   B[$A] hat eine Dimension mit dem Inhalt "F][X"
  - In den Dimensionen muessen die Zeichen ']', '$' und '\' mit '\' gequotet
    werden, um sie als diese Zeichen zu verwenden,
    z.B. VAR1[a$b] hat als Dimensionswert "a<Wert von b>"
    z.B. VAR1[a\$b] hat als Dimensionswert "a$b"
    z.B. VAR1[a\\$b] hat als Dimensionswert "a\<Wert von b>"
  - Aufeinanderfolgende '$' werden von rechts nach links abgearbeitet
  - Um das Ende einer Variablen von einem darauffolgenden gueltigen Zeichen
    abzugrenzen, muss der Variablenname nach dem '$' mit '{' und '}' geklammert
    werden,
    z.B. der String "$ABC_def_012?WERT" verwendet die Variable "ABC_def_012"
    z.B. der String "${ABC_d}ef_012?WERT" verwendet die Variable "ABC_d"
  - Ein Teil des Wertes einer Variablen kann erhalten werden mit:
    ${<Variable>:<Offset ab 0>[:<Laenge>},
    z.B. gesetzt ist: A="1234", B="3"
         dann gilt:   ${A:1:2}="23"
                      ${A:1}="234"
                      ${A:$B}="4"
  - Variablennamen koennen durch weitere Variablen dargestellt werden,
    wobei diese darstellen koennen:
    - einen Teil vom Variablennamen
      z.B. gesetzt ist: B="C"
           dann gilt:   Variable $B ist die Variable C
                        Variable A$B ist die Variable AC
    - einen Teil vom Variablennamen und eine oder mehrere Dimensionen
      z.B. gesetzt ist: B="C[4]"
           dann gilt:   Variable A$B ist die Variable AC[4]
      z.B. gesetzt ist: B="[4][5]"
           dann gilt:   Variable A[1]${B}[9] ist die Variable A[1][4][5][9]
  - Variablen koennen verschiedenen Hashs zugewiesen sein; die Zugehoerigkeit
    wird durch einen vorangestellten Kenner und einem '#' dargestellt.
    Variablen mit Hashkenner sind global, und das zugehorige Hash ist ein
    Unterhash von hs_global mit Key=Hashkenner im Struct fuer Variablen-Hashes.
    Variablen ohne Hashkenner sind lokal, und das zugehorige Hash ist hs_lokal
    der aktuellen Ebene (eb_pos) im Struct fuer Variablen-Hashes.
    Der Hashkenner kann auch durch eine Variable dargestellt werden,
    z.B. "ABC#F" ist die Variable "F" im Unterhash von hs_global mit Key "ABC"
    z.B. "F" ist die Variable "F" in hs_lokal der aktuellen Ebene
    z.B. gesetzt ist: G="ABC" und H="F"
         dann gilt:   Variable ${G}#$H ist die Variable ABC#F
    z.B. gesetzt ist: G="ABC#" und H="F"
         dann gilt:   Variable $G$H ist die Variable ABC#F
  - Eine Sondervariante sind die Referenzvariablen im Hash hs_ref der
    aktuellen Ebene.
    Sie verweisen auf eine Variable der naechsthoeheren Ebene, die damit in der
    aktuellen Ebene gelesen und gesetzt werden kann. Referenzvariablen verweisen
    immer sowohl auf die Variable als auch das Feld mit gleichem Namen.
    Referenzvariablen beginnen mit '#', der Name ist ein Kenner, mit dem
    die Variable hoeherer Ebene ermittelt werden kann, und eventuelle folgende
    Dimensionen beziehen sich auf die ermittelte Variable.
    Referenzvariablen koennen auch auf Referenzvariablen hoeherer Ebene
    verweisen.
    Z.B. Referenzvariable #X verweist auf
         naechsthoehere Ebenen-Variable D[1][2],
         dann gilt:  #X = D[1][2]       (auf der naechsthoeheren Ebene)
         dann gilt:  #X[Y] = D[1][2][Y] (auf der naechsthoeheren Ebene)
    Z.B. Referenzvariable #X verweist auf
         naechsthoehere Ebenen-Referenzvariable #Y,
         und #Y verweist auf naechsthoehere Ebenen-Variable D[1][2],
         dann gilt:  #X = D[1][2]       (auf der uebernaechsthoeheren Ebene)
         dann gilt:  #X[Y] = D[1][2][Y] (auf der uebernaechsthoeheren Ebene)
    Somit ist die Referenz sowohl fuer das Feld @D[1][2] als auch
    fuer die Variable D[1][2] gegeben.
  - Die Prioritaet von '$' ist niedriger als von '#',
    z.B. gesetzt ist: VAR="ENV" und ENV#A1="4" und VAR#A1="3"
         dann gilt:   $ENV#A1    == "4"
                      $$VAR#A1   == ${$VAR#A1} == ${${VAR#A1}} == ${3} == (leer)
                      ${$VAR}#A1 == ${${VAR}#A1} == ${ENV#A1} == 4
  - Es gilt allgemein:
    $A[1]   ==  ${A[1]}
    $$A[1]  ==  ${$A[1]}  ==  ${${A[1]}}
    z.B. gesetzt ist: A="B" und A[1]="3" und B[1]="7"
         dann gilt:   $A[1]     ==  ${A[1]}    ==  "3"
                      ${A}[1]   ==  B[1]
                      $${A}[1]  ==  ${${A}[1]} == $B[1] == "7"
  - Beim Stringparsen gilt:
    $A$B sind 2 Variablen hintereinander: $A und $B
    ${A$B} ist eine Variable mit Namen "A<Inhalt von B>"
    $$A[1]$B sind 2 Variablen hintereinander: $$A[1] und $B
    ${$A[1]$B} ist eine Variable mit Namen "<Inhalt von A[1]><Inhalt von B>"
    z.B. gesetzt ist: A="a" und C="c" und D="d"
                      und B[cd]="b" und ab="d" und d[E]="e"
         dann gilt:   $${$A${B[$C$D]}}[E]
                    = ${${${A}${B[$C$D]}}[E]}
                    = ${${${A}${B[$C$D]}}[E]}
                    = ${${a${B[$C$D]}}[E]}
                    = ${${a${B[c$D]}}[E]}
                    = ${${a${B[cd]}}[E]}
                    = ${${ab}[E]}
                    = ${d[E]}
                    = e
+++ */


/* ++++++++++++++++
 * +++ Beispiel +++
 * ++++++++++++++++

  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <sys/types.h>
  #include <unistd.h>
  #include <errno.h>
  #include <sammel3.h>

  // Funktion zur Ausgabe der Hash-Eintraege
  static void
  ausgabe(struct SML3_hash *hs1, struct SML3_hashelem *he1)
  {
    struct SML3_hash *hsptr;
    const void *cptr;

    hsptr = SML3_hashtophash(hs1);
    // Key
    if (SML3_hashelem_keypath(&hsptr, he1, &cptr, NULL)) {
      printf("%s", (const char *)cptr);
    }
    while (SML3_hashelem_keypath(&hsptr, he1, &cptr, NULL)) {
      printf("[%s]", (const char *)cptr);
    }
    // Value
    printf(" = \"%s\"\n", (char *)SML3_hashelem_valget(he1, NULL));
  }

  // gibt Hilfe aus
  static void
  hilfe(void)
  {
    printf("\nLese ein bis EOF:\n");
    printf(" - <Variable>=<Wert>\n");
    printf("   => setzt <Variable> auf <Wert>\n");
    printf(" - \"+\" [<Referenzvariable>=<referenzierter Variablenname> ...]\n");
    printf("   => geht eine Ebene hinab, referenziert evtl. Variablen\n");
    printf(" - \"-\"\n");
    printf("   => geht eine Ebene hinauf\n");
    printf(" - \":\" <Formel>\n");
    printf("   => berechnet Formel\n");
    printf(" - \"=\" <Boolscher Ausdruck>\n");
    printf("   => ermittelt wahr oder falsch\n");
    printf(" - \"?\"\n");
    printf("   => gibt diese Hilfe aus\n");
  }

  // Hauptfunktion
  int
  main(int argc, char **argv)
  {
    struct SML3_formel_vhash *vhash;
    struct SML3_hash *hs1;
    struct SML3_hashelem *he0, *he1;
    int i1;
    char buf[1024], *pkey, *pval;

    // Struct fuer die Variablen-Hashes fuer 5 Ebenen erhalten
    vhash = SML3_formel_ebene_new(5);

    // stdin bis EOF einlesen und alle gesetzten Variablen ausgeben

    hilfe();

    for (;;) {

      // einlesen
      printf("\nEingabe: "); fflush(stdout);
      if (fgets(buf, sizeof(buf), stdin) == NULL) { break; }
      SML3_schnipp(buf, " \t\r\n", 3);
      pkey = buf;

      if (*pkey == '+') {  // Ebene hinabgehen
        struct SML3_hash *hsref = SML3_hashnew(NULL, 0);
        char *pend;
        pkey++;
        // parsen auf wiederholte Referenzvariablen: <Referenzvariable>=<referenzierter Variablenname> ...
        for (;;) {
          pkey += strspn(pkey, " \t");  // Referenzvariable
          pend = strpbrk(pkey, " \t");  // Leerzeichen oder Stringende
          if (pend != NULL) { *pend = '\0'; }
          pval = strchr(pkey, '=');  // referenzierter Variablenname
          if (pval != NULL) {
            *pval++ = '\0';
            // hsref setzen: <Referenzvariable> = <referenzierter Variablenname>
            SML3_hashelem_valset(SML3_hashset(hsref, pkey, strlen(pkey) + 1), pval, strlen(pval) + 1);
          }
          if (pend == NULL) { break; }
          pkey = pend + 1;
        }
        SML3_formel_ebene_down(vhash, hsref);
        SML3_hashfree(&hsref);

      } else if (*pkey == '-') {  // Ebene hinaufgehen
        SML3_formel_ebene_up(vhash);

      } else if (*pkey == ':') {  // Formel berechnen
        SML3_int64 iwert;
        double dwert;
        int prez = -1;

        pkey++; pkey += strspn(pkey, " \t");
        if (SML3_formel_rechne(vhash, &iwert, &dwert, &prez, pkey, NULL) != NULL) {
          printf(" => Formelberechnung ergibt: ");
          if (prez == 0) {  // Ergebniswert ist Ganzzahl in iwert
            printf("%" SMLINT64_FORMAT "d\n", iwert);
          } else {  // Ergebniswert ist Bruchzahl in dwert
            printf("%.2f\n", dwert);
          }
        } else {
          fprintf(stderr, "%s\n", SML3_fehlermsg());
        }
        printf("[Return] "); fflush(stdout);
        if (fgets(buf, sizeof(buf), stdin) == NULL) { break; }

      } else if (*pkey == '=') {  // boolschen Ausdruck ermitteln
        pkey++; pkey += strspn(pkey, " \t");
        if (SML3_formel_booltest(vhash, -1, 0, pkey, NULL, &i1) != NULL) {
          printf(" => boolscher Ausdruck ergibt: %s\n", i1 ? "wahr" : "falsch");
        } else {
          fprintf(stderr, "%s\n", SML3_fehlermsg());
        }
        printf("[Return] "); fflush(stdout);
        if (fgets(buf, sizeof(buf), stdin) == NULL) { break; }

      } else if (*pkey == '?') {  // Hilfe ausgeben
        hilfe();
        printf("[Return] "); fflush(stdout);
        if (fgets(buf, sizeof(buf), stdin) == NULL) { break; }

      } else if (*pkey != '\0') {  // Variable setzen
        pval = strchr(pkey, '=');
        if (pval == NULL) { continue; }
        *pval++ = '\0';
        pval += strspn(pval, " \t");
        // Key ermitteln und Hashelement erhalten
        if (SML3_formel_expandvar(vhash, &he1, pkey, NULL, 1) == NULL) {
          fprintf(stderr, "%s\n", SML3_fehlermsg());
          break;
        }
        if (!SML3_hashelem_typ_is_normal(he1)) { continue; }  // ist keine Variable, ist vermutlich Feld
        // Value setzen
        if (*pval == '\0') {  // loeschen
          SML3_hashdel(he1);
        } else {  // setzen, dabei Variablenwerte aufloesen
          struct SML3_gummi gm1 = SML3_GUM_INITIALIZER;
          size_t gmpos = 0;
          if (SML3_formel_expandstring(vhash, &gm1, &gmpos, 0, pval, NULL) == NULL) {
            fprintf(stderr, "%s\n", SML3_fehlermsg());
            break;
          }
          SML3_hashelem_valset(he1, SML3_gumgetval(&gm1), gmpos + 1);
          SML3_gumdest(&gm1);
        }
      }

      // ausgeben
      printf("\nAusgabe:\n");
      printf(" - globale Hashs:\n");
      for (he0 = SML3_hashsublist(vhash->hs_global, NULL); he0 != NULL; he0 = SML3_hashsublist(vhash->hs_global, he0)) {
        printf(" - %s#:\n", (char *)SML3_hashelem_keyget(he0, NULL));  // Hashkenner
        hs1 = SML3_hashsubhash(he0);
        for (he1 = SML3_hashlist(hs1, NULL, 1); he1 != NULL; he1 = SML3_hashlist(hs1, he1, 1)) {
          printf("   ");
          ausgabe(hs1, he1);
        }
      }
      printf(" - lokale Ebenen-Hashs:\n");
      for (i1 = 0; i1 <= vhash->eb_pos; i1++) {
        printf("   - Ebene %d:\n", i1 + 1);
        printf("     - Variablenhash:\n");
        for (he1 = SML3_hashlist(vhash->ebene[i1].hs_lokal, NULL, 1); he1 != NULL; he1 = SML3_hashlist(vhash->ebene[i1].hs_lokal, he1, 1)) {
          printf("       ");
          ausgabe(vhash->ebene[i1].hs_lokal, he1);
        }
        printf("     - Referenzhash:\n");
        for (he1 = SML3_hashlist(vhash->ebene[i1].hs_ref, NULL, 1); he1 != NULL; he1 = SML3_hashlist(vhash->ebene[i1].hs_ref, he1, 1)) {
          printf("       ");
          ausgabe(vhash->ebene[i1].hs_ref, he1);
        }
      }
    }
    printf("\n");

    // Struct fuer die Variablen-Hashes freigeben
    SML3_formel_ebene_free(&vhash);

    exit(0);
  }
+++ */


/* ++++++++++++++++++ */
/* +++ Funktionen +++ */
/* ++++++++++++++++++ */

#include <sys/types.h>

/* struct fuer Variablen-Hashes */
struct SML3_formel_vhash {
  struct SML3_hash *hs_global;  /* globales Variablenhash ueber alle Ebenen (Hashkenner sind Keys von Unterhashes) */
  int eb_max;                   /* maximale Anzahl Ebenen */
  int eb_pos;                   /* aktuelle Ebenenposition (oberste Ebene = Startebene = 0) */
  struct {                      /* Feld fuer Ebenen */
    struct SML3_hash *hs_lokal;   /* lokales Variablenhash */
    struct SML3_hash *hs_ref;     /* Referenzvariablenhash: <Referenzname> = <referenzierter Variablenname (ohne $ oder @)> */
  } *ebene;
};


/** SML3_formel_expandvar [thread-sicher]:
 * loest Variable auf, setzt deren Hash-Element in 2.Arg
 * 1.Arg: Struct fuer die Variablen-Hashes (struct SML3_formel_vhash)
 * 2.Arg: fuer Rueckgabe Hash-Element der auszuwertenden Variable,
 *        falls Variable ein Feld ist, wird Hash-Element eines Subhashs zurueckgegeben
 * 3.Arg: Startpointer Variablenname
 *        (normale Variable: Beginn auf Variablennamen, Feldvariable: Beginn auf Feldzeichen '@')
 * 4.Arg: Endepointer Gesamtstring (exkl.) oder NULL = bis Stringende
 * 5.Arg: ob Hash-Element anlegen, falls nicht vorhanden (0 = nein, 1 = ja, -1 = nein (will nur Variablenende haben))
 * Rueckgabe: Pointer auf Zeichen hinter Variablenname oder NULL = Fehler
 * SML3-errno-Wert: EINVAL = Fehler Uebergabeparameter
 *
 * Variablennamen und ihre Dimensionswerte koennen nicht binaer sein,
 * sie haben jeweils zum Schluss ein 0-Zeichen.
 *
 * Soll das Hash-Element eines Subhashs fuer einen Hashkenner zurueckgegeben werden,
 * wird im 2.Arg der Hashkenner mit '#' als Feldvariable uebergeben,
 * z.B.:  um das Hash, in dem alle Variablen von "ABC#" liegen, zu erhalten,
 *        wird im 2.Arg uebergeben: "@ABC#"
 */
extern const char * SML3_formel_expandvar(struct SML3_formel_vhash *, struct SML3_hashelem **, const char *, const char *, int);


/** SML3_formel_expandvalue [thread-sicher]:
 * ermittelt Variablenwert, setzt ihn in 2.+3.Arg
 * 1.Arg: Struct fuer die Variablen-Hashes (struct SML3_formel_vhash)
 * 2.Arg: fuer Rueckgabe Variablenwert
 * 3.Arg: fuer Rueckgabe Anzahl Zeichen im 2.Arg
 * 4.Arg: Startpointer Variablenname (Beginn auf Variablenzeichen '$')
 * 5.Arg: Endepointer Gesamtstring (exkl.) oder NULL = bis Stringende
 * Rueckgabe: Pointer auf Zeichen hinter Variablenname oder NULL = Fehler
 * SML3-errno-Wert: EINVAL = Fehler Uebergabeparameter
 */
extern const char * SML3_formel_expandvalue(struct SML3_formel_vhash *, struct SML3_gummi *, size_t *, const char *, const char *);


/** SML3_formel_rechne [thread-sicher]:
 * errechnet Formel
 * Eine Formel besteht aus:
 *  - Zahlen:
 *    - Ganzzahlen
 *    - Bruchzahlen mit '.'
 *  - Variablen: 
 *    - Wert = String: repraesentiert Zahl
 *  - Operatoren:
 *    - Einer-Ops: Vorzeichen: + -
 *                 Negation: !
 *                 Einer-Komplement: ~
 *    - Zweier-Ops: Bitweise: & | ^   (niedrigste Prioritaet)
 *                  Shift: << >>      (naechsthoehere Prioritaet)
 *                  Strich: + -       (naechsthoehere Prioritaet)
 *                  Punkt: * / %      (hoechste Prioritaet)
 *  - Klammern
 *  - mathematischen Funktionen (z.B. sqrt())
 * 1.Arg: Struct fuer die Variablen-Hashes (struct SML3_formel_vhash)
 * 2.Arg: fuer Rueckgabe Formelwert als SML3_int64
 * 3.Arg: fuer Rueckgabe Formelwert als double
 * 4.Arg: Wert: gewuenschte Kommastellenanzahl je Einzelwert (0 - 9) oder -1 = egal
 *        Rueckgabe: 0 = Formelwert ist Ganzzahl, 1 = keine Ganzzahl
 * 5.Arg: Startpointer Formel
 * 6.Arg: Endepointer Gesamtstring (exkl.) oder NULL = bis Stringende
 * Rueckgabe: Pointer auf Zeichen hinter Formel oder NULL = Fehler
 * SML3-errno-Wert: EINVAL = Fehler Uebergabeparameter
 *                  ERANGE = Wert einer Funktion nicht darstellbar
 */
extern const char * SML3_formel_rechne(struct SML3_formel_vhash *, SML3_int64 *, double *, int *, const char *, const char *);


/** SML3_formel_expandstring [thread-sicher]:
 * ermittelt String (loest Variablen auf), setzt ihn in 2.+3.Arg.
 * Ermittlung geht bis zum nicht gequoteten Endezeichen, falls gesetzt,
 * maximal aber bis zum Endepointer Gesamtstring. Quotung mit Backslash.
 * Verarbeitet Escapesequenzen!
 * 1.Arg: Struct fuer die Variablen-Hashes (struct SML3_formel_vhash)
 * 2.Arg: fuer Rueckgabe ermittelten String
 * 3.Arg: Startposition im 2.Arg (wird aktualisiert)
 * 4.Arg: Endezeichen oder 0 = keins
 *        Falls 0 (kein Endezeichen), werden mehrere Spaces durch eins ersetzt
 *        und am Anfang und Ende entfernt,
 *        Falls 256 (auch kein Endezeichen), bleiben die Spaces
 * 5.Arg: Startpointer String
 * 6.Arg: Endepointer Gesamtstring (exkl.) oder NULL = bis Stringende
 * Rueckgabe: Pointer auf Zeichen hinter Stringende (z.B. Endezeichen)
 *            oder NULL = Fehler
 * SML3-errno-Wert: EINVAL = Fehler Uebergabeparameter
 */
extern const char * SML3_formel_expandstring(struct SML3_formel_vhash *, struct SML3_gummi *, size_t *, int, const char *, const char *);


/** SML3_formel_booltest [thread-sicher]:
 * testet Bool-Ausdruck,
 * - miteinander verglichen werden koennen:
 *   - Formeln: Vergleichsoperatoren sind:
 *     -eq  (gleich)
 *     -ne  (ungleich)
 *     -ge  (groesser gleich)
 *     -le  (kleiner gleich)
 *     -gt  (groesser)
 *     -lt  (kleiner)
 *   - Strings: Vergleichsoperatoren sind:
 *     =~  (reg. Ausdruck: enthaelt (case-insensitive))
 *     !~  (reg. Ausdruck: enthaelt nicht (case-insensitive))
 *     =   (gleich)
 *     !=  (ungleich)
 *     >=  (groesser gleich)
 *     <=  (kleiner gleich)
 *     >   (groesser)
 *     <   (kleiner)
 *   - die Stringvergleichoperatoren ohne reg. Ausdruck koennen mit Zusatz sein
 *     - {i}  = Vergleich case-insensitive
 *     - {u}  = Vergleich von 2 UTF-8 Strings (werden evtl. vorher konvertiert)
 *     - {ui} = Vergleich case-insensitive von 2 UTF-8 Strings (werden evtl. vorher konvertiert)
 *       {iu} = Vergleich case-insensitive von 2 UTF-8 Strings (werden evtl. vorher konvertiert)
 *     (Bsp: "Text1" >={ui} "Text2")
 * - einzelne Vergleiche koennen mit boolschem UND und ODER verbunden werden:
 *     &&  (UND)
 *     ||  (ODER)
 * - geklammert werden die Vergleiche mit '(' und ')'
 * 1.Arg: Struct fuer die Variablen-Hashes (struct SML3_formel_vhash)
 * 2.Arg: falls Formel: gewuenschte Kommastellenanzahl je Einzelwert oder -1 = egal
 * 3.Arg: Endezeichen oder 0 = keins
 * 4.Arg: Startpointer String
 * 5.Arg: Endepointer Gesamtstring (exkl.) oder NULL = bis Stringende
 * 6.Arg: fuer Rueckgabe, ob wahr (=1) oder falsch (=0)
 *        oder NULL = nicht ermitteln
 * Rueckgabe: Pointer auf Zeichen hinter Bool-Ausdruck oder NULL = Fehler
 * SML3-errno-Wert: EINVAL = Fehler Uebergabeparameter
 */
extern const char * SML3_formel_booltest(struct SML3_formel_vhash *, int, int, const char *, const char *, int *);


/** SML3_formel_ebene_new [thread-sicher]:
 * gibt neues Struct fuer die Variablen-Hashes zurueck
 * 1.Arg: maximale Anzahl Ebenen
 * Rueckgabe: Struct fuer die Variablen-Hashes
 */
extern struct SML3_formel_vhash * SML3_formel_ebene_new(int);


/** SML3_formel_ebene_free [thread-sicher]:
 * gibt Struct fuer die Variablen-Hashes frei
 * 1.Arg: Adresse auf Struct fuer die Variablen-Hashes
 */
extern void SML3_formel_ebene_free(struct SML3_formel_vhash **);


/** SML3_formel_ebene_down [thread-sicher]:
 * geht eine Ebene hinab
 * 1.Arg: Struct fuer die Variablen-Hashes
 * 2.Arg: Hash mit Referenzvariablen: <Referenzname> = <referenzierter Variablenname>
 *                                    (z.B.:  "#name" = "D[1][2]")
 *        oder NULL
 * Rueckgabe: 0 = OK oder -1 = Fehler
 * SML3-errno-Wert: EINVAL = Fehler Uebergabeparameter
 *                  ENOSPC = tiefste Ebene bereits erreicht
 */
extern int SML3_formel_ebene_down(struct SML3_formel_vhash *, struct SML3_hash *);


/** SML3_formel_ebene_up [thread-sicher]:
 * geht eine Ebene hinauf
 * 1.Arg: Struct fuer die Variablen-Hashes
 * Rueckgabe: 0 = OK oder -1 = Fehler
 * SML3-errno-Wert: EINVAL = Fehler Uebergabeparameter
 *                  ENOSPC = hoechste Ebene bereits erreicht
 */
extern int SML3_formel_ebene_up(struct SML3_formel_vhash *);

#endif /* SML3__FORMEL_H_ */
