Voila un plotter de fonctions simple ecrit
/*
* PLOT.CPP - Dessiner un graph
* Design & Programmation : ELAATIFI Sidi Mohamed
* <el******@menara.ma>
* 01/2005
*/
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <graphics.h>
#include <stdlib.h>
#include <dos.h>
#include "pile.h"
/*
******** Interpreteur ****************************
*/
/*
* Constantes & Macros
*/
#define MAXBUF 300
#define ZEROBUF(x) memset(x,0,MAXBUF)
/*
* la liste des symbole support‚s
*/
typedef enum
{
LeX = 1000, // variable x
Pi,
E1,
Nombre, // nombre entier
ParD, // prenthese droit
ParG, // --------- Gauche
Plus, // +
Moin, // -
Multiplier, // *
Diviser, // /
Sin, // Sinus
Cos, // Cosinus
Tan, // ...
Sqrt,
Ln,
Exp,
ACos,
ATan,
Sinh,
Cosh,
Tanh,
Pow,
Abs,
ASin,
Separateur, // Separateurs tel espace ' ' et nouvelle ligne '\n'
Erreur // Token indefini ou erreur
}Token;
/*
* Type lexical
*/
typedef struct
{
int s;
int d[100];
}Fonction;
typedef struct
{
int size;
char data[100];
}Buffer;
/*
* Donn‚es Globales utilis‚es dans tout le programme
*/
char valeurLex[MAXBUF];
int valeurLexTaille=0;
int valeurLexEntier=0;
/*
* Analyse lexicale
* ****************
* Ici on decrit toute les fonctions que l'analyseur peut
* utiliser ...
*/
int est_Num(char c)
{
return c >='0' && c <='9';
}
int est_Alpha(char c)
{
return c>='a'&& c<='z';
}
int est_Oper(char c)
{
return c=='+'||c=='*'||c=='-'||c=='/'||c=='^';
}
int est_Sep(char c)
{
return c==' '||c=='\n';
}
int est_Pars(char c)
{
return c==')'||c=='(';
}
char Get(Buffer* b)
{
return b->data[b->size++];
}
void Put(Buffer* b,char c)
{
//b->data[b->size--] = c;
b->size--;
}
Token AnalyseLexic(Buffer* b)
{
char c;
char done = 0; // false
ZEROBUF(valeurLex);
valeurLexTaille = 0;
//char* pstr = *p;
c = Get(b)/*fgetc(f)*/ ;
if(est_Num(c)) {
Put(b,c)/*ungetc(c,f)*/;
int s = sscanf((char*)(b->data+b->size),"%d",&valeurLexEntier);
b->size += s;
return Nombre;
}
else if(est_Oper(c)) {
switch(c)
{
case '+':
return Plus;
case '-':
return Moin;
case '/':
return Diviser;
case '*':
return Multiplier;
case '^':
return Pow;
}
}
else if(est_Alpha(c)) {
if( c == 'x' )
return LeX;
else
{
char buf[6];
int index=0;
while(c!=EOF && !done)
{
buf[index++] = c;
c = Get(b)/*fgetc(f)*/;
if(!est_Alpha(c))
{
Put(b,c) /*ungetc(c,f)*/;
done = 1;
}
}
buf[index] = 0;
strcpy(valeurLex,buf);
#define SI_F(x) if(!strcmp(buf,x))
#define ESI_F(x) else if(!strcmp(buf,x))
SI_F("sin")
return Sin;
ESI_F("cos")
return Cos;
ESI_F("tan")
return Tan;
ESI_F("exp")
return Exp;
ESI_F("sqrt")
return Sqrt;
ESI_F("ln")
return Ln;
ESI_F("asin")
return ASin;
ESI_F("acos")
return ACos;
ESI_F("atan")
return ATan;
ESI_F("sinh")
return Sinh;
ESI_F("cosh")
return Cosh;
ESI_F("tanh")
return Tanh;
ESI_F("abs")
return Abs;
ESI_F("pi")
return Pi;
return Erreur;
}
}
else if(est_Pars(c))
{
if( c == ')' )
return ParD;
return ParG;
}
else if(est_Sep(c))
return Separateur;
return Erreur;
}
/*
* Analyseur syntaxique
* ********************
* L'autre part du ce p'tit evaluateur d'expression ;-)
* ici j'aurais … decrir les fonctions du analyseur syntaxique
*/
void compileExpr(Fonction* fn,Buffer* b)
{
Pile pile;
char done = 0;
Token t;
fn->s = 0;
Pile_Init(&pile);
while(!done)
{
t = AnalyseLexic(b);
if( t == ParD)
{
Token t1 = (Token)Pile_Pop(&pile);//operation
Token t2 = (Token)Pile_Pop(&pile);// ParG
Token t = t1;
if( t1 == ParG )
t = t2;
fn->d[fn->s++] = t;
}
else if( t == Nombre )
{
fn->d[fn->s++] = valeurLexEntier;
}
else if( t == LeX )
{
fn->d[fn->s++] = LeX;
}
else if( t == Erreur)
{
while(pile.index > 0)
fn->d[fn->s++] = Pile_Pop(&pile);
done = 1;
}
else if( t == Separateur)
{
while(pile.index > 0)
fn->d[fn->s++] = Pile_Pop(&pile);
done = 1;
}
else
{
Pile_Push(&pile,t);
}
}
}
/*
* Evaluation de l'experssion compil‚
*/
#define INDEF 3000
double evalueExpr(Fonction f,double x)
{
rPile p;
double a = 0.0;
rPile_Init(&p);
double ans = 0.0;
for(int i=0;i<f.s;i++)
{
if( f.d[i] < LeX )
rPile_Push(&p,f.d[i]);
else
{
switch(f.d[i] )
{
case LeX:
rPile_Push(&p,x);
break;
case Plus:
ans = rPile_Pop(&p) + rPile_Pop(&p);
rPile_Push(&p,ans);
break;
case Moin:
ans = -rPile_Pop(&p);
if( p.index>0)
ans+=rPile_Pop(&p);
rPile_Push(&p,ans);
break;
case Multiplier:
ans = rPile_Pop(&p) * rPile_Pop(&p);
rPile_Push(&p,ans);
break;
case Diviser:
a = rPile_Pop(&p);
ans = rPile_Pop(&p);
if( a!= 0)
ans /= a;
else
return INDEF;
rPile_Push(&p,ans);
break;
case Sin:
ans = sin( rPile_Pop(&p) );
rPile_Push(&p,ans);
break;
/*case Sin:
ans = rPile_Pop(&p)
rPile_Push(&p,ans);
break;
*/
case Cos:
ans = cos( (double)rPile_Pop(&p) );
rPile_Push(&p,ans);
break;
case Tan:
ans = rPile_Pop(&p);
if( abs(ans) != M_PI_2)
ans = tan(ans);
else
return INDEF;
rPile_Push(&p,ans);
break;
case Ln:
ans = rPile_Pop(&p);
if( ans > 0)
ans = log( ans );
else
return INDEF;
rPile_Push(&p,ans);
break;
case Sqrt:
ans = rPile_Pop(&p);
if( ans >= 0)
ans = sqrt(ans);
else
return INDEF;
rPile_Push(&p,ans);
break;
case ASin:
a = rPile_Pop(&p);
if( a >= -1 && a <= 1)
ans = asin(a);
rPile_Push(&p,ans);
break;
case ACos:
a = rPile_Pop(&p);
if( a >= -1 && a <= 1)
ans = acos(a);
rPile_Push(&p,ans);
break;
case ATan:
a = rPile_Pop(&p);
ans = atan(a);
rPile_Push(&p,ans);
case Sinh:
a = rPile_Pop(&p);
ans = sinh(a);
rPile_Push(&p,ans);
break;
case Cosh:
ans = cosh(a);
a = rPile_Pop(&p);
rPile_Push(&p,ans);
break;
case Tanh:
a = rPile_Pop(&p);
tanh(a);
rPile_Push(&p,ans);
break;
case Exp:
ans = exp(rPile_Pop(&p));
rPile_Push(&p,ans);
break;
case Pow:
double b = rPile_Pop(&p);
a = rPile_Pop(&p);
if(b>0)
ans = pow(b,a);
else if( b!= 0)
if(a>0)
ans = mypow(b,(unsigned)a);
rPile_Push(&p,ans);
break;
case Abs:
a = rPile_Pop(&p);
ans = fabs(a);
rPile_Push(&p,ans);
break;
}
}
}
return rPile_Pop(&p);
}
/*
* Gestion graphique
*/
#define MINY 0
#define MINX 0
#define MAXX 639
#define MAXY 400
#define MIDX (MAXX+MINX)/2
#define MIDY (MAXY+MINY)/2
#define STER 30
int timeout = 0;
void const_graph()
{
int gdriver = DETECT, gmode, errorcode;
int xmax, ymax;
initgraph(&gdriver, &gmode, "..\\BGI");
}
void dessiner_fenetre(char * titre)
{
// cadre
setlinestyle(SOLID_LINE,1,1);
setcolor(15);
outtextxy(MIDX-4*strlen(titre),MAXY+70,titre);
setfillstyle(SOLID_FILL,1);
bar(MINX,MINY,MAXX,MAXY);
rectangle(MINX,MINY,MAXX,MAXY);
setlinestyle(DOTTED_LINE,1,1);
setcolor(9);
for(int i=-MIDX/STER;i<=MIDX/STER;i++)
{
line(MIDX+i*STER,MINY,MIDX+i*STER,MAXY);
}
for(i=-MIDY/STER;i<=MIDY/STER;i++)
{
line(MINX,MIDY+i*STER,MAXX,MIDY+i*STER);
}
// echele
setcolor(15);
setlinestyle(SOLID_LINE,1,1);
line(MIDX,MINY,MIDX,MAXY);
line(MINX,MIDY,MAXX,MIDY);
}
void dessiner_erreur(char* str)
{
setcolor(4);
outtextxy(MIDX-strlen(str)*4,MAXY+10,str);
}
void dessiner_foncstr(char *str)
{
setfillstyle(SOLID_FILL,0);
bar(MINX,MAXY+50,MINX+300,MAXY+60);
setcolor(15);
outtextxy(MINX,MAXY+50,"f(x) = ");
setcolor(7);
outtextxy(MINX+64,MAXY+50,str);
}
void lire_fonction(Fonction *fn,char *chaine)
{
char done = 0;
int index = 0;
char c;
while(!done)
{
dessiner_foncstr(chaine);
c = getch();
if( c == 13 )
{
done = 1;
chaine[index] = 0;
}
else
if( c == 8)
{
chaine[--index] = 0;
}
else
chaine[index++] = c;
}
Buffer b;
b.size = 0;
strcpy(b.data,chaine);
compileExpr(fn,&b);
}
void dessiner_fonction(Fonction fn,int zoomx,int zoomy)
{
const float fact = 1;
int y = 0;
float x = 0;
double e;
int gr[MIDX*2];
setlinestyle(SOLID_LINE,1,1);
for(int i=-MIDX;i<MIDX;i++)
{
x = (float) i / zoomx;
e = evalueExpr(fn,x);
if(e != INDEF)
{
y = (float) zoomy*e;
gr[MIDX+i] = MIDY-y;
}
else
{
gr[MIDX+i] = INDEF;
}
}
setcolor(14);
for(i=-MIDX;i<MIDX-1;i++)
{
int j = MIDX+i;
if((gr[j+1] <MAXY && gr[j+1] >MINY) && (gr[j]>=MINY && gr[j] <= MAXY))
{
if(timeout == 1)
delay(20);
line(j,gr[j],j+1,gr[j+1]);
}
//putpixel(j,gr[j],14);
}
}
void detr_graph()
{
closegraph();
}
/*
* Main
*/
char* INFO = "Par ELAATIFI Sidi Mohamed 2005 <el******@menara.ma>";
void main()
{
char choix;
char chaine[100];
clrscr();
Fonction f;
Buffer b;
b.size = 0;
f.d[0] = LeX;
f.s = 1;
strcpy(chaine,"x");
const_graph();
int zoomx = STER;
int zoomy = STER;
choix = 0;
while(choix != 27 && choix!='q')
{
if( zoomx <= 10 )
zoomx = 10;
if( zoomy <= 10)
zoomy = 10;
dessiner_fenetre(INFO);
dessiner_fonction(f,zoomx,zoomy);
dessiner_erreur("+ - * / Pour agrandir ou deminuer l'echelle |
s:entr‚e nouvelle | r:redefinir l'echelle");
dessiner_foncstr(chaine);
choix = getch();
switch(choix)
{
case '+':
zoomx+=5;
break;
case '-':
zoomx-=5;
break;
case '*':
zoomy+=5;
break;
case '/':
zoomy-=5;
break;
case 's':
memset(chaine,0,100);
memset(&f,0,sizeof(f));
lire_fonction(&f,chaine);
break;
case 'd':
dessiner_fenetre(INFO);
timeout = 1;
dessiner_fonction(f,zoomx,zoomy);
dessiner_erreur("+ - * / Pour agrandir ou deminuer l'echelle |
s:entr‚e nouvelle | r:redefinir l'echelle");
dessiner_foncstr(chaine);
timeout = 0;
break;
case 'r':
zoomx = STER;
zoomy = STER;
break;
}
}
detr_graph();
}