Salome HOME
PN pour notation scientifique
[tools/eficas.git] / convert / parseur_python.py
1 # -*- coding: utf-8 -*-
2 #            CONFIGURATION MANAGEMENT OF EDF VERSION
3 # ======================================================================
4 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
5 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
6 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
7 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
8 # (AT YOUR OPTION) ANY LATER VERSION.
9 #
10 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
11 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
12 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
13 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
14 #
15 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
16 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
17 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
18 #
19 #
20 # ======================================================================
21 import sys,string,re
22
23 class ENTITE_JDC :
24     def __init__(self,pere):
25         self.texte = ''
26         pere.l_objets.append(self)
27
28     def set_text(self,texte):
29         self.texte = texte
30
31     def append_text(self,texte):
32         """
33         Ajoute texte à self.texte en mettant un retour chariot à la fin de texte
34         """
35         texte = texte+'\n'
36         self.texte = self.texte +texte
37
38 class COMMENTAIRE(ENTITE_JDC):
39
40     def __str__(self):
41         """
42         Retourne une chaîne de caractères représentants self
43         sous une forme interprétable par EFICAS
44         """
45         s='COMMENTAIRE("""'+self.texte+'""")\n\n'
46         return s
47
48     def append_text(self,texte):
49         """
50         Ajoute texte à self.texte en enlevant le # initial
51         """
52         texte = texte+'\n'
53         if texte[0] == '#':
54             self.texte = self.texte+texte[1:]
55         else:
56             # le dièse n'est pas sur le premier caractère
57             amont,aval = string.split(texte,'#',1) # on découpe suivant la première occurrence de #
58             self.texte = self.texte +amont + aval
59         
60 class COMMANDE(ENTITE_JDC):
61
62     def __str__(self):
63         """
64         Retourne self.texte
65         """
66         return self.texte+'\n'
67         
68     def get_nb_par(self):
69         """
70         Retourne la différence entre le nombre de parenthèses ouvrantes
71         et le nombre de parenthèses fermantes présentes dans self.texte
72         Peut donc retourner un entier négatif
73         """
74         # faire attention aux commentaires contenus dans self.texte
75         # qui peuvent eux-mêmes contenir des parenthèses !!!!
76         l_lignes = string.split(self.texte,'\n')
77         nb = 0
78         for ligne in l_lignes:
79             ligne = string.split(ligne,'#')[0]
80             nb = nb + (string.count(ligne,'(')-string.count(ligne,')'))
81         return nb
82
83 class AFFECTATION(ENTITE_JDC):
84
85     def append_text(self,texte):
86         """
87         Ajoute texte à self.texte en enlevant tout retour chariot et tout point virgule
88         """
89         if texte[-1] == '\n' : texte = string.strip(texte[0:-1])\r
90         if texte[-1] == ';' : texte = string.strip(texte[0:-1])
91         self.texte = self.texte+texte
92         
93     def __str__(self):
94         """
95         Retourne une expression de l'affectation compréhensible par ACCAS
96         et exploitable par EFICAS
97         """
98         nom,valeur = string.split(self.texte,'=',1)
99         nom = string.strip(nom)
100         if valeur[-1] == '\n': valeur = valeur[:-1]
101         valeur = string.strip(valeur)
102         ## traitement des "
103         if valeur[0]=='"':
104            valeur=valeur[1:-1]
105         if valeur[-1]=='"':
106            valeur=valeur[0:-2]
107
108         return nom+' = PARAMETRE(nom=\''+nom+'\',valeur="'+valeur+'")\n\n'
109
110 class COMMANDE_COMMENTARISEE(ENTITE_JDC):
111
112     def append_text(self,texte):
113         """
114         Ajoute texte à self.texte en enlevant les doubles commentaires
115         """
116         texte = string.strip(texte)
117         texte = string.strip(texte[2:])
118         self.texte = self.texte+(len(self.texte)>0)*'\n'+texte
119
120     def __str__(self):
121         """
122         Retourne une expression de la commande commentarisée compréhensible par ACCAS
123         et exploitable par EFICAS
124         """
125         return "COMMANDE_COMM(texte='''"+self.texte+"''')\n"
126
127 class AFFECTATION_EVAL(ENTITE_JDC):
128
129     def append_text(self,texte):
130         """
131         Ajoute texte à self.texte en enlevant tout retour chariot
132         """
133         if texte[-1] == '\n' : texte = texte[1:-1]
134         self.texte = self.texte+texte
135         
136     def __str__(self):
137         """
138         Retourne une expression du paramètre EVAL compréhensible par ACCAS
139         et exploitable par EFICAS
140         """
141         nom,valeur = string.split(self.texte,'=',1)
142         nom = string.strip(nom)
143         if valeur[-1] == '\n': valeur = valeur[:-1]
144         valeur = string.strip(valeur)
145         return nom+' = PARAMETRE_EVAL(nom=\''+nom+'\',valeur=\''+valeur+'\')\n\n'
146         
147 class PARSEUR_PYTHON:
148     """
149     Cette classe sert à générer un objet PARSEUR_PYTHON qui réalise l'analyse d'un texte 
150     représentant un JDC Python en distinguant :
151       - les commentaires inter commandes
152       - les affectations
153       - les commandes
154     """
155     pattern_commande   = re.compile(r'^([A-Z][A-Z0-9_]+)([ \t\r\f\v]*)\(([\w\W]*)')
156     pattern_eval       = re.compile(r'^(EVAL)([ \t\r\f\v]*)\(([\w\W]*)')
157     pattern_ligne_vide = re.compile(r'^[\t\r\f\v\n]+')
158     
159     def __init__(self,texte):
160         self.texte = texte
161         self.l_objets=None
162         self.appli=None
163
164     def is_affectation(self,texte):
165         """
166         Méthode booléenne qui retourne 1 si le texte est celui d'une affectation dans un jeu de commandes
167         Aster, 0 sinon
168         """
169         if '=' not in texte : return 0
170         if self.pattern_commande.match(texte):
171             # cas d'une procédure ...
172             return 0
173         amont,aval = string.split(texte,'=',1)
174         aval = string.strip(aval)
175         if self.pattern_commande.match(aval):
176             return 0
177         else:
178             return 1
179
180     def is_eval(self,texte):
181         """
182         Méthode booléenne qui retourne 1 si le texte est celui d'une affectation de type EVAL
183         dans un jeu de commandes Aster, 0 sinon
184         """
185         if '=' not in texte : return 0
186         if self.pattern_commande.match(texte):
187             # cas d'une procédure ...
188             return 0
189         amont,aval = string.split(texte,'=',1)
190         aval = string.strip(aval)
191         if not self.pattern_commande.match(aval) : return 0
192         if self.pattern_eval.match(aval):
193             return 1
194         else:
195             return 0
196             
197     def is_commande(self,texte):
198         """
199         Méthode booléenne qui retourne 1 si le texte est celui d'une commande dans un jeu de commandes
200         Aster, 0 sinon
201         """
202         if self.pattern_commande.match(texte):
203             # cas d'une procédure ...
204             return 1
205         # A ce stade il faut avoir un OPER ou une MACRO, bref un '=' !
206         if '=' not in texte : return 0
207         # on a un texte de la forme xxxx = yyyyy
208         # --> reste à analyser yyyy
209         amont,aval = string.split(texte,'=',1)
210         aval = string.strip(aval)
211         if self.pattern_commande.match(aval):
212             return 1
213         else:
214             return 0
215
216     def analyse(self):
217         """
218         Eclate la chaine self.texte en self.l_objets une liste lignes d'instructions
219         et de commentaires (parmi lesquels des instructions "commentarisées").
220         """
221         #AY##l_lignes = open(self.fichier,'r').readlines()
222         l_lignes = string.split(self.texte,'\n')
223         commentaire_courant             = None
224         commande_courante               = None
225         affectation_courante            = None
226         commande_commentarisee_courante = None
227         self.l_objets = []
228         cpt = 0
229         for ligne in l_lignes :
230             cpt = cpt+1
231             if string.strip(ligne) == '':
232                 # il s'agit d'un saut de ligne
233                 # --> on l'ignore
234                 continue
235             else:
236                 liste = string.split(ligne,'##',1)
237                 if len(liste) > 1:
238                     # on a trouvé un double commentaire dans la ligne
239                     before,after = liste
240                     if string.strip(before) == '':
241                         # il s'agit d'une commande commentarisée
242                         if commentaire_courant :
243                             commentaire_courant = None
244                         elif commande_courante :
245                             # on a un objet commentarisé à l'intérieur d'une commande
246                             # --> non traité pour l'instant
247                             commande_courante.append_text(ligne)
248                         elif commande_commentarisee_courante :
249                             # commande_commentarisee en cours : on ajoute la ligne
250                             commande_commentarisee_courante.append_text(ligne)
251                         else:
252                             # on crée un objet commande_commentarisee_courante
253                             commande_commentarisee_courante = COMMANDE_COMMENTARISEE(self)
254                             commande_commentarisee_courante.append_text(ligne)
255                         # si la ligne courante se termine par un ';', on décide - par hypothèse et peut-être à tort - que
256                         # la commande commentarisée courante est terminée !!
257                         if re.search( '; *$', ligne ) != None :
258                             commande_commentarisee_courante = None
259                         continue
260                     else:
261                         # on a un double commentaire en fin de ligne
262                         # --> pour l'instant on ne fait rien
263                         pass
264                 new_ligne = string.split(ligne,'#')[0] # on enlève toute la partie commentaire de la ligne
265                 new_ligne = string.strip(new_ligne)
266                 if new_ligne == '' :
267                     # la ligne n'est qu'un commentaire précédé d'éventuels blancs
268                     if commande_courante :
269                         # il s'agit d'un commentaire à l'intérieur d'une commande --> on ne fait rien
270                         commande_courante.append_text(ligne)
271                     elif commentaire_courant :
272                         # il s'agit de la nième ligne d'un commentaire entre deux commandes
273                         # --> on ajoute cette ligne au commentaire courant
274                         commentaire_courant.append_text(ligne)
275                     else :
276                         # il s'agit d'un commentaire entre deux commandes
277                         # --> on le crée et il devient le commentaire courant
278                         commentaire_courant = COMMENTAIRE(self)
279                         commentaire_courant.append_text(ligne)
280                 else:
281                     # la ligne contient des données autre qu'un éventuel commentaire
282                     if commentaire_courant :
283                         # on clôt un éventuel commentaire courant
284                         commentaire_courant = None
285                     if commande_courante :
286                         commande_courante.append_text(ligne)
287                         if commande_courante.get_nb_par() == 0:
288                             # la commande courante est terminée (autant de parenthèses fermantes qu'ouvrantes)
289                             try :
290                                self.analyse_reel(commande_courante.texte)
291                             except :
292                                pass
293                             commande_courante = None
294                     else:
295                         # il peut s'agir d'une commande ou d'une affectation ...
296                         # ou de la poursuite d'une affectation !!!!!
297                         # ou d'un EVAL !!!
298                         if self.is_eval(new_ligne):
299                             # --> affectation de type EVAL
300                             if affectation_courante : affectation_courante = None
301                             affectation = AFFECTATION_EVAL(self)
302                             affectation.append_text(ligne)
303                         elif self.is_affectation(new_ligne):
304                             # --> affectation
305                             affectation_courante = AFFECTATION(self)
306                             affectation_courante.append_text(ligne)
307                         elif self.is_commande(new_ligne):
308                             # --> commande
309                             commande_courante = COMMANDE(self)
310                             commande_courante.append_text(ligne)
311                             affectation_courante = None
312                             if commande_courante.get_nb_par() == 0:
313                                 # la commande courante est terminée (autant de parenthèses fermantes qu'ouvrantes)
314                                 self.analyse_reel(commande_courante.texte)
315                                 commande_courante = None
316                         else:
317                             #--> poursuite d'une affectation
318                             # PN -- pour Empecher une erreur pas propre
319                             if affectation_courante != None :
320                                affectation_courante.append_text(ligne)
321                             #affectation_courante.append_text(ligne)
322
323
324     def enleve (self,texte) :
325         i=0
326         chaine=""
327         while (i<len(texte)):
328           if (texte[i] == " " or texte[i] == "\n" or texte[i] == "\t") :
329              i=i+1
330           else :
331              chaine=chaine+texte[i]
332              i=i+1
333         return chaine 
334             
335     def construit_genea(self,texte):
336         indiceC=0
337         mot=""
338         dict_reel_concept={}
339
340         # traitement pour chaque caractere
341         while (indiceC < len(texte)): 
342            c=texte[indiceC]
343            if ( c == "," or c == "(" or c == ")"):
344               mot=""
345            elif ( c== "="):
346               valeur=""
347               nouvelindice=indiceC+1
348               if texte[nouvelindice] != "(":
349                  while ( texte[nouvelindice] != ","):
350                     valeur=valeur+texte[nouvelindice]
351                     nouvelindice=nouvelindice+1
352                     if nouvelindice == len(texte) :
353                         nouvelindice=nouvelindice -1
354                         break
355                  if mot in self.appli.liste_simp_reel:
356                     if valeur[0] != "'":
357                        try :
358                          clef=eval(valeur)
359                          if str(clef) != str(valeur) :
360                             dict_reel_concept[clef]=valeur
361                        except :
362                          pass
363                  mot=""
364                  indiceC=nouvelindice
365               else:
366                # s agit -il d un tuple 
367                  if texte[nouvelindice+1] != "(":
368                     tuple=False
369                     while ( texte[nouvelindice] != "="):
370                        if texte[nouvelindice] == ")" :
371                           tuple=True
372                           break
373                        else :
374                           nouvelindice=nouvelindice+1
375                           if nouvelindice == len(texte) :
376                              nouvelindice=nouvelindice -1
377                              break
378                     if tuple :
379                        valeur=texte[indiceC+1:nouvelindice+1]
380                        indiceC=nouvelindice+1 
381                        if mot in self.appli.liste_simp_reel:
382                           valeur=valeur[1:-1]
383                           for val in valeur.split(',') :
384                           # Attention la derniere valeur est""
385                              try :
386                                 if val[0] != "'":
387                                   clef=eval(val)
388                                   if str(clef) != str(val) :
389                                      dict_reel_concept[clef]=val
390                              except :
391                                   pass
392                        mot=""
393                # ou de ( imbriqueés
394                  else :
395                     mot=""
396            else :
397               mot=mot+texte[indiceC]
398            indiceC=indiceC+1
399         # traitement du dernier inutile
400         # c est un ; 
401         return dict_reel_concept
402
403     def analyse_reel(self,commande) :
404         nomConcept=None
405         # On verifie qu on a bien un OPER
406         # et pas une MACRO
407         if commande.find("=") > commande.find("(") :
408            return
409         if commande.find("=") > 0:
410            epure1=self.enleve(commande)
411            nomConcept=epure1.split("=")[0]
412            index=epure1.find("=")
413            epure2=epure1[index+1:len(epure1)].replace("_F(","(")
414            dict_reel_concept=self.construit_genea(epure2)
415         if nomConcept !=None :
416            if len(dict_reel_concept) != 0:
417               self.appli.dict_reels[nomConcept]=dict_reel_concept
418
419     def get_texte(self,appli=None):
420         """
421         Retourne le texte issu de l'analyse
422         """
423         self.appli=appli
424         if not self.l_objets : self.analyse()
425         txt=''
426         for obj in self.l_objets:
427             txt = txt+str(obj)
428         return txt
429
430 if __name__ == "__main__" :
431     #fichier = 'D:/Eficas_dev/Tests/zzzz100a.comm'
432     fichier = 'U:/Eficas_dev/Tests/test_eval.comm'
433     texte = open(fichier,'r').read()
434     txt = PARSEUR_PYTHON(texte).get_texte()
435     print txt
436