Newsgroup: it.comp.programmare
Titolo: Aiuto Java problemi di parsing e calcoli

Salve a tutti voi del forum,
sono dietro a redigere un progettino in java, per un esame universitario, 
premetto che non sono una programmatrice, e sto diventando matta per 
scrivere quattro righe di codice..
Lo scopo del progetto è quello di leggere da un data base valori di alcuni 
campi, inserirle in degli array e farci dei calcoli..
I campi di questi datbase contengono sia dati,(numeri reali) che stringhe 
che non sono altro le operazioni che devono essere eseguite usando i dati 
recuperati dal primo database.
Tra le miriadi di problematiche ho anche quello di ottenere il risultato di 
alcuni calcoli scritti in formato stringa contenuti in un array di stringhe, 
come questo;
// ======= calcoli =============
String [] calcoli;
calcoli = new [n];
calcoli[0] = "id1+id2-id3";
calcoli[1] = "(id1+id2)*id3";
calcoli[2] = "((id1+id2)/id4)+id3";
calcoli[3] = "(((id1+id2)/id4)+id3)*3,14";
calcoli[4] = "(id4/365)+(12,3*id2)";
oltre a non capire come fare una sorta di parsing(credo che si scriva così) 
che tenga conto di parentesi tonde annidate (e non), e di numeri con e senza 
virgola (ho le variabili "reali") che sono contenute in un array come 
questo:
// ======= array valori ===========
double []valori;
valori = new double[4];
valori[0] = 0;
valori[1] = 10,89;
valori[2] = 110,894444;
valori[3] = 0,89;
valori[4] = 3;
nel caso dei calcoli
per esempio
double id0 = 0; -->valori[0]
double id1 = 10,89; -->valori[1]
double id2 = 110,894444; -->valori[2]
double id3 = 0,89; -->valori[3]
double id4 = 3; -->valori[4]
Alla fine dovrei ottenere dalla classe o dal metodo utlizzato i seguenti 
risultati..
se seleziono l'array "calcoli" con indice 0 dovrò ottenere:
120,8944 --> (id1+id2-id3)
se seleziono l'array "calcoli" con indice 1 dovrò ottenere:
108,3882 --> "(id1+id2)*id3"
se seleziono l'array "calcoli" con indice 2 dovrò ottenere:
41,4848146666667 --> "((id1+id2)/id4)+id3"
se seleziono l'array "calcoli" con indice 3 dovrò ottenere:
130,2623 --> "(((id1+id2)/id4)+id3)*3,14"
se seleziono l'array "calcoli" con indice 4 dovrò ottenere:
1364,01 --> "(id4/365)+(12,3*id2)"
La cosa interessante sarebbe poi trovare un modo di indirizzare il valore 
della variabile sull'array dei dati, nel senso che se ho per esempio:
calcoli[0] = "id1+id2-id3";
mi vada a prendere il valore delle variabili direttamente dentro l'array dei 
dati ad esempio valori[1] + valori[2] - valori[3]
avete qualche idea su come procedere?
vi ringrazio anticipatamente Linda ^^
Ps: avete qualche idea su come collegarmi al driver odbc di windows? e poi 
come posso passare i dati letti in un array? se avete qualche esempio sono 
molto graditi.
Pss: sto tentando di usare eclipse 3.2 

 e poi come posso passare i dati letti in un array? 
Ti torna un recordset, e popoli l'array con un ciclo.

 Sembra semplice
