home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / text / misc / cvt / source / cvtparse.c < prev    next >
C/C++ Source or Header  |  1994-05-28  |  41KB  |  1,412 lines

  1. /*                                                               -*- C -*-
  2.  *  CVTPARSE.C
  3.  *
  4.  *  (c)Copyright 1993 by Tobias Ferber,  All Rights Reserved
  5.  */
  6.  
  7. #include <stdarg.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11.  
  12. #include "cvt.h"
  13.  
  14. #ifndef isprint
  15. #define isprint(c) (' '<=(c) && (c)<='~')
  16. #endif /* !isprint */
  17.  
  18.  
  19. /*** / LERROR / ***/
  20.  
  21. void lerror(long line, const char *fmt, ...)
  22. /* gibt eine Fehlermeldung 'fmt' f"ur die Zeile #line aus. */
  23.   va_list argp;
  24.   va_start(argp,fmt);
  25.   fprintf(ferr,"line %ld: ",line);
  26.   vfprintf(ferr,(char *)fmt,argp);
  27.   fprintf(ferr,"\n");
  28.   fflush(ferr);
  29.   ++global_numerrors;
  30.   va_end(argp);
  31. }
  32.  
  33.  
  34. /*** / READCRULE / ***/
  35.  
  36. crule_t *readcrule(FILE *fp)
  37. /*
  38.    Diese Funktion bildet den lexical Scanner.  Sie überliest Leerzeichen,
  39.    TABs, Zeilenwechsel und Kommentare, liest die nächste Transformationsregel
  40.    ein und baut daraus eine crule_t Struktur auf.  Ein Zeiger auf diese
  41.    crule_t Struktur (vom Typ crule_t *) wird zurückgegeben.
  42.  
  43.    Fehlermeldungen werden mit lerror() ausgegeben, die Zeilennummern werden
  44.    hier gezählt.  Man beachte, daß deshalb keine andere Funktion 'fp'
  45.    über ein Zeilenende schieben darf, da sonst die Nummerierung falsch wird.
  46.  
  47.    Diese Funktion überliest alle Zeichen, die Teil eines Kommentares sind.
  48.    Ein Kommentar ist (wie in C) alles zwischen einem '/' + '*' Token
  49.    und dem korrespondierenden '*' + '/'.  Es sind auch C++ Kommentare
  50.    (hier 'remark' genannt) erlaubt.  Letztere werden durch zwei Slashes
  51.    '/' + '/' eingeleitet und reichen dann bis zum Ende der Zeile in der
  52.    sie auftreten.  Genau wie in C (und C++) sind geschachtelte Kommentare
  53.    (nested comments) hier NICHT erlaubt.
  54. */
  55.  
  56. {
  57.   static unsigned char *xhsbuf= (unsigned char *)0L;
  58.   static unsigned long bufsize= 0L;
  59.  
  60.   /* Der xhs-Buffer ist statisch & dynamisch und wird beim jungfräulichen
  61.      Aufruf dieser Funktion aufgebaut.  Dabei werden zunächst 'XHSBUFSIZE'
  62.      Bytes allokiert und bei jedem Überlauf ebensoviele mittels realloc()
  63.      angehängt. */
  64.  
  65.   static unsigned long line= 1;  /* line counter */
  66.  
  67.   crule_t *cr;               /* current rule */
  68.   unsigned long n=0;         /* #of chars read into xhsbuf[] */
  69.   unsigned char c;           /* currently read character */
  70.  
  71.   int ccode= 0;              /* char code built up by collecting digits */
  72.   int ccdigits= 0;           /* #of digits collected for ccode */
  73.  
  74.   char xhs='l';              /* working on the lhs ('l') or rhs ('r') */
  75.  
  76.   /* local script file scanner modes */
  77.  
  78.   typedef enum {
  79.  
  80.     data_mode,               /* Im data_mode werden "white" characters
  81.                               * enfernt.  Vom data_mode aus kann bis auf
  82.                               * in den instruction_mode in jeden anderen
  83.                               * scanner mode übergegangen werden. */
  84.  
  85.     instruction_mode,        /* In den instruction_mode wird übergegangen,
  86.                               * wenn ein data packet beendet ist.
  87.                               * Der Scanner erwartet dann entweder ein
  88.                               * concatenation token (CATSYM) oder ein
  89.                               * derivation token `->'.  Auch in diesem
  90.                               * scanner mode werden "white" characters
  91.                               * entfernt. */
  92.  
  93.     decimal_mode,
  94.     hex_mode,
  95.     octal_mode,              /* In diesen Modi werden die Ziffern für ein
  96.                               * character token eingesammelt.  In den
  97.                               * decimal_mode kann nur vom data_mode aus
  98.                               * übergegangen werden, während die beiden
  99.                               * anderen Modi auch über den string_mode
  100.                               * erreicht werden können. */
  101.  
  102.     string_mode,             /* Im string_mode werden die Zeichen für
  103.                               * ein data packet direkt eingesammelt, also
  104.                               * ohne Umweg über die character codes.
  105.                               * In den string_mode wird übergegangen, wenn
  106.                               * der Scanner im data_mode auf ein double
  107.                               * quote `"' stößt.  Ein weiteres (nicht mit
  108.                               * einem Backslash "escapetes" double quote
  109.                               * bringt den scanner in den instruction_mode. */
  110.  
  111.     remark_mode,
  112.     comment_mode,            /* Diese Modi können sowohl vom data_mode
  113.                               * als auch vom instruction_mode aus erreicht
  114.                               * werden, wenn der Scanner auf den entsprechenden
  115.                               * comment leader (s.o) trifft.
  116.                               * In diesem Fall wird der momentane scanner
  117.                               * mode in einen Stack gepushed und am Ende
  118.                               * des Kommentars wieder gepoppt. */
  119.  
  120.     return_mode,             /* In den return_mode wird übergegangen, wenn
  121.                               * die Transformationsregel komplett ist, also
  122.                               * wenn ein RTERM im instruction_mode auf der
  123.                               * rechten Seite gefunden wurde. */
  124.  
  125.     error_mode,              /* Wenn etwas in den Schlüpfer geht, so geht
  126.                               * auch der Scanner.  Nämlich in den error_mode
  127.                               * über ;)  Die Zeichen bis zum nächsten RTERM
  128.                               * oder EOF werden dann überlesen. */
  129.  
  130.     panic_mode,              /* Im Vergleich zum error_mode kehrt der scanner
  131.                               * im panic_mode sofort zurück ohne bis zum
  132.                               * nächsten RTERM weiterzulesen. */
  133.   } smode_t;
  134.  
  135.   smode_t smode;             /* current scanner mode */
  136.   smode_t smstack;           /* previous scanner mode; needed to restore
  137.                               * 'smode' e.g. when leaving 'remark_mode' */
  138.  
  139.   /* Um den von dieser Funktion allokierten xhsbuf wieder freizugeben
  140.      genügt es, diese mit einem FILE *fp == NULL aufzurufen.
  141.      Unabhängig von der Existenz des xhsbuf ist ein Aufruf dieser Funktion
  142.      mit fp == NULL ungefährlich. */
  143.  
  144.   if(!fp)
  145.   { if(xhsbuf)
  146.     { free(xhsbuf);
  147.       xhsbuf= (unsigned char *)0L;
  148.     }
  149.     bufsize= 0L;
  150.     line= 1;
  151.     return NIL(crule_t);
  152.   }
  153.  
  154.   /* Initially we expect some char data */
  155.   smode= smstack= data_mode;
  156.  
  157.   if(!xhsbuf)
  158.   {
  159.     xhsbuf= (unsigned char *)malloc(XHSBUFSIZE * sizeof(char));
  160.  
  161.     if(!xhsbuf)
  162.     { echo("Not enough memory to read rules.");
  163.       return NIL(crule_t);
  164.     }
  165.     bufsize= XHSBUFSIZE;
  166.   }
  167.  
  168.   if( ! (cr= new()) )
  169.   {
  170.     lerror(line,"Ran out of memory w/ %ld rules read.",global_numrules);
  171.     smode= panic_mode;
  172.   }
  173.  
  174.   /* let's roll... */
  175.   while( smode != return_mode  &&
  176.          smode != error_mode   &&
  177.          smode != panic_mode   &&  !ferror(fp) && !feof(fp) )
  178.   {
  179.     c= fgetc(fp);
  180.  
  181.     if(feof(fp) && c!=(unsigned char)EOF)
  182.     {
  183. #ifdef DEBUG
  184.       printf("scanner: line %ld: feof()==TRUE but fgetc()==0x%02x\n",
  185.         line, (int)(c&0xFF));
  186. #endif /* DEBUG */
  187.       c= (unsigned char)EOF;
  188.     }
  189.  
  190. #ifdef _DCC /* buggy shareware DICE */
  191.     switch( (int) c & 0xFF )
  192.  
  193. #else
  194.     switch(c)
  195.  
  196. #endif
  197.     {
  198.  
  199. /**/  case ' ':
  200.       case '\t':
  201.         switch(smode)
  202.         {
  203.           case decimal_mode:
  204.             xhsbuf[n++]= (char)ccode;
  205.             smode= instruction_mode;
  206.             break;
  207.  
  208.           case hex_mode:
  209.           case octal_mode:
  210.             if(smstack==string_mode)
  211.             {
  212.               if(ccdigits==0)
  213.               { /* can not happen in octal_mode in string_mode */
  214.                 lerror(line,"\\x used with no following hex digits");
  215.                 smode= error_mode;
  216.               }
  217.               else /* ccdigits > 0 */
  218.               {
  219.                 xhsbuf[n++]= (char)ccode;
  220.                 smode= smstack; /* == string_mode */
  221.                 ungetc(c,fp);
  222.               }
  223.             }
  224.             else /* smstack != string_mode */
  225.             {
  226.               if(ccdigits==0)
  227.               {
  228.                 if(smode==hex_mode)
  229.                 {
  230.                   lerror(line,"$ used with no following hex digits");
  231.                   smode= error_mode;
  232.                 }
  233.                 else /* smode==octal_mode */
  234.                 {
  235.                   xhsbuf[n++]= (char)ccode; /* == 0 */
  236.                   smode= instruction_mode;
  237.                 }
  238.               }
  239.               else /* ccdigits > 0 */
  240.               {
  241.                 xhsbuf[n++]= (char)ccode;
  242.                 smode= instruction_mode;
  243.               }
  244.             }
  245.             break;
  246.  
  247.           case string_mode:
  248.             xhsbuf[n++]= c;
  249.             break;
  250.  
  251.           case data_mode:
  252.           case instruction_mode:
  253.           case remark_mode:
  254.           case comment_mode:
  255.           case return_mode:
  256.           case error_mode:
  257.           case panic_mode:
  258.             break;
  259.         }
  260.         break;
  261.  
  262. /**/  case '\n':
  263.       case '\r':
  264.         switch(smode)
  265.         {
  266.           case decimal_mode:
  267.             xhsbuf[n++]= (char)ccode;
  268.             smode= instruction_mode;
  269.             break;
  270.  
  271.           case hex_mode:
  272.           case octal_mode:
  273.             if(smstack==string_mode)
  274.             {
  275.               lerror(line,"unterminated string at EOL; missing quotes");
  276.               smode= error_mode;
  277.             }
  278.             else /* smstack != string_mode */
  279.             {
  280.               if(ccdigits==0)
  281.               {
  282.                 if(smode==hex_mode)
  283.                 {
  284.                   lerror(line,"$ used with no following hex digits");
  285.                   smode= error_mode;
  286.                 }
  287.                 else /* smode==octal_mode */
  288.                 {
  289.                   xhsbuf[n++]= (char)ccode; /* == 0 */
  290.                   smode= smstack; /* == instruction_mode */
  291.                 }
  292.               }
  293.               else /* ccdigits > 0 */
  294.               {
  295.                 xhsbuf[n++]= (char)ccode;
  296.                 smode= smstack; /* == instruction_mode */
  297.               }
  298.             }
  299.             break;
  300.  
  301.           case string_mode:
  302.             lerror(line,"unterminated string at EOL; missing quotes");
  303.             smode= error_mode;
  304.             break;
  305.  
  306.           case remark_mode:
  307.             smode= smstack;
  308.             break;
  309.  
  310.           case data_mode:
  311.           case instruction_mode:
  312.           case comment_mode:
  313.           case return_mode:
  314.           case error_mode:
  315.           case panic_mode:
  316.             break;
  317.         }
  318.         line++; /* in any case */
  319.  
  320.         /*
  321.          * look foreward and forget about the second character of
  322.          * the newline tuple if there is one.
  323.          */
  324.  
  325.         { int d= fgetc(fp);
  326.           if(!( (c=='\n' && d=='\r') || (c=='\r' && d=='\n') ))
  327.             ungetc(d,fp);
  328.         }
  329.         break;
  330.  
  331. /**/  case CATSYM:
  332.         switch(smode)
  333.         {
  334.           case data_mode:
  335.             lerror(line,"extra `%c' or missing character data",c);
  336.             smode= error_mode;
  337.             break;
  338.  
  339.           case instruction_mode:
  340.             smode= data_mode;
  341.             break;
  342.  
  343.           case decimal_mode:
  344.             xhsbuf[n++]= (char)ccode;
  345.             smode= data_mode;
  346.             break;
  347.  
  348.           case hex_mode:
  349.           case octal_mode:
  350.             if(smstack==string_mode)
  351.             {
  352.               if(ccdigits==0)
  353.               { /* can not happen in octal_mode in string mode */
  354.                 lerror(line,"\\x used with no following hex digits");
  355.                 smode= error_mode;
  356.               }
  357.               else /* ccdigits > 0 */
  358.               {
  359.                 xhsbuf[n++]= (char)ccode;
  360.                 smode= smstack; /* == string_mode */
  361.                 ungetc(c,fp);
  362.               }
  363.             }
  364.             else /* smstack != string_mode */
  365.             {
  366.               if(ccdigits==0)
  367.               {
  368.                 if(smode==hex_mode)
  369.                 {
  370.                   lerror(line,"$ used with no following hex digits");
  371.                   smode= error_mode;
  372.                 }
  373.                 else /* smode==octal_mode */
  374.                 {
  375.                   xhsbuf[n++]= (char)ccode; /* == 0 */
  376.                   smode= data_mode;
  377.                 }
  378.               }
  379.               else /* ccdigits > 0 */
  380.               {
  381.                 xhsbuf[n++]= (char)ccode;
  382.                 smode= data_mode;
  383.               }
  384.             }
  385.             break;
  386.  
  387.           case string_mode:
  388.             xhsbuf[n++]= c;
  389.             break;
  390.  
  391.           case remark_mode:
  392.           case comment_mode:
  393.           case return_mode:
  394.           case error_mode:
  395.           case panic_mode:
  396.             break;
  397.         }
  398.         break;
  399.  
  400. /**/  case '-':
  401.         switch(smode)
  402.         {
  403.           case data_mode:
  404.             lerror(line,"misplaced unary minus `%c'",c);
  405.             smode= error_mode;
  406.             break;
  407.  
  408.           case instruction_mode:
  409.             switch(c= fgetc(fp))
  410.             {
  411.               case '>':
  412.                 if(xhs=='l')
  413.                 {
  414.                   if(n>0)
  415.                   {
  416.                     char *t;
  417.  
  418.                     if( t= (char *)malloc(n*sizeof(char)) )
  419.                     {
  420.                       memcpy(t, xhsbuf, n);
  421.                       cr->lhs= t;
  422.                       cr->l= n;
  423.                       xhs= 'r';
  424.                       smode= data_mode;
  425.                       n= 0;
  426.                     }
  427.                     else /* t == (char *)0 */
  428.                     {
  429.                       lerror(line,"not enough memory for another %d bytes lhs",n);
  430.                       smode= panic_mode;
  431.                     }
  432.                   }
  433.                   else /* n==0 */
  434.                   {
  435.                     lerror(line,"malformed or empty lhs; misplaced `->'");
  436.                     smode= error_mode;
  437.                   }
  438.                 }
  439.                 else /* xhs=='r' */
  440.                 {
  441.                   lerror(line,"more than one derivation token `->' in this rule");
  442.                   smode= error_mode;
  443.                 }
  444.                 break;
  445.  
  446.               default:
  447.                 lerror(line,"misplaced minus sign `-'; subtraction not supported",c);
  448.                 smode= error_mode;
  449.                 break;
  450.             }
  451.             break;
  452.  
  453.           case decimal_mode:
  454.             xhsbuf[n++]= (char)ccode;
  455.             smode= instruction_mode;
  456.             ungetc(c,fp);
  457.             break;
  458.  
  459.           case hex_mode:
  460.           case octal_mode:
  461.             if(smstack==string_mode)
  462.             {
  463.               if(ccdigits==0)
  464.               { /* can not happen in octal_mode in string_mode */
  465.                 lerror(line,"\\x used with no following hex digits");
  466.                 smode= error_mode;
  467.               }
  468.               else /* ccdigits > 0 */
  469.               {
  470.                 xhsbuf[n++]= (char)ccode;
  471.                 smode= smstack; /* == string_mode */
  472.                 ungetc(c,fp);
  473.               }
  474.             }
  475.             else /* smstack != string_mode */
  476.             {
  477.               if(ccdigits==0)
  478.               {
  479.                 if(smode==hex_mode)
  480.                 {
  481.                   lerror(line,"$ used with no following hex digits");
  482.                   smode= error_mode;
  483.                 }
  484.                 else /* smode==octal_mode */
  485.                 {
  486.                   xhsbuf[n++]= (char)ccode; /* == 0 */
  487.                   smode= instruction_mode;
  488.                   ungetc(c,fp);
  489.                 }
  490.               }
  491.               else /* ccdigits > 0 */
  492.               {
  493.                 xhsbuf[n++]= (char)ccode;
  494.                 smode= instruction_mode;
  495.                 ungetc(c,fp);
  496.               }
  497.             }
  498.             break;
  499.  
  500.           case string_mode:
  501.             xhsbuf[n++]= c;
  502.             break;
  503.  
  504.           case remark_mode:
  505.           case comment_mode:
  506.           case return_mode:
  507.           case error_mode:
  508.           case panic_mode:
  509.             break;
  510.         }
  511.         break;
  512.  
  513. /**/  case RTERM:
  514.         switch(smode)
  515.         {
  516.           case data_mode:
  517.             if(xhs=='r')
  518.             {
  519.               if(n==0) /* allow an empty RHS */
  520.               {
  521.                 smode= return_mode;
  522.               }
  523.               else
  524.               {
  525.                 lerror(line,"extra `%c' or `->' before `%c'",CATSYM,c);
  526.                 smode= error_mode;
  527.               }
  528.             }
  529.             else /* xhs=='l' */
  530.             {
  531.               if(n==0)
  532.               {
  533.                 lerror(line,"empty rule or extra `%c'",c);
  534.               }
  535.               else
  536.               {
  537.                 lerror(line,"extra `%c' before `%c'",CATSYM,c);
  538.                 lerror(line,"missing derivation token `->'");
  539.               }
  540.               smode= error_mode;
  541.             }
  542.             break;
  543.  
  544.           case instruction_mode:
  545.             if(xhs=='r')
  546.             {
  547.               smode= return_mode;
  548.             }
  549.             else
  550.             {
  551.               lerror(line,"missing derivation token `->'");
  552.               smode= error_mode;
  553.             }
  554.             break;
  555.  
  556.           case decimal_mode:
  557.             if(xhs=='r')
  558.             {
  559.               xhsbuf[n++]= (char)ccode;
  560.               smode= return_mode;
  561.             }
  562.             else /* xhs=='l' */
  563.             {
  564.               lerror(line,"missing derivation token `->'");
  565.               smode= error_mode;
  566.             }
  567.             break;
  568.  
  569.           case hex_mode:
  570.           case octal_mode:
  571.             if(xhs=='r')
  572.             {
  573.               if(smstack==string_mode)
  574.               {
  575.                 if(ccdigits==0)
  576.                 { /* can not happen in octal_mode in string_mode */
  577.                   lerror(line,"\\x used with no following hex digits");
  578.                   smode= error_mode;
  579.                 }
  580.                 else /* ccdigits > 0 */
  581.                 {
  582.                   xhsbuf[n++]= (char)ccode;
  583.                   smode= smstack; /* == string_mode */
  584.                   ungetc(c,fp);
  585.                 }
  586.               }
  587.               else /* smstack != string_mode */
  588.               {
  589.                 if(ccdigits==0)
  590.                 {
  591.                   if(smode==hex_mode)
  592.                   {
  593.                     lerror(line,"$ used with no following hex digits");
  594.                     smode= error_mode;
  595.                   }
  596.                   else /* smode==octal_mode */
  597.                   {
  598.                     xhsbuf[n++]= (char)ccode; /* == 0 */
  599.                     smode= return_mode;
  600.                   }
  601.                 }
  602.                 else /* ccdigits > 0 */
  603.                 {
  604.                   xhsbuf[n++]= (char)ccode;
  605.                   smode= return_mode;
  606.                 }
  607.               }
  608.             }
  609.             else /* xhs=='l' */
  610.             {
  611.               lerror(line,"missing derivation token `->'");
  612.               smode= error_mode;
  613.             }
  614.             break;
  615.  
  616.           case string_mode:
  617.             xhsbuf[n++]= c;
  618.             break;
  619.  
  620.           case remark_mode:
  621.           case comment_mode:
  622.           case return_mode:
  623.           case error_mode:
  624.           case panic_mode:
  625.             break;
  626.         }
  627.         break;
  628.  
  629.       /* Ein EOF character kann auch auftreten wenn das Ende des
  630.          Streams noch gar nicht erreicht ist.  Es werden also diese
  631.          beiden Fälle separat betrachtet: */
  632.  
  633. /**/  case (unsigned char)EOF:
  634.         switch(smode)
  635.         {
  636.           case data_mode:
  637.             if( feof(fp) )
  638.             {
  639.               if(xhs=='l')
  640.               {
  641.                 if(n > 0)
  642.                 {
  643.                   lerror(line,"malformed rule at EOF; missing `->'");
  644.                   smode= error_mode;
  645.                 }
  646.                 /* else wird am Ende der Schleife sowieso behandelt */
  647.               }
  648.               else /* xhs=='r' */
  649.               {
  650.                 if(n==0)
  651.                 {
  652.                   lerror(line,"missing `%c' at EOF; rhs is empty",RTERM);
  653.                 }
  654.                 else
  655.                 {
  656.                   lerror(line,"malformed rhs at EOF; expected `%c' (not `%c')",RTERM,CATSYM);
  657.                 }
  658.                 smode= error_mode;
  659.               }
  660.             }
  661.             else /* !feof(fp) */
  662.             {
  663.               lerror(line,"misplaced EOF character `\\x%02x'",c);
  664.               smode= error_mode;
  665.             }
  666.             break;
  667.  
  668.           case instruction_mode:
  669.             if( feof(fp) )
  670.             {
  671.               if(xhs=='l')
  672.               {
  673.                 lerror(line,"malformed rule at EOF; incomplete lhs");
  674.               }
  675.               else
  676.               {
  677.                 lerror(line,"unexpected EOF; missing `%c'",RTERM);
  678.               }
  679.               smode= error_mode;
  680.             }
  681.             else /* !feof(fp) */
  682.             {
  683.               lerror(line,"misplaced EOF character `\\x%02x'",c);
  684.               smode= error_mode;
  685.             }
  686.             break;
  687.  
  688.           case decimal_mode:
  689.           case hex_mode:
  690.           case octal_mode:
  691.             if( feof(fp) )
  692.             {
  693.               lerror(line,"unexpected end of input; missing `%c'",RTERM);
  694.             }
  695.             else
  696.             {
  697.               lerror(line,"misplaced EOF character `\\x%02x'",c);
  698.             }
  699.             smode= error_mode;
  700.             break;
  701.  
  702.           case string_mode:
  703.             if( feof(fp) )
  704.             {
  705.               lerror(line,"unterminated string at EOF");
  706.               smode= error_mode;
  707.             }
  708.             else /* !feof(fp) */
  709.             {
  710.               xhsbuf[n++]= c;
  711.             }
  712.             break;
  713.  
  714.           case comment_mode:
  715.             if( feof(fp) )  /* else ist dann Wurschd */
  716.             {
  717.               lerror(line,"unterminated comment at EOF; closing `*/' missing");
  718.               smode= error_mode;
  719.             }
  720.             break;
  721.  
  722.           case remark_mode:
  723.           case return_mode:
  724.           case error_mode:
  725.           case panic_mode:
  726.             break;
  727.         }
  728.         break;
  729.  
  730. /**/  case '$':
  731.         switch(smode)
  732.         {
  733.           case data_mode:
  734.             smstack= instruction_mode;
  735.             smode= hex_mode;
  736.             ccode= 0;
  737.             ccdigits= 0;
  738.             break;
  739.  
  740.           case instruction_mode:
  741.           case decimal_mode:
  742.             lerror(line,"misplaced hex token `%c' or missing `%c'",c,CATSYM);
  743.             smode= error_mode;
  744.             break;
  745.  
  746.           case hex_mode:
  747.           case octal_mode:
  748.             if(smstack==string_mode)
  749.             {
  750.               if(ccdigits==0)
  751.               { /* can not happen in octal_mode in string_mode */
  752.                 lerror(line,"\\x used with no following hex digits");
  753.                 smode= error_mode;
  754.               }
  755.               else /* ccdigits > 0 */
  756.               {
  757.                 xhsbuf[n++]= (char)ccode;
  758.                 smode= smstack; /* == string_mode */
  759.                 ungetc(c,fp);
  760.               }
  761.             }
  762.             else /* smstack != string_mode */
  763.             {
  764.               lerror(line,"misplaced hex token `%c' or missing `%c'",c,CATSYM);
  765.               smode= error_mode;
  766.             }
  767.             break;
  768.  
  769.           case string_mode:
  770.             xhsbuf[n++]= c;
  771.             break;
  772.  
  773.           case remark_mode:
  774.           case comment_mode:
  775.           case return_mode:
  776.           case error_mode:
  777.           case panic_mode:
  778.             break;
  779.         }
  780.         break;
  781.  
  782. /**/  case '\"':
  783.         switch(smode)
  784.         {
  785.           case data_mode:
  786.             smode= string_mode;
  787.             break;
  788.  
  789.           case instruction_mode:
  790.           case decimal_mode:
  791.             lerror(line,"unmatched quotes or missing `%c'",CATSYM);
  792.             smode= error_mode;
  793.             break;
  794.  
  795.           case hex_mode:
  796.           case octal_mode:
  797.             if(smstack==string_mode)
  798.             {
  799.               if(ccdigits==0)
  800.               { /* can not happen in octal_mode in string_mode */
  801.                 lerror(line,"\\x used with no following hex digits");
  802.                 smode= error_mode;
  803.               }
  804.               else /* ccdigits > 0 */
  805.               {
  806.                 xhsbuf[n++]= (char)ccode;
  807.                 smode= smstack; /* == string_mode */
  808.                 ungetc(c,fp);
  809.               }
  810.             }
  811.             else /* smstack != string_mode */
  812.             {
  813.               lerror(line,"unmatched quotes or missing `%c'",CATSYM);
  814.               smode= error_mode;
  815.             }
  816.             break;
  817.  
  818.           case string_mode:
  819.             smode= instruction_mode;
  820.             break;
  821.  
  822.           case remark_mode:
  823.           case comment_mode:
  824.           case return_mode:
  825.           case error_mode:
  826.           case panic_mode:
  827.             break;
  828.         }
  829.         break;
  830.  
  831. /**/  case '\\':
  832.         switch(smode)
  833.         {
  834.           case data_mode:
  835.           case instruction_mode:
  836.           case decimal_mode:
  837.             lerror(line,"misplaced escape character `%c' or missing quotes",c);
  838.             smode= error_mode;
  839.             break;
  840.  
  841.           case hex_mode:
  842.           case octal_mode:
  843.             if(smstack==string_mode)
  844.             {
  845.               if(ccdigits==0)
  846.               { /* can not happen in octal_mode in string_mode */
  847.                 lerror(line,"\\x used with no following hex digits");
  848.                 smode= error_mode;
  849.               }
  850.               else /* ccdigits > 0 */
  851.               {
  852.                 xhsbuf[n++]= (char)ccode;
  853.                 smode= smstack; /* == string_mode */
  854.                 ungetc(c,fp);
  855.               }
  856.             }
  857.             else /* smstack != string_mode */
  858.             {
  859.               lerror(line,"misplaced escape character `%c' or missing quotes",c);
  860.               smode= error_mode;
  861.             }
  862.             break;
  863.  
  864.           case string_mode:
  865.  
  866.             /* character constants taken from 'The C++ Programming Language'
  867.              * Second Edition, Bjarne Stroustup, AT&T Bell Laboratories */
  868.  
  869.             switch(c= fgetc(fp))
  870.             {
  871.               case 'n':  xhsbuf[n++]= '\n'; break;  /* newline */
  872.               case 't':  xhsbuf[n++]= '\t'; break;  /* horizontal tab */
  873.               case 'v':  xhsbuf[n++]= '\v'; break;  /* vertical tab */
  874.               case 'b':  xhsbuf[n++]= '\b'; break;  /* backspace */
  875.               case 'r':  xhsbuf[n++]= '\r'; break;  /* carriage return */
  876.               case 'f':  xhsbuf[n++]= '\f'; break;  /* form feed */
  877.               case 'a':  xhsbuf[n++]= '\a'; break;  /* alert */
  878.               case '\\': xhsbuf[n++]= '\\'; break;  /* backslash */
  879.               case '?':  xhsbuf[n++]= '\?'; break;  /* question mark */
  880.               case '\'': xhsbuf[n++]= '\''; break;  /* single quote */
  881.               case '\"': xhsbuf[n++]= '\"'; break;  /* double quote */
  882.               case '0':
  883.               case '1':
  884.               case '2':
  885.               case '3':
  886.               case '4':
  887.               case '5':
  888.               case '6':
  889.               case '7':
  890.                 smstack= smode; /* == string_mode */
  891.                 smode= octal_mode;
  892.                 ccode= (int)c-'0';
  893.                 ccdigits= 1;
  894.                 break;
  895.  
  896.               case 'x':
  897.               case 'X': /* how about the uppercase 'X' ? */
  898.                 smstack= smode; /* == string_mode */
  899.                 smode= hex_mode;
  900.                 ccode= 0;
  901.                 ccdigits= 0;
  902.                 break;
  903.  
  904.               default:
  905.                 lerror(line,
  906.                   ( isprint(c)
  907.                   ? "unknown escape sequence `\\%c'"
  908.                   : "unknown escape sequence: `\\' followed by char code 0x%x"
  909.                   ),c
  910.                 );
  911.                 smode= error_mode;
  912.                 break;
  913.             }
  914.             break;
  915.  
  916.           case remark_mode:
  917.           case comment_mode:
  918.           case return_mode:
  919.           case error_mode:
  920.           case panic_mode:
  921.             break;
  922.         }
  923.         break;
  924.  
  925. /**/  case '/':
  926.         switch(smode)
  927.         {
  928.           case data_mode:
  929.           case instruction_mode:
  930.             switch(c= fgetc(fp))
  931.             {
  932.               case '*':
  933.                 smstack= smode;
  934.                 smode= comment_mode;
  935.                 break;
  936.  
  937.               case '/':
  938.                 smstack= smode;
  939.                 smode= remark_mode;
  940.                 break;
  941.  
  942.               default:
  943.                 if(smode==data_mode)
  944.                 {
  945.                   lerror(line,"missing or unexpected slash `/'");
  946.                 }
  947.                 else /* smode==instruction_mode */
  948.                 {
  949.                   lerror(line,"misplaced single slash `/'; division not supported");
  950.                 }
  951.                 smode= error_mode;
  952.                 ungetc(c,fp);
  953.                 break;
  954.             }
  955.             break;
  956.  
  957.           case decimal_mode:
  958.             xhsbuf[n++]= (char)ccode;
  959.             smode= instruction_mode;
  960.             ungetc(c,fp);
  961.             break;
  962.  
  963.           case hex_mode:
  964.           case octal_mode:
  965.             if(smstack==string_mode)
  966.             {
  967.               if(ccdigits==0)
  968.               { /* can not happen in octal_mode in string_mode */
  969.                 lerror(line,"\\x used with no following hex digits");
  970.                 smode= error_mode;
  971.               }
  972.               else /* ccdigits > 0 */
  973.               {
  974.                 xhsbuf[n++]= (char)ccode;
  975.                 smode= smstack; /* == string_mode */
  976.                 ungetc(c,fp);
  977.               }
  978.             }
  979.             else /* smstack != string_mode */
  980.             { if(ccdigits==0)
  981.               {
  982.                 if(smode==hex_mode)
  983.                 {
  984.                   lerror(line,"$ used with no following hex digits");
  985.                   smode= error_mode;
  986.                 }
  987.                 else /* smode==octal_mode */
  988.                 {
  989.                   xhsbuf[n++]= (char)ccode; /* == 0 */
  990.                   smode= instruction_mode;
  991.                   ungetc(c,fp);
  992.                 }
  993.               }
  994.               else /* ccdigits > 0 */
  995.               {
  996.                 xhsbuf[n++]= (char)ccode;
  997.                 smode= instruction_mode;
  998.                 ungetc(c,fp);
  999.               }
  1000.             }
  1001.             break;
  1002.  
  1003.           case string_mode:
  1004.             xhsbuf[n++]= c;
  1005.             break;
  1006.  
  1007.           case remark_mode:
  1008.           case comment_mode:
  1009.           case return_mode:
  1010.           case error_mode:
  1011.           case panic_mode:
  1012.             break;
  1013.         }
  1014.         break;
  1015.  
  1016. /**/  case '*':
  1017.         switch(smode)
  1018.         {
  1019.           case comment_mode:
  1020.             switch(c= fgetc(fp))
  1021.             {
  1022.               case '/':
  1023.                 smode= smstack; /* data_mode or instruction_mode */
  1024.                 break;
  1025. #ifdef OBSOLETE
  1026.               default:
  1027.                 ungetc(c,fp);
  1028.                 break;
  1029. #endif
  1030.             }
  1031.             break;
  1032.  
  1033.           case decimal_mode:
  1034.             lerror(line,"misplaced asterisk `%c'; multiplication not supported",c);
  1035.             smode= error_mode;
  1036.             break;
  1037.  
  1038.           case hex_mode:
  1039.           case octal_mode:
  1040.             if(smstack==string_mode)
  1041.             {
  1042.               if(ccdigits==0)
  1043.               { /* can not happen in octal_mode in string_mode */
  1044.                 lerror(line,"\\x used with no following hex digits");
  1045.                 smode= error_mode;
  1046.               }
  1047.               else /* ccdigits > 0 */
  1048.               {
  1049.                 xhsbuf[n++]= (char)ccode;
  1050.                 smode= smstack; /* == string_mode */
  1051.                 ungetc(c,fp);
  1052.               }
  1053.             }
  1054.             else /* smstack != string_mode */
  1055.             {
  1056.               lerror(line,"misplaced asterisk `%c'; multiplication not supported",c);
  1057.               smode= error_mode;
  1058.             }
  1059.             break;
  1060.  
  1061.           case string_mode:
  1062.             xhsbuf[n++]= c;
  1063.             break;
  1064.  
  1065.           case data_mode:
  1066.           case instruction_mode:
  1067.             lerror(line,"misplaced or unexpected asterisk `%c'",c);
  1068.             break;
  1069.  
  1070.           case remark_mode:
  1071.           case return_mode:
  1072.           case error_mode:
  1073.           case panic_mode:
  1074.             break;
  1075.         }
  1076.         break;
  1077.  
  1078. /**/  case '0':
  1079.       case '1':
  1080.       case '2':
  1081.       case '3':
  1082.       case '4':
  1083.       case '5':
  1084.       case '6':
  1085.       case '7':
  1086.       case '8':
  1087.       case '9':
  1088.         switch(smode)
  1089.         {
  1090.           case data_mode:
  1091.             smstack= instruction_mode;
  1092.             if(c=='0')
  1093.             {
  1094.               smode= octal_mode;
  1095.               ccdigits= 0; /* allow another 'global_maxoctdigits' */
  1096.             }
  1097.             else /* c > '0' */
  1098.             {
  1099.               smode= decimal_mode;
  1100.             }
  1101.             ccode= (int)c-'0';
  1102.             break;
  1103.  
  1104.           case instruction_mode:
  1105.             lerror(line,"misplaced digit `%c' -- extra space or missing `%c'",c,CATSYM);
  1106.             smode= error_mode;
  1107.             break;
  1108.  
  1109.           case decimal_mode:
  1110.             ccode= ccode * 10 + c-'0';
  1111.             if(ccode > global_numchars)
  1112.             {
  1113.               lerror(line,"decimal value out of range for character (> %d)",
  1114.                 global_numchars-1);
  1115.               smode= error_mode;
  1116.             }
  1117.             break;
  1118.  
  1119.           case hex_mode:
  1120.             {
  1121.               int cc= ccode * 0x10 + c-'0';
  1122.  
  1123.               if(cc >= global_numchars)
  1124.               {
  1125.                 if(smstack==string_mode)
  1126.                 {
  1127.                   if(ccdigits==0)
  1128.                   { /* can only happen if global_numchars < 0x0F */
  1129.                     lerror(line,"\\x used with no following hex digits");
  1130.                     smode= error_mode;
  1131.                   }
  1132.                   else /* ccdigits > 0 */
  1133.                   {
  1134.                     xhsbuf[n++]= (char)ccode;
  1135.                     smode= smstack; /* == string_mode */
  1136.                     ungetc(c,fp);
  1137.                   }
  1138.                 }
  1139.                 else /* smstack != string_mode */
  1140.                 {
  1141.                   lerror(line,"hex value out of range for character (> $%x)",
  1142.                     global_numchars-1);
  1143.                   smode= error_mode;
  1144.                 }
  1145.               }
  1146.               else /* cc < global_numchars */
  1147.               {
  1148.                 ++ccdigits;
  1149.                 if(smstack == string_mode &&
  1150.                   ccdigits >= global_maxhexdigits)
  1151.                 {
  1152.                   xhsbuf[n++]= (char)cc;
  1153.                   smode= smstack; /* == string_mode */
  1154.                 }
  1155.                 else ccode= cc;
  1156.               }
  1157.             }
  1158.             break;
  1159.  
  1160.           case octal_mode:
  1161.             if(c=='8' || c=='9')
  1162.             {
  1163.               if(smstack==string_mode)
  1164.               {
  1165.                 xhsbuf[n++]= (char)ccode;
  1166.                 smode= smstack; /* == string_mode */
  1167.                 ungetc(c,fp);
  1168.               }
  1169.               else /* smstack != string_mode */
  1170.               {
  1171.                 lerror(line,"not an octal digit: `%c'",c);
  1172.                 smode= error_mode;
  1173.               }
  1174.             }
  1175.             else /* '0'<=c && c<='7' */
  1176.             {
  1177.               int cc= ccode * 010 + c-'0';
  1178.  
  1179.               if(cc >= global_numchars)
  1180.               {
  1181.                 if(smstack==string_mode)
  1182.                 {
  1183.                   /* we can be sure that ccdigits is >= 1 */
  1184.                   xhsbuf[n++]= ccode;
  1185.                   smode= smstack; /* == string_mode */
  1186.                   ungetc(c,fp);
  1187.                 }
  1188.                 else /* smstack != string_mode */
  1189.                 {
  1190.                   lerror(line,"octal value out of range for character (> 0%o)",
  1191.                     global_numchars-1);
  1192.                   smode= error_mode;
  1193.                 }
  1194.               }
  1195.               else /* cc < gobal_numchars */
  1196.               {
  1197.                 ++ccdigits;
  1198.                 if(smstack == string_mode &&
  1199.                   ccdigits >= global_maxoctdigits)
  1200.                 {
  1201.                   xhsbuf[n++]= (char)cc;
  1202.                   smode= smstack; /* == string_mode */
  1203.                 }
  1204.                 else ccode= cc;
  1205.               }
  1206.             }
  1207.             break;
  1208.  
  1209.           case string_mode:
  1210.             xhsbuf[n++]= c;
  1211.             break;
  1212.  
  1213.           case remark_mode:
  1214.           case comment_mode:
  1215.           case return_mode:
  1216.           case error_mode:
  1217.           case panic_mode:
  1218.             break;
  1219.         }
  1220.         break;
  1221.  
  1222. /**/  case 'A': case 'a':
  1223.       case 'B': case 'b':
  1224.       case 'C': case 'c':
  1225.       case 'D': case 'd':
  1226.       case 'E': case 'e':
  1227.       case 'F': case 'f':
  1228.         switch(smode)
  1229.         {
  1230.           case data_mode:
  1231.             lerror(line,"misplaced character `%c' -- missing quotes or `$'",c);
  1232.             smode= error_mode;
  1233.             break;
  1234.  
  1235.           case instruction_mode:
  1236.             lerror(line,"misplaced character `%c' -- extra space or missing quotes",c);
  1237.             smode= error_mode;
  1238.             break;
  1239.  
  1240.           case decimal_mode:
  1241.             lerror(line,"not a decimal digit: `%c'",c);
  1242.             smode= error_mode;
  1243.             break;
  1244.  
  1245.           case hex_mode:
  1246.             {
  1247.               int cc= ccode * 0x10 + toupper(c)-'A' + 0x0A;
  1248.  
  1249.               if(cc >= global_numchars)
  1250.               {
  1251.                 if(smstack==string_mode)
  1252.                 {
  1253.                   if(ccdigits==0)
  1254.                   { /* can only happen if global_numchars < 0x0F */
  1255.                     lerror(line,"\\x used with no following hex digits");
  1256.                     smode= error_mode;
  1257.                   }
  1258.                   else /* ccdigits > 0 */
  1259.                   {
  1260.                     xhsbuf[n++]= (char)ccode;
  1261.                     smode= smstack; /* == string_mode */
  1262.                     ungetc(c,fp);
  1263.                   }
  1264.                 }
  1265.                 else /* smstack != string_mode */
  1266.                 {
  1267.                   lerror(line,"hex value out of range for character (> $%x)",
  1268.                     global_numchars-1);
  1269.                   smode= error_mode;
  1270.                 }
  1271.               }
  1272.               else /* cc < global_numchars */
  1273.               {
  1274.                 ++ccdigits;
  1275.                 if(smstack == string_mode &&
  1276.                   ccdigits >= global_maxhexdigits)
  1277.                 {
  1278.                   xhsbuf[n++]= (char)cc;
  1279.                   smode= smstack; /* == string_mode */
  1280.                 }
  1281.                 else ccode= cc;
  1282.               }
  1283.             }
  1284.             break;
  1285.  
  1286.           case octal_mode:
  1287.             if(smstack==string_mode)
  1288.             {
  1289.               xhsbuf[n++]= ccode;
  1290.               smode= smstack; /* == string_mode */
  1291.               ungetc(c,fp);
  1292.             }
  1293.             else
  1294.             {
  1295.               lerror(line,"not an octal digit: `%c'",c);
  1296.               smode= error_mode;
  1297.             }
  1298.             break;
  1299.  
  1300.           case string_mode:
  1301.             xhsbuf[n++]= c;
  1302.             break;
  1303.  
  1304.           case remark_mode:
  1305.           case comment_mode:
  1306.           case return_mode:
  1307.           case error_mode:
  1308.           case panic_mode:
  1309.             break;
  1310.         }
  1311.         break;
  1312.  
  1313. /**/  default:
  1314.         switch(smode)
  1315.         {
  1316.           case data_mode:
  1317.           case instruction_mode:
  1318.           case decimal_mode:
  1319.           case hex_mode:
  1320.           case octal_mode:
  1321.             if( isprint(c) )
  1322.             {
  1323.               lerror(line,"parse error: misplaced character `%c'",c);
  1324.             }
  1325.             else /* !isprint(c) */
  1326.             {
  1327.               lerror(line,"parse error: unknown character code 0x%x",c);
  1328.             }
  1329.             smode= error_mode;
  1330.             break;
  1331.  
  1332.           case string_mode:
  1333.             xhsbuf[n++]= c;
  1334.             break;
  1335.  
  1336.           case remark_mode:
  1337.           case comment_mode:
  1338.           case return_mode:
  1339.           case error_mode:
  1340.           case panic_mode:
  1341.             break;
  1342.         }
  1343.         break;
  1344.     }
  1345.  
  1346.     if(n >= bufsize)
  1347.     {
  1348.       bufsize += XHSBUFSIZE;
  1349.       xhsbuf= (unsigned char *)realloc(xhsbuf, bufsize);
  1350.       if(!xhsbuf)
  1351.       {
  1352.         lerror(line,"not enough memory to enlarge scanner buffer to %ld bytes",
  1353.           bufsize);
  1354.         smode= panic_mode;
  1355.       }
  1356. #ifdef DEBUG
  1357.       else if(debuglevel >= 1)
  1358.       {
  1359.         printf("scanner buffer enlarged to %ld bytes in line %ld\n",
  1360.           bufsize, line);
  1361.       }
  1362. #endif /* DEBUG */
  1363.     }
  1364.  
  1365.     /* avoid generation of further, spurious error messages */
  1366.  
  1367.     if( smode == error_mode && c != RTERM )
  1368.     {
  1369.       while( !feof(fp) && !ferror(fp) && (c= fgetc(fp)) != RTERM )
  1370.       {
  1371.         if(c=='\n' || c=='\r')
  1372.         {
  1373.           int d= fgetc(fp);
  1374.           if(!( (c=='\n' && d=='\r') || (c=='\r' && d=='\n') ))
  1375.             ungetc(d,fp);
  1376.  
  1377.           ++line;
  1378.         }
  1379.       }
  1380.     }
  1381.   }
  1382.  
  1383.   if(smode == return_mode)
  1384.   {
  1385.     cr->ln= line;
  1386.  
  1387.     if(n>0)
  1388.     { char *t;
  1389.       if( t= (char *)malloc(n*sizeof(char)) )
  1390.       { memcpy(t, xhsbuf, n);
  1391.         cr->rhs= t;
  1392.         cr->r= n;
  1393.         ++global_numrules;
  1394.       }
  1395.       else
  1396.       {
  1397.         lerror(line,"not enough memory for another %d bytes rhs",n);
  1398.         smode= panic_mode;
  1399.       }
  1400.     }
  1401.     else /* just to be sure... */
  1402.     {
  1403.       cr->rhs= (char *)0L;
  1404.       cr->r= 0L;
  1405.       ++global_numrules;
  1406.     }
  1407.   }
  1408.  
  1409.   return (smode == return_mode) ? cr : dispose(cr);
  1410. }
  1411.