Newsgroup: it.comp.lang.pascal
Titolo: Operazioni

Salve
Vorrei sapere come trasformare un input in operazione.
Mi spiego...
[....]
readln (operazione);
y:= OPERAZIONE x ;
readln (x);
writeln (y);
[....]
dove operazione potrebbe essere "sin (x)", "sqr(x)", "2*x+5" etc...
spero di essere stato chiaro ... GRAZIE
__________________________________________________________
E-Mail:
(
rena...@lycosmail.com
)
__________________________________________________________
I.C.Q.: 17079401
_________________________________________________________
Visita il mio sito in perenne costruzione
http://hophop.com/renato
_________________________________________________________
René
:-)

CIAO
--
fabi...@rocketmail.com

dove operazione potrebbe essere "sin (x)", "sqr(x)", "2*x+5" etc...
In pratica quello che vuoi scrivere e' un parser di espressioni.
Nel tuo caso, dovendo contemplare anche le variabili hai bisogno di
una tavola dei simboli in cui memorizzarne il nome di ogni simbolo e
il valore da esso contenuto.
Si dovrebbe usare una tavola hash.
Un metodo semplice per implementare il parser e' quello di costruire
due stack, uno per gli operandi ed uno per gli operatori e di
utilizzare la notazione polacca inversa.
Ad esempio, l'espressione "2*x+5" diventerebbe "+*2x5" cioe'
un'addizione tra ( una moltiplicazione tra 2 e x ) e 5.
Lo stack degli operatori sarebbe cosi' costituito : +*x
mentre quello degli operandi come : 2x5
Estrai il primo operatore che e' + e, dato che questa e' un'operazione
binaria, estrai due operandi.
Se uno dei due operandi e' una variabile, controlli se e' nella tavola
dei simboli, ed in tal caso ne estrai il valore, altrimenti lo chiedi
all'utente e la inserisci nella tavola dei simboli.
Ripeti lo stesso procedimento per l'altro operando.
Sommi i valori e fai un "push" del valore restituito nello stack degli
operandi.
Ripeti tutta l'operazione sino a che lo stack degli operatori non e'
vuoto.
In realta' questo e' un metodo molto semplice ma ne esistono di piu'
complicati.
Uno di essi e' il procedimento top-bottom ricorsivo.
Un'altro, piu' complesso, e' quello dello shift-reduce parsing, che e'
una tecnica adottata anche nella risoluzione delle produzioni nelle
grammatiche dei linguaggi.
Ovvero il procedimento usato per scrivere i compilatori.

Ehm ... ?
Non ci ho capito niente ! :-)

Non ci ho capito niente ! :-)
Ok, lasciamo stare gli stack e tutto il resto, per non complicarci la
vita ;)
Ti ho scritto il sorgente di seguito che risolve espressioni in
notazione polacca inversa (notazione pre-fissa).
Puoi adattarlo alle tue esigenze.
Non e' difficile scrivere una funzione che trasformi una formula dalla
notazione in-fissa a quella pre-fissa e puoi farlo per esercizio.
Sul libro di N. Wirth "Linguaggio Pascal" c'e' quella che converte da
in-fissa a post-fissa.
Il codice e' stato compilato con lo GNU Pascal ma non dovrebbe darti
problemi se usi il Turbo Pascal.
Sulla mia macchina, dando in pasto al programma un' espressione del
tipo (-5+(5*3-4*6*2))/(2*6) in notazione polacca inversa, da' il
seguente output :
risolutore di espressioni in notazione polacca inversa
inserisci l'espressione in forma corretta : /+-05-*53**462*26
-3.1666667e+00
program parser (input, output) ;
var  formula : packed array [1..50] of char ; 
     i, j, l : integer ;
     function is_operator(c : char) : boolean;
     begin
       is_operator := (c = '+') or (c = '-') or 
                      (c = '*') or (c = '/') ;
     end ;
     function leggi_espressione : real ;
     var op1, op2 : real ;
         c : char ;
     begin
       inc(j);
       c := formula[j] ;
       if is_operator(c) then
       begin
         op1 := leggi_espressione ;
         op2 := leggi_espressione ;
         case c of
           '+' : leggi_espressione := op1 + op2 ;
           '-' : leggi_espressione := op1 - op2 ;
           '*' : leggi_espressione := op1 * op2 ;
           '/' : leggi_espressione := op1 / op2 ;
         end ;
       end 
       else leggi_espressione := ord(c) - ord('0') ;
     end ;