immagino che per te sia semplice, ma io che  ho fatto ragioneria sarei a mio 
agio con un bilancio..
taglio anche io qualche riga..
pensavo di fare cosě visto che non conosco la notazione polacca..
pensavo di elaborare cosě la stringa delle operazioni:
usare un ciclo for con charAt per leggere carattere per carattere della 
stringa.
fino a qui dovrebbe essere semplice, poi pensavo di fare cosě:
1) fare un metoto a cui passare la variabile di destra dall'operatore, 
l'operatore, e la variabile di sinistra dell'operatore e  restituire un 
valore.
2) dare priorita alle oprazioni che stanno nelle parentesi tonde piů 
interne.. per questo pensavo di fare cosě, scansionavo la stringa appena 
trovo una prentesi tonda incremento il livello della operazione, poi eseguo 
o valuto l'operazione appena trovo una parentesi chiusa..
Per la singola variabile pensavo di mettere i caratteri dentro un array e 
poi appena verifico che č una variabile o un numero appendo i caratteri per 
generare la variabile o il valore reale..
Credo che ci sia una ricorsione visto che ci sono piů livelli di parentesi, 
ma non so come fare.. cioč ho +/- in testa come deve fare ma non lo so fare 
come codice..
http://www.di.unipi.it/~andrea/Didattica/SP-LSD-04/LSD/AlberiBinari/EsprArit/main.html
questo per quello che mi dicevi per la notazione polacca??
l'semempio č interessante ma non saperei bene come modicarlo..
Come database č lo stesso che uso al lavoro un MySql con driver odbc.. ma 
non so come muovermi.. da Java..
cosa indendi con rtecordset ?? č un oggetto??? ma come faccio a passare gli 
l'istruzione sql?
Grazie per la risposta Linda^^ 

 gli l'istruzione sql?
Urca, siamo messi male.
Comunque ci sono delle classi gia' pronte per questa cosa.
Basta cercare in rete e trovi un sacco di esempi gia' pronti
Qui ce n'e' un sacco.
http://www.java2s.com/Code/Java/Database-SQL-JDBC/CatalogDatabase-SQL-JDBC.htm

tutte, o i segni delle operazioni potrebbero essere messi a caso...
Il parser può facilmente validare la semantica in base alle produzioni
della grammatica.

 
A me sembra ragionevole la parte che legge i dati e fa i calcoli. Chi si 
occupa di statisca potrebbe averne bisogno per implementare qualche 
analisi molto particolare.
La parte sull'analizzatore lessicale mi sembra molto meno ragionevole.
Potresti postare il testo preciso dell'esercizio? Per esempio, i nomi 
delle variabili sono sempre id1, id2, etc? Oppure puoi avere 
un'espressione del tipo: "(z*(x-var)+42)"? Inoltre, solo le quattro 
operazioni, o anche qualche altro operatore o funzione tipo 
"5+log(id1)-2^id2"? ("^" per l'elevamento a potenza).
In ogni caso, l'approccio piu' semplice, secondo me, è un parser a 
discesa ricorsiva ("recursive descent parser" o "RDP" su Google) che 
puoi realizzare in modo semiautomatico direttamente dalla grammatica 
delle espressioni.
Se ti è permesso usare altri tool (o se vuoi fare un confronto con il 
parser che scriverai "a mano") puoi usare un "parser generator". Se dai 
un'occhiata a runcc (
http://runcc.sourceforge.net/
) nella sua home page 
ci trovi un esempio classico: il parsing di espressioni aritmetiche :)
Non ti consiglio di cercare di creare un algoritmo da zero come quello 
che hai descritto, il parsing è uno dei campi piu' studiati 
dell'informatica ed esistono soluzioni già pronte per qualunque tipo di 
problema.

