home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Programming / jikes-1.02 / src / stream.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-05  |  29.6 KB  |  863 lines

  1. // $Id: stream.cpp,v 1.11 1999/08/26 15:34:10 shields Exp $
  2. //
  3. // This software is subject to the terms of the IBM Jikes Compiler
  4. // License Agreement available at the following URL:
  5. // http://www.ibm.com/research/jikes.
  6. // Copyright (C) 1996, 1998, International Business Machines Corporation
  7. // and others.  All Rights Reserved.
  8. // You must accept the terms of that agreement to use this software.
  9. //
  10. #include "config.h"
  11. #include <ctype.h>
  12. #include "stream.h"
  13. #include "code.h"
  14. #include "zip.h"
  15. #include "symbol.h"
  16. #include "control.h"
  17. #include "semantic.h"
  18.  
  19. wchar_t *LexStream::KeywordName(int kind)
  20. {
  21.     switch(kind)
  22.     {
  23.         case TK_abstract:     return StringConstant::US_abstract; break;
  24.         case TK_boolean:      return StringConstant::US_boolean;  break;
  25.         case TK_break:        return StringConstant::US_break;    break;
  26.         case TK_byte:         return StringConstant::US_byte;     break;
  27.         case TK_case:         return StringConstant::US_case; break;
  28.         case TK_catch:        return StringConstant::US_catch; break;
  29.         case TK_char:         return StringConstant::US_char; break;
  30.         case TK_class:        return StringConstant::US_class; break;
  31.         case TK_const:        return StringConstant::US_const; break;
  32.         case TK_continue:     return StringConstant::US_continue; break;
  33.         case TK_default:      return StringConstant::US_default; break;
  34.         case TK_do:           return StringConstant::US_do; break;
  35.         case TK_double:       return StringConstant::US_double; break;
  36.         case TK_else:         return StringConstant::US_else; break;
  37.         case TK_extends:      return StringConstant::US_extends; break;
  38.         case TK_false:        return StringConstant::US_false; break;
  39.         case TK_final:        return StringConstant::US_final; break;
  40.         case TK_finally:      return StringConstant::US_finally; break;
  41.         case TK_float:        return StringConstant::US_float; break;
  42.         case TK_for:          return StringConstant::US_for; break;
  43.         case TK_goto:         return StringConstant::US_goto; break;
  44.         case TK_if:           return StringConstant::US_if; break;
  45.         case TK_implements:   return StringConstant::US_implements; break;
  46.         case TK_import:       return StringConstant::US_import; break;
  47.         case TK_instanceof:   return StringConstant::US_instanceof; break;
  48.         case TK_int:          return StringConstant::US_int; break;
  49.         case TK_interface:    return StringConstant::US_interface; break;
  50.         case TK_long:         return StringConstant::US_long; break;
  51.         case TK_native:       return StringConstant::US_native; break;
  52.         case TK_new:          return StringConstant::US_new; break;
  53.         case TK_null:         return StringConstant::US_null; break;
  54.         case TK_package:      return StringConstant::US_package; break;
  55.         case TK_private:      return StringConstant::US_private; break;
  56.         case TK_protected:    return StringConstant::US_protected; break;
  57.         case TK_public:       return StringConstant::US_public; break;
  58.         case TK_return:       return StringConstant::US_return; break;
  59.         case TK_short:        return StringConstant::US_short; break;
  60.         case TK_static:       return StringConstant::US_static; break;
  61.         case TK_strictfp:     return StringConstant::US_strictfp; break;
  62.         case TK_super:        return StringConstant::US_super; break;
  63.         case TK_switch:       return StringConstant::US_switch; break;
  64.         case TK_synchronized: return StringConstant::US_synchronized; break;
  65.         case TK_this:         return StringConstant::US_this; break;
  66.         case TK_throw:        return StringConstant::US_throw; break;
  67.         case TK_throws:       return StringConstant::US_throws; break;
  68.         case TK_transient:    return StringConstant::US_transient; break;
  69.         case TK_true:         return StringConstant::US_true; break;
  70.         case TK_try:          return StringConstant::US_try; break;
  71.         case TK_void:         return StringConstant::US_void; break;
  72.         case TK_volatile:     return StringConstant::US_volatile; break;
  73.         case TK_while:        return StringConstant::US_while; break;
  74.  
  75.         case TK_PLUS_PLUS:                  return StringConstant::US_PLUS_PLUS; break;
  76.         case TK_MINUS_MINUS:                return StringConstant::US_MINUS_MINUS; break;
  77.         case TK_EQUAL_EQUAL:                return StringConstant::US_EQUAL_EQUAL; break;
  78.         case TK_LESS_EQUAL:                 return StringConstant::US_LESS_EQUAL; break;
  79.         case TK_GREATER_EQUAL:              return StringConstant::US_GREATER_EQUAL; break;
  80.         case TK_NOT_EQUAL:                  return StringConstant::US_NOT_EQUAL; break;
  81.         case TK_LEFT_SHIFT:                 return StringConstant::US_LEFT_SHIFT; break;
  82.         case TK_RIGHT_SHIFT:                return StringConstant::US_RIGHT_SHIFT; break;
  83.         case TK_UNSIGNED_RIGHT_SHIFT:       return StringConstant::US_UNSIGNED_RIGHT_SHIFT; break;
  84.         case TK_PLUS_EQUAL:                 return StringConstant::US_PLUS_EQUAL; break;
  85.         case TK_MINUS_EQUAL:                return StringConstant::US_MINUS_EQUAL; break;
  86.         case TK_MULTIPLY_EQUAL:             return StringConstant::US_MULTIPLY_EQUAL; break;
  87.         case TK_DIVIDE_EQUAL:               return StringConstant::US_DIVIDE_EQUAL; break;
  88.         case TK_AND_EQUAL:                  return StringConstant::US_AND_EQUAL; break;
  89.         case TK_OR_EQUAL:                   return StringConstant::US_OR_EQUAL; break;
  90.         case TK_XOR_EQUAL:                  return StringConstant::US_XOR_EQUAL; break;
  91.         case TK_REMAINDER_EQUAL:            return StringConstant::US_REMAINDER_EQUAL; break;
  92.         case TK_LEFT_SHIFT_EQUAL:           return StringConstant::US_LEFT_SHIFT_EQUAL; break;
  93.         case TK_RIGHT_SHIFT_EQUAL:          return StringConstant::US_RIGHT_SHIFT_EQUAL; break;
  94.         case TK_UNSIGNED_RIGHT_SHIFT_EQUAL: return StringConstant::US_UNSIGNED_RIGHT_SHIFT_EQUAL; break;
  95.         case TK_OR_OR:                      return StringConstant::US_OR_OR; break;
  96.         case TK_AND_AND:                    return StringConstant::US_AND_AND; break;
  97.  
  98.         case TK_PLUS:                       return StringConstant::US_PLUS; break;
  99.         case TK_MINUS:                      return StringConstant::US_MINUS; break;
  100.         case TK_NOT:                        return StringConstant::US_NOT; break;
  101.         case TK_REMAINDER:                  return StringConstant::US_REMAINDER; break;
  102.         case TK_XOR:                        return StringConstant::US_XOR; break;
  103.         case TK_AND:                        return StringConstant::US_AND; break;
  104.         case TK_MULTIPLY:                   return StringConstant::US_MULTIPLY; break;
  105.         case TK_OR:                         return StringConstant::US_OR; break;
  106.         case TK_TWIDDLE:                    return StringConstant::US_TWIDDLE; break;
  107.         case TK_DIVIDE:                     return StringConstant::US_DIVIDE; break;
  108.         case TK_GREATER:                    return StringConstant::US_GREATER; break;
  109.         case TK_LESS:                       return StringConstant::US_LESS; break;
  110.         case TK_LPAREN:                     return StringConstant::US_LPAREN; break;
  111.         case TK_RPAREN:                     return StringConstant::US_RPAREN; break;
  112.         case TK_LBRACE:                     return StringConstant::US_LBRACE; break;
  113.         case TK_RBRACE:                     return StringConstant::US_RBRACE; break;
  114.         case TK_LBRACKET:                   return StringConstant::US_LBRACKET; break;
  115.         case TK_RBRACKET:                   return StringConstant::US_RBRACKET; break;
  116.         case TK_SEMICOLON:                  return StringConstant::US_SEMICOLON; break;
  117.         case TK_QUESTION:                   return StringConstant::US_QUESTION; break;
  118.         case TK_COLON:                      return StringConstant::US_COLON; break;
  119.         case TK_COMMA:                      return StringConstant::US_COMMA; break;
  120.         case TK_DOT:                        return StringConstant::US_DOT; break;
  121.         case TK_EQUAL:                      return StringConstant::US_EQUAL; break;
  122.         case TK_EOF:                        return StringConstant::US_EOF; break;
  123.         default:                            break;
  124.     }
  125.  
  126.     return StringConstant::US_EMPTY;
  127. }
  128.  
  129.  
  130. LexStream::~LexStream()
  131. {
  132. #ifdef TEST
  133.     control.line_count += (file_read * (line_location.Length() - 3));
  134. #endif
  135.  
  136.     DestroyInput();
  137.  
  138.     delete [] columns;
  139.     delete [] comment_buffer;
  140.     comment_buffer = NULL;
  141. }
  142.  
  143.  
  144. //
  145. //
  146. //
  147. ::LiteralSymbol *LexStream::LiteralSymbol(TokenIndex i)
  148. {
  149.     Symbol *symbol = tokens[i].additional_info.symbol;
  150.     return (symbol && (Kind(i) != TK_LBRACE) ? symbol -> LiteralCast() : (::LiteralSymbol *) NULL);
  151. }
  152.  
  153.  
  154. //
  155. //
  156. //
  157. ::NameSymbol *LexStream::NameSymbol(TokenIndex i)
  158. {
  159.     Symbol *symbol = tokens[i].additional_info.symbol;
  160.     return (symbol && (Kind(i) != TK_LBRACE) ? symbol -> NameCast() : (::NameSymbol *) NULL);
  161. }
  162.  
  163.  
  164. //
  165. // Name of input file where the token appeared.
  166. //
  167. char *LexStream::FileName() { return file_symbol -> FileName(); }
  168. int LexStream::FileNameLength() { return file_symbol -> FileNameLength(); }
  169.  
  170.  
  171. void LexStream::InitializeColumns()
  172. {
  173.     if (! columns)
  174.     {
  175.         columns = new unsigned short[token_stream.Length()];
  176.  
  177.         int col = 0,
  178.             start = 0,
  179.             k = 1;
  180.  
  181.         for (int i = 0; i < input_buffer_length; i++)
  182.         {
  183.             if (Code::IsNewline(input_buffer[i]))
  184.                 start = i;
  185.             else
  186.             {
  187.                 if (input_buffer[i] == U_HORIZONTAL_TAB)
  188.                 {
  189.                     int offset = (i - start) - 1;
  190.                     start -= ((Tab::TabSize() - 1) - offset % Tab::TabSize());
  191.                 }
  192.                 else if (tokens[k].Location() == i)
  193.                 {
  194.                     int col = i - start;
  195.                     columns[k++] = (col < USHRT_MAX ? col : 0);
  196.                 }
  197.             }
  198.         }
  199.     }
  200.  
  201.     return;
  202. }
  203.  
  204.  
  205. //
  206. //
  207. //
  208. void LexStream::CompressSpace()
  209. {
  210.     tokens = token_stream.Array();
  211.     if (control.option.dump_errors)
  212.         InitializeColumns();
  213.     comments = comment_stream.Array();
  214.     locations = line_location.Array();
  215.     types = type_index.Array();
  216.  
  217.     return;
  218. }
  219.  
  220.  
  221. //
  222. // Find and return the index of the first comment that immediately
  223. // follows tok. Return 0 if there is not a comment that immediately
  224. // follows tok.
  225. //
  226. LexStream::CommentIndex LexStream::FirstComment(TokenIndex tok)
  227. {
  228.     unsigned location = Location(tok);
  229.     int lo = 0,
  230.         hi = comment_stream.Length() - 1,
  231.         i = 0;
  232.  
  233.     if (lo < hi)
  234.     {
  235.         do
  236.         {
  237.             int mid = (lo + hi) / 2;
  238.  
  239.             if (comment_stream[mid].location < location)
  240.                  lo = mid + 1;
  241.             else hi = mid - 1;
  242.         } while (lo < hi);
  243.  
  244.         //
  245.         // at this stage lo == hi
  246.         //
  247.         i = (comment_stream[lo].location > location ? lo : lo + 1);
  248.     }
  249.  
  250.     return (i < comment_stream.Length() && comment_stream[i].previous_token == tok ? i : 0);
  251. }
  252.  
  253.  
  254. unsigned LexStream::FindLine(unsigned location)
  255. {
  256.     int lo = 0,
  257.         hi = line_location.Length() - 1;
  258.  
  259. assert(locations);
  260.     //
  261.     // we can place the exit test at the bottom of the loop
  262.     // since the line_location array will always contain at least
  263.     // one element.
  264.     //
  265.     do
  266.     {
  267.         int mid = (lo + hi) / 2;
  268.  
  269.         if (locations[mid] == location)
  270.             return mid;
  271.         if (locations[mid] < location)
  272.              lo = mid + 1;
  273.         else hi = mid - 1;
  274.     } while (lo < hi);
  275.  
  276.     return (locations[lo] > location ? lo - 1 : lo);
  277. }
  278.  
  279.  
  280. void LexStream::ReadInput()
  281. {
  282.     if (file_symbol -> IsZip())
  283.     {
  284.         ZipFile *zipfile = new ZipFile(file_symbol);
  285.  
  286.         if (zipfile -> Buffer() == NULL)
  287.         {
  288.             fprintf(stderr, "chaos: Don\'t know how to process compressed (\".java\") source in a zip file\n");
  289.             assert(false);
  290.         }
  291.         else if (! file_symbol -> lex_stream) // Once the zip file is loaded, it never changes. So, we only read it the first time
  292.         {
  293.             file_symbol -> lex_stream = this;
  294.             ProcessInput(zipfile -> Buffer(), file_symbol -> uncompressed_size);
  295.         }
  296.         delete zipfile;
  297.     }
  298.     else
  299.     {
  300.         struct stat status;
  301.         ::SystemStat(FileName(), &status);
  302.  
  303.         file_symbol -> mtime = status.st_mtime; // actual time stamp of file read
  304.         file_symbol -> lex_stream = this;
  305.  
  306. #if defined(UNIX_FILE_SYSTEM) || defined(AMIGAOS_FILE_SYSTEM)
  307.         FILE *srcfile = ::SystemFopen(FileName(), "r");
  308.         if (srcfile != NULL)
  309.         {
  310.             char *buffer = new char[status.st_size];
  311.             size_t file_size = ::SystemFread(buffer, sizeof(char), status.st_size, srcfile, control.option.ascii);
  312.             fclose(srcfile);
  313.             ProcessInput(buffer, file_size);
  314.             delete [] buffer;
  315.         }
  316. #elif defined(WIN32_FILE_SYSTEM)
  317. #include <windows.h>
  318.         HANDLE srcfile = CreateFile(FileName(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
  319.         if (srcfile != INVALID_HANDLE_VALUE)
  320.         {
  321.             HANDLE mapfile = CreateFileMapping(srcfile, NULL, PAGE_READONLY, 0, 0, NULL);
  322.             if (mapfile != INVALID_HANDLE_VALUE)
  323.             {
  324.                 char *buffer = (char *) MapViewOfFile(mapfile, FILE_MAP_READ, 0, 0, 0);
  325.                 DWORD file_size = GetFileSize(srcfile, NULL);
  326.                 ProcessInput(buffer, file_size);
  327.                 if (buffer)
  328.                     UnmapViewOfFile(buffer);
  329.                 CloseHandle(mapfile);
  330.             }
  331.  
  332.             CloseHandle(srcfile);
  333.         }
  334. #endif
  335.     }
  336.  
  337.     initial_reading_of_input = false;
  338.  
  339.     return;
  340. }
  341.  
  342.  
  343. void LexStream::RereadInput()
  344. {
  345.     if (input_buffer) // if input already available, do nothing
  346.         ;
  347.     else if (file_symbol -> IsZip())
  348.     {
  349.         ZipFile *zipfile = new ZipFile(file_symbol);
  350.  
  351.         if (zipfile -> Buffer() == NULL)
  352.         {
  353.             fprintf(stderr, "chaos: Don\'t know how to process compressed (\".java\") source in a zip file\n");
  354.             assert(false);
  355.         }
  356.         else ProcessInput(zipfile -> Buffer(), file_symbol -> uncompressed_size);
  357.         delete zipfile;
  358.     }
  359.     else
  360.     {
  361.         struct stat status;
  362.         ::SystemStat(FileName(), &status);
  363.  
  364.         if (status.st_mtime == file_symbol -> mtime)
  365.         {
  366. #if defined(UNIX_FILE_SYSTEM) || defined(AMIGAOS_FILE_SYSTEM)
  367.             FILE *srcfile = ::SystemFopen(FileName(), "r");
  368.             if (srcfile != NULL)
  369.             {
  370.                 char *buffer = new char[status.st_size];
  371.                 size_t file_size = ::SystemFread(buffer, sizeof(char), status.st_size, srcfile, control.option.ascii);
  372.                 fclose(srcfile);
  373.                 ProcessInput(buffer, file_size);
  374.                 delete [] buffer;
  375.             }
  376. #elif defined(WIN32_FILE_SYSTEM)
  377.             HANDLE srcfile = CreateFile(FileName(), GENERIC_READ, FILE_SHARE_READ,
  378.                                         NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
  379.             if (srcfile != INVALID_HANDLE_VALUE)
  380.             {
  381.                 HANDLE mapfile = CreateFileMapping(srcfile, NULL, PAGE_READONLY, 0, 0, NULL);
  382.                 if (mapfile != INVALID_HANDLE_VALUE)
  383.                 {
  384.                     char *buffer = (char *) MapViewOfFile(mapfile, FILE_MAP_READ, 0, 0, 0);
  385.                     DWORD file_size = GetFileSize(srcfile, NULL);
  386.                     ProcessInput(buffer, file_size);
  387.                     if (buffer)
  388.                         UnmapViewOfFile(buffer);
  389.                     CloseHandle(mapfile);
  390.                 }
  391.  
  392.                 CloseHandle(srcfile);
  393.             }
  394. #endif
  395.         }
  396.         else
  397.         {
  398.             // TODO: File has changed !!!
  399.         }
  400.     }
  401.  
  402.     return;
  403. }
  404.  
  405.  
  406. //
  407. // Read file_size Ascii characters from srcfile, convert them to unicode and
  408. // store them in input_buffer.
  409. //
  410. void LexStream::ProcessInput(char *buffer, long filesize)
  411. {
  412. #ifdef TEST
  413.     file_read++;
  414. #endif
  415.  
  416.     input_buffer = new wchar_t[filesize + 4];
  417.     wchar_t *input_ptr = input_buffer;
  418.     *input_ptr = U_LINE_FEED; // add an initial '\n';
  419.  
  420.     if (buffer)
  421.     {
  422.         char *source_ptr = buffer,
  423.              *source_tail = &(buffer[filesize - 1]); // point to last character read from the file.
  424.  
  425.         while(source_ptr <= source_tail)
  426.         {
  427.             *(++input_ptr) = (*source_ptr++) & 0x00ff; // The (& 0x00ff) guarantees that quantity is copied as unsigned value
  428.  
  429.             if (*input_ptr == U_CARRIAGE_RETURN)
  430.             {
  431.                 *input_ptr = U_LINE_FEED;
  432.                 if (*source_ptr == U_LINE_FEED)
  433.                     source_ptr++;
  434.             }
  435.             else if (*input_ptr == U_BACKSLASH)
  436.             {
  437.                 if (*source_ptr == U_BACKSLASH)
  438.                     *(++input_ptr) = *source_ptr++;
  439.                 else if (*source_ptr == U_u)
  440.                 {
  441.                     char *u_ptr = source_ptr;
  442.  
  443.                     for (source_ptr++; source_ptr <= source_tail && *source_ptr == U_u; source_ptr++)
  444.                         ;
  445.                     *input_ptr = 0;
  446.                     int i;
  447.                     for (i = 0; source_ptr <= source_tail && isxdigit(*source_ptr) && i < 4; i++)
  448.                     {
  449.                         int multiplier[4] = {4096, 256, 16, 1};
  450.  
  451.                         char ch = *source_ptr++;
  452.                         switch(ch)
  453.                         {
  454.                             case U_a: case U_A:
  455.                                 *input_ptr += (10 * multiplier[i]);
  456.                                 break;
  457.                             case U_b: case U_B:
  458.                                 *input_ptr += (11 * multiplier[i]);
  459.                                 break;
  460.                             case U_c: case U_C:
  461.                                 *input_ptr += (12 * multiplier[i]);
  462.                                 break;
  463.                             case U_d: case U_D:
  464.                                 *input_ptr += (13 * multiplier[i]);
  465.                                 break;
  466.                             case U_e: case U_E:
  467.                                 *input_ptr += (14 * multiplier[i]);
  468.                                 break;
  469.                             case U_f: case U_F:
  470.                                 *input_ptr += (15 * multiplier[i]);
  471.                                 break;
  472.                             default:
  473.                                 *input_ptr += ((ch - U_0) * multiplier[i]);
  474.                         }
  475.                     }
  476.  
  477.                     if (i != 4)
  478.                     {
  479.                         if (initial_reading_of_input)
  480.                             bad_tokens.Next().Initialize(StreamError::INVALID_UNICODE_ESCAPE,
  481.                                                          (unsigned) (input_ptr - input_buffer),
  482.                                                          (unsigned) (input_ptr - input_buffer) + (source_ptr - u_ptr));
  483.  
  484.                         source_ptr = u_ptr;
  485.                         *input_ptr = U_BACKSLASH;
  486.                     }
  487.                     else if (*input_ptr == U_CARRIAGE_RETURN)
  488.                     {
  489.                         *input_ptr = U_LINE_FEED;
  490.                         if (*source_ptr == U_LINE_FEED)
  491.                             source_ptr++;
  492.                         else if (*source_ptr == U_BACKSLASH)
  493.                         {
  494.                             int i;
  495.                             for (i = 1; (source_ptr + i) <= source_tail && source_ptr[i] == U_u; i++)
  496.                                 ;
  497.                             if (i > 1 && (source_ptr + i + 3) <= source_tail
  498.                                       && source_ptr[i]     == U_0
  499.                                       && source_ptr[i + 1] == U_0
  500.                                       && source_ptr[i + 2] == U_0
  501.                                       && source_ptr[i + 3] == U_a) // the escape sequence of \n is \u000a
  502.                                 source_ptr += (i + 4);
  503.                         }
  504.                     }
  505.                 }
  506.             }
  507.         }
  508.  
  509.         //
  510.         // Remove all trailing spaces
  511.         //
  512.         while((input_ptr > input_buffer) && Code::IsSpace(*input_ptr))
  513.             input_ptr--;
  514.     }
  515.  
  516.     //
  517.     // If the very last character is not CTL_Z then add CTL_Z
  518.     //
  519.     if (*input_ptr != U_CTL_Z)
  520.     {
  521.         if (*input_ptr != U_LINE_FEED)
  522.             *(++input_ptr) = U_LINE_FEED; // if the last character is not end-of-line, add end-of-line
  523.         *(++input_ptr) = U_CTL_Z;         // Mark end-of-file
  524.     }
  525.     *(++input_ptr) = U_NULL;              // add gate
  526.  
  527.     input_buffer_length = input_ptr - input_buffer;
  528.  
  529.     return;
  530. }
  531.  
  532.  
  533. //
  534. // This procedure uses a  quick sort algorithm to sort the stream ERRORS
  535. // by their locations.
  536. //
  537. void LexStream::SortMessages()
  538. {
  539.      int lower,
  540.          upper,
  541.          lostack[32],
  542.          histack[32];
  543.  
  544.      int top,
  545.          i,
  546.          j;
  547.      StreamError pivot,
  548.                  temp;
  549.  
  550.      top = 0;
  551.      lostack[top] = 0;
  552.      histack[top] = bad_tokens.Length() - 1;
  553.  
  554.      while(top >= 0)
  555.      {
  556.          lower = lostack[top];
  557.          upper = histack[top];
  558.          top--;
  559.  
  560.          while(upper > lower)
  561.          {
  562.              //
  563.              // The array is most-likely almost sorted. Therefore,
  564.              // we use the middle element as the pivot element.
  565.              //
  566.              i = (lower + upper) / 2;
  567.              pivot = bad_tokens[i];
  568.              bad_tokens[i] = bad_tokens[lower];
  569.  
  570.              //
  571.              // Split the array section indicated by LOWER and UPPER
  572.              // using ARRAY(LOWER) as the pivot.
  573.              //
  574.              i = lower;
  575.              for (j = lower + 1; j <= upper; j++)
  576.              {
  577.                  if (bad_tokens[j].start_location < pivot.start_location)
  578.                  {
  579.                      temp = bad_tokens[++i];
  580.                      bad_tokens[i] = bad_tokens[j];
  581.                      bad_tokens[j] = temp;
  582.                  }
  583.              }
  584.              bad_tokens[lower] = bad_tokens[i];
  585.              bad_tokens[i] = pivot;
  586.  
  587.              top++;
  588.              if ((i - lower) < (upper - i))
  589.              {
  590.                  lostack[top] = i + 1;
  591.                  histack[top] = upper;
  592.                  upper = i - 1;
  593.              }
  594.              else
  595.              {
  596.                  histack[top] = i - 1;
  597.                  lostack[top] = lower;
  598.                  lower = i + 1;
  599.              }
  600.          }
  601.      }
  602.  
  603.      return;
  604. }
  605.  
  606.  
  607. //
  608. //
  609. //
  610. void LexStream::PrintMessages()
  611. {
  612.     //
  613.     // If control.option.dump_errors then the error messages have already been printed
  614.     //
  615.     if (! control.option.dump_errors)
  616.     {
  617.         RereadInput();
  618.  
  619.         if (control.option.errors)
  620.         {
  621.             char *file_name = FileName();
  622.  
  623.             Coutput << "\nFound " << NumBadTokens() << " lexical error" << (NumBadTokens() == 1 ? "" : "s")
  624.                     << " in \""
  625.                     << file_name
  626.                     << "\":";
  627.  
  628.             if (! input_buffer)
  629.             {
  630.                 int length = FileNameLength();
  631.                 wchar_t *name = new wchar_t[length + 1];
  632.                 for (int i = 0; i < length; i++)
  633.                     name[i] = file_name[i];
  634.                 name[length] = U_NULL;
  635.                 control.system_semantic -> ReportSemError(SemanticError::CANNOT_REOPEN_FILE,
  636.                                                           0,
  637.                                                           0,
  638.                                                           name);
  639.                 delete [] name;
  640.             }
  641.             else
  642.             {
  643.                 for (int i = 0; i < bad_tokens.Length(); i++)
  644.                 {
  645.                     if (FindLine(bad_tokens[i].start_location) == FindLine(bad_tokens[i].end_location))
  646.                          PrintSmallSource(i);
  647.                     else PrintLargeSource(i);
  648.  
  649.                     Coutput << "\n*** Lexical Error: ";
  650.  
  651.                     PrintMessage(bad_tokens[i].kind);
  652.                 }
  653.             }
  654.         }
  655.         else
  656.         {
  657.             for (int i = 0; i < bad_tokens.Length(); i++)
  658.                 PrintEmacsMessage(i);
  659.         }
  660.  
  661.         DestroyInput();
  662.  
  663.         Coutput.flush();
  664.     }
  665.  
  666.     return;
  667. }
  668.  
  669.  
  670. //
  671. //
  672. //
  673. void LexStream::PrintEmacsMessage(int k)
  674. {
  675.     int left_line_no    = FindLine(bad_tokens[k].start_location),
  676.         left_column_no  = FindColumn(bad_tokens[k].start_location),
  677.         right_line_no   = FindLine(bad_tokens[k].end_location),
  678.         right_column_no = FindColumn(bad_tokens[k].end_location);
  679.  
  680.     Coutput << FileName()
  681.             << ':' << left_line_no  << ':' << left_column_no
  682.             << ':' << right_line_no << ':' << right_column_no
  683.             << ":\n    Lexical: ";
  684.  
  685.     PrintMessage(bad_tokens[k].kind);
  686.  
  687.     return;
  688. }
  689.  
  690.  
  691. //
  692. // This procedure is invoked to print a small message that may
  693. // only span a single line. The parameter k points to the error
  694. // message in the error structure.
  695. //
  696. void LexStream::PrintSmallSource(int k)
  697. {
  698.     int left_line_no = FindLine(bad_tokens[k].start_location);
  699.  
  700.     Coutput << "\n\n";
  701.     Coutput.width(6);
  702.     Coutput << left_line_no;
  703.     Coutput << ". ";
  704.     for (int i = this -> LineStart(left_line_no); i <= this -> LineEnd(left_line_no); i++)
  705.         Coutput << this -> InputBuffer()[i];
  706.  
  707.     int left_column_no = FindColumn(bad_tokens[k].start_location),
  708.         right_column_no = FindColumn(bad_tokens[k].end_location);
  709.  
  710.     Coutput.width(left_column_no + 7);
  711.     Coutput << "";
  712.     if (left_column_no == right_column_no)
  713.         Coutput << '^';
  714.     else
  715.     {
  716.         int offset = 0;
  717.         for (int i = bad_tokens[k].start_location; i <= bad_tokens[k].end_location; i++)
  718.         {
  719.             if (this -> InputBuffer()[i] > 0xff)
  720.                 offset += 5;
  721.         }
  722.  
  723.         Coutput << '<';
  724.         Coutput.width(right_column_no - left_column_no + offset);
  725.         Coutput.fill('-');
  726.         Coutput << ">";
  727.         Coutput.fill(' ');
  728.     }
  729.  
  730.     return;
  731. }
  732.  
  733.  
  734. //
  735. // This procedure is invoked to print a large message that may
  736. // span more than one line. The parameter message points to the
  737. // starting line. The parameter k points to the error message in
  738. // the error structure.
  739. //
  740. void LexStream::PrintLargeSource(int k)
  741. {
  742.     int left_line_no    = FindLine(bad_tokens[k].start_location),
  743.         left_column_no  = FindColumn(bad_tokens[k].start_location),
  744.         right_line_no   = FindLine(bad_tokens[k].end_location),
  745.         right_column_no = FindColumn(bad_tokens[k].end_location);
  746.  
  747.     if (left_line_no == right_line_no)
  748.     {
  749.         if (left_line_no == 0)
  750.             Coutput << "\n";
  751.         else
  752.         {
  753.             Coutput << "\n\n";
  754.             Coutput.width(6);
  755.             Coutput << left_line_no << ". ";
  756.             for (int i = this -> LineStart(left_line_no); i <= this -> LineEnd(left_line_no); i++)
  757.                 Coutput << this -> InputBuffer()[i];
  758.  
  759.             int offset = 0;
  760.             for (int j = bad_tokens[k].start_location; j <= bad_tokens[k].end_location; j++)
  761.             {
  762.                 if (this -> InputBuffer()[j] > 0xff)
  763.                     offset += 5;
  764.             }
  765.  
  766.             Coutput.width(left_column_no + 8);
  767.             Coutput << "<";
  768.             Coutput.width(right_column_no - left_column_no + offset);
  769.             Coutput.fill('-');
  770.             Coutput << ">";
  771.             Coutput.fill(' ');
  772.         }
  773.     }
  774.     else
  775.     {
  776.         Coutput << "\n\n";
  777.         Coutput.width(left_column_no + 8);
  778.         Coutput << "<";
  779.  
  780.         int segment_size = Tab::Wcslen(input_buffer, bad_tokens[k].start_location,
  781.                                                      LineEnd(FindLine(bad_tokens[k].start_location)));
  782.         Coutput.width(segment_size - 1);
  783.         Coutput.fill('-');
  784.         Coutput << "\n";
  785.         Coutput.fill(' ');
  786.  
  787.         Coutput.width(6);
  788.         Coutput << left_line_no << ". ";
  789.         for (int i = this -> LineStart(left_line_no); i <= this -> LineEnd(left_line_no); i++)
  790.             Coutput << this -> InputBuffer()[i];
  791.  
  792.         if (right_line_no > left_line_no + 1)
  793.         {
  794.             Coutput.width(left_column_no + 7);
  795.             Coutput << " ";
  796.             Coutput << ". . .\n";
  797.         }
  798.  
  799.         Coutput.width(6);
  800.         Coutput << right_line_no << ". ";
  801.  
  802.         int offset = 0;
  803.         for (int j = this -> LineStart(right_line_no); j <= this -> LineEnd(right_line_no); j++)
  804.         {
  805.             wchar_t c = this -> InputBuffer()[j];
  806.             if (c > 0xff)
  807.                 offset += 5;
  808.             Coutput << c;
  809.         }
  810.  
  811.         Coutput.width(8);
  812.         Coutput << "";
  813.         Coutput.width(right_column_no - 1 + offset);
  814.         Coutput.fill('-');
  815.         Coutput << ">";
  816.         Coutput.fill(' ');
  817.     }
  818.  
  819.     return;
  820. }
  821.  
  822.  
  823. void LexStream::PrintMessage(StreamError::StreamErrorKind kind)
  824. {
  825.     switch(kind)
  826.     {
  827.         case StreamError::BAD_TOKEN:
  828.              Coutput << "Illegal token";
  829.              break;
  830.         case StreamError::BAD_OCTAL_CONSTANT:
  831.              Coutput << "Octal constant contains invalid digit";
  832.              break;
  833.         case StreamError::EMPTY_CHARACTER_CONSTANT:
  834.              Coutput << "Empty character constant";
  835.              break;
  836.         case StreamError::UNTERMINATED_CHARACTER_CONSTANT:
  837.              Coutput << "Character constant not properly terminated";
  838.              break;
  839.         case StreamError::UNTERMINATED_COMMENT:
  840.              Coutput << "Comment not properly terminated";
  841.              break;
  842.         case StreamError::UNTERMINATED_STRING_CONSTANT:
  843.              Coutput << "String constant not properly terminated";
  844.              break;
  845.         case StreamError::INVALID_HEX_CONSTANT:
  846.              Coutput << "The prefix 0x must be followed by at least one hex digit";
  847.              break;
  848.         case StreamError::INVALID_FLOATING_CONSTANT_EXPONENT:
  849.              Coutput << "floating-constant exponent has no digit";
  850.              break;
  851.         case StreamError::INVALID_UNICODE_ESCAPE:
  852.              Coutput << "Invalid unicode escape character";
  853.              break;
  854.         default:
  855.              assert(false);
  856.     }
  857.  
  858.     Coutput << '\n';
  859.  
  860.     return;
  861. }
  862.  
  863.