Validare un'espressione postfissa

di il
13 risposte

Validare un'espressione postfissa

Salve a tutti: avrei questo piccolo problema: dovrei trovare un modo per validare una formula in espressione postfissa con un numero di operatori non superiore a 3, del tipo:

22+ (postfissa) al posto di 2+2 (infissa)

dato che le possibilità sono varie, es:

22+34+*
234++

c'è un modo per evitare che l'utente inserisca ad es:

2+22+

Io ho fatto una mia versione della validazione, ma è lunga è tiene conto di troppi casi limite, c'è un modo generale per controllare la validità di una formula postfissa?

13 Risposte

  • Re: Validare un'espressione postfissa

    Piu modalità dai all'utente di inserire la formula e piu modalità dovrai gestire.
    Per questo nell'altro thread avevo proposto la classica infissa e poi trasformarla in postfissa.(cosa piu logica per l'utente e per il programma.)

    Posta il codice poi vediamo come fare.
  • Re: Validare un'espressione postfissa

    Usi uno stack:
    ogni volta che incontri un valore, lo inserisci sullo stack
    ogni volta che incontri un operatore, controlli se nello stack ci sono abbastanza operandi (altrimenti generi errore), esegui l'operazione (che puo' generare errore) ed inserisci il risultato sullo stack

    Si chiama RPN (Reverse Polish Notation) ed e' il modo (superiore ) con cui si utilizzano le calcolatrici Hewlett Packard, al contrario delle calcolatrici Texas ( ) che usano il SOA (Sistema Operativo Algebrico)
  • Re: Validare un'espressione postfissa

    migliorabile ha scritto:


    Usi uno stack:
    ogni volta che incontri un valore, lo inserisci sullo stack
    ogni volta che incontri un operatore, controlli se nello stack ci sono abbastanza operandi (altrimenti generi errore), esegui l'operazione (che puo' generare errore) ed inserisci il risultato sullo stack

    Si chiama RPN (Reverse Polish Notation) ed e' il modo (superiore ) con cui si utilizzano le calcolatrici Hewlett Packard, al contrario delle calcolatrici Texas ( ) che usano il SOA (Sistema Operativo Algebrico)
    Oh, no, non si tratta di risolvere un'operazione in postfissa, quello l'ho già fatto: devo solo trovare un modo per validarla, cioè controllare che l'utente non metta una formula a caso!

    vbextreme ha scritto:


    piu modalità dai all'utente di inserire la formula e piu modalità dovrai gestire.
    Per questo nell'altro thread avevo proposto la classica infissa e poi trasformarla in postfissa.(cosa piu logica per l'utente e per il programma.)

    Posta il codice poi vediamo come fare.
    Questo è il codice relativo alla validazione, ma ti avverto, prenderai paura...
    
    
    int valida_formula(elem_form_t formula){
    
        int i,                  /* variabile usata come contatore */
            right,              /* variabile usata come contatore */
            err = 0,            /* variabile che controlla la presenza di errori */
            num = 0,            /* variabile usata per contare il numero di proposizioni */
            alpha = 0,          /* variabile usata per contare il numero di connettivi binari */
            connettivi = 0,     /* variabile usata per contare il numero di conettivi generici */
            cont = 0;
    
        size_t num_elem;        /* variabile usata per calcolare la lunghezza della formula */
    
    
        /* conta il numero di elementi della formula e li
        memorizza nella variabile num_elem */
        num_elem = strlen(&formula.nome);
    
        /* controlla che la formula non ecceda il numero di caratteri massimo
        e nel caso, stampa un messaggio di errore e aggiorna err*/
        if (num_elem > 7)
        {
            printf("\nERRORE: la formula e' troppo lunga!\n");
            err++;
        }
    
        /* primo controllo sulla formula */
        for (i = 0; i < num_elem; i++){
    
            /* controlla che i singoli caratteri inseriti siano numeri da 1 a 4 o lettere,
            in caso contrario, stampa un messaggio di errore e aggiorna err */
            if (ispunct(formula.nome[i]))
            {
                err++;
                printf("\nERRORE: il carattere %c non e' valido!\n", formula.nome[i]);
            }
    
            /* conta il numero di connettivi logici binari e proposizioni */
            if (isdigit(formula.nome[i]))
                num++;
            else if (isalpha(formula.nome[i]))
                alpha++;
    
            if (isdigit(formula.nome[i]))
                if (formula.nome[i] > '4' || formula.nome[i] == '0')
                {
                err++;
                printf("\nERRORE: %c non e' un connettivo logico valido!\n", formula.nome[i]);
                }
    
    
            if (isdigit(formula.nome[i]) && isdigit(formula.nome[i - 1]))
                for(right = (i + 1); right < num_elem; right++)
                    if (isalpha(formula.nome[right]))
                    {
                        printf("\nERRORE: l'ordine dei connettivi/proposizioni è errato!\n");
                        err++;
                    }
    
        }
    
        if(isdigit(formula.nome[0]) || isalpha(formula.nome[strlen(formula.nome) - 1]))
        {
            printf("\nERRORE: la formula deve iniziare con una\n\tproposizione e finire con un connettivo!\n");
            err++;
        }
    
            /* controlla che il numero di conettivi logici binari
            sia corretto rispetto al numero di proposizioni inserite */
    
            if (isdigit(formula.nome[1]))
                if(isalpha(formula.nome[0]))
                    cont++;
            if ((alpha - num) != 1 || cont != 0)
            {
                printf("\nERRORE: il numero di connettivi logici binari non\n\te'corretto rispetto al numero di proposizioni!\n");
                err++;
            }
    
            /* la formula è corretta: esegue l'ultimo controllo sul numero massimo di connettivi */
            for (i = 0; i <= num_elem; i++)
            {
                if (isupper(formula.nome[i]))
                    connettivi++;
                if (isdigit(formula.nome[i]))
                    connettivi++;
            }
    
                if (connettivi > 3)
                printf ("Hai inserito %d connettivi logici su un massimo di 3\nripeti inserimento -> ", connettivi);
    
    
        return err;
    }
    
    e questo è tutto il codice nel caso tu voglia provarlo:
    
    
    /* inclusone delle librerie standard del sorgente */
    #include <stdio.h>
    #include <ctype.h>
    #include <string.h>
    #include <stdlib.h>
    
    
    /* struttura dati definita per memorizzare le proposizioni
    inserite dall'utente e i connettivi logici */
    typedef struct elem_form
    {
        char    nome[7];
        int     prop[7][16];
    
    }   elem_form_t;
    
    /* struttura dati definita come una pila per lavorare sulla formula */
    typedef struct elem_stack
    {
        int     valore[16];
        struct  elem_stack *succ_p;
    
    }   elem_stack_t;
    
    
    /* dichiarazione delle funzioni del programma */
    elem_form_t acquisisci_formula();
    int valida_formula();
    void valori_formula(elem_form_t *formula);
    int confronto_formule(elem_form_t *prima_formula, elem_form_t *seconda_formula);
    void risolvi_formula(elem_form_t *formula, int risultato[]);
    
    int main() {
    
        elem_form_t prima_formula,
                    seconda_formula;
    
        int i,
            contr = 0,
            risultato1[16],
            risultato2[16];
    
        printf("***************************************************\n");
        printf("Programma che acquisisce due proposizioni logiche e \nstabilisce se esse sono equivalenti\n");
        printf("Autore: Cocon Tommaso\n");
        printf("***************************************************\n\n");
    
        printf ("-Utilizza le lettere minuscole dell'alfabeto come proposizioni\n\n");
        printf ("-Se desideri anteporre il connettivo logico di negazione\n utilizza la lettera MAIUSCOLA [p.e. not(a) = A]\n\n");
        printf("Inserisci:\n");
        printf ("\t1 per il connettivo logico di congiunzione\n\n");
        printf ("\t2 per il connettivo logico di disgiunzione\n\n");
        printf ("\t3 per il connettivo logico di implicazione\n\n");
        printf ("\t4 per il connettivo logico di doppia implicazione\n\n");
        printf ("Esempio di formula ben formata: ab2cd24\n\n");
    
        printf("Inserire la prima proposizione logica -> ");
        prima_formula = acquisisci_formula();
    
        printf("Inserire la seconda proposizione logica -> ");
        seconda_formula = acquisisci_formula();
    
        valori_formula(&prima_formula);
        valori_formula(&seconda_formula);
    
        risolvi_formula(&prima_formula, risultato1);
    
        risolvi_formula(&seconda_formula, risultato2);
    
        for (i = 0; i < 16; i++)
            if (risultato1[i] != risultato2[i])
                contr++;
    
        if (contr > 0)
            printf("\nLe formule non sono equivalenti.\n");
        else
            printf("\nle formule sono equivalenti.\n");
    
    return 0;
    
    }
    
    elem_form_t acquisisci_formula(){
    
        /* dichiarazione delle variabili locali */
                             /* variabile contatore */
        int err = 0;
    
        elem_form_t formula;            /* struttura che contiene le formula */
    
    
        do
        {
    
            scanf("%s", formula.nome);
    
            err = valida_formula(formula);
    
            if (err != 0)
                printf("\n\nSono stati riscontrati %d errori complessivi,\nripetere inserimento -> ", err);
    
        }
        while (err != 0);
    
        return formula;
    }
    
    int valida_formula(elem_form_t formula){
    
        int i,                  /* variabile usata come contatore */
            right,              /* variabile usata come contatore */
            err = 0,            /* variabile che controlla la presenza di errori */
            num = 0,            /* variabile usata per contare il numero di proposizioni */
            alpha = 0,          /* variabile usata per contare il numero di connettivi binari */
            connettivi = 0,     /* variabile usata per contare il numero di conettivi generici */
            cont = 0;
    
        size_t num_elem;        /* variabile usata per calcolare la lunghezza della formula */
    
    
        /* conta il numero di elementi della formula e li
        memorizza nella variabile num_elem */
        num_elem = strlen(&formula.nome);
    
        /* controlla che la formula non ecceda il numero di caratteri massimo
        e nel caso, stampa un messaggio di errore e aggiorna err*/
        if (num_elem > 7)
        {
            printf("\nERRORE: la formula e' troppo lunga!\n");
            err++;
        }
    
        /* primo controllo sulla formula */
        for (i = 0; i < num_elem; i++){
    
            /* controlla che i singoli caratteri inseriti siano numeri da 1 a 4 o lettere,
            in caso contrario, stampa un messaggio di errore e aggiorna err */
            if (ispunct(formula.nome[i]))
            {
                err++;
                printf("\nERRORE: il carattere %c non e' valido!\n", formula.nome[i]);
            }
    
            /* conta il numero di connettivi logici binari e proposizioni */
            if (isdigit(formula.nome[i]))
                num++;
            else if (isalpha(formula.nome[i]))
                alpha++;
    
            if (isdigit(formula.nome[i]))
                if (formula.nome[i] > '4' || formula.nome[i] == '0')
                {
                err++;
                printf("\nERRORE: %c non e' un connettivo logico valido!\n", formula.nome[i]);
                }
    
    
            if (isdigit(formula.nome[i]) && isdigit(formula.nome[i - 1]))
                for(right = (i + 1); right < num_elem; right++)
                    if (isalpha(formula.nome[right]))
                    {
                        printf("\nERRORE: l'ordine dei connettivi/proposizioni è errato!\n");
                        err++;
                    }
    
        }
    
        if(isdigit(formula.nome[0]) || isalpha(formula.nome[strlen(formula.nome) - 1]))
        {
            printf("\nERRORE: la formula deve iniziare con una\n\tproposizione e finire con un connettivo!\n");
            err++;
        }
    
            /* controlla che il numero di conettivi logici binari
            sia corretto rispetto al numero di proposizioni inserite */
    
            if (isdigit(formula.nome[1]))
                if(isalpha(formula.nome[0]))
                    cont++;
            if ((alpha - num) != 1 || cont != 0)
            {
                printf("\nERRORE: il numero di connettivi logici binari non\n\te'corretto rispetto al numero di proposizioni!\n");
                err++;
            }
    
            /* la formula è corretta: esegue l'ultimo controllo sul numero massimo di connettivi */
            for (i = 0; i <= num_elem; i++)
            {
                if (isupper(formula.nome[i]))
                    connettivi++;
                if (isdigit(formula.nome[i]))
                    connettivi++;
            }
    
                if (connettivi > 3)
                printf ("Hai inserito %d connettivi logici su un massimo di 3\nripeti inserimento -> ", connettivi);
    
    
        return err;
    }
    
    void valori_formula(elem_form_t *formula){
    
        int i; /* variabile contatore */
        int modulo, risultato = 0, j, k, num_elem, cont_prop = 0;
    
        num_elem = strlen(formula->nome);
    
        for (i = 0, modulo = 2; i < num_elem; i++){
            if (isalpha(formula->nome[i]))
            {
                for (j = 0; j < 16; j++){
                    risultato = j % modulo;
                    if (cont_prop == 0){
                        if (risultato == 0){
                            formula->prop[i][j] = 0;
                        }
                        else if (risultato == 1){
                            formula->prop[i][j] = 1;
                        }
                    }
                    else if (cont_prop == 1){
                        if (risultato < 2){
                            formula->prop[i][j] = 0;
                        }
                        else if (risultato >= 2){
                            formula->prop[i][j] = 1;
                        }
                    }
                    else if (cont_prop == 2){
                        if (risultato < 4){
                            formula->prop[i][j] = 0;
                        }
                        else if (risultato >= 4){
                            formula->prop[i][j] = 1;
                        }
                    }
                    else if (cont_prop == 3){
                        if (risultato < 8){
                            formula->prop[i][j] = 0;
                        }
                        else if (risultato >= 8){
                            formula->prop[i][j] = 1;
                        };
                    }
                }
                cont_prop++;
                modulo *= 2;
            }
        }
    
        for (i = 0; i < num_elem; i++)
            if (isalpha(formula->nome[i]))
            {
                for (k = (i + 1); k < num_elem; k++)
                {
                    if (tolower(formula->nome[i]) == tolower(formula->nome[k])){
                        for (j = 0; j < 16; j++)
                            formula->prop[k][j] = formula->prop[i][j];
                    }
                }
            }
    
        for (i = 0; i < num_elem; i++)
            if(isalpha(formula->nome[i]) && isupper(formula->nome[i]))
            {
               for (j = 0; j < 16; j++)
                    if (formula->prop[i][j] == 0)
                        formula->prop[i][j] = 1;
                    else
                        formula->prop[i][j] = 0;
            }
    }
    
    
    void risolvi_formula(elem_form_t *formula, int risultato[]){
    
        elem_stack_t *cima_p,
                     *pila_p;
    
        int i, ris,
        j, k,
        val;
    
        int op[2][16];
    
        for (i = 0, j = 0; i < strlen(formula->nome); i++)
        {
            if(isalpha(formula->nome[i]))
            {
                j++;
                pila_p = (elem_stack_t *)malloc(sizeof(elem_stack_t));
    
                for (val = 0; val < 16; val++)
                        pila_p->valore[val] = formula->prop[i][val];
    
                    pila_p->succ_p = cima_p;
                    cima_p = pila_p;
            }
            else if (isdigit(formula->nome[i]))
            {
                for (k = 0; k < 2; k++)
                {
                    for (val = 0; val < 16; val++)
                        op[k][val] = cima_p->valore[val];
    
                    if (cima_p != NULL)
                        cima_p = cima_p->succ_p;
                }
    
                pila_p = (elem_stack_t *)malloc(sizeof(elem_stack_t));
    
                for (val = 0; val < 16; val++)
                {
                    if (formula->nome[i] == '1'){
                        if (op[1][val] || op[0][val]){
                            ris = 1;
                        }
                        else{
                            ris = 0;
                        }
                    }
                    else if (formula->nome[i] == '2')
                    {
                        if (op[1][val] && op[0][val]){
                            ris = 1;
                        }
                        else{
                            ris = 0;
                        }
                    }
                   else if (formula->nome[i] == '3')
                    {
                        if (op[1][val] == 1 && op[0][val] == 0){
                            ris = 0;
                        }
                        else{
                            ris = 1;
                        }
                    }
                   else if (formula->nome[i] == '4')
                    {
                        if (op[1][val] == op[0][val]){
                            ris = 1;
                        }
                        else{
                            ris = 0;
                        }
                    }
                    pila_p->valore[val] = ris;
                }
                pila_p->succ_p = cima_p;
                cima_p = pila_p;
            }
        }
    
        for (i = 0; i < 16; i++)
            risultato[i] = cima_p->valore[i];
    
    }
    
    
    
  • Re: Validare un'espressione postfissa

    Puoi anche non eseguire la funzione, e al posto di un valore usare un marker.
    Il meccanismo rimane

    Oppure puoi ricostruire l'albero che descrive l'espressione a partire dalla sequenza di valori/operazioni, e quindi validare l'albero.

    L'appriccio che hai utilizzato per l'implementazione e' un pasticcio.

    Il sistema per fare queste cose e':

    1) definire la grammatica, e rappresentarla in BNF (ad esempio)
    2) a partire dalla grammatica, implementare un parser ricorsivo discendente (o parser top down)

    Se il parser e' in gradi di parsare l'espressione, l'espressione e' corretta, altrimenti c'e' un errore, ed e' possibile sapere anche dove, oltre a che tipo di essore
  • Re: Validare un'espressione postfissa

    migliorabile ha scritto:


    Puoi anche non eseguire la funzione, e al posto di un valore usare un marker.
    Il meccanismo rimane

    Oppure puoi ricostruire l'albero che descrive l'espressione a partire dalla sequenza di valori/operazioni, e quindi validare l'albero.
    Ammetto la mia ignoranza (sono ancora al primo anno, sono tre mesi che programmo in c), la prima non l'ho capita; gli alberi li abbiamo iniziato tipo una lezione fa, ne so ancora pochissimo!
  • Re: Validare un'espressione postfissa

    Rileggi il post precedente: l'ho esteso con una serie di informazioni in piu'

    Per marker intendo un valore (tipo "1") che dice semplicemente che' c'e' un valore. Non ti serve sapere quale, ma solo che c'e'
  • Re: Validare un'espressione postfissa

    Questi sono esempi di grammatiche:

    1) per espressioni scritte in modo classico ( 2 * 3 + 5 )

    espr ::= term ('+' term)+ | term ('-' term)+ | term
    term ::= fatt ('*' fatt)+ | fatt ('/' fatt)+ | fatt
    fatt ::= numero | '(' espr ')'
    numero ::= <sequenza di cifre decimali>


    2) per espressioni scritte in RPN ( 2 3 * 5 +)

    espr ::= espr espr '+' | espr espr '-' | espr espr '*' | espr espr '/' | numero
    numero ::= <sequenza di cifre decimali>
  • Re: Validare un'espressione postfissa

    migliorabile ha scritto:


    Puoi anche non eseguire la funzione, e al posto di un valore usare un marker.
    Il meccanismo rimane

    Oppure puoi ricostruire l'albero che descrive l'espressione a partire dalla sequenza di valori/operazioni, e quindi validare l'albero.

    L'appriccio che hai utilizzato per l'implementazione e' un pasticcio.

    Il sistema per fare queste cose e':

    1) definire la grammatica, e rappresentarla in BNF (ad esempio)
    2) a partire dalla grammatica, implementare un parser ricorsivo discendente (o parser top down)

    Se il parser e' in gradi di parsare l'espressione, l'espressione e' corretta, altrimenti c'e' un errore, ed e' possibile sapere anche dove, oltre a che tipo di essore
    Ho paura che sia un po' fuori dalla mia portata, ancora... Per quanto mi sia sforzato di capire la backus naur form e una possibile implementazione per la grammatica, non riesco a cavarci molto! Ricordo che VBExtreme ci aveva postato un codice che derivava da quella, ma non sarebbe codice mio e odio riciclare codice altrui, anche perchè si tratta di ragionare con cose che ancora non conosco fin troppo bene! Comunque grazie per l'aiuto, almeno ne so più di prima
  • Re: Validare un'espressione postfissa

    Ma scusa: ritornando al titolo del thread, per validare un'espressione postfissa basta che la esegui!

    Eseguila due volte!

    La prima solo per vedere se si puo' eseguire, la seconda per avere il valore di ritorno.

    Se un operatore vuole piu' parametri di quelli presenti sullo stack, genera errore ed ecco che hai dimostrato che l'espressione non e' valida!
  • Re: Validare un'espressione postfissa

    Mi sembra una grande idea, evita moltissime righe di codice: dovrei però riuscire a catturare l'errore di segmentation fault, che si presenta quando invio la formula (sbagliata, tipo a2a) alla funzione "risolvi formula" dato che non trova due operatori op con cui lavorare: c'è un modo per gestire tale errore?
  • Re: Validare un'espressione postfissa

    Prima compilazione e da già un errore!
    num_elem = strlen(&formula.nome);
    VA COSI!
    num_elem = strlen(formula.nome);
    formula.nome è già un puntatore! per metterci la & avresti dovuto scrivere:
    num_elem = strlen(&formula.nome[0]);
    Vabbhè proseguo,prima tirata di orecchie eseguita....
    Ma lo leggi ciò che ti dice il compilatore?
  • Re: Validare un'espressione postfissa

    I connettivi devono essere dei numeri,quindi quel barbatrucco per escludere la negazione dall'algoritmo non penso sia lecita.
  • Re: Validare un'espressione postfissa

    Sì, cambiando quello che ho detto, devo modificare per implementare 0a come NOTa e non con la lettera capitale, sennò precludo il (not(not(a))). Cavolo sono tre settimane che vado avanti, sto impazzendo!

    Per il puntatore, hai ragione, grazie!!
Devi accedere o registrarti per scrivere nel forum
13 risposte