home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / rcs4.lha / rcslex.c < prev    next >
Text File  |  1993-03-03  |  23KB  |  727 lines

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