Ciao Roberto,
Nel fine settimana mi sono fatta in quattro.. ma qualcosa  ho cominciato a 
macinare..
Ovvero sono riuscita da una espressione (semplice) a trovare la parte destra 
e sinistra e di fare l'operazione come volevo io..
in fondo ti metto la lista delle cose che ho prodotto.. poi se vi va mi 
direte se č corretto..
Ovviamente la valutazione della operazione la metterň in una classe, 
Operazioni.. con due metodi, uno che mi ricava l'espressione a destra 
dell'operatore  e poi quella a sinistra, e poi con un terzo metodo che mi da 
il valore..
adesso devo trovare un modo per la questione parentesi.. e dovrň fare in 
modo di fare la ricorsione,  se non erro..
io pensavo a questo:
1) mi creo un array grande quanti sono i caratteri della stringa che contien 
il calcolo,
2) inserisco dentro le celle tutti i valori dei livelli delle parentesi il 
"(" incrementa il livello, mentre ")" decrementa il livello
3) estraggo la stringa che ha il livello delle parentesi piů alto, se ci 
sono due gruppi con lo stesso livello valuterň prima quello di sinistra e 
poi quello di destra.
4) valuto l'espressione selezionata ottenendo un valore
5) cancello dalla stringa (non so come farlo) tutti i caratteri che hanno il 
massimo livello delle parentesi (che poi č quella stringa che ho valutato al 
passo precedente)
6) inserisco dove ho appena cancellato il valore ottenuto della espressione 
(aggiungendo o sottraenso i caratteri necessari)..
7) ripeto dal passo 1 fino a che non sono a livello 0. (e dovrei ottenere un 
unico valore).
cosa te ne pare?
Poi una volta termiato questo problema mi dedicherň a leggere dal database i 
campi  e immetterli dentro gli array
Grazie di tutto Linda^^
==================  Inizio listato ==================
public class Maincalcolo {
 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  int puntatore_calcolo;
//   ======= calcoli =============
  String [] calcoli;
  calcoli = new String[5];
  calcoli[0] = "id1+id2-id3";
  calcoli[1] = "(id1+id2)*id3";
  calcoli[2] = "((id1+id2)/id4)+id3";
  calcoli[3] = "(((id1+id2)/id4)+id3)*3,14";
  calcoli[4] = "(id4/365)+(12,3*id2)";
//   ======= array valori ===========
  double []valori;
  valori = new double[15];
  valori[0] = 0;
  valori[1] = 10.89;
  valori[2] = 110.894444;
  valori[3] = 0.89;
  valori[4] = 3;
  valori[5] = 3;
  valori[6] = 3;
  valori[7] = 3;
  valori[8] = 3;
  valori[9] = 3;
  valori[10] = 3;
  valori[11] = 3;
  valori[12] = 3;
  valori[13] = 3;
  valori[14] = 3.222222222222222222222222;
//     ======== cosa voglio far calcolare
  puntatore_calcolo = 0;
  String calcolo = calcoli[puntatore_calcolo];
  calcolo.charAt(2);
  for ( int i=0 ; i < calcolo.length(); i++){
   //System.out.println("===>"+calcolo.charAt(i));
   switch (calcolo.charAt(i)) {
   case ('('): {
    System.out.println(" carattere:  aperta parentesi (  ");
    break;
   }
   case (')'): {
    System.out.println(" carattere:  chusa parentesi  ) ");
    break;
   }
   case ('i'): {
    System.out.println(" carattere:   i ");
    break;
   }
   case ('d'): {
    System.out.println(" carattere:   d ");
    break;
   }
   case ('1'): {
    System.out.println(" carattere:   1");
    break;
   }
   case ('2'): {
    System.out.println(" carattere:   2");
    break;
   }
   case ('3'): {
    System.out.println(" carattere:   3");
    break;
   }
   case ('4'): {
    System.out.println(" carattere:   4");
    break;
   }
   case ('5'): {
    System.out.println(" carattere:   5");
    break;
   }
   case ('6'): {
    System.out.println(" carattere:   6");
    break;
   }
   case ('7'): {
    System.out.println(" carattere:   7");
    break;
   }
   case ('8'): {
    System.out.println(" carattere:   8");
    break;
   }
   case ('9'): {
    System.out.println(" carattere:   9");
    break;
   }
   case ('0'): {
    System.out.println(" carattere:   0");
    break;
   }
   case (','): {
    System.out.println(" carattere:   ,");
    break;
   }
   case ('+'): {
    System.out.println(" carattere:   +");
    break;
   }
   case ('-'): {
    System.out.println(" carattere:   -");
    break;
   }
   case ('*'): {
    System.out.println(" carattere:   *");
    break;
   }
   case ('/'): {
    System.out.println(" carattere:   /");
    break;
   }
   case (' '): {
    System.out.println(" Rilevato spazio   ");
    break;
   }
   default: {
    System.out.println(" non so cosa sia!");
    break;
   }
   }
  }
  // a destra dell'operatore..
  // devo calcolare dall'inizio o dalla parentesi aperta all'operatore
  System.out.println("======== altro caso concatenare dei caratteri 
=========");
  String aaa = "id1+";
  // uso substring pre tagliare la stringa
  String bbb;
  int inizio = 0;
  int fine = 4 ;
  bbb= aaa.substring(inizio, fine);
  System.out.println(bbb);
  char [] ccc = aaa.toCharArray();
  System.out.println("======== altro caso concatenare dei caratteri 
=====2===");
  //bbb= aaa.charAt(0)+aaa.charAt(1)+aaa.charAt(2);
  calcolo= "id2+id4";
  // a destra dell'operatore stringa e numeri
  double espressioneDestra ;
  calcolo= "(((((id1-12.45)-78)*3)+2)+(23+23))";
  int livelloParentesi = 0;
  String risultatoStringa = "";
  for ( int i=0 ; i < calcolo.length(); i++){
   while ((calcolo.charAt(i)== '(')){
    livelloParentesi++;
    i++;
    System.out.println("Rilevata parentesi = livello "+i);
   }
   if ((calcolo.charAt(i)== '+')||(calcolo.charAt(i)== 
'-')||(calcolo.charAt(i)== '*')||(calcolo.charAt(i)== 
'/')||(calcolo.charAt(i)== ' ')||(calcolo.charAt(i)== '(')) {
   break;
   }
   risultatoStringa = risultatoStringa+calcolo.charAt(i);
   System.out.println("Compongo la stringa"+risultatoStringa+" 
:passaggio-->" +i) ;
  }
  if (risultatoStringa.substring(0, 2).equals("id")){
   System.out.println("  ho una variabile: "+risultatoStringa);
   int indice;
   indice = Integer.parseInt(risultatoStringa.substring(2));
   System.out.println("valore della stringa = "+valori[indice]);
   espressioneDestra = valori[indice];
  } else {
   System.out.println("  ho un numero "+risultatoStringa);
   double mioNumero;
   mioNumero = Double.parseDouble(risultatoStringa);
   System.out.println("valore del numero: "+mioNumero+" :operazione 
semplice->" +(mioNumero/3)) ;
   espressioneDestra = mioNumero;
  }
  System.out.println("RISULTATO DESTRO= "+espressioneDestra );
  // espressione sinistra..
  double espressioneSinistra;
 // String risultatoStringa = "";
  risultatoStringa = "";
  int operatoreAppoggio = 0;
  for ( int i=0 ; i < calcolo.length(); i++){
   if (operatoreAppoggio == 0){
    while (!((calcolo.charAt(i)== '+')||
      (calcolo.charAt(i)== '-')||
      (calcolo.charAt(i)== '*')||
      (calcolo.charAt(i)== '/'))){
         i++;
         System.out.println("carattere non utile "+calcolo.charAt(i));
        }
    i++;
    operatoreAppoggio++;
   }
    System.out.println("carattere UTILE!"+calcolo.charAt(i));
    if ((calcolo.charAt(i)== '+')||
     (calcolo.charAt(i)== '-')||
     (calcolo.charAt(i)== '*')||
     (calcolo.charAt(i)== '/')||
     (calcolo.charAt(i)== ' ')||
     (calcolo.charAt(i)== ')')||
     (calcolo.charAt(i)== '(')) {
     System.out.println("Problema sono uscito");
     break;
   }
   System.out.println("======================!");
   risultatoStringa = risultatoStringa+calcolo.charAt(i);
   System.out.println("Compongo la stringa sinistra"+risultatoStringa+" 
:passaggio-->" +i) ;
   }
  if (risultatoStringa.substring(0, 2).equals("id")){
   System.out.println("  ho una variabile: "+risultatoStringa);
   int indice;
   indice = Integer.parseInt(risultatoStringa.substring(2));
   System.out.println("valore della stringa = "+valori[indice]);
   espressioneSinistra = valori[indice];
  } else {
   System.out.println("  ho un numero "+risultatoStringa);
   double mioNumero;
   mioNumero = Double.parseDouble(risultatoStringa);
   System.out.println("valore del numero: "+mioNumero+" :operazione 
semplice->" +(mioNumero/3)) ;
   espressioneSinistra = mioNumero;
  }
  System.out.println("RISULTATO SINISTRO= "+espressioneSinistra );
  // operatore
  System.out.println(" ============== calcolo il l'espressione 
===================");
//   valuto l'oprazione
  char operatore;
  int indiceOperatore = 0;
  while (!((calcolo.charAt(indiceOperatore)== '+')||
    (calcolo.charAt(indiceOperatore)== '-')||
    (calcolo.charAt(indiceOperatore)== '*')||
    (calcolo.charAt(indiceOperatore)== '/'))){
       indiceOperatore++;
  }
  operatore = calcolo.charAt(indiceOperatore);
  switch (operatore){
  case ('+'): {
   System.out.println("Somma"+(espressioneDestra + espressioneSinistra));
   break;
  }
  case ('-'): {
   System.out.println("sottrazione" + (espressioneDestra - 
espressioneSinistra));
   break;
  }
  case ('*'): {
   System.out.println("Moltiplicazione"+(espressioneDestra * 
espressioneSinistra));
   break;
  }
  case ('/'): {
   System.out.println("Divisione"+(espressioneDestra / 
espressioneSinistra));
   break;
  }
  case (' '): {
   System.out.println(" Operazione mancante!  ");
   break;
  }
  }
  // problema delle parentesi
  int parentesiAperte = 0 ;
  int parentesiChiuse = 0 ;
  int livello = 0;
  int [] livelloIndice = new int[calcolo.length()] ;
  for ( int i=0 ; i < calcolo.length(); i++){
   // conto le parentesi
   if ((calcolo.charAt(i)== '(')){
    parentesiAperte++;
    livello++;
   }
   if ((calcolo.charAt(i)== ')')){
    parentesiChiuse++;
    livello--;
   }
   livelloIndice[i]= livello ;
  }// finde del for
  for (int i =0 ; i < livelloIndice.length; i++){
   System.out.print(livelloIndice[i]);
  }
  System.out.println("-");
  if (parentesiAperte != parentesiChiuse){
   System.out.println("==Problema parentesi non coincidenti==");
  }
 }// chiusura metodo
}

Grazie per la risposta
Ciao Andrea,
non ci ho capito molto, cosa intendi con top-dow w shift-reduce?
nella discussione precedente ho messo il listato di quello che ho fatto nel 
finesettimana (sono diventata matta) , per valutare una singola 
espressione.. se ti va di darci una occhiata anche il tuo parere non mi 
dispiace..
Grazie ancora per l'intresse Linda^^
"Andrea Laforgia" <a.laf...@andrealaforgia.it.invalid> ha scritto nel 
messaggio news:mq0lb49c7i39i3qi0...@4ax.com...


 ed esistono soluzioni già pronte per qualunque tipo di problema.
immagino.. ma come detto prima sono una frana in questo campo.. ho provato a 
dare una occhitata ad altri lavori e mi sono spaventata.. e in più non so 
deve e come mettere le mani..
adesso se non trovi dei grossi e scabrosi errori nel codice che ho postato 
mi rimane di studiare un modo per dare la precedeza nei calcoli date dalle 
parentesi.. dacci una occhiata
adesso devo trovare un modo per la questione parentesi.. e dovrò fare in
modo di fare la ricorsione,  se non erro..
io pensavo a questo:
1) mi creo un array grande quanti sono i caratteri della stringa che contien
il calcolo,
2) inserisco dentro le celle tutti i valori dei livelli delle parentesi il
"(" incrementa il livello, mentre ")" decrementa il livello
3) estraggo la stringa che ha il livello delle parentesi più alto, se ci
sono due gruppi con lo stesso livello valuterò prima quello di sinistra e
poi quello di destra.
4) valuto l'espressione selezionata ottenendo un valore
5) cancello dalla stringa (non so come farlo) tutti i caratteri che hanno il
massimo livello delle parentesi (che poi è quella stringa che ho valutato al
passo precedente)
6) inserisco dove ho appena cancellato il valore ottenuto della espressione
(aggiungendo o sottraenso i caratteri necessari)..
7) ripeto dal passo 1 fino a che non sono a livello 0. (e dovrei ottenere un
unico valore).
Ci sentiamo Linda^^
ps: spero di non fare troppo casino con queste rispote

  primo database.
