Newsgroup: it.comp.lang.c
Titolo: Parser funzioni matematiche

Salve mi dispiace dover ripetere una domanda
che magari è già stata sottoposta ma mi servirebbe
un parser di funzioni di matematiche per C.
Grazie Chris

 writes:

lex & yacc ?
-- 
Maurizio Loreti                      
http://wwwcdf.pd.infn.it/~loreti/mlo.html
Un. of Padova, Dept. of Physics - Padova, Italy          
lor...@padova.infn.it

 
YES, anzi Flex e Bison , nella documentazione del Bison c'e' gia pronto
solo da compilare
Marco Colandrea

un parser di funzioni di matematiche per C.
Il parser che ti ho scritto e' un recursive-descendant parser, cioe'
adotta una tecnica di discesa ricorsiva fino a raggiungere i vari
token per poi risalire.
In questo modo si rispetta la priorita' tra le operazioni, le
espressioni tra parentesi e gli argomenti di funzione.
La grammatica implementata e'
espressione ::= espressione + espressione | 
                espressione - espressione |
                fattore 
fattore ::= fattore * fattore |
            fattore / fattore |
            termine
termine ::= costante numerica | 
            ( espressione ) |
            funzione ( espressione )
 
Le funzioni gestibili sono :
rq()   : estrae la radice quadrata
ass()  : calcola il valore assoluto
quad() : eleva al quadrato
neg()  : calcola il negativo
Se ne vuoi aggiungere di altre non devi fare altro che appendere i
relativi controlli nella funzione termine().
Il parser di per se' ha alcuni piccoli difetti, per esempio non
gestisce gli spazi bianchi, non consente di avere costanti numeriche
floating point e non gestisce la divisione per zero, ma per il resto
dovrebbe funzionare bene.
Testalo comunque con diverse espressioni, perche' io l'ho sviluppato
in poco tempo e non ho avuto modo di testarlo in modo efficace.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
typedef struct {
                 double num ;
                 char   nome_funz[10] ;
               } tipo_valore ;
typedef struct {
                 char * formula ;
                 int    indice ;
               } oggetto_formula ;
typedef enum { OP_ADDZ,   /* operatore di addizione */
               OP_SOTT,   /* operatore di sottrazione */
               OP_MOLT,   /* operatore di moltiplicazione */
               OP_DIVS,   /* operatore di divisione */
               OP_PARA,   /* operatore parentesi aperta  */
               OP_PARC,   /* operatore parentesi chiusa */
               NOMEFNZ,   /* identificatore di funzione */
               COSTNUM,   /* costante numerica */
               FINEFRM    /* fine formula */
             } tipo_token ;
