Aide projet : langage C

Fermé
Gryzzly - 30 nov. 2005 à 09:08
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 18 déc. 2005 à 23:04
Salut,
j'ai du mal à démarrer mon projet et comme la date limite arrive,il faut que j'avance.
Si quelqu'un pouvait m'aider ce serait sympa.
Merci d'avance


[b]Le but du projet est d'écrire une calculatrice "en ligne",on tape des expressions et des définitions des symboles au clavier,et la calculatrice est capable d'évaluer les expressions.
Pour faciliter l'analyse syntaxique des expressions dans le projet,on écrira les expressions en notattion préfixée.[/b]
Voici un exemple de ce que pourrait donner l'interface utilisateur du projet pour une session:
[URL=http://www-igm.univ-mlv.fr/~bedon/Enseignement/superCalculette/img0.htm]lien[/URL]

les lignes qui commencent par [b]set[/b] dans l'exemple définissent des [b]symboles[/b]

[b]I Environnement[/b]
L’environnement est l’objet (qui devra etre représenté par une structure)qui contient les noms des symboles et leurs definitions.
Les symboles peuvent etre de 2 types :
-[b]des variables[/b],qui possedent un nom et dont la valeur est nécessairement une constante réelle(type double).
-[b]des fonctions[/b],qui possedent aussi un nom,ont zero,un ou plusieurs paramètres(les parametres sont reelles),et qui sont definies par des expressions,dont nous parlerons en details plus loin .Les expressions dans le corps des fonctions peuvent le cas échéant contenir des symboles qui ne sont pas encore dans l’environnement au moment de la définition de la fonction.
Les commandes agissant sur l’environnement sont les suivantes :
-[b]set <nom[params]> = <expression>[/b],qui permet d’ajouter un symbole et sa définition dans l’environnement.
-[b]unset <nom>[/b],qui permet de retirer un symbole et sa definition de l’environnement.
-[b]env [/b],qui affiche le contenu de l’environnement,c’est à dire chaque symbole qu’il contient et sa definition.
-[b]load <nom de fichier>[/b],qui permet de lire des symboles et leurs definitions à partie d’un fichier binaire.
-[b]save <nom de fichier>[/b],qui sauvegarde chaque symbole et sa definition dans un fichier binaire
L’environnement contient 2 symboles prédéfinis et dont la valeur est fixe :
-[b]MIN,[/b]qui est la plus grande valeur négative que la calculatrice puisse manipuler
-[b]MAX[/b],qui est la plus grande valeur positive que la calculatrice puisse manipuler

[b]II Commandes[/b]
Il existe 2 commandes en plus de celles agissant sur l’environnement,qui sont détaillées dans la section 1 :
-[b]eval <expression>[/b],qui evalue l’expression qui lui est fournie en argument.L’évaluation est partielle si tous les symboles contenus dans l’expression ne sont pas définis au moment de l’évaluation.Si c’est le cas ,la commande a pour effet d’afficher une expression dans laquelle les seuls symboles restant sont ceux qui ne sont pas définis.Si ça n’est pas le cas,la commande affiche la valeur réelle de l’expression.
-[b]quit[/b],qui permet de quitter le programme.

[b]III Expressions[/b]
Les expressions sont construites à partir de symboles,d’opérateurs et de constantes.
Les constantes sont toutes des réels(type double)
Les symboles sont des chaines de caractères,qui font référence par exemple à des symboles définis dans l’environnement.
[b]Les opérateurs sont les suivants :[/b]
- + est la somme binaire
- - est la différence binaire
- / est le quotient binaire
- * est le produit binaire
- @ est le plus unaire (un caractère différent de celui employé pour la somme binaire est utilisé pour faciliter l’analyse syntaxique des expressions)
- ~ est le plus unaire(meme remarque)
-l’opérateur d’application d’une fonction à des arguments,qui n’est représenté par aucun caractère.Bien que cet opérateur soit "invisible",il existe néamoins.Ainsi ,[b]si f est un symbole de fonction qui à x associe x+1 alors l’expression f 3,qui signifie "applique f à 3" vaut 4[/b]
Les expressions sont évaluées "au mieux" .Ainsi par exemple,[b]+ 1 2 donne 3[/b].De meme,[b]si x est un symbole défini dans l’environnement avec pour valeur 3,alors + 1 x donne 4[/b].S’il n’est pas défini,alors [b]+ 1 x vaut + 1 x[/b] .D’une manière générale,l’évaluation d’une expression donne soit une constante,soit une expression plus complexe construite à partir d’un opérateur et d’autres expressions.

[b]IV Définitions des fonctions[/b]
Il est possible de spécifier un "branchement" dans la définition des fonctions.Un branchement est repéré par le caractère | dans les définitions de fonctions.En voici un exemple simple :
[b]set fact(x) = | x:[0,0] 1 x:default * x fact – x 1[/b]
La signification de l’exemple est :
-si x appartient à [0,0] alors fact(x) vaut 1
-sinon,fact(x) vaut x*fact(x-1)
La syntaxe [a,b] spécifie un intervalle de valeurs.
On peut en spécifier plusieurs,qui ne comprennent pas forcément leurs bornes comme dans l’exemple précédent,qui sont nécessairement disjoints,et dont l’union contient toutes les valeurs réelles possibles :
[b]set f(x) = | x:[0,1[ 0 x:[1,2[ 1 x:[2,10] + x 1 x:]10,MAX] * 2 + 1 x x:default –1[/b]
L’exemple définit une fonction f qui vaut :
- 0 si x appartient à [0,1[
- 1 si x appartient à [1,2[
- x+1 si x appartient à [2,10]
- 2*(1+x) si x appartient à ]10,MAX]
- -1 sinon
Le calculateur affiche une erreur s’il existe des intersections entre les intervalles.
Le calculateur affiche une erreur s'il existe des intersections entre les intervalles.
Dans le cas ou la fonction a plusieurs parametres il est possible de faire des tests d'intervalles sur chaque paramètre,et de les combiner:
[b]set g(x,y) = | x:[0,1] 0 x,y:[1,2[]-2,-1] 1 x,y:[2,10][-10,-2] + x y
x,y:]10,MAX][-MAX,-10[ * 2 + y x x,y:default * x y[/b]
L'exemple définit une fonction f qui vaut:
- 0 si x appartient à [0,1]
- 1 si x appartient à [1,2[ et y à]-2,-1]
- x+y si x appartient à [2,10] et y à [-10,-2]
- 2*(y+x) si x appartient à ]10,MAX] et y à [-MAX,-1[
- x*y sinon

Notons que dans le cas de fonctions à plusieurs parametres,il est possible de faire les tests d'intervalles sur un nombre quelconques d'arguments :dans l'exemple précédent ,le premier test ne porte que sur le premier argument de la fonction,alors que les autres portent sur les deux.
Les définitions de fonctions peuvent contenir des symboles,qui appartiennent à l'environnement au moment de la définition ou non,et qui peuvent etre des fonctions.Ainsi,une fonction peut en appeler une autre,comme dans l'exemple suivant:
[b]Calc> set f(x) = | x:[0,2[ x x:default + f@1 - x 1 g@1 - x 2[/b]
qui doit afficher [b]f(x) =
x:[0,2[ -> x
x:default -> f(x-1)+g(x-2)[/b]

[b]Calc> set g(x) = | x:[0,2[ x x:default + g@1 - x 1 f@1 - x 2[/b]
qui doit afficher [b]g(x) =
x:[0,2[ -> x
x:default -> g(x-1)+f(x-2)
Calc> eval g 4
g(4) = 3[/b]
Il est nécessaire,pour que l'analyse syntaxique puisse etre réalisée correctement,de spécifier l'arité de chacun des symboles utilisés dans les expressions.Par défaut,cette arité est 0: le symbole représente alors une valeur.Dans le cas ou elle n'est pas nulle,elle doit etre précisée après le caractère @ collé au nom du symbole.Ainsi dans l'exemple précédent,les symboles [b] f et g[/b] sont des symboles d'arité 1:ce sont des fonctions,qui prennent un argument.
A voir également:

15 réponses

mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812
30 nov. 2005 à 16:16
Ton sujet est bien posé en ce sens qu'il suffit de faire les étapes une par une enrichissant progressivement ce que tu as déjà coder. Première étape, la partie interface, ensuite implémenter la partie commande, puis la partie calcul, et enfin la partie fonction.

Le sujet est assez long donc il faut en effet t'y mettre rapidement.

Pour la partie interface, il faut scaner une chaine rentree au clavier sur stdin (man scanf) et la parser (man sscanf) dans une fonction qui fera office d'analyseur syntaxique.

- Dans un premier temps, implémente juste les commandes et la déclaration et initialisation de variable.
- Ensuite implémente les opérations de base (+, - ...) en stockant les opérations dans un struct lors du sscanf. Puis fais la fonction qui fait le calcul sur une opération lémentaire.
- Puis, définir une structure d'arbre pour travailler sur des opérations non élémentaire (ensemble d'opérations élémentaires).
- Etape suivante, définir les intersections et unions d'intervalle, l'operateur d'appartenance etc... pour implementer les fonctions. On peut utiliser pour celà unestructure definissant un intervalle, ouvert ou fermé.
- Dernière étape, les fonctions ! Mais une fois que tu auras fait tout ça je pense que tu t'en sortiras seul ;-)

Si tu as des questions sur des points précis n'hesite pas a repasser)

Bonne chance
0
Salut,

je voudrais savoir si tu accepterais que je t'envoies ce que j'ai fait par mail.
0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812
3 déc. 2005 à 00:40
Euh ben mets le ici. Je ne donne pas mon mail sur les forums.
0
Salut,

comme il n'est pas possible d'envoyer de message privé,je voudrais savoir si tu es également inscrit sur un autre forum info comme ça je pourrais t'envoyer mes sources via ce forum et ton mail ne sera pas connu.
Si c'est le cas,quel est ce forum?
0
Ça va etre dur car il y a des centaines de lignes de codes.
Sinon est ce que tu pourrais m'indiquer une manière de faire car je bloque sur l'evaluation des fonctions et sur les fonctions avec intervalle.
Merci
0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812
4 déc. 2005 à 00:35
1) Définis dans un premier temps des struct intervalles, prenant en compte :
- les bornes inf et sup de l'intervalle.
- si l'intervalle est fermé ou ouvert pour chaque borne.

2) Ensuite définis une fonction sans prendre en compte le domaine de définition. C'est là qu'entre en jeu l'évaluation des littéraux, mais ça normalement tu l'as déjà fais avec les opérations.

3) Les fonctions définies par morceaux seront donc une liste de paires formée d'un struct fonction et d'un struct intervalle. La fonction d'évaluation sera donc un appelle à celle d'une fonction simple, appliquée à la fonction concernant l'intervalle adéquat (si elle existe).

Rq : En particulier les fonctions restreinte à un sous ensemble de leur domaine de définition entreront dans la catégorie des fonctions définies par morceaux : ex : x -> x^2 définie juste sur R+.


Bonne chance
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
@mamiemando

Salut,

comme il n'est pas possible d'envoyer de message privé,je voudrais savoir si tu es également inscrit sur un autre forum info comme ça je pourrais t'envoyer mes sources via ce forum et ton mail ne sera pas connu.
Si c'est le cas,quel est ce forum?
0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812
6 déc. 2005 à 19:41
Non ce n'est pas le cas désolé :/ Mets le sur une parge perso ou sur un ftp, donne moi l'adresse, et je le téléchargerai.
0
Je te mets le lien sur un forum auxquel je participe:
www.maths-forum.com
une fois sur le site,tu descends sur autres matières ,informatiques puis tu cliques que sur Morpheus(c'est mon pseudo) pour m'envoyer un MP dans lequel tu pourras mettre ton mail pour que je t'envoies mes sources car j'ai vraiment besoin d'aide.
Merci d'avance
0
Gryzzly > Gryzzly
7 déc. 2005 à 10:34
Pour faire plus simple,je te mets le lien direct:
http://www.maths-forum.com/member.php?u=1842
puis envoyer un message privé à Morpheus
0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812
7 déc. 2005 à 19:26
C'est fait
0
Je t'ai envoyé ce que j'ai fait.
0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812
8 déc. 2005 à 17:35
Ok je vais regarder ça
0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812
8 déc. 2005 à 18:31
1) fais un makefile (pour compiler tu auras juste a taper make).

Exemple simple de makefile :
OBJ= Analyse.o Environnement.o Expression.o Operation.o
SRC= Analyse.c Environnement.c Expression.c Operation.c
APP=plop
CC=g++
CFLAGS=-W -Wall -lm

depend:
    $(CC) -MM $(SRC) > .dependfile

%.o:%.c
    $(CC) $(CFLAGS) -c $<

all: $(OBJ) main.c
    $(CC) $(CFLAGS) -o $(APP) main.c $(OBJ)

clean:
    rm -f *.o $(APP)

run:
    ./$(APP)

ifeq (.dependfile,$(wildcard .dependfile))
include .dependfile
endif

Pour compiler la premiere fois, tape :
make clean depend all 

Par la suite :
make


2) Dans Analyse.c, ligne 178

        char*parametres;
        //...
        /*affichage de la fonction avec ces parametres et sa definition*/
        printf("%s(%s",ligne,parametres[0]);

Je pense que là il y a un soucis : c'est soit %s(%c si tu lis un caractère, soit %s(%s mais en utilisant un atoi pour convertir la chaine en valeur numerique.

Idem ligne 182

Ligne 62
char **pp = (char **) malloc (sizeof(char *) * n);

Ligne 73
(p != NULL) ? p = NULL : (void) 0;
Ca ne veut rien dire, que veux tu faire ?


3) Dans Environnement.h

Il ne faut pas déclarer Env, ligne 29, juste la structure. Tu déclares la variable dans main.c



Si tu peux mettre des espaces pour aérer ce sera encore mieux ;-)
Essaye de ne pas trop utilier les variables globales parce que là j'ai un peu de mal à m'y retrouver.

Pour les opérations tu as fait des pointeurs de fonctions, c'est une bonne idée. Mais je pense que pour l'instant tu pouvais juste de faire un switch sur le caractere de l'operation et retourner le resultat en consequence...

Corrige déjà tout ça et maile moi quand ta nouvelle version.

Bonne chance
0
@mamiemando

J'ai fait toutes les modifications et je t'ai tout envoyé.
0
Comment créer un programme antiviral en C++?

J'aime créer un programme antiviral qui nomme "BitKillVir AntiVirus"!
0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812
9 déc. 2005 à 11:24
Ouvre un nouveau sujet.
0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812
9 déc. 2005 à 11:25
Ok Grizzly je regarde ca ce soir
0
Salut,

j'aimerais savoir si quelqu'un pouvait m'aider
à débugger mon code car le compilateur (utilisation de
gdb) m'indique des erreurs lignes 119,169 et 252 mais
je n'arrive pas à résoudre

Merci

#include<stdio.h>
#include<stdlib.h>
#include<float.h>
#include<string.h>
#include<ctype.h>

#define MAX 100


enum Type {Operateur, Constante, Variable};


union Info  
{
  double cte;
  char *nom;
  char op;
};

struct noeud{
  enum Type type;
  union Info info;
  struct noeud *gauche;
  struct noeud *droit;
};

typedef struct noeud Noeud;
typedef struct noeud * Expression;

typedef struct _Symbole{
  int type;
  char *nom;
  double val;
  int nb_parametres;
  char **parametres;
  Expression e;
} Symbole;



/* Fonction qui gere les espaces */
void espace(char **ligne)
{
  while(*ligne[0] == ' ') ++(*ligne);
}


int EstReel(char *ligne, double *val)
{
  double v;
  char *endptr;
  
  
  v=strtod(ligne,&endptr);
  
  /* la chaine commence par un chiffre */
  if(endptr!=ligne)
    {
      /* la chaine ne contient pas que des chiffres */
      if(*endptr!='\0')
	{
	  fprintf(stderr,"erreur\n");
	  return 1;
	}
      
      /* la chaine ne contient que des chiffres */
      if(v<=DBL_MIN||v>=DBL_MAX)
	{
	  fprintf(stderr,"debordement\n");
	  return 1;
	}
      
      /* on recupere la valeur */
      *val=v;
      return 0;
    }
  else return 1;
}



/* Fonction qui teste si la chaine passee en parametre est une variable */
int EstVariable(char *ligne)
{
  if(isalpha(*ligne))
    {
      ++ligne;
      while(isalnum(*ligne))
	ligne++ ;
    }
  if(*ligne=='\0') return 0 ;
  else return 1;
}


/* Analyse d'une expression:creation de l'arbre */
Expression AnalyseExpression(char **ligne)
{
  Expression e;
  char *sep=NULL;
  
  double val;
  char c;
  
  espace(ligne);

  e = (Expression)malloc(sizeof(Noeud));
  if(e == NULL) return NULL;
  
  /* c'est un chiffre */
	if(isdigit((*ligne)[0]))
	  {
	    /* on cherche le premier blanc pour recuperer la valeur */
	    if(!(sep = strchr(*ligne,' ')))
	      {
		fprintf(stderr,"erreur\n");
			return NULL;
	      }
	    *sep = '\0';
	    
	    /* verifie que le reel est bien ecrit */
	    if(EstReel(*ligne,&val))
	      {
		fprintf(stderr,"erreur\n");
		return NULL;
	      }
	    
	    e->type = Constante;
	    e->info.cte = val;
	    e->gauche = NULL;
	    e->droit = NULL;
	    *ligne = (sep+1);
	    espace(ligne);
	  }
	
	else {
	  /* c'est une lettre */
	  if(isalpha((*ligne)[0]))
	    {
	      /* on cherche le premier blanc pour recuperer le nom */
	      if(!(sep = strchr(*ligne,' ')))
		{
		  fprintf(stderr,"erreur\n");
		  return NULL;
		}
	      *sep = '\0';
	      
	      /* verifie que la variable est bien ecrite */
	      if(EstVariable(*ligne))
		{
		  fprintf(stderr,"erreur\n");
		  return NULL;
		}
	      
	      e->type = Variable;
	      e->info.nom = *ligne;
	      e->gauche = NULL;
	      e->droit = NULL;
	      *ligne = (sep+1);
	      espace(ligne);
	    }
	  else{
	    /* le caractere est un operateur */
	    c=(*(*ligne)++);
	    if(c == '+' || c == '-' || c == '*' || c == '/')
	      {
		e->type = Operateur;
		e->info.op = c;
		e->gauche = AnalyseExpression(ligne);
		e->droit = AnalyseExpression(ligne);
	      }
	    else if(c == '@' || c == '~')
	      {
		e->type = Operateur;
		e->info.op = c;
		e->gauche = AnalyseExpression(ligne);
		e->droit = NULL;
	      }
	    else printf("Erreur,'%c' n'est pas un operateur prevu\n",c);
	  }
	}
	return e;
}



/* Affichage de l'arbre en infixe */
void Infixe(Expression e)
{

switch(e->type)
    {
    case Constante:
      printf("%f",e->info.cte);
      break;
    case Variable:
      printf("%s",e->info.nom);
      break;
    case Operateur:
      switch(e->info.op){
	case'+':
	  case'-':/* affichage infixe sans () */
	  Infixe(e->gauche);
	if(e->info.op == '+') printf("+"); 
	else printf("-");
	Infixe(e->droit);
	break;
	case'*':
	  case'/':/* affichage infixe avec () */
	  if(e->gauche->type != Operateur)
	    Infixe(e->gauche);
	  else
	    {
	      printf("(");
	      Infixe(e->gauche);
	      printf(")");
	    }
	if(e->info.op == '*') printf("*"); 
	else printf("/");
	
	if(e->droit->type != Operateur)
	  Infixe(e->droit);
	else
	  {
	    printf("(");
	    Infixe(e->droit);
	    printf(")");
	  }
	break;
	case'@':/* affichage prefixe */
	  printf("@");
	Infixe(e->gauche);
	break;
	case'~':
	  printf("~");
	Infixe(e->gauche);
	break;
      }
    }
}


int main(void)
{
  char *ligne = "           + * 1 2 7";
  Expression e = NULL;
  

  
 

  if(AnalyseExpression(&ligne)==NULL)
   {
     fprintf(stderr,"erreur\n");
     return 1;
   }
   e=AnalyseExpression(&ligne);
  
   
   return 0;
}
0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812
10 déc. 2005 à 19:47
Tu devrais ouvrir un nouveau post en fait maintenant que tout le monde voit ton code et puisse t'aider.
0
Bonjour mamiemando ,

j'ai réussi à coder tout ce qu'il faut à part les fonctions avec intervalles (cf énoncé en 1ère page).

Est ce que tu pourrais m'écrire en pseudo-code la manière de procéder.

Merci d'avance
0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812
18 déc. 2005 à 23:04
Tu peux utiliser une structure du genre :
struct intervalle{
  unsigned int type_inf;//0 si inf inclu, 1 si inf=-l'infini, 2 si inf exclu
  unsigned int type_sup;//0 si sup inclu, 1 si sup=+l'infini, 2 si sup exclu
  double inf;
  double sup;
};

Ou inf désigne la borne inférieure (sauf si c'est -l'infini) et sup la borne supérieure (sauf si c'est +l'infini).

int est_dans_intervalle(struct intervalle i,double val){
  return ( i.inf==1 || val > inf || (val==i.inf && i.inf == 0))
  &&     ( i.sup==1 || val < sup || (val==i.sup && i.sup == 0));
}

C'est pas trop dur là quand même... Faut chercher un peu ;-)
0