Capisco che sfiorerò solo il problema ma io ho una classe
in C++ che serve a leggere files di configurazione che
contengono variabili ed espressioni. Implementare parsing
e analisi sintattica come esercizio forse è un po' troppo
ma se lo devi fare, devi :)
Forse, e dico, forse, anche se C++ non è ovviamente Java,
tra quel poco di somiglianza che c'è e la struttura del
programma, è possibile che tu possa ricavare qualche
informazione utile. Il problema è che sono in partenza
stasera e leggerò la posta verso le 19.30 per poi salire
in macchina. Se leggi di qui a quell'ora, la cosa ti
interessa e mi mandi un indirizzo valido, ti mando il
codice. Non lo metto sul mio sito per non suscitare
vespai, non è quel che si dice un capolavoro di eleganza
ma per i tuoi scopi - farti un'idea - dovrebbe andare. E'
abbastanza breve, circa 2000 linee e non dovrebbe essere
un gran problema almeno capire come ti devi muovere.
ciao!
Apx.

 non ci ho capito molto, cosa intendi con top-dow w shift-reduce?
http://en.wikipedia.org/wiki/Recursive_descent_parser
http://en.wikipedia.org/wiki/Bottom-up_parsing
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 non e' affatto semplice.
Uh? Scherzi?
Il classico interprete di espressioni aritmetiche č uno degli esempi piů
facili che si possono fare (fra i non completamente banali).
Praticamente č l'esempio standard di qualunque parser generator et
similia. 
-- 
-riko


