Newsgroup: it.comp.lang.c
Titolo: Non uccidetemi...

Ok!!! Non ammazzatemi, ma non sapevo come risolvere il mio problema!!!
Quello che segue è un parser per una calcolatrice:
Viene compilato correttamente, ma non funziona!
E non riesco a capire il perchè?
Qualche anima molto, ma molto gentile, potrebbe dargli un'occhiata?
Provate a mandarlo in esecuzione...
Grazie!
Mi piacerebbe contraccambiare, ma non saprei come!
Andrea Ottolina
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <process.h>
#include <ctype.h>
#include <alloc.h>
#include <math.h>
#define DELIMITER 1
#define VARIABLE 2
#define NUMBER 3
#define FUNCTION 4
char *esp,*prog;
char token[80];
int ip=1;
int itk=1;
int er;
int tok_type;
long double result;
void evalexp(long double *answer);
void get_tok(void);
void atom(long double *answer);
void sum_exp(long double *answer);
void mul_exp(long double *answer);
void exp_exp(long double *answer);
void unary_exp(long double *answer);
void func_exp(long double *answer);
void par_exp(long double *answer);
void lowering(char *st);
int isdelim(char c);
main()
{
  clrscr();
  printf("Inserisci un espressione...\n");
  scanf("%s",esp);
  prog=esp;
  er=-1;
  tok_type=0;
  token[0]=0;
  evalexp(result);
  printf("\nIl risultato Š: %6.2f",result);
  getch();
  return(0);
}
void evalexp(long double * answer)
{
  get_tok();
  if (!*token)
  {
    er=2;
    return;
  }
  sum_exp(answer);
  if (*token) er=0;
  result = *answer;
}
void atom(long double * answer)
{
  if (tok_type==NUMBER)
  {
    *answer = atof(token);
    get_tok();
    return;
  }
  er=0;
}
void get_tok()
{
  char *temp;
  tok_type=0;
  temp=token;
  *temp='\0';
  if (!*prog) return;
  while (isspace(*prog)) ++prog;
  if (strchr("+-*/%^=()",*prog))
  {
    tok_type=DELIMITER;
    *temp=*prog;
    temp++;
    prog++;
  }
  else if(isalpha(*prog))
  {
    while (!isdelim(*prog)) *temp++=*prog++;
    tok_type=FUNCTION;
  }
  else if(isdigit(*prog))
  {
    while(!isdelim(*prog)) *temp++=*prog++;
    tok_type=NUMBER;
  }
  *temp='\0';
}
void sum_exp(long double * answer)
{
  char op;
  long double temp;
  mul_exp(answer);
  while((op=*token)=='+' || op=='-')
  {
    get_tok();
    mul_exp(&temp);
    switch (op)
    {
      case '-': *answer=*answer - temp;
                break;
      case '+': *answer=*answer + temp;
                break;
    }
  }
}
void mul_exp(long double * answer)
{
  char op;
  long double temp;
  exp_exp(answer);
  while((op = *token)== '*' || op == '/')
  {
    get_tok();
    exp_exp(&temp);
    switch (op)
    {
      case '*': *answer = *answer * temp;
                break;
      case '/': if (temp==0)
                {
                  er=3;
             break;
                }
                *answer = *answer / temp;
                break;
    }
  }
}
void exp_exp(long double * answer)
{
  long double temp, exo;
  unary_exp(answer);
  if(*token=='^')
  {
    get_tok();
    exp_exp(&temp);
   exo = *answer;
    if(temp== 0.0)
    {
      *answer = 1.0;
    return;
    }
  *answer = pow(exo,temp);
  }
}
void unary_exp(long double * answer)
{
  char op;
  op=0;
  if((tok_type == DELIMITER) && *token=='+' || *token=='-')
  {
    op=*token;
  get_tok();
  }
  func_exp(answer);
  if(op=='-') *answer = -*answer;
}
void func_exp(long double * answer)
{
  char op[]= "        ";
  long double temp=0;
  if (tok_type == FUNCTION)
  {
    strcpy(op,token);
  lowering(op);
  get_tok();
  par_exp(&temp);
    if (!strcmp(op,"cos")) *answer = cos(temp);
    else
      if (!strcmp(op,"sen")) *answer = sin(temp);
      else
        if (!strcmp(op,"tg"))
        {
          if (cos(temp)==0) er=3;
          else *answer = tan(temp);
        }
        else
          if(!strcmp(op,"cotg"))
          {
            if (sin(temp)==0) er=3;
        else *answer = cos(temp)/sin(temp);
          }
          else
            if(!strcmp(op,"arcsen"))
            {
          if ((temp<-1)||(temp>1)) er=3;
          else *answer=asin(temp);
            }
        else
              if(!strcmp(op,"arccos"))
              {
                if ((temp<-1)||(temp>1)) er=3;
          else *answer = acos(temp);
              }
              else
                if(!strcmp(op,"arctg"))  *answer=atan(temp);
                else
                  if(!strcmp(op,"arccotg")) *answer=1/atan(temp);
                  else
                    if(!strcmp(op,"ln"))
                    {
                      if (temp>=0) *answer = log(temp);
                      else er=3;
                    }
              else
                      if(!strcmp(op,"log"))
                      {
                        if (temp>=0) *answer = log10(temp);
            else er=3;
                      }
                      else
                        if(!strcmp(op,"radq"))
                        {
                          if(temp<0) er=3;
              else *answer = sqrt(temp);
                        }
                        else er=4;
  }
  else par_exp(answer);
}
void par_exp(long double * answer)
{
  if((*token=='('))
  {
  get_tok();
  sum_exp(answer);
  if(*token!= ')') er=1;
  get_tok();
  }
  else atom(answer);
}
int isdelim(char c)
{
  if (strchr("+-/*^=()",c) || c=='\r') return 1;
  return 0;
}
void lowering(char * st)
{
  int i,j = strlen(st);
  for(i=0;i<=j;i++) st[i] = tolower(st[i]);
} 

     return;
