home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1991 / 04 / txl / 2_preis / source / test.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-01-21  |  21.6 KB  |  807 lines

  1. /******************************************************
  2. *                      INTUTIL.C                      *
  3. *    Dieses  File  enthält  Utility-Funktionen zum    *
  4. *    Erstellen eines neuen Interpreterbefehls oder    *
  5. *    dessen Ausführung.                               *
  6. *          (c) 1991 Ralf Morgenstern & toolbox        *
  7. *    Dieses File beinhaltet NUR DIE ÄNDERUNGEN zur    *
  8. *    Grundversion von "INTUTIL.C". Wo es mit altem    *
  9. *    Sourcecode weitergeht, zeigt "..." an!!!!!!!!    *
  10. ******************************************************/
  11. ...
  12.  
  13. int  CmpVar (void);
  14. int  Compare (int Op);
  15. int  ReadComp (int *Op);
  16.  
  17. void ClearProg (void);
  18.                                   /* die neuen Funktionen */
  19. void    Expression (void);
  20. void    Term (void);
  21. void    Faktor (void);
  22. int     TestFunc (int *func);
  23. void    NewString (VARDEF *Var,size_t len);
  24. void    MinMax (int Ops, int minmax);
  25. void    Length (void);
  26. void    Left (void);
  27. void    Right (void);
  28. void    Mid (void);
  29. void    InStr(void);
  30.  
  31. int TestComma (void);
  32. int GetStringVar (VAR **str);
  33. int GetLong (long *val);
  34. ...
  35.  
  36. static int expOk;/* ist der ausgewertete Ausdruck korrekt */
  37.  
  38. /* die Namen der Interpreterfunktionen */
  39. static  char    *ifuncs[] = { "sqr","sqrt","sin","cos","tan"
  40.                              ,"atan","ln","exp","min","max",
  41.                               "laenge",  "links",  "rechts"
  42.                               ,"mitte", "suche", NULL };
  43.  
  44.                       /* und zugehörige Tokens zum Aufruf */
  45. #define  NEGOP  'a'
  46. #define  SQROP  'b'
  47. #define  SQRTOP 'c'
  48. #define  SINOP  'd'
  49. #define  COSOP  'e'
  50. #define  TANOP  'f'
  51. #define  ATANOP 'g'
  52. #define  LNOP   'h'
  53. #define  EXPOP  'i'
  54.  
  55. /* BEACHTE : einige der Funktionen werden direkt (also nicht
  56.              über CalcResult aufgerufen), und brauchen daher
  57.              kein Token.                                  */
  58. ...
  59.  
  60.  if ( Steuer != EOLCHAR ){
  61.    serror( "unerwartetes Zeilenende" ); return(ERROR);
  62.  }
  63.  
  64. ...
  65.  
  66. /* NewString : neuen String bereitstellen oder
  67.                den Speicher auf neue Grö₧e erweitern
  68. */
  69. void NewString ( Var,len )
  70. VARDEF   *Var;
  71. size_t   len;
  72. {
  73.   len++; /* für '\0' Abschlu₧ */
  74.   if ( Var->variable.text == NULL )
  75.     Var->variable.text = calloc( len,sizeof(char));
  76.   else
  77.      Var->variable.text = realloc( Var->variable.text,len );
  78. }
  79. /* Einlesen eines Ausdrucks von der gerade aktuellen
  80.    Eingabeposition ab.
  81. */
  82. void
  83. ReadValue (Wert)
  84. VAR *Wert;
  85. {
  86.  Scan ();           /* Nächster Ausdruck von Eingabezeile */
  87.  switch (Steuer) {
  88.    case ZIFFER:
  89. /*
  90.  Wert->VarType = FIXNUM;
  91.  Wert->VarWert.variable.integer = atoi (ScanBuffer);
  92.  break;
  93.  führt sonst zu Fehler, da CalcExpression nur FLONUM liefert
  94. */
  95.  case FLONUM:
  96.      Wert->VarType = FLONUM;
  97.      Wert->VarWert.variable.Flotype = atof (ScanBuffer);
  98.    break;
  99.  case STRING:
  100.      Wert->VarType = STRING;
  101.         NewString ( &Wert->VarWert,strlen( ScanBuffer ));
  102.      strcpy (Wert->VarWert.variable.text,ScanBuffer);
  103.    break;
  104.  case ALPHA:
  105.  printf ("\nVariablenzuweisung noch nicht implementiert! ");
  106.    break;
  107.  case SONDER:
  108.      if (*ScanBuffer == '(') {
  109.      }
  110.      else
  111.      printf ("\nUngültiges Zeichen in Ausdruck gefunden! ");
  112.  }
  113. }
  114. /*----     SetValue Setze den Wert der Variable ----------*/
  115. void
  116. SetValue (NewVar,Wert,Type)
  117. VARDEF *NewVar,*Wert;
  118. unsigned char Type;
  119. {
  120.   switch (Type) {
  121.  case FIXNUM:
  122.      NewVar->variable.integer = Wert->variable.integer;
  123.    break;
  124.  case FLONUM:
  125.      NewVar->variable.Flotype = Wert->variable.Flotype;
  126.    break;
  127.  case ALPHA:  /* ist das so korrekt ? was mit Variablen ? */
  128.      NewVar->variable.zeichen = Wert->variable.zeichen;
  129.    break;
  130.  case STRING:
  131.      if ( NewVar->variable.text != NULL )
  132.        free( NewVar->variable.text );
  133.      NewVar->variable.text = Wert->variable.text;
  134.    break;
  135.    default:
  136.    printf ("\nZuweisung für diesen Typ nicht definiert!\n");
  137.    break;
  138.  }
  139. }
  140. ...
  141.  
  142. /* CmpVar vergleicht zwei Variablen auf
  143.    Größer, Kleiner oder Gleich.
  144. */
  145. int CmpVar ()
  146. {
  147. int  rel;
  148. int  Op;
  149.  BotStack = TopStack = malloc (EXPSTACK * sizeof(EXPDEF));
  150.  Scan ();                     /* Erstes Argument lesen... */
  151.  expOk = TRUE; Expression();         /* ... und auswerten */
  152.  if ( !expOk ){
  153.    serror ("Ungültiger 1. Ausdruck gefunden! ");
  154.    return (FALSE); /* Bedingung fehlerhaft */
  155.     }
  156.     if ( ReadComp( &Op ) == FALSE ){
  157.      serror ("Vergleichsoperator erwartet! ");
  158.    return (FALSE); /* Bedingung fehlerhaft */
  159.  }
  160.  Scan();      /* Zweites Argument lesen... */
  161.  expOk = TRUE; Expression();         /* ... und auswerten */
  162.  if ( !expOk ){
  163.    serror ("Ungültiger 2. Ausdruck gefunden! ");
  164.    return (FALSE); /* Bedingung fehlerhaft */
  165.  }
  166.     rel = Compare( Op );
  167.     free ( BotStack );
  168.   /* Beachte : Stack wird im Fehlerfall nicht freigegeben */
  169.  return (rel);
  170. }
  171.  
  172. /* ReadComp: lies Vergleichsoperator ein
  173. */
  174. int
  175. ReadComp ( Op )
  176. int  *Op;
  177. {
  178. int  relop;  /* korrekter Vergleichoperetor gefunden?     */
  179.      relop = TRUE;              /* wir sind ja Optimisten */
  180.    switch (*ScanBuffer) {
  181.      case '/':
  182.        Scan ();
  183.        if (*ScanBuffer == '=')
  184.          *Op = UNGL;
  185.        else {
  186.          SkipChar ();
  187.        }
  188.      break;
  189.      case '>':
  190.        Scan ();
  191.          if (*ScanBuffer == '=')
  192.      *Op = GRGL;
  193.          else {
  194.            SkipChar ();
  195.            *Op = GR;
  196.          }
  197.      break;
  198.      case '<':
  199.        Scan ();
  200.          if (*ScanBuffer == '=')
  201.      *Op = KLGL;
  202.          else {
  203.            SkipChar ();
  204.            *Op = KL;
  205.          }
  206.      break;
  207.      case '=':
  208.        *Op = GL;
  209.      break;
  210.      default:
  211.        relop = FALSE;
  212.      break;
  213.    }
  214.    return( relop );
  215. }
  216. /* Compare
  217.  Vergleiche die Ausdrücke auf dem Stack.
  218. */
  219. int Compare ( Op )
  220. int Op;
  221. {
  222. EXPDEF *Var1,*Var2;
  223. int     rel;
  224.  if ((Var2 = PopExp()) == NULL) {
  225.    return(FALSE);
  226.  }
  227.  if ((Var1 = PopExp()) == NULL) {
  228.    return( Var2->val.wert != 0 );
  229.  }
  230.  if (Var1->type == Var2->type) {
  231.    if ( Var1->type == ZAHL ){
  232.     switch (Op) { /* hier wird endlich verglichen */
  233.      case GL:
  234.        return ((Var1->val.wert == Var2->val.wert) ?
  235.                 TRUE : FALSE);
  236.      case GRGL:
  237.        return ((Var1->val.wert >= Var2->val.wert) ?
  238.                 TRUE : FALSE);
  239.      case GR:
  240.        return ((Var1->val.wert > Var2->val.wert) ?
  241.                 TRUE : FALSE);
  242.      case KLGL:
  243.        return ((Var1->val.wert <= Var2->val.wert) ?
  244.                 TRUE : FALSE);
  245.      case KL:
  246.        return ((Var1->val.wert < Var2->val.wert) ?
  247.                 TRUE : FALSE);
  248.      case UNGL:
  249.        return ((Var1->val.wert != Var2->val.wert) ?
  250.                 TRUE : FALSE);
  251.         }/*switch*/
  252.       }/* ZAHL */
  253.       else if ( Var1->type == TEXT ){
  254.         rel = strcmp( Var1->val.text,Var2->val.text );
  255.         switch ( Op ) {
  256.          case   GL : return (( rel == 0 ) ? TRUE : FALSE );
  257.          case GRGL : return (( rel >= 0 ) ? TRUE : FALSE );
  258.          case   GR : return (( rel >  0 ) ? TRUE : FALSE );
  259.          case KLGL : return (( rel <= 0 ) ? TRUE : FALSE );
  260.          case   KL : return (( rel <  0 ) ? TRUE : FALSE );
  261.          case UNGL : return (( rel != 0 ) ? TRUE : FALSE );
  262.         }
  263.      }                                            /* TEXT */
  264.  }                                          /* type equal */
  265.  return(TRUE);                    /* nur für den Compiler */
  266. }                                              /* Compare */
  267.                               /* druckt eine Variable aus */
  268. void
  269. PrintVar (Name)
  270. char *Name;
  271. {
  272. VAR  *Variable;
  273.  
  274. /* wenn es Variable mit dem gesuchten Namen gibt, merken! */
  275.  if ((Variable = IsVariable (Name)) != NULL) {
  276.    switch (Variable->VarType) {
  277.     case FIXNUM:
  278.       printf ("%d",Variable->VarWert.variable.integer);
  279.     break;
  280.     case FLONUM:
  281.       printf ("%f",Variable->VarWert.variable.Flotype);
  282.     break;
  283.     case STRING:
  284.       printf( "%s",Variable->VarWert.variable.text );
  285.     break;
  286.     default:
  287.     printf ("\nVariablentyp kann nicht gedruckt werden!\n");
  288.     break;
  289.    }
  290.  }
  291.  else {
  292.    char buffer[40];
  293.    sprintf (buffer,"Variable <%s> unbekannt! ",Name);
  294.    fatal_error (buffer);
  295.  }
  296. }
  297.  
  298. /* CalcExpression: berechnet das Ergebnis eines Ausdrucks
  299. */
  300. int CalcExpression (Result)
  301. VAR *Result;
  302. {
  303. /* VAR *Variable; */
  304.  BotStack = TopStack = malloc (EXPSTACK * sizeof(EXPDEF));
  305.  Scan ();  /* den ersten Ausdruck einlesen */
  306.  if (Steuer == EOLCHAR)
  307.    return (ERROR);
  308.  expOk = TRUE; Expression();
  309.     SetResultValue( Result );
  310.  free (BotStack);  /* Speicher wieder freigeben */
  311.  if ( expOk ) return (OK);
  312.  else return (ERROR);
  313. }
  314.  
  315. /* Expression, Term und Faktor werten einen Ausdruck aus */
  316. void Expression (void)
  317. {
  318. char  addop;
  319.   if (( Steuer == SONDER ) &&
  320.       (( *ScanBuffer == '+' ) || ( *ScanBuffer == '-' )) &&
  321.       expOk ){
  322.     addop = *ScanBuffer;
  323.     Scan(); Term();
  324.     if ( addop == '-' ) CalcResult( NEGOP,1 );
  325.   }
  326.   else Term();
  327.   while (( Steuer == SONDER ) &&
  328.          (( *ScanBuffer == '+' ) || ( *ScanBuffer == '-' ))
  329.          && expOk ){
  330.     addop = *ScanBuffer;
  331.     Scan(); Term();
  332.     CalcResult( addop,2 );
  333.   }
  334. }/* Expression */
  335. void Term (void )
  336. {
  337. char  mulop;
  338.   Faktor();
  339.   while (( Steuer == SONDER ) &&
  340.          (( *ScanBuffer == '*' ) || ( *ScanBuffer == '/' ))
  341.          && expOk ){
  342.     mulop = *ScanBuffer;
  343.     Scan(); Faktor();
  344.     CalcResult( mulop,2 );
  345.   }
  346. }/* Term */
  347.  
  348. ...
  349. int TestFunc ( func )
  350. int  *func;
  351. {
  352. register int i,j;
  353.   for ( i=0;
  354.         ( ifuncs[ i ] != NULL ) &&
  355.         ( j = strcmp( ifuncs[ i ],ScanBuffer ) != 0 );
  356.         i++ );
  357.   *func = i;
  358.   return( j );
  359. }/* TestFunc */
  360.  
  361. /* SetResultValue: wandelt das Berechnungsergebnis in die
  362.    Variablenstruktur */
  363. void
  364. SetResultValue (Result)
  365. VAR *Result;
  366. {
  367.  switch (BotStack->type) {
  368.    case ZAHL:  /* Zahlen in Fließkommadarstellung */
  369.      Result->VarWert.variable.Flotype = BotStack->val.wert;
  370.      Result->VarType = FLONUM;
  371.    break;
  372.    case TEXT:
  373.      Result->VarWert.variable.text = BotStack->val.text;
  374.      Result->VarType = STRING;
  375.    break;
  376.    case FELD:
  377.    fatal_error ("Arrayzuweisung noch nicht implementiert!");
  378.    break;
  379.    default:
  380.      fatal_error ("Unbekannter Zahlentyp gefunden! ");
  381.    break;
  382.  }
  383. }
  384. /* PushExp
  385.  welche in ScanBuffer steht auf Stack ablegen.
  386. */
  387. void
  388. PushExp ()
  389. {
  390. VAR *Variable;
  391.    switch (Steuer) {
  392.      case  ZIFFER:
  393.      case  FLONUM:
  394.        TopStack->type = ZAHL;
  395.        TopStack->val.wert = atof (ScanBuffer);
  396.      break;
  397.      case  ALPHA:
  398. /* Wenn es die Variable gibt, Zeiger drauf und merken!    */
  399.        if ((Variable = IsVariable (ScanBuffer)) != NULL) {
  400.          switch (Variable->VarType) {
  401.            case ZIFFER:
  402.              TopStack->type = ZAHL;
  403.              TopStack->val.wert =
  404.                        Variable->VarWert.variable.integer;
  405.            break;
  406.            case FLONUM:
  407.              TopStack->type = ZAHL;
  408.              TopStack->val.wert = Variable->
  409.                                   VarWert.variable.Flotype;
  410.            break;
  411.            case STRING :
  412.             TopStack->type = TEXT;
  413.                TopStack->val.text =
  414.                malloc(strlen(Variable->VarWert.variable.text
  415.                       )+1);
  416.                strcpy( TopStack->val.text,
  417.                        Variable->VarWert.variable.text );
  418.            break;
  419.            default :
  420.            serror ("Typ für Operation nicht erlaubt! ");
  421.            break;
  422.          }
  423.        }
  424.        else
  425.          serror ("Variable nicht definiert! ");
  426.      break;
  427.      case STRING:
  428.     TopStack->type = TEXT;
  429.          TopStack->val.text = malloc( strlen(ScanBuffer)+1);
  430.          strcpy( TopStack->val.text,ScanBuffer );
  431.      break;
  432.      default:
  433.        serror ("Keine Operation für diesen Typ vorhanden!");
  434.      break;
  435.    }
  436.    TopStack++;  /* Stackpointer an die nächste Position */
  437. }
  438.  
  439. /* CalcResult: berechnet das Ergebnis eines Ausdrucks,
  440. der sich auf dem Stack befindet
  441. */
  442. void
  443. CalcResult ( Op,Ops )
  444. int  Op,Ops;
  445. {
  446. EXPDEF *Var1,*Var2,Result;
  447. char    *v1,*v2;
  448. size_t  l1,l2;
  449.   /* da die Anzahl der Parameter schon in <Faktor> überprüft
  450.      wird, sparen wir uns hier weitere Kontrollen
  451.   */
  452.   Var1 = PopExp();
  453.   if( Ops > 1 ) Var2 = PopExp();
  454.   if (( Ops == 1 ) || ( Var1->type == Var2->type )) {
  455.    if ( Var1->type == ZAHL ){
  456.         switch (Op) {
  457.        case '+':
  458.          Result.val.wert = Var2->val.wert + Var1->val.wert;
  459.        break;
  460.        case '-':
  461.          Result.val.wert = Var2->val.wert - Var1->val.wert;
  462.        break;
  463.        case '*':
  464.          Result.val.wert = Var2->val.wert * Var1->val.wert;
  465.        break;
  466.        case '/':
  467.          Result.val.wert = Var2->val.wert / Var1->val.wert;
  468.        break;
  469.        case  NEGOP :
  470.          Result.val.wert = -Var1->val.wert;
  471.        break;
  472.        case  SQROP :
  473.          Result.val.wert = Var1->val.wert * Var1->val.wert;
  474.        break;
  475.        case  SQRTOP :
  476.          Result.val.wert = sqrt ( Var1->val.wert );
  477.        break;
  478.        case  SINOP :
  479.          Result.val.wert = sin ( Var1->val.wert*M_PI/180 );
  480.        break;
  481.        case  COSOP :
  482.          Result.val.wert = cos ( Var1->val.wert*M_PI/180 );
  483.        break;
  484.        case  TANOP :
  485.          Result.val.wert = tan ( Var1->val.wert*M_PI/180 );
  486.        break;
  487.        case  ATANOP :
  488.          Result.val.wert = 180/M_PI*atan ( Var1->val.wert );
  489.        break;
  490.        case  LNOP   :
  491.          Result.val.wert = log ( Var1->val.wert );
  492.        break;
  493.        case  EXPOP  :
  494.          Result.val.wert = exp ( Var1->val.wert );
  495.        break;
  496.      }/* switch */
  497.   TopStack->val.wert = Result.val.wert;
  498.    }/* ZAHL */
  499.    else if ( Var1->type == TEXT ){
  500.      /* für / + *  gemeinsame Anweisungen */
  501.         l1 = strlen( Var1->val.text );
  502.         l2 = strlen( Var2->val.text );
  503.         v1 = Var1->val.text;
  504.         switch ( Op ){
  505.           case '+' :
  506.           Var2->val.text = realloc( Var2->val.text,l1+l2+1);
  507.           v2 = Var2->val.text;
  508.           while ( *v2++ != '\0' ); v2--; /* ohne '\0' */
  509.           v1 = Var1->val.text;
  510.           while (( *v2++ = *v1++ ) != '\0' );
  511.           break;
  512.           case '*' :
  513.           case '/' :
  514.             if ( l1 > l2 ) l1 = l2;
  515.             v2 = Var2->val.text;
  516.             if ( Op == '/' ) v2 += ( l2 - l1 );
  517.        /* bis auf diese Anweisung, sind die beiden gleich */
  518.            while ( l1-- > 0 ) *v2++ = *v1++; /* ohne '\0' */
  519.           break;
  520.         }/* switch Op */
  521.         free( Var1->val.text );
  522.         TopStack->val.text = Var2->val.text;
  523.     }/* TEXT */
  524.      TopStack->type = Var1->type;
  525.      TopStack++;
  526.   }
  527.   else
  528.   serror("Operation für Variablentyp nicht implementiert!");
  529.  
  530. }/* CalcResult */
  531.  
  532. /* MinMax: Je  nach Wert des Parameters minmax, Minimum oder
  533.           Maximum  der durch Ops bestimmten Anzahl Werte auf
  534.           dem Stack,ermitteln eine Funktion für min und max.
  535.           , weil beide bis auf den Vergleich identisch sind.
  536. */
  537. void MinMax ( Ops,minmax )
  538. int Ops,minmax;
  539. {
  540. EXPDEF  Result,*Var;
  541.   Var = PopExp();
  542.   Result.val.wert = Var->val.wert;
  543.   Result.type = Var->type;
  544.  
  545. /* eigentlich müssen wir noch auf ZAHL testen */
  546.   while ( --Ops > 0 ){
  547.     Var = PopExp();
  548.     if ( Var->type != Result.type ){
  549.       serror( "nur gleiche Typen für <max> erlaubt" );
  550.       break;
  551.     }
  552.     if ( minmax == 1 ){
  553.       if ( Var->val.wert > Result.val.wert )
  554.         Result.val.wert = Var->val.wert;
  555.     }
  556.     else{
  557.       if ( Var->val.wert < Result.val.wert )
  558.         Result.val.wert = Var->val.wert;
  559.     }
  560.   }
  561.   TopStack->type = Result.type;
  562.   TopStack->val.wert = Result.val.wert;
  563.   TopStack++;
  564. }/* MinMax */
  565.  
  566. /* Length : die Länge eines Strings */
  567. void Length( void )
  568. {
  569. EXPDEF  *top;
  570. size_t  len;
  571.   top = PopExp();
  572.   if ( top->type != TEXT ){
  573.     fatal_error( "STRING erwartet in <laenge>" ); return;
  574.   }
  575.   len = strlen( top->val.text );
  576.   free( top->val.text );
  577.   TopStack->type = ZAHL;
  578.   TopStack->val.wert = (float)len;
  579.   TopStack++;
  580. }/* Length */
  581. /* Left : die durch anz bestimmte Anzahl Zeichen  von links
  582.           her aus einem String.
  583.    Syntax : links "(" String "," Zahl ")"
  584.             String und zahl können jeweils ein Ausdruck des
  585.             entsprechenden Typs sein.
  586.    Bsp.  setze l=links(s+"...",x-2);
  587. */
  588. void Left( void )
  589. {
  590. EXPDEF  *str,*anz;
  591. char    *s;
  592.   anz = PopExp();
  593.   if ( anz->type != ZAHL ){
  594.     fatal_error( "<links> erwartet ZAHL als 2. P." );
  595.     return;
  596.   }
  597.   str = PopExp();
  598.   if ( str->type != TEXT ){
  599.     fatal_error( "<links> erwartet STRING als 1. P." );
  600.     return;
  601.   }
  602.   s = str->val.text + (long)anz->val.wert;
  603.   *s = '\0';     /* den Rest einfach abschneiden */
  604.   TopStack->type = TEXT;
  605.   TopStack->val.text = str->val.text;
  606.   TopStack++;
  607. }/* Left */
  608. /* Right : wie Left, nur sind hier die Zeichen vom rechten
  609.            Ende her gewünscht
  610.    Syntax : rechts "(" String "," Zahl ")"
  611. */
  612. void Right( void )
  613. {
  614. EXPDEF  *str,*anz;
  615. char    *s,*d;
  616. size_t  l;
  617.   anz = PopExp();
  618.   if ( anz->type != ZAHL ){
  619.     fatal_error( "<rechts> erwartet ZAHL als 2. P." );
  620.     return;
  621.   }
  622.   str = PopExp();
  623.   if ( str->type != TEXT ){
  624.     fatal_error( "<rechts> STRING als 1. P." ); return;
  625.   }
  626.   l = strlen( str->val.text );
  627.   if ( (long)anz->val.wert > l ) anz->val.wert = l;
  628.   s = str->val.text;
  629.   d = s + ( l - (long)anz->val.wert );
  630.   while ( (*s++ = *d++ ) != '\0' );
  631.            /* den rechten Teil zum Stringanfang hinziehen */
  632.   TopStack->type = TEXT;
  633.   TopStack->val.text = str->val.text;
  634.   TopStack++;
  635. }
  636. /* Right
  637.              Mid : hier wird mitten hinein gegriffen
  638.              Syntax mitte "(" String "," Zahl1 "," Zahl2 ")"
  639.              "Zahl1" bestimmt, ab welcher Position "Zahl"
  640.              "viel" Zeichen genommen werden.
  641. */
  642. void Mid ( void )
  643. {
  644. EXPDEF  *str,*start,*anzahl;
  645. char    *mid,*s,*d;
  646. int     ab,anz,len;
  647.   anzahl = PopExp();
  648.   if ( anzahl->type != ZAHL ){
  649.     fatal_error( "<mitte> erwartet ZAHL als 3.P." );
  650.     return;
  651.   }
  652.   else anz = (int)anzahl->val.wert;
  653.   start = PopExp();
  654.   if ( start->type != ZAHL ){
  655.     fatal_error( "<mitte> erwartet ZAHL als 2.P." );
  656.     return;
  657.   }
  658.   else ab = (int)start->val.wert;
  659.   str = PopExp();
  660.   if ( str->type != TEXT ){
  661.     fatal_error( "<mitte> erwartet STRING als 1.P." );
  662.     return;
  663.   }
  664.   else len = (int)strlen( str->val.text );
  665.   if ( ab > len ){   /* Anfangsposition hinter Stringende */
  666.     *TopStack->val.text = '\0';
  667.   }
  668.   else {
  669.     if ( anz > ( len - ab )) anz = len - ab;
  670.     mid = calloc( anz,sizeof( char ));
  671.     s = str->val.text + (long)ab;
  672.     d = mid;
  673.     while ( anz-- > 0 ) *d++ = *s++;  *d = '\0';
  674.     free( str->val.text );
  675.     TopStack->val.text = mid;
  676.   }
  677.   TopStack->type = TEXT;
  678.   TopStack++;
  679. /* Mid */
  680.  
  681. /* Instr : suche pattern in String ab Position start
  682.    Syntax : suche "(" String "," Stringvariable "," Zahl ")"
  683.    Bsp.  setze pos=suche("wie","na wie geht's",0);
  684. */
  685.  
  686. void InStr( void )
  687. {
  688. EXPDEF  *pattern,*str,*start;
  689. char    *search,*find;
  690. size_t  len;
  691. long    ab,pos;
  692.   start = PopExp();
  693.   if ( start->type != ZAHL ){
  694.     serror( "<suche> erwartet ZAHL als 2.P." ); return;
  695.   }
  696.   else ab = (long)start->val.wert;
  697.   str = PopExp();
  698.   if ( str->type != TEXT ){
  699.     serror( "<suche> erwartet STRING als 2.P." ); return;
  700.   }
  701.   else len = strlen( str->val.text );
  702.   pattern = PopExp();
  703.   if ( pattern->type != TEXT ){
  704.     serror( "<suche> erwartet STRING als 1.P." ); return;
  705.   }
  706.   if ( ab > len ){   /* Anfangsposition hinter Stringende */
  707.     TopStack->val.wert = -1;
  708.   }
  709.   else {
  710.     search = str->val.text + ab;           /* ab hier ... */
  711.     find = strstr( search,pattern->val.text ); /* .suchen */
  712.     if ( find == NULL ) pos = -1;       /* nicht gefunden */
  713.     else pos = find - str->val.text;  /* bei pos gefunden */
  714.     free( str->val.text );
  715.     free( pattern->val.text );
  716.     TopStack->val.wert = (float)pos;
  717.   }
  718.   TopStack->type = ZAHL;
  719.   TopStack++;
  720. }/* InStr */
  721.  
  722. /* PopExp
  723.  Holt einen Ausdruck vom Variablenstack
  724. */
  725.  
  726. EXPDEF *
  727. PopExp ()
  728. {
  729.   if (TopStack-- != BotStack)
  730.     return (TopStack);
  731.   else
  732.     return (NULL);
  733. }
  734.  
  735. /* ClearProg: den Speicherplatz, der durch das Programm
  736. belegt ist, freigeben
  737. */
  738.  
  739. void
  740. ClearProg ()
  741. {
  742. PRGZEILE *Memory;
  743.  ActLine = FirstLine;  /* Zeiger auf erste Programmzeile */
  744.  while (ActLine) {
  745.    Memory = ActLine;             /* wird gleich benötigt */
  746.    ActLine = ActLine->NextZeile;
  747.                             /* das ist die nächste Zeile */
  748.    free (Memory);             /* Speicherplatz freigeben */
  749.  }
  750.  FirstLine = ActLine = NULL;      /* Zeiger zurücksetzen */
  751. }
  752.  
  753. /* TestComma : teste ob das zeichen im ScanBuffer
  754.                ein "," ist
  755. */
  756.  
  757. int TestComma()
  758. {
  759.   if (( Steuer == SONDER ) && ( *ScanBuffer == ',' ))
  760.     return ( TRUE );
  761.   else{
  762.     serror( ", erwartet" ); return ( FALSE );
  763.   }
  764. }
  765.  
  766. /* GetStringVar : lies den nächsten Bezeichner und liefere
  767.                   die zugehörige Variable
  768. */
  769.  
  770. int GetStringVar ( str )
  771. VAR  **str;
  772. {
  773.   Scan();
  774.   if( Steuer != ALPHA ){
  775.     serror( "Bezeichner erwartet" );
  776.     return( FALSE );
  777.   }
  778.   if (( *str = IsVariable( ScanBuffer )) == NULL ){
  779.     fatal_error( "Variable existiert nicht" );
  780.     return( FALSE );
  781.   }
  782.   return ( TRUE );
  783. }
  784.  
  785. /* GetLong : lies und berechne den nächsten Ausdruck, und
  786.               liefere seinen Wert als long-Grö₧e
  787. */
  788. int GetLong ( val )
  789. long  *val;
  790. {
  791. VAR  Var;
  792.   CalcExpression( &Var );
  793.   if ( Var.VarType == FLONUM ){
  794.     *val = (long)Var.VarWert.variable.Flotype;
  795.     return ( TRUE );
  796.   }
  797.   else if ( Var.VarType == FIXNUM ){
  798.     *val = (long)Var.VarWert.variable.integer;
  799.     return ( TRUE );
  800.   }
  801.   else{
  802.     serror( "ZAHL erwartet" ); return( FALSE );
  803.   }
  804. }
  805. /*--------------------------------------------------------*/
  806. /*                   Ende von INTUTIL.C                   */
  807.