Per inciso, quasi tutti come esempio introduttivo mostrano una soluzione
al tuo problema. 
-- 
-riko

 facili che si possono fare (fra i non completamente banali).
Concordo. Non c'è nulla di particolarmente complicato nel costruire un
parser di espressioni matematiche, a meno ovviamente di non voler
dedicarsi a cose veramente banali. Oltretutto ormai è possibile trovare
esempi di questo tipo di funzionalità praticamente ovunque: nei libri di
testo (Stroustrup e Wirth li hanno illustrati spesso), tra i codici di
esempio dei compilatori (Borland ha sempre distribuito un piccolo
spread-sheet con uno shift-reduce parser di espressioni matematiche) e
ovunque sulla rete.


 deve e come mettere le mani..
Proprio per questo non dovresti cercare di creare una soluzione da
zero.
Per esempio, hai considerato il segno? Puoi avere espressioni del
tipo: "-id2 * (+4.3 * -id1) + 0.3e-1.3".
Come vedi tutti ti consigliano di guardare meglio su internet. Non
posso che ripetermi, lascia perdere l'idea di creare un algoritmo ad
hoc e studia qualcosa sulle grammatiche secondo me fai prima e con
risultati migliori.
Queste 7 righe definiscono il parser (ed il lexer) che ti serve,
comprese le regole di precedenza. Tutto il resto del programma si
deriva da queste definizioni in modo (semi)automatico.
expr = term '+' expr | term '-' expr | term
term = fact '*' term | fact '/' term | fact
fact =  VAR | num |  '-' fact | '(' expr ')'
num = INT | FLOAT
var = /id\d+/
int = /\d+/
float = /\d+\.\d+([eE][+-]?\d+\.\d+)?/
P.S. Ho scritto la grammatica e le espressioni regolari "a mente".

 ovunque sulla rete.
Aggiungo, Kernighan e Pike fanno quello stesso esempio sia su "The Unix
Programming Environment", sia su "The Practice of Programming" (e per
inciso, il secondo č un libro che consiglio a spada tratta -- il primo č
molto bello, solo che rimane un po' piů datato). 
-- 
-riko

"The Practice of Programming"
L'ho letto diverso tempo fa, non ricordavo del parser.
Consiglio anch'io la lettura di questo must.

 L'ho letto diverso tempo fa, non ricordavo del parser.
Non è nemmeno lontanamente dettagliato come la versione su Unix
Programming Environment. Di fatto è poco più di un cenno (4 pagine).
Comunque ne parlano.
-- 
-riko