home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 31 / CDASC_31_1996_juillet_aout.iso / vrac / cuj0796.zip / SAKS.ZIP / SCANNER3.H < prev    next >
C/C++ Source or Header  |  1996-04-22  |  6KB  |  240 lines

  1. Listing 5 - The source file that implements the scanner and
  2. token classes that support unlimited lookahead.
  3.  
  4. //
  5. // scanner.cpp
  6. //
  7. // Copyright (C) 1996 by Dan Saks.
  8. // May be copied for private, non-commercial use,
  9. // provided this copyright notice remains intact.
  10. // All other rights reserved.
  11. //
  12.  
  13. #include <ctype.h>
  14. #include <iostream.h>
  15. #include <string.h>
  16.  
  17. #include "scanner.h"
  18.  
  19. #define DIM(a) (sizeof(a)/sizeof(a[0]))
  20.  
  21. scanner::pair const scanner::keyword[] =
  22.     {
  23.         { "bool", token::TYPE_KEYWORD },
  24.         { "char", token::TYPE_KEYWORD },
  25.         { "const", token::CONST },
  26.         { "double", token::TYPE_KEYWORD },
  27.         { "float", token::TYPE_KEYWORD },
  28.         { "int", token::TYPE_KEYWORD },
  29.         { "void", token::TYPE_KEYWORD },
  30.         { "volatile", token::VOLATILE },
  31.         { "wchar_t", token::TYPE_KEYWORD }
  32.     };
  33.  
  34. token scanner::backup()
  35.     {
  36.     assert(looking_ahead);
  37.     if (!getting_from_queue)
  38.         in_queue.push_back(current_token);
  39.     looking_ahead = false;
  40.     return get();
  41.     }
  42.  
  43. token scanner::get()
  44.     {
  45.     if (!looking_ahead)
  46.         {
  47.         if (in_queue.empty())
  48.             current_token = scan();
  49.         else
  50.             {
  51.             current_token = in_queue.front();
  52.             in_queue.pop_front();
  53.             }
  54.         }
  55.     else // looking_ahead
  56.         {
  57.         if (!getting_from_queue)
  58.             {
  59.             in_queue.push_back(current_token);
  60.             current_token = scan();
  61.             }
  62.         else if (in_queue_iterator != in_queue.end())
  63.             current_token = *in_queue_iterator++;
  64.         else
  65.             {
  66.             getting_from_queue = false;
  67.             current_token = scan();
  68.             }
  69.         }
  70.     return current_token;
  71.     }
  72.  
  73. void scanner::mark()
  74.     {
  75.     assert(!looking_ahead);
  76.     assert(current_token.kind() != token::NO_VALUE);
  77.     looking_ahead = true;
  78.     getting_from_queue = !in_queue.empty();
  79.     if (getting_from_queue)
  80.         {
  81.         in_queue.push_front(current_token);
  82.         in_queue_iterator = in_queue.begin();
  83.         ++in_queue_iterator;
  84.         }
  85.     }
  86.  
  87. void scanner::reset()
  88.     {
  89.     bool found_a_semicolon = false;
  90.     while (!in_queue.empty())
  91.         {
  92.         current_token = in_queue.front();
  93.         in_queue.pop_front();
  94.         if (current_token.kind() == token::SEMICOLON)
  95.             {
  96.             found_a_semicolon = true;
  97.             break;
  98.             }
  99.         }
  100.     if (!found_a_semicolon)
  101.         {
  102.         int c;
  103.         while ((c = in_stream.get()) != EOF)
  104.             if (c == ';' || c == '\n')
  105.                 break;
  106.         }
  107.     current_token = token();
  108.     getting_from_queue = !in_queue.empty();
  109.     looking_ahead = false;
  110.     }
  111.  
  112. token scanner::scan()
  113.     {
  114.     int c;
  115.     token::category kind;
  116.     string text;
  117.     while (isspace(c = in_stream.get()))
  118.         ;
  119.     //
  120.     // scan an integer-literal
  121.     //
  122.     if (isdigit(c))
  123.         {
  124.         kind = token::INT_LITERAL;
  125.         do
  126.             {
  127.             text += char(c);
  128.             c = in_stream.get();
  129.             }
  130.         while (isdigit(c));
  131.         in_stream.putback(c);
  132.         }
  133.     //
  134.     // scan an identifier, a name, or a type-keyword
  135.     //
  136.     else if (isalpha(c) || c == '_')
  137.         {
  138.         kind = token::IDENTIFIER;
  139.         do
  140.             {
  141.             text += char(c);
  142.             c = in_stream.get();
  143.             }
  144.         while (isalnum(c) || c == '_');
  145.         in_stream.putback(c);
  146.         if (isupper(text[0]))
  147.             kind = token::NAME;
  148.         else
  149.             for (int i = 0; i < DIM(keyword); ++i)
  150.                 if (text == keyword[i].text)
  151.                     {
  152.                     kind = keyword[i].kind;
  153.                     break;
  154.                     }
  155.         }
  156.     //
  157.     // scan a scope-resolution operator
  158.     //
  159.     else if (c == ':')
  160.         {
  161.         if ((c = in_stream.get()) != ':')
  162.             {
  163.             in_stream.putback(c);
  164.             kind = token::NO_SUCH;
  165.             text = ":";
  166.             }
  167.         else
  168.             {
  169.             kind = token::SCOPE;
  170.             text = "::";
  171.             }
  172.         }
  173.     //
  174.     // scan a single-character operator
  175.     //
  176.     else if (strchr("*&[]();,", c) != 0)
  177.         {
  178.         kind = token::category(c);
  179.         text = char(c);
  180.         }
  181.     //
  182.     // scan end-of-file
  183.     //
  184.     else if (c == EOF)
  185.         kind = token::NO_MORE;
  186.     //
  187.     // there's no such token
  188.     //
  189.     else
  190.         {
  191.         kind = token::NO_SUCH;
  192.         text = char(c);
  193.         }
  194.     return token(kind, text);
  195.     }
  196.  
  197. const char *image(token::category tc)
  198.     {
  199.     switch (tc)
  200.         {
  201.         case token::AMPERSAND:
  202.             return "&";
  203.         case token::COMMA:
  204.             return ",";
  205.         case token::LEFT_BRACKET:
  206.             return "[";
  207.         case token::LEFT_PAREN:
  208.             return "(";
  209.         case token::RIGHT_BRACKET:
  210.             return "]";
  211.         case token::RIGHT_PAREN:
  212.             return ")";
  213.         case token::SEMICOLON:
  214.             return ";";
  215.         case token::STAR:
  216.             return "*";
  217.         case token::NO_MORE:
  218.             return "end of input";
  219.         case token::SCOPE:
  220.             return "::";
  221.         case token::INT_LITERAL:
  222.             return "int literal";
  223.         case token::IDENTIFIER:
  224.             return "identifier";
  225.         case token::NAME:
  226.             return "name";
  227.         case token::TYPE_KEYWORD:
  228.             return "type keyword";
  229.         case token::CONST:
  230.             return "const";
  231.         case token::VOLATILE:
  232.             return "volatile";
  233.         }
  234.     return "no such token";
  235.     }
  236.  
  237.  
  238.  
  239.  
  240.