home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1991 / 09 / bob / bobscn.c < prev    next >
Text File  |  1991-07-11  |  8KB  |  397 lines

  1. /* bobscn.c - a lexical scanner */
  2. /*
  3.     Copyright (c) 1991, by David Michael Betz
  4.     All rights reserved
  5. */
  6.  
  7. #include <setjmp.h>
  8. #include "bob.h"
  9.  
  10. /* useful definitions */
  11. #define LSIZE    200
  12.  
  13. /* keyword table */
  14. static struct { char *kt_keyword; int kt_token; } ktab[] = {
  15. { "class",    T_CLASS        },
  16. { "static",    T_STATIC    },
  17. { "if",        T_IF        },
  18. { "else",    T_ELSE        },
  19. { "while",    T_WHILE        },
  20. { "return",    T_RETURN    },
  21. { "for",    T_FOR        },
  22. { "break",    T_BREAK        },
  23. { "continue",     T_CONTINUE    },
  24. { "do",        T_DO        },
  25. { "new",    T_NEW        },
  26. { "nil",    T_NIL        },
  27. { NULL,        0        }};
  28.  
  29. /* token name table */
  30. static char *t_names[] = {
  31. "<eof>",
  32. "<string>",
  33. "<identifier>",
  34. "<number>",
  35. "class",
  36. "static",
  37. "if",
  38. "else",
  39. "while",
  40. "return",
  41. "for",
  42. "break",
  43. "continue",
  44. "do",
  45. "new",
  46. "<=",
  47. "==",
  48. "!=",
  49. ">=",
  50. "<<",
  51. ">>",
  52. "&&",
  53. "||",
  54. "++",
  55. "--",
  56. "+=",
  57. "-=",
  58. "*=",
  59. "/=",
  60. "::",
  61. "->"};
  62.  
  63. /* global variables */
  64. int t_value;        /* numeric value */
  65. char t_token[TKNSIZE+1];/* token string */
  66.  
  67. /* local variables */
  68. static int (*getcf)();    /* getc function */
  69. static void *getcd;    /* getc data */
  70. static int savetkn;    /* look ahead token */
  71. static int savech;    /* look ahead character */
  72. static int lastch;    /* last input character */
  73. static char line[LSIZE];/* last input line */
  74. static char *lptr;    /* line pointer */
  75. static int lnum;    /* line number */
  76.  
  77. /* init_scanner - initialize the scanner */
  78. init_scanner(gf,gd)
  79.   int (*gf)(); void *gd;
  80. {
  81.     /* remember the getc function and data */
  82.     getcf = gf; getcd = gd;
  83.  
  84.     /* setup the line buffer */
  85.     lptr = line; *lptr = '\0';
  86.     lnum = 0;
  87.  
  88.     /* no lookahead yet */
  89.     savetkn = T_NOTOKEN;
  90.     savech = '\0';
  91.  
  92.     /* no last character */
  93.     lastch = '\0';
  94. }
  95.  
  96. /* token - get the next token */
  97. int token()
  98. {
  99.     int tkn;
  100.  
  101.     if ((tkn = savetkn) != T_NOTOKEN)
  102.     savetkn = T_NOTOKEN;
  103.     else
  104.     tkn = rtoken();
  105.     return (tkn);
  106. }
  107.  
  108. /* stoken - save a token */
  109. stoken(tkn)
  110.   int tkn;
  111. {
  112.     savetkn = tkn;
  113. }
  114.  
  115. /* tkn_name - get the name of a token */
  116. char *tkn_name(tkn)
  117.   int tkn;
  118. {
  119.     static char tname[2];
  120.     if (tkn <= _TMAX)
  121.     return (t_names[tkn]);
  122.     tname[0] = tkn;
  123.     tname[1] = '\0';
  124.     return (tname);
  125. }
  126.  
  127. /* rtoken - read the next token */
  128. static int rtoken()
  129. {
  130.     int ch,ch2;
  131.  
  132.     /* check the next character */
  133.     for (;;)
  134.     switch (ch = skipspaces()) {
  135.     case EOF:    return (T_EOF);
  136.     case '"':    return (getstring());
  137.     case '\'':    return (getcharacter());
  138.     case '<':    switch (ch = getch()) {
  139.             case '=':
  140.                 return (T_LE);
  141.             case '<':
  142.                 return (T_SHL);
  143.             default:
  144.                 savech = ch;
  145.                 return ('<');
  146.             }
  147.     case '=':    switch (ch = getch()) {
  148.             case '=':
  149.                 return (T_EQ);
  150.             default:
  151.                 savech = ch;
  152.                 return ('=');
  153.             }
  154.     case '!':    switch (ch = getch()) {
  155.             case '=':
  156.                 return (T_NE);
  157.             default:
  158.                 savech = ch;
  159.                 return ('!');
  160.             }
  161.     case '>':    switch (ch = getch()) {
  162.             case '=':
  163.                 return (T_GE);
  164.             case '>':
  165.                 return (T_SHR);
  166.             default:
  167.                 savech = ch;
  168.                 return ('>');
  169.             }
  170.     case '&':    switch (ch = getch()) {
  171.             case '&':
  172.                 return (T_AND);
  173.             default:
  174.                 savech = ch;
  175.                 return ('&');
  176.             }
  177.     case '|':    switch (ch = getch()) {
  178.             case '|':
  179.                 return (T_AND);
  180.             default:
  181.                 savech = ch;
  182.                 return ('|');
  183.             }
  184.     case '+':    switch (ch = getch()) {
  185.             case '+':
  186.                 return (T_INC);
  187.             case '=':
  188.                 return (T_ADDEQ);
  189.             default:
  190.                 savech = ch;
  191.                 return ('+');
  192.             }
  193.     case '-':    switch (ch = getch()) {
  194.             case '-':
  195.                 return (T_DEC);
  196.             case '=':
  197.                 return (T_SUBEQ);
  198.             case '>':
  199.                 return (T_MEMREF);
  200.             default:
  201.                 savech = ch;
  202.                 return ('-');
  203.             }
  204.     case '*':    switch (ch = getch()) {
  205.             case '=':
  206.                 return (T_MULEQ);
  207.             default:
  208.                 savech = ch;
  209.                 return ('*');
  210.             }
  211.     case '/':    switch (ch = getch()) {
  212.             case '=':
  213.                 return (T_DIVEQ);
  214.             case '/':
  215.                 while ((ch = getch()) != EOF)
  216.                 if (ch == '\n')
  217.                     break;
  218.                 break;
  219.             case '*':
  220.                 ch = ch2 = EOF;
  221.                 for (; (ch2 = getch()) != EOF; ch = ch2)
  222.                 if (ch == '*' && ch2 == '/')
  223.                     break;
  224.                 break;
  225.             default:
  226.                 savech = ch;
  227.                 return ('/');
  228.             }
  229.             break;
  230.     case ':':    switch (ch = getch()) {
  231.             case ':':
  232.                 return (T_CC);
  233.             default:
  234.                 savech = ch;
  235.                 return (':');
  236.             }
  237.     default:    if (isdigit(ch))
  238.                 return (getnumber(ch));
  239.             else if (isidchar(ch))
  240.                 return (getid(ch));
  241.             else {
  242.                 t_token[0] = ch;
  243.                 t_token[1] = '\0';
  244.                 return (ch);
  245.             }
  246.     }
  247. }
  248.  
  249. /* getstring - get a string */
  250. static int getstring()
  251. {
  252.     char *p;
  253.     int ch;
  254.  
  255.     /* get the string */
  256.     p = t_token;
  257.     while ((ch = literalch()) != EOF && ch != '"')
  258.     *p++ = ch;
  259.     if (ch == EOF)
  260.     savech = EOF;
  261.     *p = '\0';
  262.     return (T_STRING);
  263. }
  264.  
  265. /* getcharacter - get a character constant */
  266. static int getcharacter()
  267. {
  268.     t_value = literalch();
  269.     t_token[0] = t_value;
  270.     t_token[1] = '\0';
  271.     if (getch() != '\'')
  272.     parse_error("Expecting a closing single quote");
  273.     return (T_NUMBER);
  274. }
  275.  
  276. /* literalch - get a character from a literal string */
  277. static int literalch()
  278. {
  279.     int ch;
  280.     if ((ch = getch()) == '\\')
  281.     switch (ch = getch()) {
  282.     case 'n':  ch = '\n'; break;
  283.     case 't':  ch = '\t'; break;
  284.     case EOF:  ch = '\\'; savech = EOF; break;
  285.     }
  286.     return (ch);
  287. }
  288.  
  289. /* getid - get an identifier */
  290. static int getid(ch)
  291.   int ch;
  292. {
  293.     char *p;
  294.     int i;
  295.  
  296.     /* get the identifier */
  297.     p = t_token; *p++ = ch;
  298.     while ((ch = getch()) != EOF && isidchar(ch))
  299.     *p++ = ch;
  300.     savech = ch;
  301.     *p = '\0';
  302.  
  303.     /* check to see if it is a keyword */
  304.     for (i = 0; ktab[i].kt_keyword != NULL; ++i)
  305.     if (strcmp(ktab[i].kt_keyword,t_token) == 0)
  306.         return (ktab[i].kt_token);
  307.     return (T_IDENTIFIER);
  308. }
  309.  
  310. /* getnumber - get a number */
  311. static int getnumber(ch)
  312.   int ch;
  313. {
  314.     char *p;
  315.  
  316.     /* get the number */
  317.     p = t_token; *p++ = ch; t_value = ch - '0';
  318.     while ((ch = getch()) != EOF && isdigit(ch)) {
  319.     t_value = t_value * 10 + ch - '0';
  320.     *p++ = ch;
  321.     }
  322.     savech = ch;
  323.     *p = '\0';
  324.     return (T_NUMBER);
  325. }
  326.  
  327. /* skipspaces - skip leading spaces */
  328. static skipspaces()
  329. {
  330.     int ch;
  331.     while ((ch = getch()) != '\0' && isspace(ch))
  332.     ;
  333.     return (ch);
  334. }
  335.  
  336. /* isidchar - is this an identifier character */
  337. static int isidchar(ch)
  338.   int ch;
  339. {
  340.     return (isupper(ch)
  341.          || islower(ch)
  342.          || isdigit(ch)
  343.          || ch == '_');
  344. }
  345.  
  346. /* getch - get the next character */
  347. static int getch()
  348. {
  349.     int ch;
  350.     
  351.     /* check for a lookahead character */
  352.     if ((ch = savech) != '\0')
  353.     savech = '\0';
  354.  
  355.     /* check for a buffered character */
  356.     else {
  357.     while ((ch = *lptr++) == '\0') {
  358.  
  359.         /* check for being at the end of file */
  360.         if (lastch == EOF)
  361.         return (EOF);
  362.  
  363.         /* read the next line */
  364.         lptr = line;
  365.         while ((lastch = (*getcf)(getcd)) != EOF && lastch != '\n')
  366.         *lptr++ = lastch;
  367.         *lptr++ = '\n'; *lptr = '\0';
  368.         lptr = line;
  369.         ++lnum;
  370.     }
  371.     }
  372.  
  373.     /* return the current character */
  374.     return (ch);
  375. }
  376.  
  377. /* parse_error - report an error in the current line */
  378. parse_error(msg)
  379.   char *msg;
  380. {
  381.     extern jmp_buf error_trap;
  382.     char buf[LSIZE],*src,*dst;
  383.  
  384.     /* redisplay the line with the error */
  385.     sprintf(buf,">>> %s <<<\n>>> in line %d <<<\n%s",msg,lnum,line);
  386.     osputs(buf);
  387.  
  388.     /* point to the position immediately following the error */
  389.     for (src = line, dst = buf; src < lptr-1; ++src)
  390.     *dst++ = (*src == '\t' ? '\t' : ' ');
  391.     *dst++ = '^'; *dst++ = '\n'; *dst = '\0';
  392.     osputs(buf);
  393.  
  394.     /* invoke the error trap */
  395.     longjmp(error_trap,1);
  396. }
  397.