home *** CD-ROM | disk | FTP | other *** search
/ ftp.ee.pdx.edu / 2014.02.ftp.ee.pdx.edu.tar / ftp.ee.pdx.edu / pub / users / Harry / compilers / yapp / lexer.c < prev    next >
C/C++ Source or Header  |  2003-05-23  |  15KB  |  416 lines

  1. /* lexer.c
  2. **
  3. ** The PCAT lexer with modifications for use as a YAPP preprocessor.
  4. **
  5. ** Harry Porter, 10/8/98.
  6. **               11/4/98 - YAPP modifications.
  7. **
  8. ** This file provides the routine getToken() which returns a single token
  9. ** for every call.  It returns zero after the source code file
  10. ** has been exhausted.  It reads from stdin.
  11. **
  12. ** This file also contains calls to lexError().
  13. */
  14.  
  15. #include <stdio.h>
  16. #include <stdarg.h>
  17. #include <float.h>
  18. #include <string.h>
  19. #include "lexer.h"
  20.  
  21. int getToken (void);
  22. void lexError (char *msg);
  23. void initKeywords ();
  24. char *strsave (char *str);
  25.  
  26. union tokenValue tokenValue;
  27. int currentLine;
  28. int errorsDetected;
  29.  
  30. #define MAX_STR_LEN 255          /* Strings are limited to 255 characters. */
  31.  
  32. #define NUM_KEYWORDS 90
  33. char * keywords [NUM_KEYWORDS+1];
  34. int keywordTokens [NUM_KEYWORDS+1];
  35. int tableInitialized = 0;
  36.  
  37.  
  38.  
  39. /* getToken ()
  40. **
  41. ** Scan the next token and return it.  Side-effects tokenVal and
  42. ** currentLine.
  43. */
  44. int getToken (void) {
  45.   int ch, ch2;
  46.   int intVal, t, intOverflow, realOverflow;
  47.   double exp, realVal;
  48.   char lexError2 [] = "Illegal character xxxxxxx in string ignoredxxxxxx";
  49.   char buffer [MAX_STR_LEN+1];          /* buffer for saving a string */
  50.   int next, i;                             /* index into buffer */
  51.  
  52.   while (1) {
  53.     ch = getchar ();
  54.  
  55.     /* Process enf-of-file... */
  56.     if (ch == EOF) {
  57.       return 0;
  58.  
  59.     /* Process newline... */
  60.     } else if (ch == '\n') {
  61.       currentLine ++;
  62.       if (currentLine > 0) {
  63.         printf ("\n-%d ", currentLine);
  64.       }
  65.  
  66.     /* Process other white space... */
  67.     } else if (ch == ' ' || ch == '\t') {
  68.       /* do nothing */
  69.  
  70.     /* Process left-parenthesis and comments... */
  71.     } else if (ch == '(') {
  72.       ch2 = getchar ();
  73.       if (ch2 != '*') {     /* Just a left-parenthesis... */
  74.         ungetc (ch2, stdin);
  75.         return '(';
  76.       } else {              /* A comment... */
  77.         ch2 = ' ';
  78.         do {
  79.           ch = ch2;
  80.           ch2 = getchar ();
  81.           if (ch2 == EOF) {
  82.             lexError ("End-of-file encountered within a comment");
  83.             ungetc (ch2, stdin);
  84.             return 0;
  85.           } else if (ch2 == '\n') {
  86.             currentLine++;
  87.           }
  88.         } while (ch != '*' || ch2 != ')');
  89.       }
  90.  
  91.     /* Process strings... */
  92.     } else if (ch == '"') {
  93.       next = 0;
  94.       while (1) {
  95.         ch2 = getchar ();
  96.         if (ch2 == '"') {
  97.           break;
  98.         } else if (ch2 == '\n') {
  99.           lexError ("End-of-line encountered within a string");
  100.           ungetc (ch2, stdin);
  101.           break;
  102.         } else if (ch2 == 0) {
  103.           lexError ("EOF encountered within a string--VALID MESSAGE?");
  104.           ungetc (ch2, stdin);
  105.           break;
  106.         } else if ((ch2 < 32) || (ch2 > 126)) {
  107.           sprintf (lexError2,
  108.               "Illegal character \\%03o in string ignored", ch2);
  109.           lexError (lexError2);
  110.         } else {
  111.           if (next >= MAX_STR_LEN) {
  112.             lexError ("Maximum string length (255) exceeded");
  113.           } else {
  114.             buffer [next++] = ch2;
  115.           }
  116.         }
  117.       }
  118.       buffer [next++] = '\0';
  119.       tokenValue.svalue = strsave (buffer);
  120.       return STRING;
  121.  
  122.     /* Process identifiers... */
  123.     } else if (isalpha (ch)) {
  124.       next = 0;
  125.       while (isalpha (ch) || isdigit (ch)) {
  126.         if (next >= MAX_STR_LEN) {
  127.           lexError ("Maximum identifier length (255) exceeded");
  128.         } else {
  129.           buffer [next++] = ch;
  130.         }
  131.         ch = getchar ();
  132.       }
  133.       ungetc (ch, stdin);
  134.       buffer [next++] = '\0';
  135.       tokenValue.svalue = strsave (buffer);
  136.       if (!tableInitialized) {
  137.         initKeywords ();
  138.         tableInitialized = 1;
  139.       }
  140.       for (i = 0; i <= NUM_KEYWORDS; i++) {
  141.         if (tokenValue.svalue == keywords [i]) {
  142.           return keywordTokens [i];
  143.         }
  144.       }
  145.       return ID;
  146.  
  147.     /* Process numbers... */
  148.     } else if (isdigit (ch)) {
  149.       next = intVal = intOverflow = realOverflow= 0;
  150.       exp = 1.0;
  151.       realVal = 0.0;
  152.       while (isdigit (ch)) {
  153.         t = intVal * 10 + (ch - '0');
  154.         if (t < intVal) {
  155.           intOverflow = 1;
  156.         }
  157.         intVal = t;
  158.         realVal = (realVal * 10.0) + (double) (ch - '0');
  159.         if (realVal > DBL_MAX) {
  160.           realOverflow = 1;
  161.         }
  162.         ch = getchar ();
  163.       }
  164.       /* If no decimal point, this is an integer so return. */
  165.       if (ch != '.') {
  166.         ungetc (ch, stdin);
  167.         if (intOverflow) {
  168.           lexError ("Integer out of range (0..2147483647)");
  169.           intVal = 0;
  170.         }
  171.         tokenValue.ivalue = intVal;
  172.         return INTEGER;
  173.       }
  174.       /* We have a decimal number; scan the fractional part. */
  175.       ch = getchar ();
  176.       while (isdigit (ch)) {
  177.         exp *= 10.0;
  178.         realVal = realVal + ((float) (ch - '0') / exp);
  179.         ch = getchar ();
  180.       }
  181.       ungetc (ch, stdin);
  182.       if (realOverflow) {
  183.         lexError ("Real number is too large");
  184.         tokenValue.rvalue = 0.0;
  185.       } else {
  186.         tokenValue.rvalue = realVal;
  187.       }
  188.       return REAL;
  189.  
  190.     /* Check for : and := ... */
  191.     } else if (ch == ':') {
  192.       ch2 = getchar ();
  193.       if (ch2 == '=') {
  194.         return ASSIGN;
  195.       } else {
  196.         ungetc (ch2, stdin);
  197.         return ':';
  198.       }
  199.  
  200.     /* Check for > >= >] ... */
  201.     } else if (ch == '>') {
  202.       ch2 = getchar ();
  203.       if (ch2 == '=') {
  204.         return GEQ;
  205.       } else if (ch2 == ']') {
  206.         return RBAG;
  207.       } else {
  208.         ungetc (ch2, stdin);
  209.         return '>';
  210.       }
  211.  
  212.     /* Check for < <= <> ... */
  213.     } else if (ch == '<') {
  214.       ch2 = getchar ();
  215.       if (ch2 == '=') {
  216.         return LEQ;
  217.       } else if (ch2 == '>') {
  218.         return NEQ;
  219.       } else {
  220.         ungetc (ch2, stdin);
  221.         return '<';
  222.       }
  223.  
  224.     /* Check for [ and [< ... */
  225.     } else if (ch == '[') {
  226.       ch2 = getchar ();
  227.       if (ch2 == '<') {
  228.         return LBAG;
  229.       } else {
  230.         ungetc (ch2, stdin);
  231.         return '[';
  232.       }
  233.  
  234.     /* Check for remaining single character operator symbols */
  235.     } else if (strchr("+-*/=;,.()]{}", ch)) {
  236.       return ch;
  237.  
  238.     /* Otherwise, we have an invalid character; ignore it. */
  239.     } else {
  240.       sprintf (lexError2,
  241.           "Illegal character \\%03o ignored", ch);
  242.       lexError (lexError2);
  243.     }
  244.   }
  245. }
  246.  
  247.  
  248.  
  249. /* initKeywords ()
  250. **
  251. ** This routine initializes the "keywords" and the "keywordTokens" arrays.
  252. */
  253. void initKeywords () {
  254.   keywords [0] = strsave ("and");        keywordTokens [0] = AND;
  255.   keywords [1] = strsave ("array");        keywordTokens [1] = ARRAY;
  256.   keywords [2] = strsave ("begin");        keywordTokens [2] = BEGIN;
  257.   keywords [3] = strsave ("by");        keywordTokens [3] = BY;
  258.   keywords [4] = strsave ("div");        keywordTokens [4] = DIV;
  259.   keywords [5] = strsave ("do");        keywordTokens [5] = DO;
  260.   keywords [6] = strsave ("else");        keywordTokens [6] = ELSE;
  261.   keywords [7] = strsave ("elseif");        keywordTokens [7] = ELSEIF;
  262.   keywords [8] = strsave ("end");        keywordTokens [8] = END;
  263.   keywords [9] = strsave ("exit");        keywordTokens [9] = EXIT;
  264.   keywords [10] = strsave ("for");        keywordTokens [10] = FOR;
  265.   keywords [11] = strsave ("if");        keywordTokens [11] = IF;
  266.   keywords [12] = strsave ("is");        keywordTokens [12] = IS;
  267.   keywords [13] = strsave ("loop");        keywordTokens [13] = LOOP;
  268.   keywords [14] = strsave ("mod");        keywordTokens [14] = MOD;
  269.   keywords [15] = strsave ("not");        keywordTokens [15] = NOT;
  270.   keywords [16] = strsave ("of");        keywordTokens [16] = OF;
  271.   keywords [17] = strsave ("or");        keywordTokens [17] = OR;
  272.   keywords [18] = strsave ("procedure");    keywordTokens [18] = PROCEDURE;
  273.   keywords [19] = strsave ("program");        keywordTokens [19] = PROGRAM;
  274.   keywords [20] = strsave ("read");        keywordTokens [20] = READ;
  275.   keywords [21] = strsave ("record");        keywordTokens [21] = RECORD;
  276.   keywords [22] = strsave ("return");        keywordTokens [22] = RETURN;
  277.   keywords [23] = strsave ("then");        keywordTokens [23] = THEN;
  278.   keywords [24] = strsave ("to");        keywordTokens [24] = TO;
  279.   keywords [25] = strsave ("type");        keywordTokens [25] = TYPE;
  280.   keywords [26] = strsave ("var");        keywordTokens [26] = VAR;
  281.   keywords [27] = strsave ("while");        keywordTokens [27] = WHILE;
  282.   keywords [28] = strsave ("write");        keywordTokens [28] = WRITE;
  283.  
  284.   keywords [29] = strsave ("E");        keywordTokens [29] = SY_E;
  285.   keywords [30] = strsave ("T");        keywordTokens [30] = SY_T;
  286.   keywords [31] = strsave ("F");        keywordTokens [31] = SY_F;
  287.   keywords [32] = strsave ("prog");        keywordTokens [32] = NT_PROGRAM;
  288.   keywords [33] = strsave ("body");        keywordTokens [33] = NT_BODY;
  289.   keywords [34] = strsave ("decls");        keywordTokens [34] = NT_DECLS;
  290.   keywords [35] = strsave ("stmts");        keywordTokens [35] = NT_STMTS;
  291.   keywords [36] = strsave ("varDecls");        keywordTokens [36] = NT_VARDECLS;
  292.   keywords [37] = strsave ("typeDecls");    keywordTokens [37] = NT_TYPEDECLS;
  293.   keywords [38] = strsave ("procDecls");    keywordTokens [38] = NT_PROCDECLS;
  294.   keywords [39] = strsave ("decl");        keywordTokens [39] = NT_DECL;
  295.   keywords [40] = strsave ("stmt");        keywordTokens [40] = NT_STMT;
  296.   keywords [41] = strsave ("varDecl");        keywordTokens [41] = NT_VARDECL;
  297.   keywords [42] = strsave ("typeDecl");        keywordTokens [42] = NT_TYPEDECL;
  298.   keywords [43] = strsave ("procDecl");        keywordTokens [43] = NT_PROCDECL;
  299.   keywords [44] = strsave ("idList");        keywordTokens [44] = NT_IDLIST;
  300.   keywords [45] = strsave ("optionalType");    keywordTokens [45] = NT_OPTIONALTYPE;
  301.   keywords [46] = strsave ("expr");        keywordTokens [46] = NT_EXPR;
  302.   keywords [47] = strsave ("type2");        keywordTokens [47] = NT_TYPE;
  303.   keywords [48] = strsave ("components");    keywordTokens [48] = NT_COMPONENTS;
  304.   keywords [49] = strsave ("component");    keywordTokens [49] = NT_COMPONENT;
  305.   keywords [50] = strsave ("formalParams");    keywordTokens [50] = NT_FORMALPARAMS;
  306.   keywords [51] = strsave ("fpSections");    keywordTokens [51] = NT_FPSECTIONS;
  307.   keywords [52] = strsave ("fpSection");    keywordTokens [52] = NT_FPSECTION;
  308.   keywords [53] = strsave ("lValues");        keywordTokens [53] = NT_LVALUES;
  309.   keywords [54] = strsave ("lValue");        keywordTokens [54] = NT_LVALUE;
  310.   keywords [55] = strsave ("actualParams");    keywordTokens [55] = NT_ACTUALPARAMS;
  311.   keywords [56] = strsave ("actuals");        keywordTokens [56] = NT_ACTUALS;
  312.   keywords [57] = strsave ("writeParams");    keywordTokens [57] = NT_WRITEPARAMS;
  313.   keywords [58] = strsave ("writeExprs");    keywordTokens [58] = NT_WRITEEXPRS;
  314.   keywords [59] = strsave ("writeExpr");    keywordTokens [59] = NT_WRITEEXPR;
  315.   keywords [60] = strsave ("elseIfs");        keywordTokens [60] = NT_ELSEIFS;
  316.   keywords [61] = strsave ("optionalElse");    keywordTokens [61] = NT_OPTIONALELSE;
  317.   keywords [62] = strsave ("optionalBy");    keywordTokens [62] = NT_OPTIONALBY;
  318.   keywords [63] = strsave ("optionalExpr");    keywordTokens [63] = NT_OPTIONALEXPR;
  319.   keywords [64] = strsave ("unaryOp");        keywordTokens [64] = NT_UNARYOP;
  320.   keywords [65] = strsave ("binaryOp2");    keywordTokens [65] = NT_BINARYOP2;
  321.   keywords [66] = strsave ("compValues");    keywordTokens [66] = NT_COMPVALUES;
  322.   keywords [67] = strsave ("moreCompValues");    keywordTokens [67] = NT_MORECOMPVALUES;
  323.   keywords [68] = strsave ("arrayValues");    keywordTokens [68] = NT_ARRAYVALUES;
  324.   keywords [69] = strsave ("moreArrayValues");    keywordTokens [69] = NT_MOREARRAYVALUES;
  325.   keywords [70] = strsave ("arrayValue");    keywordTokens [70] = NT_ARRAYVALUE;
  326.   keywords [71] = strsave ("moreExpr2");    keywordTokens [71] = NT_MOREEXPR2;
  327.   keywords [72] = strsave ("moreExpr3");    keywordTokens [72] = NT_MOREEXPR3;
  328.   keywords [73] = strsave ("moreExpr4");    keywordTokens [73] = NT_MOREEXPR4;
  329.   keywords [74] = strsave ("binaryOp3");    keywordTokens [74] = NT_BINARYOP3;
  330.   keywords [75] = strsave ("binaryOp4");    keywordTokens [75] = NT_BINARYOP4;
  331.   keywords [76] = strsave ("expr2");    keywordTokens [76] = NT_EXPR2;
  332.   keywords [77] = strsave ("expr3");    keywordTokens [77] = NT_EXPR3;
  333.   keywords [78] = strsave ("expr4");    keywordTokens [78] = NT_EXPR4;
  334.   keywords [79] = strsave ("expr5");    keywordTokens [79] = NT_EXPR5;
  335.   keywords [80] = strsave ("E2");    keywordTokens [80] = SY_E2;
  336.   keywords [81] = strsave ("T2");    keywordTokens [81] = SY_T2;
  337.   keywords [82] = strsave ("bexpr");    keywordTokens [82] = SY_BEXPR;
  338.   keywords [83] = strsave ("bterm");    keywordTokens [83] = SY_BTERM;
  339.   keywords [84] = strsave ("bfactor");    keywordTokens [84] = SY_BFACTOR;
  340.   keywords [85] = strsave ("true");    keywordTokens [85] = SY_TRUE;
  341.   keywords [86] = strsave ("false");    keywordTokens [86] = SY_FALSE;
  342.   keywords [87] = strsave ("A");    keywordTokens [87] = SY_A;
  343.   keywords [88] = strsave ("a");    keywordTokens [88] = SY_a;
  344.   keywords [89] = strsave ("b");    keywordTokens [89] = SY_b;
  345.   keywords [90] = strsave ("S");    keywordTokens [90] = SY_S;
  346.   
  347.   /* Make sure NUM_KEYWORDS is the same as the number on the line above. */
  348. }
  349.  
  350.  
  351.  
  352. /* strsave.c
  353. **
  354. ** A string saving routine to be used by the lexer.
  355. **
  356. ** For CS301
  357. **
  358. ** See Aho,Sethi,Ullman pp.435-437 for details.
  359. **
  360. ** Jingke Li, 1/20/97.
  361. ** Modified: Harry Porter, 10/9/97.
  362. **
  363. */
  364.  
  365. #define STRING_TABLE_SIZE 211    /* Size of hash table for storing strings */
  366.  
  367. typedef struct string {
  368.     struct string *next;         /* pointer to next bucket entry */
  369.     char s[1];                   /* the string itself */
  370. } String;
  371.  
  372. static String *string_table [STRING_TABLE_SIZE];
  373.  
  374. /*
  375. ** strsave()
  376. **   This routine is passed a pointer to a string of characters, terminated
  377. **   by '\0'.  It looks it up in the table.  If an equal string is already
  378. **   there, it returns a pointer to the copy previously stored in the table.
  379. **   If not found, it copies the new string into the table and returns a
  380. **   pointer to this new copy.
  381. **
  382. **   After calling this routine, you can use pointer comparisons to check
  383. **   for equality, rather than the more expensive test for character equality.
  384. **   Furthermore, each different string will only be stored once, saving space.
  385. **
  386. */
  387. char *strsave (char *str)
  388. {
  389.    unsigned h = 0, g;
  390.    char *p;
  391.    String *b;
  392.  
  393.    for ( p = str; *p != '\0'; p++ ) {
  394.      h = (h << 4) + (*p);
  395.      if (g = h & 0xf0000000) {
  396.        h = h ^ (g >> 24);
  397.        h = h ^ g;
  398.      }
  399.    }
  400.    h %= STRING_TABLE_SIZE;
  401.  
  402.    for (b = string_table[h]; b; b = b->next) 
  403.      if (strcmp(b->s,str) == 0)
  404.        return(b->s);
  405.  
  406.    b = (String *) malloc(sizeof(String) + strlen(str) + 1);
  407.    if (b==0) {
  408.      fprintf (stderr, "*****  Compiler Error: Malloc failed in strsave  *****\n");
  409.      exit (1);
  410.    }
  411.    strcpy(b->s, str);
  412.    b->next = string_table[h];
  413.    string_table[h] = b;
  414.    return(b->s);
  415. }
  416.