/** file: StrInExp: trasforma Stringhe in EXP (nella R.Interna) */
import java.io.*;
import java.util.*;
import java.awt.*;
import java.lang.Exception;
/** ================
IL TOKENIZER
================ */
/** Il "TOKENIZER" e' un oggetto a cui viene data una stringa e
che rende (facendo chiamate successive) la stringa
spezzettata in "token", cioe' disgregata nei sui "componenti"
(ridefinibili tramite opportuni metodi) */
class ExpTokenizer extends StreamTokenizer { // trasforma STR in TOKEN
TextArea msgOut;
/** Costruttore del disgregatore di espressioni */
ExpTokenizer (InputStream I) throws Exception {
super (I);
parseNumbers ();
eolIsSignificant (true);
ordinaryChar ('(');
ordinaryChar (')');
ordinaryChar ('+');
ordinaryChar ('*');
ordinaryChar ('-');
ordinaryChar ('/');
ordinaryChar ('=');
ordinaryChar ('X');
ordinaryChar ('Y');
ordinaryChar ('A');
ordinaryChar ('B');
quoteChar('"');
slashStarComments (false);
}
ExpTokenizer (String s, TextArea AreaOut) throws Exception {
this (new StringBufferInputStream(s)); // chiama costruttore di sopra!
msgOut = AreaOut;
msgOut.appendText ("ExpTokenizer - inizializzato con "+ s +"\n");
}
/** Rimette dentro il "tokenizer" l'ultimo "token" prelevato.
Si annulla l'ultima operazione "next". */
public void pushBack () {
if (ttype != TT_EOF) {
msgOut.appendText ("Tokenizer - 'pushBack' di '");
switch (ttype) {
case TT_WORD: msgOut.appendText (sval+"'\n"); break;
case TT_NUMBER: msgOut.appendText (nval+"'\n"); break;
default: msgOut.appendText ((char)ttype +"'\n");
}//switch
super.pushBack();
}
}
/** Rende il prossimo "token" */
public Token next() throws Exception {
Token T; // Token da rendere
int TType = nextToken(); // Prende il nuovo valore dal Tokenizer
msgOut.appendText ("Tokenizer - 'next' rende token '");
switch (TType) {
case TT_WORD: msgOut.appendText (sval+"'\n"); break;
case TT_NUMBER: msgOut.appendText (nval+"'\n"); break;
case TT_EOF: msgOut.appendText ("EOTok'\n"); break;
default: msgOut.appendText ((char)TType +"'\n");
}//switch
switch (TType) { // Controlla il token preso
case TT_WORD: { // IDENTIFICATORE composto o operatore (letterale)
if ((sval.compareTo("sqr") == 0) ||
(sval.compareTo("sqrt")== 0) ||
(sval.compareTo("inv") == 0))
T = new Token(sval, 'O');
else
T = new Token(sval, 'I');
break;
}
case TT_NUMBER: T = new Token(""+nval, 'N'); break; // NUMERO
case '(':
case ')':
case '=':
case '+':
case '-':
case '*':
case '/': T = new Token((char)TType+"", 'O'); break;
case 'X':
case 'Y':
case 'A':
case 'B': T = new Token((char)TType+"", 'I'); break;
case TT_EOF: T = new Token("FINE",'$'); break;
case TT_EOL: T = next(); break;
default: T = new Token((char)TType+"");
} //switch
return T; // rende oggetto (token) creato
} //next
} //ExpTokenizer
/** =======================================
LE CLASSI TOKEN (rese dal TOKENIZER)
======================================= */
class Token {
String MyInfo;
char MyTipo; // 'N' per NUM, 'I' per ID,
// 'O' per operatore o '$' per nullo
public Token (String Informaz, char Tipo) {
MyInfo = Informaz;
MyTipo = Tipo;
}
public Token (String Informaz) {
this (Informaz, 'O');
}
public String Info() { return MyInfo; }
public String toString() { return MyInfo+" ["+MyTipo+"]"; }
public boolean Contiene(String EQuesto) {
return (MyInfo.compareTo(EQuesto) == 0);
}
public boolean ENumero() { return (MyTipo == 'N'); }
public boolean EIdentific() { return (MyTipo == 'I'); }
public boolean EOperatore() { return (MyTipo == 'O'); }
public boolean NoPiuToken() { return (MyTipo == '$'); }
}
/** =============
IL PARSER
============= */
class StrParser { // Legge la sequenza di token e rende la R.I. (in Exp)
//Nota: in ingresso riceve il Tokenizer
ExpTokenizer ETokeniz;
TextArea msgOut;
StrParser (ExpTokenizer ETokz, TextArea AreaOut) throws Exception {
ETokeniz = ETokz;
msgOut = AreaOut;
msgOut.appendText ("Parser - inizializzato\n");
}
// Insieme delle produzioni per le TRE NOTAZIONI:
// Notazione PREfissa (pre) INfissa (in) POSTfissa (post)
// E::= + E E E::= E + T E::= E E +
// E::= - E E E::= E - T E::= E E -
// E::= = ID E E::= ID = E E::= ID E =
// E::= T
// E::= * E E T::= T * F E::= E E *
// E::= / E E T::= T / F E::= E E /
// E::= F T::= F E::= F
// F::= ( E )
// E::= sqr E F::= sqr F F::= E sqr
// E::= sqrt E F::= sqrt F F::= E sqrt
// E::= inv E F::= inv F F::= E inv
// F::= NUM F::= NUM F::= NUM
// F::= ID F::= ID F::= ID
// Nota: SOLO la notazione INfissa ha bisogno delle parentesi!
// Ora tolgo la RICORSIONE SINISTRA dalle ultime due!
// Notazione PREfissa (pre) INfissa (in) POSTfissa (post)
// E::= + E E E ::= T RE E ::= F UN RE
// E::= - E E E ::= ID = E RE::= §
// E::= = ID E RE::= + T RE RE::= F UN RO RE
// RE::= - T RE RO::= + UN
// RE::= § RO::= - UN
// T ::= F RT RO::= * UN
// E::= * E E RT::= * F RT RO::= / UN
// E::= / E E RT::= / F RT RO::= =
// E::= F RT::= § RO::= F UN RO RO
// F ::= ( E ) UN::= §
// E::= sqr E F ::= sqr F UN::= sqr UN
// E::= sqrt E F ::= sqrt F UN::= sqrt UN
// E::= inv E F ::= inv F UN::= inv UN
// F::= NUM F ::= NUM F ::= NUM
// F::= ID F ::= ID F ::= ID
// E quindi CODIFICO ogni NON TERMINALE con una PROCEDURA
/** ====================
NOTAZIONE INFISSA
==================== */
public Exp RendiExpDaNotazInfissa () throws Exception {
msgOut.appendText ("INIZIO LA COSTRUZIONE STR-->R.I.\n"
+"(*) Elaboro in Notazione INFISSA\n");
Exp ExpResa = ExpIN(); // RENDE R.I.
Token NuoTok= ETokeniz.next(); // prendo prossimo token
if (NuoTok.NoPiuToken()) // (dovrebbe verificarsi cio')
return ExpResa; // tutto ok, stringa totalmente consumata
else
throw new Exception("NON HO CONSUMATO L'INTERA STRINGA!"); // errore
}//RendiExpDaNotazInfissa
protected Exp ExpIN() throws Exception {
// E ::= T RE
msgOut.appendText ("RendiExpIN inizio E=T\n");
Exp Term = TermIN();
Exp ExpDaRendere = RestExpIN(Term);
msgOut.appendText ("RendiExpIN fine di E=T\n");
return ExpDaRendere;
}//ExpIN
protected Exp RestExpIN(Exp Stato) throws Exception {
// E ::= ID = E (messo qui per verificare che sia ID)
// RE::= + T RE
// RE::= - T RE
// RE::= §
Exp ExpDaRendere;
msgOut.appendText ("RendiExpIN inizio RE=+T|-T|null\n");
Token NuovoToken = ETokeniz.next (); // prendo prossimo token
if (NuovoToken.NoPiuToken()) { // Token finiti
msgOut.appendText ("RendiExpIN no piu' token\n");
ExpDaRendere = Stato; // Rendo la RI avuta in ingresso
}
else
if (NuovoToken.Contiene("+")) { // Trovo un "+"
msgOut.appendText ("RendiExpIN riconosc. +T\n");
Exp Term = TermIN();
Exp NuovoStato = new PiuExp (Stato, Term);
ExpDaRendere = RestExpIN (NuovoStato);
}
else
if (NuovoToken.Contiene("-")) { // Trovo un "-"
msgOut.appendText ("RendiExpIN riconosc. -T\n");
Exp Term = TermIN();
Exp NuovoStato = new MenExp (Stato, Term);
ExpDaRendere = RestExpIN (NuovoStato);
}
else
if (NuovoToken.Contiene("=")) { // Trovo un "="
msgOut.appendText ("RendiExpIN riconosc. ID=E\n");
if (!(Stato instanceof IdentRefExp))
throw new Exception("IL PRIMO ARG. DI '=' DEV'ESSERE UN SIMBOLO"); // errore
Exp LValue = new IdentExp (((IdentRefExp)Stato).Val()); // l-value!
Exp RValue = ExpIN();
ExpDaRendere = new AssignExp (LValue, RValue);
}
else {
msgOut.appendText ("RendiExpIN pushback in RE\n");
ETokeniz.pushBack(); // ri-inserisco l'operat.non elaborato
ExpDaRendere = Stato; // Rendo la RI avuta in ingresso
}
msgOut.appendText ("RendiExpIN fine RE=+T|-T|null\n");
return ExpDaRendere;
}//RestExpIN
protected Exp TermIN() throws Exception {
// T ::= F RT
msgOut.appendText ("RendiExpIN inizio T=F\n");
Exp Fact = FactIN();
Exp ExpDaRendere = RestTermIN(Fact);
msgOut.appendText ("RendiExpIN fine T=F\n");
return ExpDaRendere;
}//TermIN
protected Exp RestTermIN(Exp Stato) throws Exception {
// RT::= * F RT
// RT::= / F RT
// RT::= §
Exp ExpDaRendere;
msgOut.appendText ("RendiExpIN inizio RT=*F|/F|null\n");
Token NuovoToken = ETokeniz.next (); // Prendo prossimo token
if (NuovoToken.NoPiuToken()) { // Token finiti
msgOut.appendText ("RendiExpIN no piu' token\n");
ExpDaRendere = Stato; // Rendo la RI avuta in ingresso
}
else
if (NuovoToken.Contiene("*")) { // Trovo un "*"
msgOut.appendText ("RendiExpIN riconosc. *F\n");
Exp Fact = FactIN();
Exp NuovoStato = new PerExp (Stato, Fact);
ExpDaRendere = RestTermIN (NuovoStato);
}
else
if (NuovoToken.Contiene("/")) { // Trovo un "/"
msgOut.appendText ("RendiExpIN riconosc. /F\n");
Exp Fact = FactIN();
Exp NuovoStato = new DivExp (Stato, Fact);
ExpDaRendere = RestTermIN (NuovoStato);
}
else {
msgOut.appendText ("RendiExpIN pushback in RT\n");
ETokeniz.pushBack(); // ri-inserisco l'operat.non elaborato
ExpDaRendere = Stato; // Rendo la RI avuta in ingresso
}
msgOut.appendText ("RendiExpIN fine RT=*F|/F|null\n");
return ExpDaRendere;
}//RestTermIN
protected Exp FactIN() throws Exception {
// F ::= ( E )
// F ::= sqr F
// F ::= sqrt F
// F ::= inv F
Exp ExpDaRendere;
msgOut.appendText ("RendiExpIN inizio F=(E)\n");
Token NuovoToken = ETokeniz.next (); // prendo prossimo token
if (NuovoToken.Contiene("(")) { // Trovo una "("
msgOut.appendText ("RendiExpIN riconosc. TONDA APERTA\n");
ExpDaRendere = ExpIN();
NuovoToken = ETokeniz.next (); // prendo prossimo token
if (!(NuovoToken.Contiene(")")))
throw new Exception("MANCA UNA TONDA CHIUSA"); // errore
}
else
if (NuovoToken.Contiene("sqr")) { // Trovo un "sqr"
msgOut.appendText ("RendiExpIN riconosc. SQR\n");
Exp EspInt = FactIN();
ExpDaRendere = new SqrExp (EspInt);
}
else
if (NuovoToken.Contiene("sqrt")) { // Trovo un"sqrt"
msgOut.appendText ("RendiExpIN riconosc. SQRT\n");
Exp EspInt = FactIN();
ExpDaRendere = new SqrtExp (EspInt);
}
else
if (NuovoToken.Contiene("inv")) { // Trovo un "inv"
msgOut.appendText ("RendiExpIN riconosc. INV\n");
Exp EspInt = FactIN();
ExpDaRendere = new InvExp (EspInt);
}
else
ExpDaRendere = FactNumIdALL(NuovoToken);
msgOut.appendText ("RendiExpIN fine F=(E)\n");
return ExpDaRendere;
}//FactIN
protected Exp FactNumIdALL (Token NuovoToken) throws Exception {
// F::= NUM
// F::= ID
Exp ExpDaRendere;
msgOut.appendText ("RendiExpXX inizio F=NUM|ID\n");
if (NuovoToken.Contiene("-")) { // Controllo "-NUM"
NuovoToken = ETokeniz.next(); // prendo prossimo token
if (NuovoToken.ENumero()) { // Trovo un NUMERO
msgOut.appendText ("RendiExpXX riconosc. -NUMERO\n");
NuovoToken = new Token ("-"+NuovoToken.Info(),'N');
// questo nuovo token verra' usato tra poco:
}
}
if (NuovoToken.ENumero()) { // Trovo un NUMERO
msgOut.appendText ("RendiExpXX riconosc. NUMERO "+NuovoToken+"\n");
double Valore = (new Double(NuovoToken.Info())).doubleValue();
ExpDaRendere = new NumExp (Valore);
}
else
if (NuovoToken.EIdentific()) { // Trovo IDENTIFICAT.
msgOut.appendText ("RendiExpXX riconosc. IDENTIF. "+NuovoToken+"\n");
ExpDaRendere = new IdentRefExp (NuovoToken.Info()); // r-value!
}
else
throw new Exception("ESPRESSIONE NON RAPPRESENTABILE"); // errore
msgOut.appendText ("RendiExpXX fine F=NUM|ID\n");
return ExpDaRendere;
}//FactNumIdALL
/** =====================
NOTAZIONE PREFISSA
===================== */
public Exp RendiExpDaNotazPrefissa () throws Exception {
msgOut.appendText ("INIZIO LA COSTRUZIONE STR-->R.I.\n"
+"(*) Elaboro in Notazione PREFISSA\n");
Exp ExpResa = ExpPRE(); // RENDE R.I.
Token NuoTok= ETokeniz.next(); // prendo prossimo token
if (NuoTok.NoPiuToken()) // (dovrebbe verificarsi cio')
return ExpResa; // tutto ok, stringa totalmente consumata
else
throw new Exception("NON HO CONSUMATO L'INTERA STRINGA!"); // errore
}
protected Exp ExpPRE() throws Exception {
// E::= + E E
// E::= - E E
// E::= = ID E
// E::= * E E
// E::= / E E
// E::= sqr E
// E::= sqrt E
// E::= inv E
// E::= F
Exp ExpDaRendere;
msgOut.appendText ("RendiExpPRE inizio RT=+ E E|* E E|..\n");
Token NuovoToken = ETokeniz.next (); // prendo prossimo token
if (NuovoToken.Contiene("+")) { // Trovo un "+"
msgOut.appendText ("RendiExpPRE riconosc. + F F\n");
Exp Arg1 = ExpPRE();
Exp Arg2 = ExpPRE();
ExpDaRendere = new PiuExp (Arg1, Arg2);
}
else
if (NuovoToken.Contiene("-")) { // Trovo un "-"
msgOut.appendText ("RendiExpPRE riconosc. - F F\n");
Exp Arg1 = ExpPRE();
Exp Arg2 = ExpPRE();
ExpDaRendere = new MenExp (Arg1, Arg2);
}
else
if (NuovoToken.Contiene("*")) { // Trovo un "*"
msgOut.appendText ("RendiExpPRE riconosc. * F F\n");
Exp Arg1 = ExpPRE();
Exp Arg2 = ExpPRE();
ExpDaRendere = new PerExp (Arg1, Arg2);
}
else
if (NuovoToken.Contiene("/")) { // Trovo un "/"
msgOut.appendText ("RendiExpPRE riconosc. / F F\n");
Exp Arg1 = ExpPRE();
Exp Arg2 = ExpPRE();
ExpDaRendere = new DivExp (Arg1, Arg2);
}
else
if (NuovoToken.Contiene("=")) { // Trovo un "="
msgOut.appendText ("RendiExpPRE riconosc. = ID E\n");
Exp ID = FactNumIdALL (NuovoToken);
if (!(ID instanceof IdentRefExp))
throw new Exception("IL PRIMO ARG. DI '=' DEV'ESSERE UN SIMBOLO"); // errore
Exp LValue = new IdentExp (((IdentRefExp)ID).Val()); // l-value!
Exp RValue = ExpPRE();
ExpDaRendere = new AssignExp (LValue, RValue);
}
else
if ((NuovoToken.Contiene("(")) ||
(NuovoToken.Contiene(")"))) // Trovo "(" o" )"
throw new Exception("NON SI DEVONO USARE LE PARENTESI!");
else
if (NuovoToken.Contiene("sqr")) { // Trovo "sqr"
msgOut.appendText ("RendiExpIN riconosc. SQR\n");
Exp EspInterna = ExpPRE();
ExpDaRendere = new SqrExp (EspInterna);
}
else
if (NuovoToken.Contiene("sqrt")) { //Trovo "sqrt"
msgOut.appendText ("RendiExpIN riconosc. SQRT\n");
Exp EspInterna = ExpPRE();
ExpDaRendere = new SqrtExp (EspInterna);
}
else
if (NuovoToken.Contiene("inv")) { //Trovo"inv"
msgOut.appendText ("RendiExpIN riconosc. INV\n");
Exp EspInterna = ExpPRE();
ExpDaRendere = new InvExp (EspInterna);
}
else
ExpDaRendere = FactNumIdALL (NuovoToken);
// nota: richiamo il riconoscimento di NUM o ID o errore
msgOut.appendText ("RendiExpPRE fine RT=+ E E|* E E|..\n");
return ExpDaRendere;
}//ExpPRE
/** ======================
NOTAZIONE POSTFISSA
====================== */
public Exp RendiExpDaNotazPostfissa () throws Exception {
msgOut.appendText ("INIZIO LA COSTRUZIONE STR-->R.I.\n"
+"(*) Elaboro in Notazione POSTFISSA\n");
Exp ExpResa = ExpPOST(); // RENDE R.I.
Token NuoTok= ETokeniz.next(); // prendo prossimo token
if (NuoTok.NoPiuToken()) // (dovrebbe verificarsi cio')
return ExpResa; // tutto ok, stringa totalmente consumata
else
throw new Exception("NON HO CONSUMATO L'INTERA STRINGA!"); // errore
}//RendiExpDaNotazPostfissa
protected Exp ExpPOST() throws Exception {
// E ::= F UN RE
msgOut.appendText ("RendiExpPOST inizio E=F\n");
Token NuovoToken = ETokeniz.next(); // prendo prossimo token
Exp Fatt1 = FactNumIdALL (NuovoToken);
Exp ExpConUnario = UnPOST (Fatt1);
Exp ExpDaRendere = RestExpPOST (ExpConUnario);
msgOut.appendText ("RendiExpPOST fine di E=F RE\n");
return ExpDaRendere;
}//ExpPOST
protected Exp RestExpPOST (Exp Fatt1) throws Exception {
// RE::= §
// RE::= F UN RO RE
Exp ExpDaRendere;
msgOut.appendText ("RendiExpPOST inizio RE=F RO RE\n");
Token NuovoToken = ETokeniz.next (); // prendo prossimo token
if (NuovoToken.NoPiuToken()) { // Token finiti
msgOut.appendText ("RendiExpPOST no piu' token\n");
ExpDaRendere = Fatt1; // Rendo la RI avuta in ingresso
}
else {
Exp Fatt2 = FactNumIdALL (NuovoToken);
Exp ExpUnaria2 = UnPOST (Fatt2);
Exp ResRO = RestOperPOST (Fatt1, ExpUnaria2);
ExpDaRendere = RestExpPOST (ResRO);
}
msgOut.appendText ("RendiExpPOST fine RE=F RO RE\n");
return ExpDaRendere;
}//RestExpPOST
protected Exp RestOperPOST (Exp Fatt1, Exp Fatt2) throws Exception {
// RO::= + UN
// RO::= - UN
// RO::= * UN
// RO::= / UN
// RO::= =
// RO::= F UN RO RO
Exp ExpDaRendere;
msgOut.appendText ("RendiExpPOST inizio RO=+|-|*|..|F RO RO\n");
Token NuovoToken = ETokeniz.next (); // prendo prossimo token
if (NuovoToken.Contiene("+")) { // Trovo un "+"
msgOut.appendText ("RendiExpPOST riconosc. F F +\n");
Exp ExpCalco = new PiuExp (Fatt1, Fatt2);
ExpDaRendere = UnPOST (ExpCalco);
}
else
if (NuovoToken.Contiene("-")) { // Trovo un "-"
msgOut.appendText ("RendiExpPOST riconosc. F F -\n");
Exp ExpCalco = new MenExp (Fatt1, Fatt2);
ExpDaRendere = UnPOST (ExpCalco);
}
else
if (NuovoToken.Contiene("*")) { // Trovo un "*"
msgOut.appendText ("RendiExpPOST riconosc. F F *\n");
Exp ExpCalco = new PerExp (Fatt1, Fatt2);
ExpDaRendere = UnPOST (ExpCalco);
}
else
if (NuovoToken.Contiene("/")) { // Trovo un "/"
msgOut.appendText ("RendiExpPOST riconosc. F F /\n");
Exp ExpCalco = new DivExp (Fatt1, Fatt2);
ExpDaRendere = UnPOST (ExpCalco);
}
else
if (NuovoToken.Contiene("=")) { // Trovo un "="
msgOut.appendText ("RendiExpPOST riconosc. ID E =\n");
if (!(Fatt1 instanceof IdentRefExp))
throw new Exception("IL PRIMO ARG. DI '=' DEV'ESSERE UN SIMBOLO"); // errore
Exp LValue = new IdentExp (((IdentRefExp)Fatt1).Val()); // l-value!
ExpDaRendere = new AssignExp (LValue, Fatt2);
}
else {
Exp Fatt3 = FactNumIdALL (NuovoToken);
Exp ExpUnaria3 = UnPOST (Fatt3);
Exp OpFatt23 = RestOperPOST (Fatt2, ExpUnaria3);
ExpDaRendere = RestOperPOST (Fatt1, OpFatt23);
}
msgOut.appendText ("RendiExpPOST fine RO=+|-|*|..|F RO RO\n");
return ExpDaRendere;
}//RestOperPOST
protected Exp UnPOST (Exp ExpProbabile) throws Exception {
// UN::= §
// UN::= sqr UN
// UN::= sqrt UN
// UN::= inv UN
Exp ExpDaRendere;
msgOut.appendText ("RendiExpPOST inizio UN=null|sqr|..\n");
Token NuovoToken = ETokeniz.next (); // prendo prossimo token
if (NuovoToken.Contiene("sqr")) { // Trovo "sqr"
msgOut.appendText ("RendiExpIN riconosc. SQR\n");
Exp AltraExpProb = new SqrExp (ExpProbabile);
ExpDaRendere = UnPOST (AltraExpProb);
}
else
if (NuovoToken.Contiene("sqrt")) { //Trovo "sqrt"
msgOut.appendText ("RendiExpIN riconosc. SQRT\n");
Exp AltraExpProb = new SqrtExp (ExpProbabile);
ExpDaRendere = UnPOST (AltraExpProb);
}
else
if (NuovoToken.Contiene("inv")) { // Trovo "inv"
msgOut.appendText ("RendiExpIN riconosc. INV\n");
Exp AltraExpProb = new InvExp (ExpProbabile);
ExpDaRendere = UnPOST (AltraExpProb);
}
else{
ETokeniz.pushBack(); // ri-inserisco token non elaborato
ExpDaRendere = ExpProbabile;
}
msgOut.appendText ("RendiExpPOST fine UN=null|sqr|..\n");
return ExpDaRendere;
}//UnPOST
} //StrParser
//*FINE FILE*