package chat;



import java.io.IOException;

import java.io.Reader;

import java.io.StreamTokenizer;



/**
 * Implementazione del <i>lexer</i> specifico per la seguente grammatica:
 * <p>
 * <i>scopo</i> ::= <i>nome</i> / <i>chiave</i> @ <i>endpoint</i><br>
 * <i>nome</i> ::= ( a |...| z | A |...| Z | 0 |...| 9 | _ | $ ) { a |...| z | A |...| Z | 0 |...| 9 | _ | $ }<sup>31</sup><br>
 * <i>chiave</i> ::= <i>numero</i> { , <i>numero</i> }<br>
 * <i>endpoint</i> ::= <i>ip</i> : <i>numero</i> { @ <i>ip</i> : <i>numero</i> }<br>
 * <i>ip</i> ::= <i>numero</i> . <i>numero</i> . <i>numero</i> . <i>numero</i><br>
 * <i>numero</i> ::= 0 [ x <i>cifra-hex</i> { <i>cifra-hex</i> } | { <i>cifra</i> } ] | <i>cifra-non-nulla</i> { <i>cifra</i> }<br>
 * <i>cifra</i> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9<br>
 * <i>cifra-non-nulla</i> ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9<br>
 * <i>cifra-hex</i> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | f | A | B | C | D | E | F
 * <p>
 * Sono riconosciuti i commenti in stile C e C++.
 * <p>
 *
 * @author    <em>Marco Cimatti</em>
 * @version   1.0
 */
class Lexer extends StreamTokenizer {

  /**
   * Unico costruttore che inizializza il <i>lexer</i> con i
   * caratteri separatori specificati dalla grammatica.
   *
   * @param   r   il <code>java.io.Reader</code> su cui
   *              poggiare questa specializzazione di
   *              <code>java.io.StreamTokenizer</code>.
   */
  Lexer(Reader r) {
    super(r);
    resetSyntax();
    wordChars('a', 'z');
    wordChars('A', 'Z');
    wordChars('0', '9');
    wordChars('_', '_');
    wordChars('$', '$');
    commentChar(';');                   // Carattere di inizio dei commenti sino a fine linea

    slashStarComments(true);            // Riconosciuti i commenti con sintassi C...

    slashSlashComments(true);           // ...e C++

    whitespaceChars('\t', '\t');        // I separatori fra le parole

    whitespaceChars('\r', '\r');    
    whitespaceChars(' ', ' ');
    eolIsSignificant(false);            // 'End Of Line' come un blank

    ordinaryChar('/');                  // 4 tipi di token specifici

    ordinaryChar(',');
    ordinaryChar('@');
    ordinaryChar(':');
    ordinaryChar('.');
  }

  /**
   * Specializzazione di <code>java.io.StreamTokenizer.nextToken()</code>
   * per il corretto parsing dei numeri (naturali in notazione decimale ed
   * esadecimale Java-<i>like</i>, prefissati cioč da <code>0x</code>).
   *
   * @return      Il valore di <code>java.io.StreamTokenizer.ttype</code>, cioč il tipo del token letto.
   * @exception   java.io.IOException   se generata da <code>java.io.StreamTokenizer.nextToken()</code>.
   */
  public int nextToken() throws IOException {
    if (super.nextToken() == TT_WORD)
      try {
        nval  = sval.startsWith("0x") ? Long.parseLong(sval.substring(2), 16) : Long.parseLong(sval);
        ttype = TT_NUMBER;
      } catch (NumberFormatException e) {}
    return ttype;
  }

  /**
   * <b>Funzione</b> che ritorna una rappresentazione testuale
   * del <i>token</i> corrente ultimo estratto dallo <i>stream</i>.
   *
   * @return   La versione stringa del <i>token</i> in esame;
   *           <code>""</code> in caso di <i>End Of File</i>.
   */
  String tokenCorrente() {
    switch (ttype) {
      case TT_NUMBER: return "" + (long) nval;
      case TT_WORD:   return sval;
      case TT_EOL:    return "<EOL>";
      case TT_EOF:    return "";
      default:        return "" + (char) ttype;
    }
    // Qui non si arriva mai...

  }
}


syntax highlighted by Code2HTML, v. 0.8.11