Sviluppo di ESPRESSIONI

Progettiamo una stuttura dati per le espressioni.
Le espressioni sono definite per induzione strutturale
BASE
Valore (reale enorme)
Identificatore
PASSO
Chiamata di funzione
Applicazione di operatore
pertanto le realizziamo con un record con due componenti:
tipo dell'espressione
semplicemente un carattere
('i' per identificatore, 'v' per valore, 'c' per chiamata di funzione, 'a' per applicazione),
contenuto
realizzato come tipo unione, con un'alternativa per ogni possibile forma delle espressioni.
La corrispondente dichiarazione di tipo C è
typedef  struct EXP * ESPRESSIONE;
struct EXP{
    char Type;
    union {               
        REALE_ENORME Value;
        IDENT Identifier ;
        struct { IDENT Function;
                 ESPRESSIONE Arg ;
               } Call;
        struct { ESPRESSIONE Op1, Op2;
                 char Oper;
                } OppAppl;
    } Cont;
};
Sviluppiamo ora le varie funzioni che appaiono nell'interfaccia del modulo.
Controllare il tipo dell'espressione
int E_Identificatore(ESPRESSIONE esp)
{
    return(esp -> Type == 'i');
}

int E_Valore(ESPRESSIONE esp)
{
    return(esp -> Type == 'v');
}

int E_Chiamata_Funzione(ESPRESSIONE esp)
{
    return(esp -> Type == 'c');
}
    
int E_Applicazione(ESPRESSIONE esp)
{
    return(esp -> Type == 'a');
}
/*controllano se un'espressione è rispettivamente un identificatore, 
un valore di tipo reale enorme, una chiamata di funzione o un'applicazione 
di un operatore*/
Selettori delle sottoparti delle espressioni
void Ident(ESPRESSIONE esp, IDENT id)
{
    Copia_Ident(id,esp -> Cont.Identifier);
}

REALE_ENORME Valore(ESPRESSIONE esp)
{
    return(esp -> Cont.Value);
}

ESPRESSIONE Parametro_Attuale(ESPRESSIONE esp)
{
    return(esp -> Cont.Call.Arg);
}
  
void Funzione(ESPRESSIONE esp, IDENT id)
{
    Copia_Ident(id,esp -> Cont.Call.Function);
}
    
ESPRESSIONE Primo_Arg(ESPRESSIONE esp)
{
    return(esp -> Cont.OppAppl.Op1);
}   
 
ESPRESSIONE Secondo_Arg(ESPRESSIONE esp)
{
    return(esp -> Cont.OppAppl.Op2);
}

char Operatore(ESPRESSIONE esp)
{
    return(esp -> Cont.OppAppl.Oper);
}
/*ritornano le varie parti di un'espressione;
tale espressione deve essere del tipo giusto, cioè deve avere tale parte*/
Lettura di un'espressione
ESPRESSIONE Leggi_Espressione(void)
{
    ESPRESSIONE e1, e2,
                esp = (ESPRESSIONE)malloc(sizeof(struct EXP));
    
    if(Look_Char() == '('){/*applicazione di operatore binario*/
        char oper;
        
        Salta('(');
        Salta_Blanks();
        e1 = Leggi_Espressione();
        Salta_Blanks();
        oper = Get_Char();
        Salta_Blanks();
        e2 = Leggi_Espressione();
        Salta(')');
        esp -> Type = 'a';
        esp -> Cont . OppAppl . Op1 = e1;
        esp -> Cont . OppAppl . Op2 = e2;
        esp -> Cont . OppAppl . Oper = oper;
    }
    else if(Look_Char() == '+' || Look_Char() == '-'){/*numero reale enorme*/
        REALE_ENORME re = Leggi_Reale_Enorme();
        esp -> Type = 'v';
        esp -> Cont . Value = re;
    }
    else if(isupper(Look_Char())){/*identificatore o applicazione di funzione*/
        IDENT id;
        
         Leggi_Ident(id);
         Salta_Blanks();
         if(Look_Char() == '('){/*applicazione di funzione*/
            Salta('(');
            Salta_Blanks();
            e1 = Leggi_Espressione();
            Salta(')');
            esp -> Type = 'c';
            Copia_Ident(esp -> Cont . Call . Function,id);
            esp -> Cont . Call . Arg = e1;
        }
        else{/*identificatore*/
             esp -> Type = 'i';
            Copia_Ident(esp -> Cont.Identifier,id);
        }
    }
    else printf("\n ERRORE: non e\' un\'espressione (Lettura)\n");
    return esp;
} 
A questo punto abbiamo sviluppato due file che faranno parte del programma, l'interfaccia e il body di questo modulo: ESPRESSIONI.h e ESPRESSIONI.c.