evalexp non prevede return
Ti consiglio di rivederlo bene questo programma e togliere queste
imperfezioni,prima di entrare nel merito dell algoritmo
Ivan Molella

evalexp non prevede return
non prevede return ???
*tutte* le funzioni prevedono un ritorno !
--
Andrea Laforgia (
andrea_...@bigfoot.com
)
---------------------------------------------

 imperfezioni,prima di entrare nel merito dell algoritmo
Il problema è che l'algoritmo dovrebbe essere corretto: ho provato a
eseguirlo con la funzione "Trace into" e sembra funzionare! Ma non aggiorna
Result (ho usato anche dei watch per verificare i valori)! Il problema deve
essere nell'interfacciamento con il programma principale, guardacaso quello
che ho fatto io...
Cmq ti ringrazio per la buona volontà che hai avuto nell'aiutarmi!
Grazie
Andrea Ottolina




fosse usato al posto di break.
break e return hanno due comportamenti diversi. Il primo ti fa uscire
dal blocco corrente, il secondo dal blocco di funzione. Comunque va
bene.


Provate a mandarlo in esecuzione...
Uff, certo che è un programma davvero lungo!
Purtroppo non ho il tempo di vedere tutto com'è fatto, ma sembra
interessante!
Il programma non funzionava, e allora ho fatto delle modifiche:
Intanto ho dovuto togliere il clrscr che nell'lcc non è definito, ma non è
un grave problema.
all'inizio del main, aggiungi questo:
esp=(char*) calloc(80, sizeof(char));
 if (esp==NULL){
  return -1;
 }
 prog=(char*) calloc (80, sizeof(char));
 if (prog==NULL){
  free (esp);
  return -1;
 }
La grandezza arbitraria (80), è data dal fatto che non ho visto a cosa
servivano le variabili, ma ho solo visto che non erano allocate... con
semplici espressioni funziona.
Bisognerebbe anche mettere tutti i vari free (almeno quei due alla fine del
main, ma anche altri nel corso del programma).
Ad esempio, nel get_tok ho allocato il *temp: indispensabile prima di
scriverci qualcosa dentro! Ma se l'allocazione non andasse a buon fine, ci
vorrebbe la possibilità di ritornare qualcosa che faccia capire che si è
verificato un errore.
Infine, una svista nel main: la funzione evalexp chiede un indirizzo, per
cui è:
evalexp(&result);
Spero di esserti stato utile (da me il programma funziona, con queste
modifiche, almeno con espressioni semplici!)
ciao,
Zeppe

 primo modo);
