home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / RCS_SRC.ZIP / RCSLEX.C < prev    next >
C/C++ Source or Header  |  1991-01-15  |  25KB  |  772 lines

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