home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / vers_con / dosrcs / rcslex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-18  |  23.8 KB  |  797 lines

  1. /*
  2.  *                     RCS file input
  3.  */
  4. #ifndef lint
  5. static char rcsid[]= "$Id: rcslex.c,v 5.2 90/07/15 11:34:18 ROOT_DOS Release $ Purdue CS";
  6. #endif
  7. /*********************************************************************************
  8.  *                     Lexical Analysis.
  9.  *                     Character mapping table,
  10.  *                     hashtable, Lexinit, nextlex, getlex, getkey,
  11.  *                     getid, getnum, readstring, printstring, savestring,
  12.  *                     checkid, serror, fatserror, error, faterror, warn, diagnose
  13.  *                     fflsbuf, puts, fprintf
  14.  *                     Testprogram: define LEXDB
  15.  *********************************************************************************
  16.  */
  17.  
  18. /* Copyright (C) 1982, 1988, 1989 Walter Tichy
  19.    Distributed under license by the Free Software Foundation, Inc.
  20.  
  21. This file is part of RCS.
  22.  
  23. RCS is free software; you can redistribute it and/or modify
  24. it under the terms of the GNU General Public License as published by
  25. the Free Software Foundation; either version 1, or (at your option)
  26. any later version.
  27.  
  28. RCS is distributed in the hope that it will be useful,
  29. but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  31. GNU General Public License for more details.
  32.  
  33. You should have received a copy of the GNU General Public License
  34. along with RCS; see the file COPYING.  If not, write to
  35. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  36.  
  37. Report problems and direct all questions to:
  38.  
  39.     rcs-bugs@cs.purdue.edu
  40.  
  41. */
  42.  
  43.  
  44.  
  45. /* $Log:    rcslex.c,v $
  46.  * Revision 5.2  90/07/15  11:34:18  ROOT_DOS
  47.  * DOS version of RCS 4.0 checked in for MODS
  48.  * by lfk@athena.mit.edu
  49.  * Also update to MSC 6.0
  50.  * 
  51.  * Revision 4.6  89/05/01  15:13:07  narten
  52.  * changed copyright header to reflect current distribution rules
  53.  * 
  54.  * Revision 4.5  88/11/08  12:00:54  narten
  55.  * changes from  eggert@sm.unisys.com (Paul Eggert)
  56.  * 
  57.  * Revision 4.5  88/08/28  15:01:12  eggert
  58.  * Don't loop when writing error messages to a full filesystem.
  59.  * Flush stderr/stdout when mixing output.
  60.  * Yield exit status compatible with diff(1).
  61.  * Shrink stdio code size; allow cc -R; remove lint.
  62.  * 
  63.  * Revision 4.4  87/12/18  11:44:47  narten
  64.  * fixed to use "varargs" in "fprintf"; this is required if it is to
  65.  * work on a SPARC machine such as a Sun-4
  66.  * 
  67.  * Revision 4.3  87/10/18  10:37:18  narten
  68.  * Updating version numbers. Changes relative to 1.1 actually relative
  69.  * to version 4.1
  70.  * 
  71.  * Revision 1.3  87/09/24  14:00:17  narten
  72.  * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  73.  * warnings)
  74.  * 
  75.  * Revision 1.2  87/03/27  14:22:33  jenkins
  76.  * Port to suns
  77.  * 
  78.  * Revision 1.1  84/01/23  14:50:33  kcs
  79.  * Initial revision
  80.  * 
  81.  * Revision 4.1  83/03/25  18:12:51  wft
  82.  * Only changed $Header to $Id.
  83.  * 
  84.  * Revision 3.3  82/12/10  16:22:37  wft
  85.  * Improved error messages, changed exit status on error to 1.
  86.  *
  87.  * Revision 3.2  82/11/28  21:27:10  wft
  88.  * Renamed ctab to map and included EOFILE; ctab is now a macro in rcsbase.h.
  89.  * Added fflsbuf(), fputs(), and fprintf(), which abort the RCS operations
  90.  * properly in case there is an IO-error (e.g., file system full).
  91.  *
  92.  * Revision 3.1  82/10/11  19:43:56  wft
  93.  * removed unused label out:;
  94.  * made sure all calls to getc() return into an integer, not a char.
  95.  */
  96.  
  97.  
  98. /*
  99. #define LEXDB
  100. /* version LEXDB is for testing the lexical analyzer. The testprogram
  101.  * reads a stream of lexemes, enters the revision numbers into the
  102.  * hashtable, and prints the recognized tokens. Keywords are recognized
  103.  * as identifiers.
  104.  */
  105.  
  106.  
  107.  
  108. #include "rcsbase.h"
  109. #include <varargs.h>
  110.  
  111.  
  112.  
  113. /* character mapping table */
  114. enum tokens map[] = {
  115.         EOFILE,         /* this will end up at ctab[-1] */
  116.         UNKN,   INSERT, UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
  117.         UNKN,   SPACE,  NEWLN,  UNKN,   SPACE,  UNKN,   UNKN,   UNKN,
  118.         UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
  119.         UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
  120.         SPACE,  EXCLA,  DQUOTE, HASH,   DOLLAR, PERCNT, AMPER,  SQUOTE,
  121.         LPARN,  RPARN,  TIMES,  PLUS,   COMMA,  MINUS,  PERIOD, DIVIDE,
  122.         DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,
  123.         DIGIT,  DIGIT,  COLON,  SEMI,   LESS,   EQUAL,  GREAT,  QUEST,
  124.         AT,     LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
  125.         LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
  126.         LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
  127.         LETTER, LETTER, LETTER, LBRACK, BACKSL, RBRACK, UPARR,  UNDER,
  128.         ACCENT, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
  129.         LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
  130.         LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
  131.         LETTER, LETTER, LETTER, LBRACE, BAR,    RBRACE, TILDE,  UNKN
  132. };
  133.  
  134.  
  135.  
  136.  
  137. struct hshentry * nexthsh;  /*pointer to next hashtable-entry, set by lookup*/
  138.  
  139. enum tokens     nexttok;    /*next token, set by nextlex                    */
  140.  
  141. int             hshenter;   /*if true, next suitable lexeme will be entered */
  142.                             /*into the symbol table. Handle with care.      */
  143. int             nextc;      /*next input character, initialized by Lexinit  */
  144.  
  145. #ifdef MSDOS
  146. int             eoftok;        /*end-of-file indicator, set to >0 on end of file*/
  147. #else
  148. int             eof;        /*end-of-file indicator, set to >0 on end of file*/
  149. #endif /* MSDOS */
  150. int             line;       /*current line-number of input                  */
  151. int             nerror;     /*counter for errors                            */
  152. int             nwarn;      /*counter for warnings                          */
  153. char *          cmdid;      /*command identification for error messages     */
  154. int             quietflag;  /*indicates quiet mode                          */
  155. FILE *          finptr;     /*input file descriptor                         */
  156.  
  157. FILE *          frewrite;   /*file descriptor for echoing input             */
  158.  
  159. int             rewriteflag;/*indicates whether to echo to frewrite         */
  160.  
  161. char            StringTab[strtsize]; /* string table and heap               */
  162.  
  163. char *          NextString;         /*pointer to next identifier in StringTab*/
  164. char *          Topchar;            /*pointer to next free byte in StringTab*/
  165.                                     /*set by nextlex, lookup                */
  166. struct hshentry hshtab[hshsize];    /*hashtable                             */
  167.  
  168.  
  169.  
  170.  
  171.  
  172. lookup() {
  173.  
  174. /* Function: Looks up the character string pointed to by NextString in the
  175.  * hashtable. If the string is not present, a new entry for it is created.
  176.  * If the string is present, TopChar is moved back to save the space for
  177.  * the string, and NextString is set to point to the original string.
  178.  * In any case, the address of the corresponding hashtable entry is placed
  179.  * into nexthsh.
  180.  * Algorithm: Quadratic hash, covering all entries.
  181.  * Assumptions: NextString points at the first character of the string.
  182.  * Topchar points at the first empty byte after the string.
  183.  */
  184.  
  185.         register int     ihash;      /* index into hashtable */
  186.         register char    * sp, * np;
  187.         int              c, delta, final, FirstScan; /*loop control*/
  188.  
  189.         /* calculate hash code */
  190.         sp = NextString;
  191.         ihash = 0;
  192.         while (*sp) ihash += *sp++;
  193.  
  194.         /* set up first search loop (c=0,step=1,until (hshsiz-1)/2 */
  195.         c=0;delta=1;final=(hshsize-1)/2;
  196.         FirstScan=true;   /*first loop */
  197.  
  198.         for (;;) {
  199.                 ihash = (ihash+c)%hshsize;   /*next index*/
  200.  
  201.                 if (hshtab[ihash].num == nil) {
  202.                         /*empty slot found*/
  203.                         hshtab[ihash].num = NextString;
  204.                         nexthsh= &hshtab[ihash];/*save hashtable address*/
  205. #                       ifdef LEXDB
  206.                         VOID printf("\nEntered: %s at %d ",nexthsh->num, ihash);
  207. #                       endif
  208.                         return;
  209.                 }
  210.                 /* compare strings */
  211.                 sp=NextString;np=hshtab[ihash].num;
  212.                 while (*sp == *np++) {
  213.                         if (*sp == 0) {
  214.                                 /* match found */
  215.                                 nexthsh= &hshtab[ihash];
  216.                                 Topchar = NextString;
  217.                                 NextString = nexthsh->num;
  218.                                 return;
  219.                         } else sp++;
  220.                 }
  221.  
  222.                 /* neither empty slot nor string found */
  223.                 /* calculate next index and repeat */
  224.                 if (c != final)
  225.                         c += delta;
  226.                 else {
  227.                         if (FirstScan) {
  228.                                 /*set up second sweep*/
  229.                                 delta = -1; final = 1; FirstScan= false;
  230.                         } else {
  231.                                 fatserror("Hashtable overflow");
  232.                         }
  233.                 }
  234.         }
  235. };
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242. Lexinit()
  243. /* Function: Initialization of lexical analyzer:
  244.  * initializes the hastable,
  245.  * initializes nextc, nexttok if finptr != NULL
  246.  */
  247. {       register int            c;
  248.  
  249.         for (c=hshsize-1; c>=0; c--) {
  250.                 hshtab[c].num = nil;
  251.         }
  252.  
  253. #ifdef MSDOS
  254.         hshenter=true; eoftok=0; line=1; nerror=0; nwarn=0;
  255. #else
  256.         hshenter=true; eof=0; line=1; nerror=0; nwarn=0;
  257. #endif /* MSDOS */
  258.         NextString=nil; Topchar = &StringTab[0];
  259.         if (finptr) {
  260.                 nextc = GETC(finptr,frewrite,rewriteflag); /*initial character*/
  261.                 nextlex();            /*initial token*/
  262.         } else {
  263.                 nextc = '\0';
  264.                 nexttok=EOFILE;
  265.         }
  266. }
  267.  
  268.  
  269.  
  270.  
  271.  
  272.  
  273.  
  274. nextlex()
  275.  
  276. /* Function: Reads the next token and sets nexttok to the next token code.
  277.  * Only if the hshenter==true, a revision number is entered into the
  278.  * hashtable and a pointer to it is placed into nexthsh.
  279.  * This is useful for avoiding that dates are placed into the hashtable.
  280.  * For ID's and NUM's, NextString is set to the character string in the
  281.  * string table. Assumption: nextc contains the next character.
  282.  */
  283. {       register c;
  284.     register FILE * fin, * frew;
  285.         register char * sp;
  286.         register enum tokens d;
  287.  
  288. #ifdef MSDOS
  289.         if (eoftok) {
  290. #else
  291.         if (eof) {
  292. #endif /* MSDOS */
  293.                 nexttok=EOFILE;
  294.                 return;
  295.         }
  296.     fin=finptr; frew=frewrite;
  297. loop:
  298.         switch(nexttok=ctab[nextc]) {
  299.  
  300.         case UNKN:
  301.         case IDCHAR:
  302.         case PERIOD:
  303.                 serror("unknown Character: %c",nextc);
  304.                 nextc=GETC(fin,frew,rewriteflag);
  305.                 goto loop;
  306.  
  307.         case NEWLN:
  308.                 line++;
  309. #               ifdef LEXDB
  310.                 VOID putchar('\n');
  311. #               endif
  312.                 /* Note: falls into next case */
  313.  
  314.         case SPACE:
  315.                 nextc=GETC(fin,frew,rewriteflag);
  316.                 goto loop;
  317.  
  318.         case EOFILE:
  319. #ifdef MSDOS
  320.                 eoftok++;
  321. #else
  322.                 eof++;
  323. #endif /* MSDOS */
  324.                 nexttok=EOFILE;
  325.                 return;
  326.  
  327.         case DIGIT:
  328.                 NextString = sp = Topchar;
  329.                 *sp++ = nextc;
  330.                 while ((d=ctab[c=GETC(fin,frew,rewriteflag)])==DIGIT ||
  331.                         d==PERIOD) {
  332.                         *sp++ = c;         /* 1.2. and 1.2 are different */
  333.                 }
  334.                 *sp++ = '\0';
  335.                 if (sp >= StringTab+strtsize) {
  336.                         /*may have written outside stringtable already*/
  337.                         fatserror("Stringtable overflow");
  338.                 }
  339.                 Topchar = sp;
  340.                 nextc = c;
  341.                 if (hshenter == true)
  342.                         lookup();      /* lookup updates NextString, Topchar*/
  343.                 nexttok = NUM;
  344.                 return;
  345.  
  346.  
  347.         case LETTER:
  348.                 NextString = sp = Topchar;
  349.                 *sp++ = nextc;
  350.                 while ((d=ctab[c=GETC(fin,frew,rewriteflag)])==LETTER ||
  351.                         d==DIGIT || d==IDCHAR) {
  352.                         *sp++ = c;
  353.                 }
  354.                 *sp++ = '\0';
  355.                 if (sp >= StringTab+strtsize) {
  356.                         /*may have written outside stringtable already*/
  357.                         fatserror("Stringtable overflow");
  358.                 }
  359.                 Topchar = sp;
  360.                 nextc = c;
  361.                 nexttok = ID;  /* may be ID or keyword */
  362.                 return;
  363.  
  364.         case SBEGIN: /* long string */
  365.                 nexttok = STRING;
  366.                 /* note: only the initial SBEGIN has been read*/
  367.                 /* read the string, and reset nextc afterwards*/
  368.                 return;
  369.  
  370.         default:
  371.                 nextc=GETC(fin,frew,rewriteflag);
  372.                 return;
  373.         }
  374. }
  375.  
  376.  
  377. int getlex(token)
  378. enum tokens token;
  379. /* Function: Checks if nexttok is the same as token. If so,
  380.  * advances the input by calling nextlex and returns true.
  381.  * otherwise returns false.
  382.  * Doesn't work for strings and keywords; loses the character string for ids.
  383.  */
  384. {
  385.         if (nexttok==token) {
  386.                 nextlex();
  387.                 return(true);
  388.         } else  return(false);
  389. }
  390.  
  391. int getkey (key)
  392. char * key;
  393. /* Function: If the current token is a keyword identical to key,
  394.  * getkey advances the input by calling nextlex and returns true;
  395.  * otherwise returns false.
  396.  */
  397. {
  398.         register char *s1,*s2;
  399.  
  400.         if (nexttok==ID) {
  401.                 s1=key; s2=NextString;
  402.                 while(*s1 == *s2++)
  403.                      if (*s1++ == '\0') {
  404.                          /* match found */
  405.                          Topchar = NextString; /*reset Topchar */
  406.                          nextlex();
  407.                          return(true);
  408.                      }
  409.         }
  410.         return(false);
  411. }
  412.  
  413.  
  414.  
  415. char * getid()
  416. /* Function: Checks if nexttok is an identifier. If so,
  417.  * advances the input by calling nextlex and returns a pointer
  418.  * to the identifier; otherwise returns nil.
  419.  * Treats keywords as identifiers.
  420.  */
  421. {
  422.         register char * name;
  423.         if (nexttok==ID) {
  424.                 name = NextString;
  425.                 nextlex();
  426.                 return name;
  427.         } else  return nil;
  428. }
  429.  
  430.  
  431. struct hshentry * getnum()
  432. /* Function: Checks if nexttok is a number. If so,
  433.  * advances the input by calling nextlex and returns a pointer
  434.  * to the hashtable entry. Otherwise returns nil.
  435.  * Doesn't work if hshenter is false.
  436.  */
  437. {
  438.         register struct hshentry * num;
  439.         if (nexttok==NUM) {
  440.                 num=nexthsh;
  441.                 nextlex();
  442.                 return num;
  443.         } else  return nil;
  444. }
  445.  
  446.  
  447. readstring()
  448. /* skip over characters until terminating single SDELIM        */
  449. /* if rewriteflag==true, copy every character read to frewrite.*/
  450. /* Does not advance nextlex at the end.                        */
  451. {       register c;
  452.     register FILE * fin,  * frew;
  453.     fin=finptr; frew=frewrite;
  454.         if (rewriteflag) {
  455.                 /* copy string verbatim to frewrite */
  456.                 while ((c=getc(fin)) != EOF) {
  457.             VOID putc(c,frew);
  458.                         if (c==SDELIM) {
  459.                                 if ((c=getc(fin)) == EOF || putc(c,frew) != SDELIM) {
  460.                                         /* end of string */
  461.                                         nextc=c;
  462.                                         return;
  463.                                 }
  464.                         }
  465.                 }
  466.         } else {
  467.                 /* skip string */
  468.                 while ((c=getc(fin)) != EOF) {
  469.                         if (c==SDELIM) {
  470.                                 if ((c=getc(fin)) != SDELIM) {
  471.                                         /* end of string */
  472.                                         nextc=c;
  473.                                         return;
  474.                                 }
  475.                         }
  476.                 }
  477.         }
  478.         nextc = c;
  479.         error("Unterminated string");
  480. }
  481.  
  482.  
  483. printstring()
  484. /* Function: copy a string to stdout, until terminated with a single SDELIM.
  485.  * Does not advance nextlex at the end.
  486.  */
  487. {
  488.         register c;
  489.     register FILE * fin;
  490.     fin=finptr;
  491.     while ((c=getc(fin)) != EOF) {
  492.                 if (c==SDELIM) {
  493.             if ((c=getc(fin)) != SDELIM) {
  494.                                 /* end of string */
  495.                                 nextc=c;
  496.                                 return;
  497.                         }
  498.                 }
  499.                 VOID putchar(c);
  500.         }
  501.         nextc = c;
  502.         error("Unterminated string");
  503. }
  504.  
  505.  
  506.  
  507. savestring(target,length)
  508. char * target; int length;
  509. /* copies a string terminated with SDELIM from file finptr to buffer target,
  510.  * but not more than length bytes. If the string is longer than length,
  511.  * the extra characters are skipped. The string may be empty, in which
  512.  * case a '\0' is placed into target.
  513.  * Double SDELIM is replaced with SDELIM.
  514.  * If rewriteflag==true, the string is also copied unchanged to frewrite.
  515.  * Returns the length of the saved string.
  516.  * Does not advance nextlex at the end.
  517.  */
  518. {
  519.         register c;
  520.     register FILE * fin, * frew;
  521.         register char * tp, * max;
  522.  
  523.     fin=finptr; frew=frewrite;
  524.         tp=target; max= target+length; /*max is one too large*/
  525.         while ((c=GETC(fin,frew,rewriteflag))!=EOF) {
  526.         *tp++ =c;
  527.                 if (c== SDELIM) {
  528.                         if ((c=GETC(fin,frew,rewriteflag))!=SDELIM) {
  529.                                 /* end of string */
  530.                                 *(tp-1)='\0';
  531.                                 nextc=c;
  532.                                 return;
  533.                         }
  534.                 }
  535.                 if (tp >= max) {
  536.                         /* overflow */
  537.                         error("string buffer overflow -- truncating string");
  538.                         target[length-1]='\0';
  539.                         /* skip rest of string */
  540.                         while ((c=GETC(fin,frew,rewriteflag))!=EOF) {
  541.                                 if ((c==SDELIM) && ((c=GETC(fin,frew,rewriteflag))!=SDELIM)) {
  542.                                         /* end of string */
  543.                                         nextc=c;
  544.                                         return;
  545.                                 }
  546.                         }
  547.                         nextc = c;
  548.                         error("Can't find %c to terminate string before end of file",SDELIM);
  549.                         return;
  550.                 }
  551.         }
  552.         nextc = c;
  553.         error("Can't find %c to terminate string before end of file",SDELIM);
  554. }
  555.  
  556.  
  557. char  *checkid(id, delim)
  558. char    *id, delim;
  559. /*   Function:  check whether the string starting at id is an   */
  560. /*              identifier and return a pointer to the last char*/
  561. /*              of the identifer. White space, delim and '\0'   */
  562. /*              are legal delimeters. Aborts the program if not */
  563. /*              a legal identifier. Useful for checking commands*/
  564. {
  565.         register enum  tokens  d;
  566.         register char    *temp;
  567.         register char    c,tc;
  568.  
  569.         temp = id;
  570.         if ( ctab[*id] == LETTER ) {
  571.             while( (d=ctab[c=(*++id)]) == LETTER || d==DIGIT || d==IDCHAR) ;
  572.             if ( c!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) {
  573.                 /* append \0 to end of id before error message */
  574.                 tc = c;
  575.                 while( (c=(*++id))!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) ;
  576.                 *id = '\0';
  577.                 faterror("Invalid character %c in identifier %s",tc,temp);
  578.                 return nil ;
  579.             } else
  580.                 return id;
  581.         } else {
  582.             /* append \0 to end of id before error message */
  583.             while( (c=(*++id))!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) ;
  584.             *id = '\0';
  585.             faterror("Identifier %s does not start with letter",temp);
  586.             return nil;
  587.         }
  588. }
  589.  
  590. writeerror()
  591. {
  592.     static looping;
  593.     if (looping)
  594.         exit(2);
  595.     looping = 1;
  596.     faterror("write error");
  597. }
  598.  
  599. nlflush(iop)
  600. register FILE * iop;
  601. {
  602.     if (putc('\n',iop)==EOF || fflush(iop)==EOF)
  603.                 writeerror();
  604. }
  605.  
  606.  
  607. /*VARARGS1*/
  608. serror(e,e1,e2,e3,e4,e5)
  609. char * e, * e1, * e2, * e3, * e4, * e5;
  610. /* non-fatal syntax error */
  611. {       nerror++;
  612.         VOID fprintf(stderr,"%s error, line %d: ", cmdid, line);
  613.         VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
  614.         nlflush(stderr);
  615. }
  616.  
  617. /*VARARGS1*/
  618. error(e,e1,e2,e3,e4,e5)
  619. char * e, * e1, * e2, * e3, * e4, * e5;
  620. /* non-fatal error */
  621. {       nerror++;
  622.         VOID fprintf(stderr,"%s error: ",cmdid);
  623.         VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
  624.         nlflush(stderr);
  625. }
  626.  
  627. /*VARARGS1*/
  628. fatserror(e,e1,e2,e3,e4,e5)
  629. char * e, * e1, * e2, * e3, * e4, * e5;
  630. /* fatal syntax error */
  631. {       nerror++;
  632.         VOID fprintf(stderr,"%s error, line %d: ", cmdid,line);
  633.         VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
  634.         VOID fprintf(stderr,"\n%s aborted\n",cmdid);
  635.         VOID cleanup();
  636.         exit(2);
  637. }
  638.  
  639. /*VARARGS1*/
  640. faterror(e,e1,e2,e3,e4,e5)
  641. char * e, * e1, * e2, * e3, * e4, * e5;
  642. /* fatal error, terminates program after cleanup */
  643. {       nerror++;
  644.         VOID fprintf(stderr,"%s error: ",cmdid);
  645.         VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
  646.         VOID fprintf(stderr,"\n%s aborted\n",cmdid);
  647.         VOID cleanup();
  648.         exit(2);
  649. }
  650.  
  651. /*VARARGS1*/
  652. warn(e,e1,e2,e3,e4,e5)
  653. char * e, * e1, * e2, * e3, * e4, * e5;
  654. /* prints a warning message */
  655. {       nwarn++;
  656.         VOID fprintf(stderr,"%s warning: ",cmdid);
  657.         VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
  658.         nlflush(stderr);
  659. }
  660.  
  661.  
  662. /*VARARGS1*/
  663. diagnose(e,e1,e2,e3,e4,e5)
  664. char * e, * e1, * e2, * e3, * e4, * e5;
  665. /* prints a diagnostic message */
  666. {
  667.         if (!quietflag) {
  668.                 VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
  669.                 nlflush(stderr);
  670.         }
  671. }
  672.  
  673.  
  674.  
  675. fflsbuf(c, iop)
  676. unsigned c; register FILE * iop;
  677. /* Function: Flush iop.
  678.  * Same routine as _flsbuf in stdio, but aborts program on error.
  679.  */
  680. {       register result;
  681.         if ((result=_flsbuf(c,iop))==EOF)
  682.                 writeerror();
  683.         return result;
  684. }
  685.  
  686.  
  687. fputs(s, iop)
  688. register char *s;
  689. register FILE *iop;
  690. /* Function: Put string s on file iop, abort on error.
  691.  * Same as puts in stdio, but with different putc macro.
  692.  */
  693. {
  694.     register r;
  695.     register c;
  696.  
  697.     while (c = *s++)
  698.         r = putc(c, iop);
  699.     return(r);
  700. }
  701.  
  702.  
  703.  
  704. fprintf(iop, fmt, va_alist)
  705. FILE *iop;
  706. char *fmt;
  707. va_dcl
  708. /* Function: formatted output. Same as fprintf in stdio,
  709.  * but aborts program on error
  710.  */
  711. {
  712.     register int value;
  713.     va_list ap;
  714.  
  715.     va_start(ap);
  716. #ifdef MSDOS
  717.     VOID vfprintf(iop, fmt, ap);
  718. #else
  719. #ifdef VFPRINTF
  720.     VOID vfprintf(iop, fmt, ap);
  721. #else
  722.     _doprnt(fmt, ap, iop);
  723. #endif
  724. #endif /* MSDOS */
  725.         if (ferror(iop)) {
  726.         writeerror();
  727.                 value = EOF;
  728.         } else value = 0;
  729.     va_end(ap);
  730.     return value;
  731. }
  732.  
  733.  
  734.  
  735. #ifdef LEXDB
  736. /* test program reading a stream of lexems and printing the tokens.
  737.  */
  738.  
  739.  
  740.  
  741. main(argc,argv)
  742. int argc; char * argv[];
  743. {
  744.         cmdid="lextest";
  745.         if (argc<2) {
  746.                 VOID fputs("No input file\n",stderr);
  747.                 exit(1);
  748.         }
  749.         if ((finptr=fopen(argv[1], "r")) == NULL) {
  750.                 faterror("Can't open input file %s\n",argv[1]);
  751.         }
  752.         Lexinit();
  753.         rewriteflag=false;
  754.         while (nexttok != EOFILE) {
  755.         switch (nexttok) {
  756.  
  757.         case ID:
  758.                 VOID printf("ID: %s",NextString);
  759.                 break;
  760.  
  761.         case NUM:
  762.                 if (hshenter==true)
  763.                    VOID printf("NUM: %s, index: %d",nexthsh->num, nexthsh-hshtab);
  764.                 else
  765.                    VOID printf("NUM, unentered: %s",NextString);
  766.                 hshenter = !hshenter; /*alternate between dates and numbers*/
  767.                 break;
  768.  
  769.         case COLON:
  770.                 VOID printf("COLON"); break;
  771.  
  772.         case SEMI:
  773.                 VOID printf("SEMI"); break;
  774.  
  775.         case STRING:
  776.                 readstring();
  777.                 VOID printf("STRING"); break;
  778.  
  779.         case UNKN:
  780.                 VOID printf("UNKN"); break;
  781.  
  782.         default:
  783.                 VOID printf("DEFAULT"); break;
  784.         }
  785.         VOID printf(" | ");
  786.         nextlex();
  787.         }
  788.         VOID printf("\nEnd of lexical analyzer test\n");
  789. }
  790.  
  791. cleanup()
  792. /* dummy */
  793. {}
  794.  
  795.  
  796. #endif
  797.