Il C č un linguaggio "free form" e quindi gli "white-spaces" (spazi, a
capi e tab) non sono significativi. Puoi mettercene quanti ne vuoi senza
alterare la sintassi delle istruzioni.
EMG

Ok grazie a tutti!
Cmq adesso funziona!
Era un'errore nel passaggio del parametro result e answer. Ora funziona, e
vi posto il codice corretto...
Ci sono delle modifiche ai nomi delle funzioni, ma non sono influenti!
Quello che non capisco sono tutte le allocazioni che fate voi! A me funziona
perfettamente senza allocare niente!
Qualcuno mi potrebbe spiegare a cosa serve fare così tanti malloc?
Da quello che so io serve per riservare dello spazio di memoria per le
variabili, ma non dovrebbe provvedere automaticamente il compilatore? O
almeno in Pascal era così....
Sapete sono alle prime armi con il C! Non l'ho mai usato prima di 2 mesi fa,
quindi molte sottigliezze non le capisco ma mi piacerebbe capirle!
Grazie, Ciao
ANDREA
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <process.h>
#include <ctype.h>
#include <alloc.h>
#include <math.h>
#include <stdlib.h>
#define DELIMITER 1
#define VARIABLE 2
#define NUMBER 3
#define FUNCTION 4
#define NUMERRCODE 5
char *esp,*prog;
char token[80];
char *messaggi[NUMERRCODE];
int er;
int tok_type;
long double *dato;
long double risultato;
double e,pi;
void Val_Espressione(long double *dato);
void Trova_Tok(void);
void Atom(long double *dato);
void Val_Somma(long double *dato);
void Val_Prodotto(long double *dato);
void Val_Esp(long double *dato);
void Val_Meno(long double *dato);
void Val_Funzione(long double *dato);
void Val_Parentesi(long double *dato);
void LowCase(char *st);
int E_Limite(char c);
main()
{
  e=exp(1);
  pi=3.1415926535;
  er=-1;
  tok_type=0;
  token[0]=0;
  messaggi[0] = "Errore di sintassi";
  messaggi[1] = "Parentesi non bilanciate";
  messaggi[2] = "Espressione assente";
  messaggi[3] = "Valore fuori dal dominio della funzione";
  messaggi[4] = "Funzione sconosciuta";
  clrscr();
  printf("Inserisci un espressione...\n");
  scanf("%s",esp);
  prog=esp;
  dato=&risultato;
  Val_Espressione(dato);
  if (er!=-1) printf("\nErrore: %s",messaggi[er]);
  else printf("\nIl risultato Š: %10.5Lf",risultato);
  getch();
  return(0);
}
void Val_Espressione(long double *dato)
{
  Trova_Tok();
  if (!*token)
  {
    er=2;
    return;
  }
  Val_Somma(dato);
  if (*token) er=0;
}
void Atom(long double *dato)
{
  if (tok_type==NUMBER)
  {
    *dato = atof(token);
    Trova_Tok();
    return;
  }
  if (tok_type==VARIABLE)
  {
    switch (*token)
    {
      case 'P': *dato=pi;
                break;
      case 'e': *dato=e;
                break;
      default: er=4;
               break;
    }
    Trova_Tok();
    return;
  }
  er=0;
}
void Trova_Tok()
{
  char *temp;
  tok_type=0;
  temp=token;
  *temp='\0';
  if (!*prog) return;
  while (isspace(*prog)) ++prog;
  if (strchr("+-*/%^=()",*prog))
  {
    tok_type=DELIMITER;
    *temp=*prog;
    temp++;
    prog++;
  }
  else if(isalpha(*prog))
  {
    while (!E_Limite(*prog)) *temp++=*prog++;
    if (!strchr("Pe",*token)) tok_type=FUNCTION;
    else tok_type=VARIABLE;
  }
  else if(isdigit(*prog))
  {
    while(!E_Limite(*prog)) *temp++=*prog++;
    tok_type=NUMBER;
  }
  *temp='\0';
}
void Val_Somma(long double *dato)
{
  char op;
  long double temp;
  Val_Prodotto(dato);
  while((op=*token)=='+' || op=='-')
  {
    Trova_Tok();
    Val_Prodotto(&temp);
    switch (op)
    {
      case '-': *dato=*dato - temp;
                break;
      case '+': *dato=*dato + temp;
                break;
    }
  }
}
void Val_Prodotto(long double * dato)
{
  char op;
  long double temp;
  Val_Esp(dato);
  while((op = *token)== '*' || op == '/')
  {
    Trova_Tok();
    Val_Esp(&temp);
    switch (op)
    {
      case '*': *dato = *dato * temp;
                break;
      case '/': if (temp==0)
                {
                  er=3;
             break;
                }
                *dato = *dato / temp;
                break;
    }
  }
}
void Val_Esp(long double * dato)
{
  long double temp, exo;
  Val_Meno(dato);
  if(*token=='^')
  {
    Trova_Tok();
    Val_Esp(&temp);
   exo = *dato;
    if(temp== 0.0)
    {
      *dato = 1.0;
    return;
    }
  *dato = pow(exo,temp);
  }
}
void Val_Meno(long double *dato)
{
  char op;
  op=0;
  if((tok_type == DELIMITER) && *token=='+' || *token=='-')
  {
    op=*token;
  Trova_Tok();
  }
  Val_Funzione(dato);
  if(op=='-') *dato = -*dato;
}
void Val_Funzione(long double *dato)
{
  char op[]= "        ";
  long double temp=0;
  if (tok_type == FUNCTION)
  {
    strcpy(op,token);
  LowCase(op);
  Trova_Tok();
  Val_Parentesi(&temp);
    if (!strcmp(op,"cos")) *dato = cos(temp);
    else
      if (!strcmp(op,"sen")) *dato = sin(temp);
      else
        if (!strcmp(op,"tg"))
        {
          if (cos(temp)==0) er=3;
          else *dato = tan(temp);
        }
        else
          if(!strcmp(op,"cotg"))
          {
            if (sin(temp)==0) er=3;
        else *dato = cos(temp)/sin(temp);
          }
          else
            if(!strcmp(op,"arcsen"))
            {
          if ((temp<-1)||(temp>1)) er=3;
          else *dato=asin(temp);
            }
        else
              if(!strcmp(op,"arccos"))
              {
                if ((temp<-1)||(temp>1)) er=3;
          else *dato = acos(temp);
              }
              else
                if(!strcmp(op,"arctg"))  *dato=atan(temp);
                else
                  if(!strcmp(op,"arccotg")) *dato=1/atan(temp);
                  else
                    if(!strcmp(op,"ln"))
                    {
                      if (temp>=0) *dato = log(temp);
                      else er=3;
                    }
              else
                      if(!strcmp(op,"log"))
                      {
                        if (temp>=0) *dato = log10(temp);
            else er=3;
                      }
                      else
                        if(!strcmp(op,"radq"))
                        {
                          if(temp<0) er=3;
              else *dato = sqrt(temp);
                        }
                        else er=4;
  }
  else Val_Parentesi(dato);
}
void Val_Parentesi(long double *dato)
{
  if((*token=='('))
  {
  Trova_Tok();
  Val_Somma(dato);
  if(*token!= ')') er=1;
  Trova_Tok();
  }
  else Atom(dato);
}
int E_Limite(char c)
{
  if (strchr("+-/*^=()",c) || c=='\r') return 1;
  return 0;
}
void LowCase(char *st)


almeno in Pascal era cosě....
Stai confondendo : non per le variabili, ma per la memoria puntata dai
puntatori. Anche in Pascal e' cosi' (vedi new() e dispose()).


 *tutte* le funzioni prevedono un ritorno !
ops,ho scritto una cavolata hai ragione :-)