Laboratorio di Programmazione M-Z Docente: Dott. Francesco Strappaveccia france.strappavecci2@unibo.it Università di Bologna, Sede di Cesena
Espressioni algebriche Uno dei compiti del compilatore è quello di valutare le espressioni algebriche: Per esempio: y = x + z (w/x + z (7 + 6)). Il compilatore, oltre a valutarne il valore numerico, deve stabilire se è sintatticamente corretta o meno. Le notazioni con cui possiamo descrivere le espressioni algebriche possono essere 3: Prefissa, Infissa e Postfissa. Nella vita reale, sin dalle prime esperienze di calcolo, abbiamo sempre avuto a che fare con la notazione Infissa.
Notazione Infissa E la notazione più comunemente usata. Infissa significa che ogni operatore binario appare in mezzo ai suoi due operandi: A }{{} + }{{} B }{{} Operando1 Operatore Operando2 A }{{} + }{{} B }{{} Operando1 Operatore Operando2 Operatore2 Operando3. }{{} c }{{} Possiamo scrivere il secondo esempio in due modi diversi, usando le parentesi e quindi indicando una precedenza nella valutazione delle varie operazioni: (A + B) C oppure (A+(B*C)). Per la valutazione di espressioni infisse, sono applicate le seguenti regole: 1. Regole di Precedenza (es. il deve essere valutato prima del +). 2. Regole associative (valutando da sinistra verso destra). 3. Regole relative alle parentesi..
Espressioni Prefisse e Postfisse Nel caso delle espressioni prefisse (postfisse) l operatore binario tra due operandi è posizionato prima (dopo) gli operandi stessi: Prefissa: +A B, (A + B). Postfissa: A B+, (A + B). Il vero vantaggio di tali espressioni è che non è necessario l uso di regole di precedenza tra le operazioni, infatti è lo stesso posizionamento degli operatori e degli operandi a dirci quali espressioni devono essere valutate per prime.
Conversione da notazione infissa a prefissa Per convertire b + c 3/2 4 è necessario compiere due passi: Individuare le precedenze: Individuare le associazioni e porre l operatore delle singole operazioni binarie prima degli operandi:
Conversione da notazione infissa a postfissa Per convertire a + b/c è necessario compiere due passi: Individuare le precedenze: Individuare le associazioni e porre l operatore delle singole operazioni binarie dopo degli operandi:
Algoritmo per la conversione da notazione infissa a postfissa. Pile Utilizzando le Pile (Stack), possiamo scrivere un algoritmo per la conversione da notazione infissa a notazione postfissa(prefissa). Utilizzando la pila possiamo tenere traccia degli operatori che incontriamo e delle parentesi. I passi dell algoritmo sono pochi e relativamente semplici: Ogni volta che incontriamo un operando, lo accodiamo nell espressione postfissa che stiamo calcolando. Ogni volta che incontriamo un operatore, lo confrontiamo con quello sulla testa della pila. Se la sua priorità è maggiore lo inseriamo nella pila (push), altrimenti togliamo dalla pila (pop) tutti gli operatori di priorità minore (o uguale) e li accodiamo nell espressione di ritorno.
Algoritmo per la conversione da notazione infissa a postfissa (II). Ogni volta che incontriamo una parentesi aperta ( la inseriamo nella pila. Ogni volta che incontriamo una parentesi chiusa ), accodiamo nella espressione postfissa tutto quello che c è sulla pila fino alla prima parentesi aperta (.
Algoritmo per la conversione da notazione infissa a postfissa (III). Esempio I A + B C D/E Infix Stack Postfix A+B*C-D/E # +B*C-D/E # A B*C-D/E # + A *C-D/E # + A B C-D/E # + * A B -D/E # + * A B C D/E # - A B C * + /E # - A B C * + D E # - / A B C * + D # - / A B C * + D E # - A B C * + D E / # A B C * + D E / -
Algoritmo per la conversione da notazione infissa a postfissa (IV). Esempio II A B (C + D) + E Infix Stack Postfix A*B-(C+D)+E # *B-(C+D)+E # A B-(C+D)+E # * A -(C+D)+E # * A B (C+D)+E # - A B * C+D)+E # - ( A B * +D)+E # - ( A B * C D)+E # - ( + A B * C )+E # - ( + A B * C D +E # - A B * C D + E # + A B * C D + - # + A B * C D + - E # A B * C D + - E +
Algoritmo per la conversione da notazione infissa a postfissa (V). Pseudo-Codice stack = Create_stack (); out_list = Create_list () while (eof ( in_infix )){ ch= getch ( in_infix ); // Prendo il carattere successivo di in_infix if(ch == operand ) add_tail ( out_list, ch); // Valuto se è un operando if(ch == ( ) push ( stack, ch); // Valuto se è una ( if(ch = ) ){ // Valuto se è una ) chpop = pop ( stack ); while ( chpop!= ( ){ add_tail ( out_list, chpop ); chpop = pop ( stack ); } } if(ch == operator ) // Valuto se è un operatore { while (! is_empty ( stack ) && pred (top ( stack )) >= pred (ch)){ chpop = pop ( stack ); add_tail (out_list, chpop ); } push ( stack, ch); } } while (! is_empty ( stack )){ // Svuoto lo stack ch = pop ( stack ); add_tail ( out_list, ch); }
Esercizi 1. Scrivere un algoritmo per trasformare un espresssione infissa in una prefissa.