home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / main.bin / StreamTokenizer.java < prev    next >
Text File  |  1997-05-20  |  25KB  |  757 lines

  1. /*
  2.  * @(#)StreamTokenizer.java    1.20 97/02/26
  3.  * 
  4.  * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  * CopyrightVersion 1.1_beta
  20.  * 
  21.  */
  22.  
  23. package java.io;
  24.  
  25.  
  26. /**
  27.  * The <code>StreamTokenizer</code> class takes an input stream and 
  28.  * parses it into "tokens", allowing the tokens to be 
  29.  * read one at a time. The parsing process is controlled by a table 
  30.  * and a number of flags that can be set to various states. The 
  31.  * stream tokenizer can recognize identifiers, numbers, quoted 
  32.  * strings, and various comment styles. 
  33.  * <p>
  34.  * Each byte read from the input stream is regarded as a character 
  35.  * in the range <code>'\u0000'</code> through <code>'\u00FF'</code>. 
  36.  * The character value is used to look up five possible attributes of 
  37.  * the character: <i>white space</i>, <i>alphabetic</i>, 
  38.  * <i>numeric</i>, <i>string quote</i>, and <i>comment character</i>. 
  39.  * Each character can have zero or more of these attributes. 
  40.  * <p>
  41.  * In addition, an instance has four flags. These flags indicate: 
  42.  * <ul>
  43.  * <li>Whether line terminators are to be returned as tokens or treated 
  44.  *     as white space that merely separates tokens. 
  45.  * <li>Whether C-style comments are to be recognized and skipped. 
  46.  * <li>Whether C++-style comments are to be recognized and skipped. 
  47.  * <li>Whether the characters of identifiers are converted to lowercase. 
  48.  * </ul>
  49.  * <p>
  50.  * A typical application first constructs an instance of this class, 
  51.  * sets up the syntax tables, and then repeatedly loops calling the 
  52.  * <code>nextToken</code> method in each iteration of the loop until 
  53.  * it returns the value <code>TT_EOF</code>. 
  54.  *
  55.  * @author  James Gosling
  56.  * @version 1.20, 02/26/97
  57.  * @see     java.io.StreamTokenizer#nextToken()
  58.  * @see     java.io.StreamTokenizer#TT_EOF
  59.  * @since   JDK1.0
  60.  */
  61.  
  62. public class StreamTokenizer {
  63.  
  64.     /* Only one of these will be non-null */
  65.     private Reader reader = null;
  66.     private InputStream input = null;
  67.  
  68.     private char buf[] = new char[20];
  69.     private int peekc;
  70.     private boolean pushedBack;
  71.     private boolean forceLower;
  72.     /** The line number of the last token read */
  73.     private int LINENO = 1;
  74.  
  75.     private boolean eolIsSignificantP = false;
  76.     private boolean slashSlashCommentsP = false;
  77.     private boolean slashStarCommentsP = false;
  78.  
  79.     private byte ctype[] = new byte[256];
  80.     private static final byte CT_WHITESPACE = 1;
  81.     private static final byte CT_DIGIT = 2;
  82.     private static final byte CT_ALPHA = 4;
  83.     private static final byte CT_QUOTE = 8;
  84.     private static final byte CT_COMMENT = 16;
  85.  
  86.     /** 
  87.      * After a call to the <code>nextToken</code> method, this field 
  88.      * contains the type of the token just read. For a single character 
  89.      * token, its value is the single character, converted to an integer. 
  90.      * For a quoted string token (see , its value is the quote character. 
  91.      * Otherwise, its value is one of the following: 
  92.      * <ul>
  93.      * <li><code>TT_WORD</code> indicates that the token is a word.
  94.      * <li><code>TT_NUMBER</code> indicates that the token is a number.
  95.      * <li><code>TT_EOL</code> indicates that the end of line has been read. 
  96.      *     The field can only have this value if the 
  97.      *     <code>eolIsSignificant</code> method has been called with the 
  98.      *     argument <code>true</code>. 
  99.      * <li><code>TT_EOF</code> indicates that the end of the input stream 
  100.      *     has been reached. 
  101.      * </ul>
  102.      *
  103.      * @see     java.io.StreamTokenizer#eolIsSignificant(boolean)
  104.      * @see     java.io.StreamTokenizer#nextToken()
  105.      * @see     java.io.StreamTokenizer#quoteChar(int)
  106.      * @see     java.io.StreamTokenizer#TT_EOF
  107.      * @see     java.io.StreamTokenizer#TT_EOL
  108.      * @see     java.io.StreamTokenizer#TT_NUMBER
  109.      * @see     java.io.StreamTokenizer#TT_WORD
  110.      */
  111.     public int ttype = TT_NOTHING;
  112.  
  113.     /** 
  114.      * A constant indicating that the end of the stream has been read. 
  115.      */
  116.     public static final int TT_EOF = -1;
  117.  
  118.     /** 
  119.      * A constant indicating that the end of the line has been read. 
  120.      */
  121.     public static final int TT_EOL = '\n';
  122.  
  123.     /** 
  124.      * A constant indicating that a number token has been read. 
  125.      */
  126.     public static final int TT_NUMBER = -2;
  127.  
  128.     /** 
  129.      * A constant indicating that a word token has been read. 
  130.      */
  131.     public static final int TT_WORD = -3;
  132.  
  133.     /* A constant indicating that no token has been read, used for
  134.      * initializing ttype.  FIXME This could be made public and
  135.      * made available as the part of the API in a future release.
  136.      */
  137.     private static final int TT_NOTHING = -4;
  138.     
  139.     /**
  140.      * If the current token is a word token, this field contains a 
  141.      * string giving the characters of the word token. When the current 
  142.      * token is a quoted string token, this field contains the body of 
  143.      * the string. 
  144.      * <p>
  145.      * The current token is a word when the value of the 
  146.      * <code>ttype</code> field is <code>TT_WORD</code>. The current token is
  147.      * a quoted string token when the value of the <code>ttype</code> field is
  148.      * a quote character.
  149.      *
  150.      * @see     java.io.StreamTokenizer#quoteChar(int)
  151.      * @see     java.io.StreamTokenizer#TT_WORD
  152.      * @see     java.io.StreamTokenizer#ttype
  153.      * @since JDK1.0
  154.      */
  155.     public String sval;
  156.  
  157.     /**
  158.      * If the current token is a number, this field contains the value 
  159.      * of that number. The current token is a number when the value of 
  160.      * the <code>ttype</code> field is <code>TT_NUMBER</code>. 
  161.      *
  162.      * @see     java.io.StreamTokenizer#TT_NUMBER
  163.      * @see     java.io.StreamTokenizer#ttype
  164.      */
  165.     public double nval;
  166.  
  167.     /** Private constructor that initializes everything except the streams. */
  168.     private StreamTokenizer() {
  169.     wordChars('a', 'z');
  170.     wordChars('A', 'Z');
  171.     wordChars(128 + 32, 255);
  172.     whitespaceChars(0, ' ');
  173.     commentChar('/');
  174.     quoteChar('"');
  175.     quoteChar('\'');
  176.     parseNumbers();
  177.     }
  178.  
  179.     /**
  180.      * Creates a stream tokenizer that parses the specified input 
  181.      * stream. The stream tokenizer is initialized to the following 
  182.      * default state: 
  183.      * <ul>
  184.      * <li>All byte values <code>'A'</code> through <code>'Z'</code>, 
  185.      *     <code>'a'</code> through <code>'z'</code>, and 
  186.      *     <code>'\u00A0'</code> through <code>'\u00FF'</code> are
  187.      *     considered to be alphabetic. 
  188.      * <li>All byte values <code>'\u0000'</code> through 
  189.      *     <code>'\u0020'</code> are considered to be white space. 
  190.      * <li><code>'/'</code> is a comment character. 
  191.      * <li>Single quote <code>'\''</code> and double quote <code>'"'</code> 
  192.      *     are string quote characters. 
  193.      * <li>Numbers are parsed. 
  194.      * <li>Ends of lines are treated as white space, not as separate tokens. 
  195.      * <li>C-style and C++-style comments are not recognized. 
  196.      * </ul>
  197.      *
  198.      * @deprecated As of JDK version 1.1, the preferred way to tokenize an
  199.      * input stream is to convert it into a character stream, for example:
  200.      * <p>
  201.      * <pre>
  202.      *   Reader r = new BufferedReader(new InputStreamReader(is));
  203.      *   StreamTokenizer st = new StreamTokenizer(r);
  204.      * </pre>
  205.      *
  206.      * @param      is        an input stream.
  207.      * @see        java.io.BufferedReader
  208.      * @see        java.io.InputStreamReader
  209.      * @see        java.io.StreamTokenizer#StreamTokenizer(java.io.Reader)
  210.      */
  211.     public StreamTokenizer(InputStream is) {
  212.     this();
  213.     input = is;
  214.     }
  215.  
  216.     /**
  217.      * Create a tokenizer that parses the given character stream.
  218.      * @since   JDK1.1
  219.      */
  220.     public StreamTokenizer(Reader r) {
  221.     this();
  222.     reader = r;
  223.     }
  224.  
  225.     /** 
  226.      * Resets this tokenizer's syntax table so that all characters are 
  227.      * "ordinary." See the <code>ordinaryChar</code> method 
  228.      * for more information on a character being ordinary. 
  229.      *
  230.      * @see     java.io.StreamTokenizer#ordinaryChar(int)
  231.      */
  232.     public void resetSyntax() {
  233.     for (int i = ctype.length; --i >= 0;)
  234.         ctype[i] = 0;
  235.     }
  236.  
  237.     /** 
  238.      * Specifies that all characters <i>c</i> in the range 
  239.      * <code>low <= <i>c</i> <= high</code> 
  240.      * are word constituents. A word token consists of a word constituent 
  241.      * followed by zero or more word constituents or number constituents. 
  242.      *
  243.      * @param   low   the low end of the range.
  244.      * @param   hi    the high end of the range.
  245.      */
  246.     public void wordChars(int low, int hi) {
  247.     if (low < 0)
  248.         low = 0;
  249.     if (hi >= ctype.length)
  250.         hi = ctype.length - 1;  
  251.     while (low <= hi)
  252.         ctype[low++] |= CT_ALPHA;
  253.     }
  254.  
  255.     /** 
  256.      * Specifies that all characters <i>c</i> in the range 
  257.      * <code>low <= <i>c</i> <= high</code> 
  258.      * are white space characters. White space characters serve only to 
  259.      * separate tokens in the input stream. 
  260.      *
  261.      * @param   low   the low end of the range.
  262.      * @param   hi    the high end of the range.
  263.      */
  264.     public void whitespaceChars(int low, int hi) {
  265.     if (low < 0)
  266.         low = 0;
  267.     if (hi >= ctype.length)
  268.         hi = ctype.length - 1;
  269.     while (low <= hi)
  270.         ctype[low++] = CT_WHITESPACE;
  271.     }
  272.  
  273.     /** 
  274.      * Specifies that all characters <i>c</i> in the range 
  275.      * <code>low <= <i>c</i> <= high</code> 
  276.      * are "ordinary" in this tokenizer. See the 
  277.      * <code>ordinaryChar</code> method for more information on a 
  278.      * character being ordinary. 
  279.      *
  280.      * @param   low   the low end of the range.
  281.      * @param   hi    the high end of the range.
  282.      * @see     java.io.StreamTokenizer#ordinaryChar(int)
  283.      */
  284.     public void ordinaryChars(int low, int hi) {
  285.     if (low < 0)
  286.         low = 0;
  287.     if (hi >= ctype.length)
  288.         hi = ctype.length - 1;
  289.     while (low <= hi)
  290.         ctype[low++] = 0;
  291.     }
  292.  
  293.     /** 
  294.      * Specifies that the character argument is "ordinary" 
  295.      * in this tokenizer. It removes any special significance the 
  296.      * character has as a comment character, word component, string 
  297.      * delimiter, white space, or number character. When such a character 
  298.      * is encountered by the parser, the parser treates it as a
  299.      * single-character token and sets <code>ttype</code> field to the
  300.      * character value. 
  301.      *
  302.      * @param   ch   the character.
  303.      * @see     java.io.StreamTokenizer#ttype
  304.      */
  305.     public void ordinaryChar(int ch) {
  306.         if (ch >= 0 && ch < ctype.length)
  307.           ctype[ch] = 0;
  308.     }
  309.  
  310.     /** 
  311.      * Specified that the character argument starts a single-line 
  312.      * comment. All characters from the comment character to the end of 
  313.      * the line are ignored by this stream tokenizer. 
  314.      *
  315.      * @param   ch   the character.
  316.      */
  317.     public void commentChar(int ch) {
  318.         if (ch >= 0 && ch < ctype.length)
  319.         ctype[ch] = CT_COMMENT;
  320.     }
  321.  
  322.     /** 
  323.      * Specifies that matching pairs of this character delimit string 
  324.      * constants in this tokenizer. 
  325.      * <p>
  326.      * When the <code>nextToken</code> method encounters a string 
  327.      * constant, the <code>ttype</code> field is set to the string 
  328.      * delimiter and the <code>sval</code> field is set to the body of 
  329.      * the string. 
  330.      * <p>
  331.      * If a string quote character is encountered, then a string is 
  332.      * recognized, consisting of all characters after (but not including) 
  333.      * the string quote character, up to (but not including) the next 
  334.      * occurrence of that same string quote character, or a line 
  335.      * terminator, or end of file. The usual escape sequences such as 
  336.      * <code>"\n"</code> and <code>"\t"</code> are recognized and 
  337.      * converted to single characters as the string is parsed. 
  338.      *
  339.      * @param   ch   the character.
  340.      * @see     java.io.StreamTokenizer#nextToken()
  341.      * @see     java.io.StreamTokenizer#sval
  342.      * @see     java.io.StreamTokenizer#ttype
  343.      */
  344.     public void quoteChar(int ch) {
  345.         if (ch >= 0 && ch < ctype.length)
  346.          ctype[ch] = CT_QUOTE;
  347.     }
  348.  
  349.     /** 
  350.      * Specifies that numbers should be parsed by this tokenizer. The 
  351.      * syntax table of this tokenizer is modified so that each of the twelve
  352.      * characters:
  353.      * <ul><code>
  354.      *      0 1 2 3 4 5 6 7 8 9 . -
  355.      * </code></ul>
  356.      * <p>
  357.      * has the "numeric" attribute. 
  358.      * <p>
  359.      * When the parser encounters a word token that has the format of a 
  360.      * double precision floating-point number, it treats the token as a 
  361.      * number rather than a word, by setting the the <code>ttype</code> 
  362.      * field to the value <code>TT_NUMBER</code> and putting the numeric 
  363.      * value of the token into the <code>nval</code> field. 
  364.      *
  365.      * @see     java.io.StreamTokenizer#nval
  366.      * @see     java.io.StreamTokenizer#TT_NUMBER
  367.      * @see     java.io.StreamTokenizer#ttype
  368.      */
  369.     public void parseNumbers() {
  370.     for (int i = '0'; i <= '9'; i++)
  371.         ctype[i] |= CT_DIGIT;
  372.     ctype['.'] |= CT_DIGIT;
  373.     ctype['-'] |= CT_DIGIT;
  374.     }
  375.  
  376.     /**
  377.      * Determines whether or not ends of line are treated as tokens.
  378.      * If the flag argument is true, this tokenizer treats end of lines 
  379.      * as tokens; the <code>nextToken</code> method returns 
  380.      * <code>TT_EOL</code> and also sets the <code>ttype</code> field to 
  381.      * this value when an end of line is read. 
  382.      * <p>
  383.      * A line is a sequence of characters ending with either a 
  384.      * carriage-return character (<code>'\r'</code>) or a newline 
  385.      * character (<code>'\n'</code>). In addition, a carriage-return 
  386.      * character followed immediately by a newline character is treated 
  387.      * as a single end-of-line token. 
  388.      * <p>
  389.      * If the <code>flag</code> is false, end-of-line characters are 
  390.      * treated as white space and serve only to separate tokens. 
  391.      *
  392.      * @param   flag   <code>true</code> indicates that end-of-line characters
  393.      *                 are separate tokens; <code>false</code> indicates that
  394.      *                 end-of-line characters are white space.
  395.      * @see     java.io.StreamTokenizer#nextToken()
  396.      * @see     java.io.StreamTokenizer#ttype
  397.      * @see     java.io.StreamTokenizer#TT_EOL
  398.      */
  399.     public void eolIsSignificant(boolean flag) {
  400.     eolIsSignificantP = flag;
  401.     }
  402.  
  403.     /** 
  404.      * Determines whether or not the tokenizer recognizes C-style comments.
  405.      * If the flag argument is <code>true</code>, this stream tokenizer 
  406.      * recognizes C-style comments. All text between successive 
  407.      * occurrences of <code>/*</code> and <code>*/</code> are discarded. 
  408.      * <p>
  409.      * If the flag argument is <code>false</code>, then C-style comments 
  410.      * are not treated specially. 
  411.      *
  412.      * @param   flag   <code>true</code> indicates to recognize and ignore
  413.      *                 C-style comments.
  414.      */
  415.     public void slashStarComments(boolean flag) {
  416.     slashStarCommentsP = flag;
  417.     }
  418.  
  419.     /** 
  420.      * Determines whether or not the tokenizer recognizes C++-style comments.
  421.      * If the flag argument is <code>true</code>, this stream tokenizer 
  422.      * recognizes C++-style comments. Any occurrence of two consecutive 
  423.      * slash characters (<code>'/'</code>) is treated as the beginning of 
  424.      * a comment that extends to the end of the line. 
  425.      * <p>
  426.      * If the flag argument is <code>false</code>, then C++-style 
  427.      * comments are not treated specially. 
  428.      *
  429.      * @param   flag   <code>true</code> indicates to recognize and ignore
  430.      *                 C++-style comments.
  431.      */
  432.     public void slashSlashComments(boolean flag) {
  433.     slashSlashCommentsP = flag;
  434.     }
  435.  
  436.     /**
  437.      * Determines whether or not word token are automatically lowercased.
  438.      * If the flag argument is <code>true</code>, then the value in the 
  439.      * <code>sval</code> field is lowercased whenever a word token is 
  440.      * returned (the <code>ttype</code> field has the 
  441.      * value <code>TT_WORD</code> by the <code>nextToken</code> method 
  442.      * of this tokenizer. 
  443.      * <p>
  444.      * If the flag argument is <code>false</code>, then the 
  445.      * <code>sval</code> field is not modified. 
  446.      *
  447.      * @param   fl   <code>true</code> indicates that all word tokens should
  448.      *               be lowercased.
  449.      * @see     java.io.StreamTokenizer#nextToken()
  450.      * @see     java.io.StreamTokenizer#ttype
  451.      * @see     java.io.StreamTokenizer#TT_WORD
  452.      */
  453.     public void lowerCaseMode(boolean fl) {
  454.     forceLower = fl;
  455.     }
  456.  
  457.     /** Read the next character */
  458.     private int read() throws IOException {
  459.     if (reader != null)
  460.         return reader.read();
  461.     else if (input != null)
  462.         return input.read();
  463.     else
  464.         throw new IllegalStateException();
  465.     }
  466.  
  467.     /** 
  468.      * Parses the next token from the input stream of this tokenizer. 
  469.      * The type of the next token is returned in the <code>ttype</code> 
  470.      * field. Additional information about the token may be in the 
  471.      * <code>nval</code> field or the <code>sval</code> field of this 
  472.      * tokenizer. 
  473.      * <p>
  474.      * Typical clients of this
  475.      * class first set up the syntax tables and then sit in a loop
  476.      * calling nextToken to parse successive tokens until TT_EOF
  477.      * is returned. 
  478.      *
  479.      * @return     the value of the <code>ttype</code> field.
  480.      * @exception  IOException  if an I/O error occurs.
  481.      * @see        java.io.StreamTokenizer#nval
  482.      * @see        java.io.StreamTokenizer#sval
  483.      * @see        java.io.StreamTokenizer#ttype
  484.      */
  485.     public int nextToken() throws IOException {
  486.     if (pushedBack) {
  487.         pushedBack = false;
  488.         return ttype;
  489.     }
  490.     byte ct[] = ctype;
  491.     int c; 
  492.     sval = null;
  493.  
  494.     if (ttype == TT_NOTHING) {
  495.         c = read();
  496.         if (c >= 0)    // ttype is surely overwritten below to its correct value.
  497.             ttype = c; // for now we just make sure it isn't TT_NOTHING
  498.     } else {
  499.         c = peekc;
  500.     }
  501.     
  502.     if (c < 0)
  503.         return ttype = TT_EOF;
  504.     int ctype = c < 256 ? ct[c] : CT_ALPHA;
  505.     while ((ctype & CT_WHITESPACE) != 0) {
  506.         if (c == '\r') {
  507.         LINENO++;
  508.         c = read();
  509.         if (c == '\n')
  510.             c = read();
  511.         if (eolIsSignificantP) {
  512.             peekc = c;
  513.             return ttype = TT_EOL;
  514.         }
  515.         } else {
  516.         if (c == '\n') {
  517.             LINENO++;
  518.             if (eolIsSignificantP) {
  519.             peekc = read();
  520.             return ttype = TT_EOL;
  521.             }
  522.         }
  523.         c = read();
  524.         }
  525.         if (c < 0)
  526.         return ttype = TT_EOF;
  527.         ctype = c < 256 ? ct[c] : CT_ALPHA;
  528.     }
  529.     if ((ctype & CT_DIGIT) != 0) {
  530.         boolean neg = false;
  531.         if (c == '-') {
  532.         c = read();
  533.         if (c != '.' && (c < '0' || c > '9')) {
  534.             peekc = c;
  535.             return ttype = '-';
  536.         }
  537.         neg = true;
  538.         }
  539.         double v = 0;
  540.         int decexp = 0;
  541.         int seendot = 0;
  542.         while (true) {
  543.         if (c == '.' && seendot == 0)
  544.             seendot = 1;
  545.         else if ('0' <= c && c <= '9') {
  546.             v = v * 10 + (c - '0');
  547.             decexp += seendot;
  548.         } else
  549.             break;
  550.         c = read();
  551.         }
  552.         peekc = c;
  553.         if (decexp != 0) {
  554.         double denom = 10;
  555.         decexp--;
  556.         while (decexp > 0) {
  557.             denom *= 10;
  558.             decexp--;
  559.         }
  560.         /* do one division of a likely-to-be-more-accurate number */
  561.         v = v / denom;
  562.         }
  563.         nval = neg ? -v : v;
  564.         return ttype = TT_NUMBER;
  565.     }
  566.     if ((ctype & CT_ALPHA) != 0) {
  567.         int i = 0;
  568.         do {
  569.         if (i >= buf.length) {
  570.             char nb[] = new char[buf.length * 2];
  571.             System.arraycopy(buf, 0, nb, 0, buf.length);
  572.             buf = nb;
  573.         }
  574.         buf[i++] = (char) c;
  575.         c = read();
  576.         ctype = c < 0 ? CT_WHITESPACE : c < 256 ? ct[c] : CT_ALPHA;
  577.         } while ((ctype & (CT_ALPHA | CT_DIGIT)) != 0);
  578.         peekc = c;
  579.         sval = String.copyValueOf(buf, 0, i);
  580.         if (forceLower)
  581.         sval = sval.toLowerCase();
  582.         return ttype = TT_WORD;
  583.     }
  584.     if ((ctype & CT_COMMENT) != 0) {
  585.         while ((c = read()) != '\n' && c != '\r' && c >= 0);
  586.         peekc = c;
  587.         return nextToken();
  588.     }
  589.     if ((ctype & CT_QUOTE) != 0) {
  590.         ttype = c;
  591.         int i = 0;
  592.         // invariants (because \Octal needs a lookahead):
  593.         //      (i)  c contains char value 
  594.         //      (ii) peekc contains the lookahead
  595.         peekc = read(); 
  596.         while (peekc >= 0 && peekc != ttype && peekc != '\n' && peekc != '\r') {
  597.             if (peekc == '\\') {
  598.                c = read();
  599.             int first = c;   // to allow \377, but not \477
  600.             if (c >= '0' && c <= '7') {
  601.             c = c - '0';
  602.             int c2 = read();
  603.             if ('0' <= c2 && c2 <= '7') {
  604.                 c = (c << 3) + (c2 - '0');
  605.                 c2 = read();
  606.                 if ('0' <= c2 && c2 <= '7' && first <= '3') {
  607.                 c = (c << 3) + (c2 - '0');
  608.                 peekc = read();
  609.                 } else
  610.                 peekc = c2;
  611.             } else
  612.               peekc = c2;
  613.             } else {
  614.                   switch (c) {
  615.             case 'a':
  616.                 c = 0x7;
  617.                 break;
  618.             case 'b':
  619.                 c = '\b';
  620.                 break;
  621.             case 'f':
  622.                 c = 0xC;
  623.                 break;
  624.             case 'n':
  625.                 c = '\n';
  626.                 break;
  627.                 case 'r':
  628.                 c = '\r';
  629.                 break;
  630.             case 't':
  631.                 c = '\t';
  632.                 break;
  633.             case 'v':
  634.                 c = 0xB;
  635.                 break;
  636.             }
  637.             peekc = read();
  638.             }
  639.         } else {
  640.             c = peekc;
  641.             peekc = read();
  642.         }
  643.         
  644.         if (i >= buf.length) {
  645.             char nb[] = new char[buf.length * 2];
  646.             System.arraycopy(buf, 0, nb, 0, buf.length);
  647.             buf = nb;
  648.         }
  649.         buf[i++] = (char) c;
  650.         }
  651.         if (peekc == ttype)  // keep \n or \r intact in peekc
  652.             peekc = read();
  653.         sval = String.copyValueOf(buf, 0, i);
  654.         return ttype;
  655.     }
  656.     if (c == '/' && (slashSlashCommentsP || slashStarCommentsP)) {
  657.         c = read();
  658.         if (c == '*' && slashStarCommentsP) {
  659.         int prevc = 0;
  660.         while ((c = read()) != '/' || prevc != '*') {
  661.             if (c == '\r') {
  662.             LINENO++;
  663.             c = read();
  664.             if (c == '\n') {
  665.                 c = read();
  666.             }
  667.             } else {
  668.                 if (c == '\n') {
  669.                 LINENO++;
  670.                 c = read();
  671.             }
  672.             }
  673.             if (c < 0)
  674.                 return ttype = TT_EOF;
  675.             prevc = c;
  676.         }
  677.         peekc = read();
  678.         return nextToken();
  679.         } else if (c == '/' && slashSlashCommentsP) {
  680.             while ((c = read()) != '\n' && c != '\r' && c >= 0);
  681.             peekc = c;
  682.         return nextToken();
  683.         } else {
  684.         peekc = c;
  685.         return ttype = '/';
  686.         }
  687.     }
  688.     peekc = read();
  689.     return ttype = c;
  690.     }
  691.  
  692.     /**
  693.      * Causes the next call to the <code>nextToken</code> method of this 
  694.      * tokenizer to return the current value in the <code>ttype</code> 
  695.      * field, and not to modify the value in the <code>nval</code> or 
  696.      * <code>sval</code> field. 
  697.      *
  698.      * @see     java.io.StreamTokenizer#nextToken()
  699.      * @see     java.io.StreamTokenizer#nval
  700.      * @see     java.io.StreamTokenizer#sval
  701.      * @see     java.io.StreamTokenizer#ttype
  702.      */
  703.     public void pushBack() {
  704.         if (ttype != TT_NOTHING)   // no-op if nextToken() not called
  705.         pushedBack = true;
  706.     }
  707.  
  708.     /**
  709.      * Return the current line number.
  710.      *
  711.      * @return  the current line number of this stream tokenizer.
  712.      */
  713.     public int lineno() {
  714.     return LINENO;
  715.     }
  716.  
  717.     /**
  718.      * Returns the string representation of the current stream token. 
  719.      *
  720.      * @return  a string representation of the token specified by the
  721.      *          <code>ttype</code>, <code>nval</code>, and <code>sval</code>
  722.      *          fields.
  723.      * @see     java.io.StreamTokenizer#nval
  724.      * @see     java.io.StreamTokenizer#sval
  725.      * @see     java.io.StreamTokenizer#ttype
  726.      */
  727.     public String toString() {
  728.     String ret;
  729.     switch (ttype) {
  730.       case TT_EOF:
  731.         ret = "EOF";
  732.         break;
  733.       case TT_EOL:
  734.         ret = "EOL";
  735.         break;
  736.       case TT_WORD:
  737.         ret = sval;
  738.         break;
  739.       case TT_NUMBER:
  740.         ret = "n=" + nval;
  741.         break;
  742.          case TT_NOTHING:  
  743.         ret = "NOTHING";
  744.         break;
  745.       default:{
  746.         char s[] = new char[3];
  747.         s[0] = s[2] = '\'';
  748.         s[1] = (char) ttype;
  749.         ret = new String(s);
  750.         break;
  751.         }
  752.     }
  753.     return "Token[" + ret + "], line " + LINENO;
  754.     }
  755.  
  756. }
  757.