root/trunk/jps2ps/exp2rpn.pl

Revision 4, 10.4 kB (checked in by jms, 7 months ago)

Chargement de jps2ps dans le SVN.

  • Property svn:executable set to *
Line 
1 #!/usr/bin/perl
2 # ========================================================================
3 #                               exp2rpn
4 # ========================================================================
5 # Jean-Michel Sarlat                                  mercredi 26 mai 2000
6 # ========================================================================
7 # Ce script  Perl  convertit  l'expression  d'une  fonction  mathématique
8 # « simple » en  notation  polonaise inverse.
9 #
10 # mail : jm-sarlat@melusine.eu.org
11 # ========================================================================
12 # Copyright (c) 2000,2004 Jean-Michel Sarlat.  All rights reserved.
13 #
14 # This program is free software; you can redistribute it and/or modify
15 # it under the same terms as Perl itself.
16
17
18 package exp2rpn;
19
20 @signes          = ("+","-","*","/","^","(",")",",");
21 @operateurs      = ("","add","sub","mul","div","exp","idiv","mod");
22 @identificateurs = ("cos","sin","tan","cotan","ln","sh","ch","th","arccos",
23                     "arcsin","arctan","sqrt","Cos","Sin","Tan","Cotan","coTan",
24                     "Arccos","Arcsin","Arctan","Exp","sinh","cosh","tanh","cotanh",
25                     "fresnelC","fresnelS","argsinh","argcosh","argtanh","log","abs",
26                     "max","min","ceiling","floor","round","truncate","factorielle",
27                     "Anp","Cnp","binomiale","Poisson","Gauss","Gammaln","Bessel_j0",
28                     "Bessel_y0","Bessel_j1","Bessel_y1");
29 ## @identificateurs = ("cos","sin","tan","ln","sh","ch","th","arccos",
30 ##                    "arcsin","arctan","argsh","argch","argth","sqrt","abs");
31
32 local $old_e = "";
33 local $old_l = "";
34
35 sub new {
36     my $classe = shift;
37     my $self = {};
38     bless($self,$classe);
39    
40     $self->{expression} = shift;
41     $self->{expression} =~ s/\s+//g;
42     # Mise en réserve de l'expression en cas d'erreur.
43     $old_e = $self->{expression};       
44    
45     my $rc = shift; # Référence à la table des variables.
46     my $c = shift; # Référence à la table des constantes.
47     push(@$rc,@$c);
48
49     my $i = shift; # Référence à la table des fonctions.
50     my $ri = [@identificateurs];
51     push(@$ri, @$i);
52    
53     # Préparation de l'expression.
54     $self->{ligne} = &Prepare($self->{expression},$rc,$ri);
55     # Mise en réserve de la ligne.
56     $old_l = $self->{ligne};
57    
58     # Constitution de la table.
59
60     my $t = [split(/ /,$self->{ligne})];
61
62     # Contruction de la chaîne RPN.
63     $self->{rpn} = &Lecture($t,0,@$t-1,$rc,$ri);   
64     $self->{rpn} =~ s/^ //;
65    
66     return $self;
67 }
68
69 sub RPN {
70     my $self = shift;
71     return $self->{rpn};
72 }
73
74 sub EXP {
75     my $self = shift;
76     return $self->{expression};
77 }
78
79 sub DESTROY {
80     my $self = shift;
81     # print "L'expression $self->{expression} a vécu!\n";
82 }
83
84 #============================ Traitement des erreurs =====================
85 sub Erreur {
86     my ($e,$i) = @_;
87     my $j = 0;
88     if ($e == 1) {
89         print STDOUT "Erreur lexicale !\n";
90         my $lerreur = ""; my $j = 0;
91         for ($j=0;$j<$i;$j++) {
92             $lerreur = $lerreur."_";
93         }
94         $lerreur .= "^";
95         print STDOUT "$old_e\n";
96         print STDOUT $lerreur."\n";
97     }
98     if ($e == 2) {
99         print STDOUT "Erreur de syntaxe !\n";
100         print STDOUT "Votre expression : $old_e\n";
101         print STDOUT "Il manque un opérateur (+,-,*,/,^) ou une accolade!\n";
102     }
103     exit(1);
104 }
105 #============================ Traitement des erreurs =====================
106
107
108    
109 #=============================== Analyseur Lexical =======================
110 # Fonction :
111 #  Élimine les espaces superflus de la chaîne d'entrée et construit une
112 #  chaine où tous les éléments (signes, fonctions, constantes, nombres)
113 #  sont reconnus et séparés par un espace. Celle-ci est alors aisément
114 #  sécable. La procédure à invoquer est [Prepare].
115 #=========================================================================
116
117 # Lire un nombre dans le flot de caractères
118 sub LireNombre {
119     my($i,$c) = @_;
120     my $nombre = "";
121     while ($c->[$i] =~ /[0-9\.]/) {
122         $nombre = $nombre.$c->[$i];
123         $i++;
124     }
125     return($nombre,$i);
126 }
127
128 #Lire une chaîne de caractères alphabétiques dans le flot de caractères
129 sub LireChaine {
130     my ($i,$c) = @_;
131     my $chaine = "";
132     while ($c->[$i] =~ /[a-zA-Z]/) {
133         $chaine = $chaine.$c->[$i];
134         $i++;
135     }
136     return($chaine,$i);
137 }
138
139 # Lire un identificateur de fonction dans le flot de caractères
140 sub LireIdentificateur {
141     my($i,$c,$ri) = @_;
142     my ($chaine,$j) = LireChaine($i,$c);
143     my $identificateur = "";
144     if ($j != $i) {
145         foreach my $id (@$ri) {
146             if ($chaine eq $id) {
147                 $identificateur = $id;
148                 $i = $j;
149             }
150         }
151     }
152     return($identificateur,$i);
153 }
154
155 # Lire la référence à une constante dans le flot de caractères
156 sub LireConstante {
157     my ($i,$c,$rc) = @_;
158     my ($chaine,$j) = LireChaine($i,$c);
159     my $constante = "";
160     if ($j != $i) {
161         foreach my $const (@$rc) {
162             if ($chaine eq $const) {
163                 $constante = $const;
164                 $i = $j;
165             }
166         }
167     }
168     return($constante,$i);
169 }
170
171 # Lire un signe dans le flot de caractères
172 sub LireSigne {
173     my($i,$c) = @_;
174     my $flag = 0;
175     my $signe = "";
176     foreach my $s (@signes) {
177         if ($c->[$i] eq $s) {
178             $signe = $s;
179             $flag = 1;
180         }
181     }
182     return($signe,$i+$flag);
183 }
184
185 # Préparation de la chaîne <expression> : $l.
186 sub Prepare {
187     my($l,$rc,$ri) = @_;
188     my($r,$i,$ii,$signe,$identificateur,$constante,$nombre);
189     # Éclatement de la chaîne (tableau anonyme).
190     my $c = [split(//,$l)];
191     $ii = 0;
192     while ($ii < @$c) {
193         ($signe,$i) = LireSigne($ii,$c);
194         if ($ii == $i) {
195                 ($identificateur,$i) = LireIdentificateur($ii,$c,$ri);
196                 if ($ii == $i) {
197                         ($constante,$i) = LireConstante($ii,$c,$rc);
198                         if ($ii == $i) {
199                                 ($nombre,$i) = LireNombre($ii,$c);
200                                 if ($ii == $i) {
201                                         Erreur(1,$i); # Erreur lexicale !
202                                 } else {
203                                         $r =  $r." $nombre";
204                                         $ii = $i;
205                                 }
206                         } else {
207                                 $r = $r." $constante";
208                                 $ii = $i;
209                         }
210                 } else {
211                         $r = $r." $identificateur";
212                         $ii = $i;
213                 }
214         } else {
215             $r = $r." $signe";
216             $ii = $i;
217         }
218     }
219     $r =~ s/^ //;
220     return($r);
221 }
222 #=============================== Analyseur Lexical =======================
223
224
225 # Lecture d'un signe d'opérateur dans la table
226 sub LectureSigne {
227     my($t,$k) = @_;
228     if ($t->[$k] eq "+") {
229         return(1);
230     }
231     if ($t->[$k] eq "-") {
232         return(2);
233     }
234     if ($t->[$k] eq "*") {
235         return(3);
236     }
237     if ($t->[$k] eq "/") {
238         return(4);
239     }
240     if ($t->[$k] eq ",") {
241         return(0);
242     }
243     if ($t->[$k] eq "^") {
244         return(5);
245     }
246 }
247
248 # Détermine la nature d'un bloc
249 sub TestBloc {
250     my($t,$k,$rc,$ri) = @_;
251     # C'est une fonction, elle est normalement suivie de (
252     if (&EstFonction($t->[$k],$ri) == 1) {
253         return($k+2,0);
254     }
255     # C'est une accolade ouvrante
256     if (&EstAccoladeO($t->[$k]) == 1) {
257         return($k+1,0);
258     }
259     # C'est une constante
260     if (&EstConstante($t->[$k],$rc) == 1) {
261         return($k+1,1);
262     }
263     # C'est un nombre
264     if (&EstNombre($t->[$k]) == 1) {
265         return($k+1,1);
266     }
267 }
268
269 # Recherche la fin d'un bloc
270 sub FinBloc {
271     my ($t,$k,$rc,$ri) = @_;
272     my ($ii,$flag) = TestBloc($t,$k,$rc,$ri);
273     while ($flag <= 0) {
274         if ($ii >= @$t) {
275             Erreur(2,$k); # Erreur de syntaxe !
276         }
277         # C'est une accolade fermante
278         # On monte, vers la sortie !
279         if ($t->[$ii] eq ")") {
280             $flag = $flag +1;
281         }
282         # C'est une accolade ouvrante
283         # On descend
284         if ($t->[$ii] eq "(") {
285             $flag = $flag -1;
286         }
287         $ii++;
288     }
289     return($ii-1);
290 }
291
292 # Lecture d'une expression
293 sub Lecture {
294     my($t,$i,$j,$rc,$ri) = @_;
295     my($k,$c,$r0,$r1,$r2,$r3);
296     $r0 = "";
297     $r1 = "";
298     $r2 = "";
299     $r3 = "";
300     $k = $i;
301     $c = "";
302     while ($k <= $j) {
303         if ($t->[$k] eq "-") {
304             $r0 = " neg";
305             $k++;
306             $i++;
307         }
308         if ($t->[$k] eq "+") {
309             $k++;
310             $i++;
311         }
312         $k = FinBloc($t,$k,$rc,$ri);
313         $c = $c . &LectureBloc($t,$i,$k,$rc,$ri);
314         $k++;
315         $s = LectureSigne($t,$k);
316         if ($s <= 0) {
317             $c = $c.$r3.$r2.$r1.$r0;
318             $r0 = "";
319             $r1 = "";
320             $r2 = "";
321             $r3 = "";
322         } elsif ($s <= 2) {
323             $c = $c.$r3.$r2.$r0.$r1;
324             $r0 = "";
325             $r1 = " $operateurs[$s]";
326             $r2 = "";
327             $r3 = "";
328         } elsif ($s <= 4) {
329             $c = $c.$r3.$r2;
330             $r3 = "";
331             $r2 = " $operateurs[$s]";
332         } else {
333             $c = $c.$r3;
334             $r3 = " $operateurs[$s]";
335         }
336         $k++;
337         $i = $k;
338     }
339     return($c);
340 }
341
342 # Détermination si l'élément est une fonction
343 sub EstFonction {
344     my($el,$ri) = @_;
345     my $res = 0;
346     foreach my $elt (@$ri) {
347         if ($el eq $elt) {
348             $res = 1;
349         }
350     }
351     return($res);
352 }
353
354 # Détermination si l'élément est une constante
355 sub EstConstante {
356     my($el,$rc) = @_;
357     my $res = 0;
358     foreach my $elt (@$rc) {
359         if ($el eq $elt) {
360             $res = 1;
361         }
362     }
363     return($res);
364 }
365
366 # Détermination si l'élément est une accolade ouvrante
367 sub EstAccoladeO {
368     my($el) = @_;
369     my $res = 0;
370     if ($el eq "(") {
371         $res = 1;
372     }
373     return($res);
374 }
375
376 # Détermination si l'élément est un nombre
377 sub EstNombre {
378     my($el) = @_;
379     my $res = 0;
380     if ($el =~ /[0-9\.]+/) {
381         $res = 1;
382     }
383     return($res);
384 }
385
386 # Lecture d'un bloc : f ( ... ), ( ... ), nombre , x, constante
387 sub LectureBloc {
388     my($t,$i,$j,$rc,$ri) = @_;
389     if (EstFonction($t->[$i],$ri)) {
390         return  Lecture($t,$i+2,$j-1,$rc,$ri)." ".$t->[$i];
391     }
392     if (EstConstante($t->[$i],$rc)) {
393         return " ".$t->[$i];
394     }
395     if (EstAccoladeO($t->[$i])) {
396         return Lecture($t,$i+1,$j-1,$rc,$ri);
397     }
398     if (EstNombre($t->[$i])) {
399         return " ".$t->[$i];
400     }
401     return "";
402 }
403
404 package main;
405
406 use Getopt::Std;
407
408 getopts("v:c:f:");
409
410 sub PrepareChaineTable {
411     my $c = shift;
412     $c =~ s/\s+/ /g;
413     $c =~ s/^ //;
414     $c =~ s/ $//;
415     return $c;
416 }
417
418 my $constantes,$variables,$fonctions;
419
420
421 # Référence à la table des variables
422 if ($opt_v) {
423     $opt_v = PrepareChaineTable($opt_v);
424     $variables = [split(/ /,$opt_v)]
425 } else {
426     $variables = ["x"];
427 }
428
429 # Référence à la table des constantes
430 if ($opt_c) {
431     $opt_c = PrepareChaineTable($opt_c);
432     $constantes = [split(/ /,$opt_c)];
433 } else {
434     $constantes = ["e","pi"];
435 }
436
437 # Référence à la table des fonctions ajoutées
438 if ($opt_f) {
439     $opt_f = PrepareChaineTable($opt_f);
440     $fonctions = [split(/ /,$opt_f)];
441 } else {
442     $fonctions = [];
443 }
444    
445 my $exp = exp2rpn->new($ARGV[0],$variables,$constantes,$fonctions);
446
447 print STDOUT $exp->RPN(), "\n";
448
449 exit(0);
Note: See TracBrowser for help on using the browser.