|
|
1.1 ! root 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, UNKN, 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: ! 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: ! 663: ! 664: #ifdef LEXDB ! 665: /* test program reading a stream of lexems and printing the tokens. ! 666: */ ! 667: ! 668: ! 669: ! 670: main(argc,argv) ! 671: int argc; char * argv[]; ! 672: { ! 673: cmdid="lextest"; ! 674: if (argc<2) { ! 675: VOID fputs("No input file\n",stderr); ! 676: exit(1); ! 677: } ! 678: if ((finptr=fopen(argv[1], "r")) == NULL) { ! 679: faterror("Can't open input file %s\n",argv[1]); ! 680: } ! 681: Lexinit(); ! 682: rewriteflag=false; ! 683: while (nexttok != EOFILE) { ! 684: switch (nexttok) { ! 685: ! 686: case ID: ! 687: VOID printf("ID: %s",NextString); ! 688: break; ! 689: ! 690: case NUM: ! 691: if (hshenter==true) ! 692: VOID printf("NUM: %s, index: %d",nexthsh->num, nexthsh-hshtab); ! 693: else ! 694: VOID printf("NUM, unentered: %s",NextString); ! 695: hshenter = !hshenter; /*alternate between dates and numbers*/ ! 696: break; ! 697: ! 698: case COLON: ! 699: VOID printf("COLON"); break; ! 700: ! 701: case SEMI: ! 702: VOID printf("SEMI"); break; ! 703: ! 704: case STRING: ! 705: readstring(); ! 706: VOID printf("STRING"); break; ! 707: ! 708: case UNKN: ! 709: VOID printf("UNKN"); break; ! 710: ! 711: default: ! 712: VOID printf("DEFAULT"); break; ! 713: } ! 714: VOID printf(" | "); ! 715: nextlex(); ! 716: } ! 717: VOID printf("\nEnd of lexical analyzer test\n"); ! 718: } ! 719: ! 720: cleanup() ! 721: /* dummy */ ! 722: {} ! 723: ! 724: ! 725: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.