package chat;
import cryptix.provider.rsa.RawRSAPublicKey;
import java.io.ByteArrayInputStream;
import java.io.Reader;
import java.io.IOException;
import java.net.InetAddress;
import java.security.PublicKey;
import java.util.Vector;
/**
* Il <i>parser</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 Parser {
/**
* Il lexer incapsulato, associato allo stream fisico.
*
* @see Lexer
*/
private Lexer lexer;
/**
* Unico costruttore.
*
* @param stream il <code>java.io.Reader</code> su cui far agire il lexer <code>lexer</code>.
* @see #lexer
*/
Parser(Reader stream) {
lexer = new Lexer(stream);
}
/**
* <b>Procedura</b> associata alla regola di produzione "nome"
* della grammatica.
*
* @exception IOException se generata dal <i>lexer</i>.
* @exception RuntimeException in caso di errori sintattici.
* @return una stringa formata secondo la produzione "nome".
*/
protected String nome() throws IOException {
if (lexer.ttype == lexer.TT_WORD || lexer.ttype == lexer.TT_NUMBER) {
String buf = lexer.sval;
lexer.nextToken();
return buf;
}
else
throw new RuntimeException("Nome non valido alla linea " + lexer.lineno() + ".");
}
/**
* <b>Procedura</b> associata alla regola di produzione "chiave"
* della grammatica.
*
* @exception IOException se generata dal <i>lexer</i>.
* @exception RuntimeException in caso di errori sintattici.
* @return la <code>cryptix.provider.rsa.RawRSAPublicKey</code>
* ottenuta mediante la sintassi espressa della
* riscrittura "chiave".
*/
protected PublicKey chiave() throws IOException {
Vector v = new Vector();
while (true) {
long l = numero();
if ((l & 0xff) != l)
throw new RuntimeException("Numero " + l + " non byte alla linea " + lexer.lineno() + ".");
v.add(new Byte((byte) (l & 0xff)));
if (lexer.ttype != ',')
break;
lexer.nextToken();
}
byte[] buf = new byte[v.size()];
for (int i = 0; i < buf.length; ++i)
buf[i] = ((Byte) v.get(i)).byteValue();
return new RawRSAPublicKey(new ByteArrayInputStream(buf));
}
/**
* <b>Procedura</b> associata alla regola di produzione "endpoint"
* della grammatica.
*
* @exception IOException se generata dal <i>lexer</i>.
* @exception RuntimeException in caso di errori sintattici.
* @return l'<code>Endpoint</code> secondo la sintassi della
* regola di riscrittura "endpoint" della grammatica.
* @see Endpoint
*/
protected Endpoint endpoint() throws IOException {
InetAddress IP = ip();
if (lexer.ttype != ':')
throw new RuntimeException("Atteso ':', trovato [" + tokenCorrente() + "] alla linea " + lexer.lineno() + ".");
lexer.nextToken();
long porta = numero();
if (porta < 0 || 0xffff < porta)
throw new RuntimeException("Numero di porta TCP/UDP " + porta + " illegale alla linea " + lexer.lineno() + ".");
return new Endpoint(IP, (int) porta);
}
/**
* <b>Procedura</b> associata alla regola di produzione "ip"
* della grammatica.
*
* @exception IOException se generata dal <i>lexer</i> oppure
* se l'indirizzo Internet letto
* non rappresenta un IP valido.
* @exception RuntimeException in caso di errori sintattici.
* @return il <code>java.net.InetAddress</code> in base alla
* produzione "ip" della grammatica.
*/
protected InetAddress ip() throws IOException {
String IP = "" + numero();
for (int i = 1; i < 4; ++i) {
if (lexer.ttype != '.')
throw new RuntimeException("Atteso '.', trovato [" + tokenCorrente() + "] alla linea " + lexer.lineno() + ".");
lexer.nextToken();
IP += "." + numero();
}
return InetAddress.getByName(IP); // IP illegale => IOException!
}
/**
* <b>Procedura</b> associata alla regola di produzione "numero"
* della grammatica.
*
* @exception IOException se generata dal <i>lexer</i>.
* @exception RuntimeException in caso di errori sintattici.
* @return il <code>long</code> secondo la riscrittura "numero" della grammatica.
*/
protected long numero() throws IOException {
if (lexer.ttype != lexer.TT_NUMBER)
throw new RuntimeException("Atteso un numero, trovato [" + tokenCorrente() + "] alla linea " + lexer.lineno() + ".");
long l = (long) lexer.nval;
lexer.nextToken();
return l;
}
/**
* <b>Procedura</b> per avanzare lungo il flusso di caratteri; da
* invocare <u>OBBLIGATORIAMENTE</u> all'avvio per portare il
* <i>lexer</i> interno sul primo <i>token</i> disponibile dallo
* <i>stream</i> di lettura.
*
* @exception IOException se generata dal <i>lexer</i>.
* @see #lexer
*/
void avanzaToken() throws IOException {
lexer.nextToken();
}
/**
* <b>Funzione</b> che restituisce il token disponibile
* dal <code>Lexer lexer</code>, senza estrarne uno nuovo.
*
* @return La stringa costituita dal token ultimo estratto.
* @see #lexer
* @see Lexer
* @see Lexer#tokenCorrente()
*/
String tokenCorrente() {
return lexer.tokenCorrente();
}
/**
* <b>Procedura</b> che estrae la prima parola disponibile
* dallo <i>stream</i> cui è associato il <code>Lexer lexer</code>.
* Realizza lo scopo della grammatica:
* <p>
* <i>scopo</i> ::= <i>nome</i> / <i>chiave</i> @ <i>endpoint</i>
*
* @exception IOException se prodotta da <code>lexer</code>.
* @exception RuntimeException in caso di errori sintattici o semantici.
* @return Il primo <code>Contatto</code> disponibile nel flusso
* di <code>char</code> dello <i>stream</i> di <code>lexer</code>.
* @see Contatto
*/
Contatto prossimo() throws IOException {
String nome = nome();
if (lexer.ttype != '/')
throw new RuntimeException("Atteso '/', trovato [" + tokenCorrente() + "] alla linea " + lexer.lineno() + ".");
lexer.nextToken();
PublicKey chiave = chiave();
if (lexer.ttype != '@')
throw new RuntimeException("Atteso '@', trovato [" + tokenCorrente() + "] alla linea " + lexer.lineno() + ".");
lexer.nextToken();
Contatto c = new Contatto(nome, chiave, endpoint());
while (lexer.ttype == '@') {
lexer.nextToken();
c.aggiungi(endpoint());
}
return c;
}
}
syntax highlighted by Code2HTML, v. 0.8.11