begin
  j := 0 ;
  writeln('risolutore di espressioni in notazione polacca inversa');
  write('inserisci l''espressione in forma corretta : ');
  readln(formula);
  l := length(formula);
  writeln(leggi_espressione);
end.


iQA/AwUBNvvGon9t9oJRSnUyEQJljwCfdU6vCbNPbJXazdk32vO63sMHpkMAoIWT
Q/ZaerHZqR/IPIYXbCZ2w6kR
=xAMT
-----END PGP SIGNATURE-----

quella di andare a leggere l'input ed interpretare tutti gli operatori
Allora, vediamo di applicare le stesse regole che valgono per gli
interpreti e/o per i compilatori.
Cioe' definiamo la grammatica che dobbiamo gestire e le produzioni per
risolverla.
Preciso subito che il "parsing" delle espressioni (che sia esso quello
di un compilatore che di un risolutore di espressioni matematiche) si
scompone sempre in due componenti fondamentali : l'analizzatore
lessicale e il parser vero e proprio.
La grammatica di un'espressione semplice potrebbe essere cosi'
definita :
ESPR   ::= ESPR + ESPR | ESPR - ESPR | _ESPR
_ESPR  ::= _ESPR * _ESPR | _ESPR / _ESPR | __ESPR
__ESPR ::= numero reale | 
           identificatore_fn ( ESPR ) |
           ( ESPR ) | 
           identificatore 
Ora, l'analizzatore lessicale (che si puo' racchiudere in una
funzione) sara' quello che leggendo l'input carattere per carattere ci
fornira' di volta in volta i cosiddetti "token", cioe' raggruppera' ad
esempio i caratteri 5 4 3 presenti nell'input e restituira' un oggetto
numerico avente valore 543.0 oppure riconoscera' i caratteri in
sequenza s q r t ( e restituira' un oggetto rappresentante la funzione
sqrt().         
Supponendo di chiamare la funzione analizzatore lessicale col nome di
"next_token()" lo pseudo-codice del parser sarebbe :
function getESPR() : real;
var op1, op2 : real;
function get__ESPR() : real;
begin 
  if (next_token = numero reale) then get__ESPR := numero reale
  else
  if (next_token = parentesi aperta) ten get__ESPR := getESPR
  else
  if (next_token = identificatore_fn) then 
     get__ESPR := funzione corrispondente( getESPR )
  else
  if (next_token = identificatore) then
     get__ESPR := valore nella tabella dei simboli (identificatore)
end;
function get_ESPR() : real;
var op1, op2 : real ;
begin
  op1 := get__ESPR();
  if (next_token = operatore *) then
  begin
     op2 := get__ESPR();
     get_ESPR := op1 * op2;
  end
  else
  if (next_token = operatore /) then
  begin
     op2 := get__ESPR();
     get_ESPR := op1 / op2;
  end
  else get_ESPR := op1;
end;    
begin { inizio di getESP() }
  op1 := get_ESPR();
  if (next_token = operatore +) then
  begin
    op2 := get_ESPR();
    getESPR := op1 + op2;
  end
  else
  if (next_token = operatore -) then
  begin
    op2 := get_ESPR();
    getESPR := op1 - op2;
  end
  else getESPR := op1;
end;
Questa tecnica e' chiamata "recursive-descendant" e va bene se si
vuole implementare il parser di un'espressione anche piuttosto
complicata.
Diventa invece problematica quando la si adotta per un compilatore.
Infatti in quest'ultimo caso si adopera solitamente la tecnica di
"shift-reducing" che non e' ricorsiva, ma adotta una macchina a stati
finiti e uno stack per operandi e operatori.
Ogni qual volta riconosce la possibilita' di risolvere una produzione
lo fa ed avanza di un passo verso la risoluzione finale.
Da molto tempo, pero', per affrontare questo problema sono nati due
tool molto utili chiamati Lex e Yacc.
Il primo genera l'analizzatore lessicale ed il secondo il parser.
Le versioni portate sotto DOS (i due tool sono per Unix) sono Flex e
Bison.
Quando la Borland distribui' il Turbo Pascal 4.0 diede anche uno
spreadsheet chiamato MicroCalc.
Nella documentazione dei sorgenti c'era scritto che il parser era
stato scritto avvalendosi sia di Lex che di Yacc.

 dove operazione potrebbe essere "sin (x)", "sqr(x)", "2*x+5" etc...
http://www.geocities.com/SiliconValley/2926/tpf.html
chapter "numerics/math", look for "parser". 
If you have an older version of Turbo Pascal (Ver. 3, 4, 5.0) you
got MicroCalc, a small spreadsheet calculator with a parser unit.
Franz Glaser