From ecd16166cde1ffa3edfbaa897b049d532e234ab6 Mon Sep 17 00:00:00 2001 From: Pixel Date: Wed, 2 May 2001 22:14:21 +0000 Subject: Pouet --- lib/exceptions.c | 12 ++++++++---- lib/fonctions.c | 52 ++++++++++++++++++++++++++++++++++++++++------------ lib/hash.c | 3 +++ lib/interface.c | 33 +++++++++++++++++++++++++++++---- lib/numbers.c | 2 +- lib/parser.c | 6 +----- lib/pile.c | 42 ++++++++++++++++++++---------------------- lib/polynom.c | 21 +++++++++++++++------ lib/scalaires.c | 16 ++++++++++++++++ 9 files changed, 133 insertions(+), 54 deletions(-) (limited to 'lib') diff --git a/lib/exceptions.c b/lib/exceptions.c index 89d15c4..b19df9b 100644 --- a/lib/exceptions.c +++ b/lib/exceptions.c @@ -20,6 +20,8 @@ char *contexts[128]; int clevel = 0; int global_error = 0; +/* Les fonctions strdup et malloc sont réécrites ici afin de simplifier la vie en cas d'erreur. */ + char *Estrdup(char *o) { char *r; @@ -48,6 +50,8 @@ void *Emalloc(size_t s) return r; } +/* Les routines de manipulation de la pile de contexte d'erreurs */ + void pushcontext(char *c) { if (clevel == 128) { @@ -82,20 +86,20 @@ void exception(int level, char *msg) int i; switch (level) { case 1: - fprintf(stderr, "Error detected. Showing context.\n"); + fprintf(stderr, _("Non-fatal error detected. Showing context.\n")); for (i = 0; i < clevel; i++) { fprintf(stderr, " (%i) - %s\n", i, contexts[i]); } - fprintf(stderr, " Error description: %s\n", msg); + fprintf(stderr, _(" Error description: %s\n"), msg); flush_pile(); global_error = 1; break; default: - fprintf(stderr, "Error detected. Showing context.\n"); + fprintf(stderr, _("Fatal error detected. Showing context.\n")); for (i = 0; i < clevel; i++) { fprintf(stderr, " (%i) - %s\n", i, contexts[i]); } - fprintf(stderr, " Error description: %s\n", msg); + fprintf(stderr, _(" Error description: %s\n"), msg); clearterm(); exit(1); break; diff --git a/lib/fonctions.c b/lib/fonctions.c index eca44cb..2d25eea 100644 --- a/lib/fonctions.c +++ b/lib/fonctions.c @@ -19,7 +19,7 @@ #define _(x) x #endif - +/* Nous allons utiliser des pointeurs sur des fonctions. Voici donc les typedefs pour notre structure... */ typedef void (*func_name)(polynome arg1, polynome arg2, polynome arg3); typedef struct func_t { @@ -28,6 +28,7 @@ typedef struct func_t { int arite; } func_t; +/* ... et la structure elle-même */ static func_t func_table[] = { { deriv, "deriv", 1, }, @@ -38,9 +39,13 @@ static func_t func_table[] = { { setdisplay, "setdisplay", 1 }, { reinit, "reinit", 0 }, { exit_call, "exit", 0 }, + { setsmartprint, "setsmartprint", 1 }, { NULL, NULL, -1 } }; + +/* On cherche simplement la routine a appeler parmi la table des fonctions */ + void appel_fonction(char *nom, int arite, polynome p1, polynome p2, polynome p3) { int i=0; @@ -60,9 +65,10 @@ void appel_fonction(char *nom, int arite, polynome p1, polynome p2, polynome p3) } else { exception(1,_("appel_fonction: non-existent function")); } +} -} +/* Fonction de dérivation - rajoute le résultat sur la pile. */ void deriv(polynome p1, polynome p2, polynome p3) { @@ -71,14 +77,14 @@ void deriv(polynome p1, polynome p2, polynome p3) while (p1) { if (p1->degre) { t=ply_constr(rat_constr((p1->coef.num)*(p1->degre), p1->coef.denom), (p1->degre-1)); - if (t) { - if (resultat) { - temp->suiv = t; - temp = t; - } else { - resultat = t; - temp = t; - } + if (t) { + if (resultat) { + temp->suiv = t; + temp = t; + } else { + resultat = t; + temp = t; + } } } p1=p1->suiv; @@ -86,15 +92,19 @@ void deriv(polynome p1, polynome p2, polynome p3) push_pile_poly(resultat); } + +/* Fonction paresseuse */ + void derivn(polynome p1, polynome p2, polynome p3) { pile_elem temp; int i; if (p1) { if ((p1->degre==0) && (p1->coef.num>0) && (p1->coef.denom==1)) { - push_pile_poly(p2); + push_pile_poly(NULL); for(i=0; icoef.num; i++) { - temp=pop_pile(1); + temp = pop_pile(1); + ply_destruct(temp.poly); deriv(temp.poly, NULL, NULL); } } else { @@ -105,6 +115,9 @@ void derivn(polynome p1, polynome p2, polynome p3) } } + +/* Intégration d'un polynome */ + void integ(polynome p1, polynome p2, polynome p3) { polynome resultat = NULL, temp = NULL, t; @@ -126,6 +139,8 @@ void integ(polynome p1, polynome p2, polynome p3) push_pile_poly(resultat); } +/* Quelques fonctions explicites... */ + void printvars(polynome p1, polynome p2, polynome p3) { AfficheTableau(variables); @@ -142,6 +157,7 @@ void help(polynome p1, polynome p2, polynome p3) ". setdisplay(n); set integer display format\n" "\tn=1: DECIMAL, n=2: HEXA\n" "\tn=3: OCTAL, n=4: FLOAT\n" + ". smartprint(bool); toggle smart print of polynoms\n" ". reinit(); clear all variables\n" ". exit(); end program\n")); } @@ -184,3 +200,15 @@ void exit_call(polynome p1, polynome p2, polynome p3) { quit = 1; } + +void setsmartprint(polynome p1, polynome p2, polynome p3) { + if (p1) { + if ((!p1->degre)) { + smartprint = p1->coef.num; + } else { + exception(1, _("setsmartprint: invalid arg")); + } + } else { + smartprint = 0; + } +} diff --git a/lib/hash.c b/lib/hash.c index f1cc597..5009611 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -16,6 +16,9 @@ #define _(x) x #endif +/* L'ensemble de ce code source nous sert à implémenter une table de hachage qui nous sera utile + pour le stockage des variables du programme. C'est juste histoire d'aller un peu plus vite qu'une + simple liste chaînée. */ static char *CHAINEHACHAGE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"; diff --git a/lib/interface.c b/lib/interface.c index f698318..3a3c6fc 100644 --- a/lib/interface.c +++ b/lib/interface.c @@ -1,5 +1,6 @@ #include #include +#include #include "config.h" #include "interface.h" #include "terminal.h" @@ -9,6 +10,11 @@ int quit; +char * ancien = NULL; + +/* Ces deux fonctions nous servent à insérer ou supprimer un caractère dans une chaîne. Utile pour l'utilisation des +touches backspace, suppr et insert */ + void supprime(char * ch) { for (; *ch; ch++) { *ch = *(ch + 1); @@ -26,6 +32,9 @@ void inserer(char * ch, char c) { *ch = c; } +/* La boucle de l'interface. Même si elle a l'air longue, elle ne fait que tester les différents cas +en fonction des touches enfoncées. */ + void ifloop(void) { int cread, i, insert = 0; int gotesc = 0; @@ -44,9 +53,6 @@ void ifloop(void) { cread = fgetc(input); switch (cread) { case 49: /* Home */ - for (i = 0; i < position; i++) { - printf("\010"); - } position = 0; break; case 50: /* Insert */ @@ -72,6 +78,23 @@ void ifloop(void) { break; } break; + case 79: + cread = fgetc(input); + switch (cread) { + case 82: /* F3 */ + for (i = 0; i < position; i++) { + printf("\010"); + } + strcpy(buffer, ancien); + position = strlen(buffer); + printf("%s", buffer); + break; + default: + gotesc = 0; + break; + + } + break; default: gotesc = 0; break; @@ -98,6 +121,8 @@ void ifloop(void) { case 10: /* Entrée */ printf("\n"); clearterm(); + if (ancien) free(ancien); + ancien = Estrdup(buffer); parse_line(buffer); if (quit) break; initterm(); @@ -124,7 +149,7 @@ void ifloop(void) { printf("\010"); } break; - default: + default: /* Tout caractère autre, on le rajoute à la position en cours */ if (insert) { inserer(&(buffer[position]), cread); printf("%s", &(buffer[position])); diff --git a/lib/numbers.c b/lib/numbers.c index 7d0c64a..100cabd 100644 --- a/lib/numbers.c +++ b/lib/numbers.c @@ -73,7 +73,7 @@ int char_to_number(char *st, int *valid) rationnel char_to_rat(char *st, int *valid) -{ /* cette fonction tente de traduire une chaine en flottant */ +{ /* cette fonction tente de traduire une chaine en rationnel */ int dotnum = 0, deci = 1, temp = 0; while (*st) { diff --git a/lib/parser.c b/lib/parser.c index 529516b..74a7b71 100644 --- a/lib/parser.c +++ b/lib/parser.c @@ -3,6 +3,7 @@ * Interpreteur de ligne de commande * */ + #include #include #ifdef HAVE_CONFIG_H @@ -45,9 +46,6 @@ static operator_t operators[] = { {255, -1, -1} }; - - - /* Fonction interne: convertit un operateur en sa structure */ static operator_t get_op(op_t op) @@ -243,8 +241,6 @@ void parse_line(char *line) op = pop_op(); if (((op & 127) == '(')) break; - if (((op & 127) == '[')) - exception(1, _("Parse error: enclosure mismatch")); act_pile(get_func(op)); } if (global_error) break; diff --git a/lib/pile.c b/lib/pile.c index dd43a6e..11f1327 100644 --- a/lib/pile.c +++ b/lib/pile.c @@ -18,8 +18,10 @@ pile_elem result_pile[PILE_MAX]; unsigned int pile_ptr = 0; unsigned int result_pile_ptr = 0; -/* fonctions basiques sur la pile d operandes */ +/* Fonctions basiques sur la pile d'opérandes. Elle seront appelées par le parser. */ +/* La fonction push_pile est générique. Le parser lui transmet une chaîne de caractères, et cette +fonction va tenter de la convertir en ce qui lui semble le mieux pour empiler */ void push_pile(char *st) { int valid1, valid2, valid3; @@ -35,23 +37,23 @@ void push_pile(char *st) r_number = char_to_rat(st, &valid2); valid3 = is_mute(st); poly = (polynome) NomVarToVar(st, variables, &valid4); - if (valid1) { /* il s agit d un entier */ + if (valid1) { /* il s'agit d'un entier */ pushcontext(_("it's an integer")); push_pile_poly(ply_constr(rat_constr(i_number, 1), 0)); popcontext(); - } else if (valid2) { /* il s agit d un flottant */ + } else if (valid2) { /* il s'agit d'un flottant */ pushcontext(_("it's a float")); push_pile_poly(ply_constr(r_number, 0)); popcontext(); - } else if (valid3) { /* il s agit de x */ + } else if (valid3) { /* il s'agit de x */ pushcontext(_("it's X")); push_pile_poly(ply_constr(rat_constr(1, 1), 1)); popcontext(); - } else if (valid4) { /* il s agit d une variable */ + } else if (valid4) { /* il s'agit d'une variable */ pushcontext(_("it's a variable")); push_pile_poly(ply_copy(poly)); popcontext(); - } else { /* il s agit d un nom */ + } else { /* il s'agit d'un nom */ pushcontext(_("it's a name")); if (*st == '\'') { st++; @@ -61,14 +63,12 @@ void push_pile(char *st) popcontext(); } popcontext(); - - #ifdef DEBUG - fprintf(stderr, "exiting push_pile\n"); #endif } +/* Fonctions "atomiques" appelées par push_pile() */ void push_pile_poly(polynome poly) { @@ -108,6 +108,8 @@ void push_pile_string(char *st) } +/* Dépilement */ + pile_elem pop_pile(unsigned int count) { char buf[50]; @@ -121,6 +123,8 @@ pile_elem pop_pile(unsigned int count) return pile[pile_ptr]; } +/* Vidage (appelée en cas d'erreur) */ + void flush_pile(void) { int i; @@ -144,8 +148,8 @@ void flush_pile(void) -/* fonctions basiques sur la pile de resultats */ - +/* Fonctions basiques sur la pile de resultats. Grâce à cette pile résultat, nous pouvons passer un résultat +à l'interface, dès que le parser aura terminé son travail. */ void move_to_resultat_pile(void) { pile_elem temp; @@ -189,7 +193,6 @@ char * pop_resultat(void) return result; } - polynome return_last(int *valid) { if (!result_pile_ptr) { @@ -202,12 +205,12 @@ polynome return_last(int *valid) } - int has_resultat(void) { return (result_pile_ptr ? 1 : 0); } -/* fonctions avancees sur la pile d operandes */ +/* Fonctions avancées sur la pile d'opérandes. Nous allons surtout manipuler les opérandes de la pile, à l'aide +des opérateurs que le parser nous enverra. */ char *affichage_level_1(void) { @@ -223,7 +226,6 @@ char *affichage_level_1(void) break; case T_INT: result = (char *) Emalloc(11 * sizeof(char)); - sprintf(result, "%10d", pile[pile_ptr - 1].val); break; } @@ -237,7 +239,7 @@ int is_mute(char *st) return !(strcmp(st, mute)); } - +/* Cette fonction est appelée par le parser, et est donc un énorme switch qui va tester l'opérateur passé en paramètre */ void act_pile(int func) { pile_elem operande1, operande2; @@ -423,11 +425,7 @@ void act_pile(int func) exception(1, _("act_pile: OP_FUNC_CALL need only one argument for a polynom evaluation")); } if (operande[0].poly->degre == 0) { - push_pile_poly(ply_constr - (rat_constr_from_double - (ply_valuation - (operande2.poly, rat_to_double(operande[0].poly->coef))), - 0)); + push_pile_poly(ply_constr(ply_valuation(operande2.poly, operande[0].poly->coef), 0)); if (operande[0].poly) ply_destruct(operande[0].poly); ply_destruct(operande2.poly); @@ -453,7 +451,7 @@ void act_pile(int func) popcontext(); } - +/* Fonction de déboguage uniquement */ void affichage_pile(void) { int i; diff --git a/lib/polynom.c b/lib/polynom.c index b502849..e2e88d3 100644 --- a/lib/polynom.c +++ b/lib/polynom.c @@ -19,6 +19,7 @@ int smartprint = 1; +/* Les fonctions de base pour la construction et la destruction de polynomes */ polynome ply_constr(rationnel coef, int degre) { /* constructeur monome */ polynome temp; @@ -69,7 +70,9 @@ polynome ply_copy(polynome poly) } - +/* Voici toutes les fonctions de manipulation de polynôme. La fonction d'addition est la plus importante +puisqu'elle nous sert à construire un polynome entier à partir de monomes. Sa structure est comparable à celle +de l'opération 'fusion' dans le cas du tri fusion */ polynome ply_addition(polynome poly1, polynome poly2) { /* addition de deux polynomes */ @@ -129,6 +132,7 @@ polynome ply_addition(polynome poly1, polynome poly2) return resultat; } +/* Nous avons choisi de réécrire cette fonction entièrement, plutôt que de bricoler à partir de la fonction addition */ polynome ply_soustraction(polynome poly1, polynome poly2) { /* soustraction de deux polynomes */ @@ -188,7 +192,7 @@ polynome ply_soustraction(polynome poly1, polynome poly2) return resultat; } - +/* La fonction multiplication se base sur la fonction addition, suivant les mathématiques classiques */ polynome ply_multiplication(polynome poly1, polynome poly2) { /* multiplication de deux polynomes */ polynome temp = NULL, t, resultat = NULL, r, tempresult = NULL, poly2init; @@ -220,6 +224,11 @@ polynome ply_multiplication(polynome poly1, polynome poly2) return resultat; } + +/* L'algorithme pour la division et le modulo est le même. Seul le return change. En effet, pour faire le calcul, nous +utilisons la méthode simple vue en cours de mathématiques, qui consiste à poser la division sur une feuille et à effectuer +une série de multiplications élémentaires et de soustractions. Nous obtenons donc le quotient ET le reste. */ + polynome ply_division(polynome dividende, polynome diviseur) { /* division de deux polynomes */ polynome interdividende = ply_copy(dividende), interdiviseur = NULL, inter = NULL, reste = dividende, resultat = NULL, r = NULL; @@ -323,12 +332,12 @@ polynome ply_exposant(polynome poly, unsigned int exp) } -double ply_valuation(polynome poly, double point) -{ /* valuation d'un polynome en un point */ - double result = 0; +rationnel ply_valuation(polynome poly, rationnel point) +{ /* évaluation d'un polynome en un point */ + rationnel result = rat_constr_zero(); while (poly) { - result += rat_to_double(poly->coef) * pow(point, (poly->degre)); + result = rat_addition(result, rat_multiplication(poly->coef, rat_pow(point, poly->degre))); poly = poly->suiv; } return result; diff --git a/lib/scalaires.c b/lib/scalaires.c index 5dd6bb1..eb7b7c6 100644 --- a/lib/scalaires.c +++ b/lib/scalaires.c @@ -13,9 +13,12 @@ #define _(x) x #endif +/* Cette précision est utilisée dans le cas où nous devons convertir un double en rationnel */ #define PRECISION 1E6 typedisplay display; +/* Fonction interne uniquement */ + static unsigned long long pgcd(unsigned long long a, unsigned long long b) { if (a < b) @@ -113,6 +116,19 @@ rationnel rat_division(rationnel rat1, rationnel rat2) } +/* On choisit délibérément de faire une puissance 'lente' pour éviter de faire des overflow +trop facilement */ + +rationnel rat_pow(rationnel rat, unsigned int p) +{ /* puissance */ + for (; p; p--) { + rat = rat_multiplication(rat, rat); + } + return rat; +} + +/* On convertit un rationnel en une chaîne. Le booléen first indique si on le rationnel devra être placé en début de chaîne (pour +les signes) */ char *rat_to_string(rationnel rat, int first) { -- cgit v1.2.3