void errore_sintassi ( oggetto_formula * f )
{
     int i ;
     puts ("errore di sintassi nella formula :") ;
     printf ( "%s\n", f->formula ) ;
     for (i = 0 ; i < f->indice-1 ; i++)
         putchar(' ');
     printf("^\n");
     exit ( 1 ) ;
}
tipo_token prossimo_token ( oggetto_formula * f, tipo_valore * v )
{
     char cnum[20] ;
     int i = 0 ;
     if ( f->formula[f->indice] )
     {
        if ( isdigit ( f->formula[f->indice] ) )
        {
           while ( isdigit ( f->formula[f->indice] ) && (i < 20) )
                 cnum[i++] = f->formula[f->indice++] ;
           cnum[i] = 0 ;
           v->num = atof ( cnum ) ;
           return COSTNUM ;
        }
        else
        if ( isalpha (f->formula[f->indice]) )
        {
           while ( (isalpha (f->formula[f->indice]) ||
                    isdigit (f->formula[f->indice])) &&
                   (i < 10) )
                 v->nome_funz[i++] = f->formula[f->indice++] ;
           v->nome_funz[i] = 0 ;
           if (f->formula[f->indice++] == '(')
              return NOMEFNZ ;
           else errore_sintassi ( f ) ;
        }
        else
        switch ( f->formula[f->indice++] )
        {
               case '+' : return OP_ADDZ ;
               case '-' : return OP_SOTT ;
               case '*' : return OP_MOLT ;
               case '/' : return OP_DIVS ;
               case '(' : return OP_PARA ;
               case ')' : return OP_PARC ;
               default  : errore_sintassi( f ) ;
        }
     }
     else return FINEFRM ;
}
int atteso ( oggetto_formula * f, const tipo_token t )
{
    int i = f->indice ;
    tipo_valore dummy ;
    tipo_token tk = prossimo_token ( f, &dummy ) ;
    if (tk == t) return 1 ;
    else
    {
       f->indice = i ;
       return 0 ;
    }
}
double termine ( oggetto_formula * f )
{
       tipo_token t ;
       tipo_valore v ;
       double x ;
       extern double espressione( oggetto_formula * f ) ;
       switch ( t = prossimo_token( f, &v ) )
       {
              case COSTNUM : return v.num ;
              case OP_PARA : x = espressione ( f ) ;
                             if ( atteso ( f, OP_PARC ) )
                                return x ;
                             else
                                errore_sintassi( f ) ;
              case NOMEFNZ : x = espressione ( f ) ;
                             if ( atteso ( f, OP_PARC ) )
                             {
                                if (!strcmp(v.nome_funz, "rq"))
                                   return sqrt ( x ) ;
                                else
                                if (!strcmp(v.nome_funz, "ass"))
                                   return abs ( x ) ;
                                else
                                if (!strcmp(v.nome_funz, "neg"))
                                   return ( -x ) ;
                                else
                                if (!strcmp(v.nome_funz, "quad"))
                                   return ( x*x ) ;
                             }
                             else errore_sintassi( f ) ;
              default : errore_sintassi( f ) ;
       }
}
double fattore ( oggetto_formula * f )
{
       double op1, op2 ;
       int attesoMOLT, attesoDIVS ;
       op1 = termine ( f ) ;
       while ( (attesoMOLT = atteso ( f, OP_MOLT )) ||
               (attesoDIVS = atteso ( f, OP_DIVS )) )
       {
          op2 = termine ( f ) ;
          if ( attesoMOLT ) op1 = op1 * op2 ;
          else
          if ( attesoDIVS ) op1 = op1 / op2 ;
       }
       return op1 ;
}
double espressione ( oggetto_formula * f )
{
       double op1, op2 ;
       int attesoADDZ, attesoSOTT ;
       op1 = fattore ( f ) ;
       while ( (attesoADDZ = atteso ( f, OP_ADDZ )) ||
               (attesoSOTT = atteso ( f, OP_SOTT )) )
       {
          op2 = fattore ( f ) ;
          if ( attesoADDZ ) op1 = op1 + op2 ;
          else
          if ( attesoSOTT ) op1 = op1 - op2 ;
       }
       return op1 ;
}
void assegna_formula ( oggetto_formula * f, const char * testo )
{
     f->indice = 0 ;
     f->formula = malloc ( strlen(testo) + 1 ) ;
     strcpy ( f->formula, testo ) ;
}
int main ( void )
{
    int counter = 0 ;
    oggetto_formula mia_formula ;
    assegna_formula ( &mia_formula,
                      "(neg(5)-rq(quad(5)-4*6*1))/(2*6)" ) ;
    printf ( "%f\n", espressione ( &mia_formula ) ) ;
    return 0 ;
}

solo da compilare
Be', dipende da quale sistema.
lex & yacc per Unix
flex & bison per DOS
tra l'altro flex & bison vengono distribuiti con il pacchetto DJGPP.
So anche dell'esistenza di un altro clone yacc per DOS che si chiama
byacc

 token per poi risalire.
Come ti ho già chiesto una volta, ma questi programmi che mandi sono
tuoi o li trovi da qualche parte? Nel caso fossero tuoi, i miei
complimenti: a prima vista sembrano scritti veramente bene.
EMG

 flex & bison per DOS
flex & bison sono anche per unix.
(anzi, a dire il vero le versioni DOS sono un porting delle omonime 
utility gnu per unix).
giulio
-- 
Boycott Microsoft: 
http://www.boycott-ms.org/

utility gnu per unix).
Eppure io ricordo che flex e' il porting per DOS di lex e bison il
porting di yacc.
Probabilmente mi sbaglio...

complimenti: a prima vista sembrano scritti veramente bene.
Grazie della benevolenza di quel "a prima vista" ;)))))
In realta' sto cercando di riunire i programmi postati al ng in una
piccola libreria da distribuire in rete.

 Probabilmente mi sbaglio...
-----------------
[giu...@linux.darkstar ~]# man bison
BISON(1)                                                 BISON(1)
NAME
       bison - GNU Project parser generator (yacc replacement)
-----------------
sono utility GNU fatte, tra l'altro, per rimpiazzare quelle gią esistenti 
sotto unix (flex & yacc) con una diversa licenza.
come saprai il progetto GNU ha come sistema operativo il sistema
gnu/[linux,hurd] e non il dos :-)
tra l'altro basta vedere la sintassi degli switch e la presenza delle
"man pages" per capire che non si tratta di programmi "ideati" per il dos.


 wrote:
[ snip ]
AL>Eppure io ricordo che flex e' il porting per DOS di lex e bison il
AL>porting di yacc.
No, sono utility della GNU di cui esiste il porting sotto DOS.
Vengono corrente distribuite sotto Linux, ad esempio...
[root@fokhouse /root]# rpm -qi {bison,flex} | grep GNU
Summary     : GNU parser generator
This is the GNU parser generator which is mostly compatible with yacc. Many
Summary     : GNU fast lexical analyzer generator
This is the GNU fast lexical analyzer generator. It generates lexical
Ciao ciao,
Andrea
-- 
"...Unix, MS-DOS, and Windows NT (also known as the Good, the Bad, and 
 the Ugly)."
(by Matt Welsh)