Salome HOME
ajout pour accepter les accents sous python 2.3
[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         return nom+' = PARAMETRE(nom=\''+nom+'\',valeur="'+valeur+'")\n\n'
103
104 class COMMANDE_COMMENTARISEE(ENTITE_JDC):
105
106     def append_text(self,texte):
107         """
108         Ajoute texte à self.texte en enlevant les doubles commentaires
109         """
110         texte = string.strip(texte)
111         texte = string.strip(texte[2:])
112         self.texte = self.texte+(len(self.texte)>0)*'\n'+texte
113
114     def __str__(self):
115         """
116         Retourne une expression de la commande commentarisée compréhensible par ACCAS
117         et exploitable par EFICAS
118         """
119         return "COMMANDE_COMM(texte='''"+self.texte+"''')\n"
120
121 class AFFECTATION_EVAL(ENTITE_JDC):
122
123     def append_text(self,texte):
124         """
125         Ajoute texte à self.texte en enlevant tout retour chariot
126         """
127         if texte[-1] == '\n' : texte = texte[1:-1]
128         self.texte = self.texte+texte
129         
130     def __str__(self):
131         """
132         Retourne une expression du paramètre EVAL compréhensible par ACCAS
133         et exploitable par EFICAS
134         """
135         nom,valeur = string.split(self.texte,'=',1)
136         nom = string.strip(nom)
137         if valeur[-1] == '\n': valeur = valeur[:-1]
138         valeur = string.strip(valeur)
139         return nom+' = PARAMETRE_EVAL(nom=\''+nom+'\',valeur=\''+valeur+'\')\n\n'
140         
141 class PARSEUR_PYTHON:
142     """
143     Cette classe sert à générer un objet PARSEUR_PYTHON qui réalise l'analyse d'un texte 
144     représentant un JDC Python en distinguant :
145       - les commentaires inter commandes
146       - les affectations
147       - les commandes
148     """
149     pattern_commande   = re.compile(r'^([A-Z][A-Z0-9_]+)([ \t\r\f\v]*)\(([\w\W]*)')
150     pattern_eval       = re.compile(r'^(EVAL)([ \t\r\f\v]*)\(([\w\W]*)')
151     pattern_ligne_vide = re.compile(r'^[\t\r\f\v\n]+')
152     
153     def __init__(self,texte):
154         self.texte = texte
155         self.l_objets=None
156
157     def is_affectation(self,texte):
158         """
159         Méthode booléenne qui retourne 1 si le texte est celui d'une affectation dans un jeu de commandes
160         Aster, 0 sinon
161         """
162         if '=' not in texte : return 0
163         if self.pattern_commande.match(texte):
164             # cas d'une procédure ...
165             return 0
166         amont,aval = string.split(texte,'=',1)
167         aval = string.strip(aval)
168         if self.pattern_commande.match(aval):
169             return 0
170         else:
171             return 1
172
173     def is_eval(self,texte):
174         """
175         Méthode booléenne qui retourne 1 si le texte est celui d'une affectation de type EVAL
176         dans un jeu de commandes Aster, 0 sinon
177         """
178         if '=' not in texte : return 0
179         if self.pattern_commande.match(texte):
180             # cas d'une procédure ...
181             return 0
182         amont,aval = string.split(texte,'=',1)
183         aval = string.strip(aval)
184         if not self.pattern_commande.match(aval) : return 0
185         if self.pattern_eval.match(aval):
186             return 1
187         else:
188             return 0
189             
190     def is_commande(self,texte):
191         """
192         Méthode booléenne qui retourne 1 si le texte est celui d'une commande dans un jeu de commandes
193         Aster, 0 sinon
194         """
195         if self.pattern_commande.match(texte):
196             # cas d'une procédure ...
197             return 1
198         # A ce stade il faut avoir un OPER ou une MACRO, bref un '=' !
199         if '=' not in texte : return 0
200         # on a un texte de la forme xxxx = yyyyy
201         # --> reste à analyser yyyy
202         amont,aval = string.split(texte,'=',1)
203         aval = string.strip(aval)
204         if self.pattern_commande.match(aval):
205             return 1
206         else:
207             return 0
208
209     def analyse(self):
210         """
211         Eclate la chaine self.texte en self.l_objets une liste lignes d'instructions
212         et de commentaires (parmi lesquels des instructions "commentarisées").
213         """
214         #AY##l_lignes = open(self.fichier,'r').readlines()
215         l_lignes = string.split(self.texte,'\n')
216         commentaire_courant             = None
217         commande_courante               = None
218         affectation_courante            = None
219         commande_commentarisee_courante = None
220         self.l_objets = []
221         cpt = 0
222         for ligne in l_lignes :
223             cpt = cpt+1
224             if string.strip(ligne) == '':
225                 # il s'agit d'un saut de ligne
226                 # --> on l'ignore
227                 continue
228             else:
229                 liste = string.split(ligne,'##',1)
230                 if len(liste) > 1:
231                     # on a trouvé un double commentaire dans la ligne
232                     before,after = liste
233                     if string.strip(before) == '':
234                         # il s'agit d'une commande commentarisée
235                         if commentaire_courant :
236                             commentaire_courant = None
237                         elif commande_courante :
238                             # on a un objet commentarisé à l'intérieur d'une commande
239                             # --> non traité pour l'instant
240                             commande_courante.append_text(ligne)
241                         elif commande_commentarisee_courante :
242                             # commande_commentarisee en cours : on ajoute la ligne
243                             commande_commentarisee_courante.append_text(ligne)
244                         else:
245                             # on crée un objet commande_commentarisee_courante
246                             commande_commentarisee_courante = COMMANDE_COMMENTARISEE(self)
247                             commande_commentarisee_courante.append_text(ligne)
248                         # si la ligne courante se termine par un ';', on décide - par hypothèse et peut-être à tort - que
249                         # la commande commentarisée courante est terminée !!
250                         if re.search( '; *$', ligne ) != None :
251                             commande_commentarisee_courante = None
252                         continue
253                     else:
254                         # on a un double commentaire en fin de ligne
255                         # --> pour l'instant on ne fait rien
256                         pass
257                 new_ligne = string.split(ligne,'#')[0] # on enlève toute la partie commentaire de la ligne
258                 new_ligne = string.strip(new_ligne)
259                 if new_ligne == '' :
260                     # la ligne n'est qu'un commentaire précédé d'éventuels blancs
261                     if commande_courante :
262                         # il s'agit d'un commentaire à l'intérieur d'une commande --> on ne fait rien
263                         commande_courante.append_text(ligne)
264                     elif commentaire_courant :
265                         # il s'agit de la nième ligne d'un commentaire entre deux commandes
266                         # --> on ajoute cette ligne au commentaire courant
267                         commentaire_courant.append_text(ligne)
268                     else :
269                         # il s'agit d'un commentaire entre deux commandes
270                         # --> on le crée et il devient le commentaire courant
271                         commentaire_courant = COMMENTAIRE(self)
272                         commentaire_courant.append_text(ligne)
273                 else:
274                     # la ligne contient des données autre qu'un éventuel commentaire
275                     if commentaire_courant :
276                         # on clôt un éventuel commentaire courant
277                         commentaire_courant = None
278                     if commande_courante :
279                         commande_courante.append_text(ligne)
280                         if commande_courante.get_nb_par() == 0:
281                             # la commande courante est terminée (autant de parenthèses fermantes qu'ouvrantes)
282                             commande_courante = None
283                     else:
284                         # il peut s'agir d'une commande ou d'une affectation ...
285                         # ou de la poursuite d'une affectation !!!!!
286                         # ou d'un EVAL !!!
287                         if self.is_eval(new_ligne):
288                             # --> affectation de type EVAL
289                             if affectation_courante : affectation_courante = None
290                             affectation = AFFECTATION_EVAL(self)
291                             affectation.append_text(ligne)
292                         elif self.is_affectation(new_ligne):
293                             # --> affectation
294                             affectation_courante = AFFECTATION(self)
295                             affectation_courante.append_text(ligne)
296                         elif self.is_commande(new_ligne):
297                             # --> commande
298                             commande_courante = COMMANDE(self)
299                             commande_courante.append_text(ligne)
300                             affectation_courante = None
301                             if commande_courante.get_nb_par() == 0:
302                                 # la commande courante est terminée (autant de parenthèses fermantes qu'ouvrantes)
303                                 commande_courante = None
304                         else:
305                             #--> poursuite d'une affectation
306                             affectation_courante.append_text(ligne)
307
308
309     def get_texte(self):
310         """
311         Retourne le texte issu de l'analyse
312         """
313         if not self.l_objets : self.analyse()
314         txt=''
315         for obj in self.l_objets:
316             txt = txt+str(obj)
317         return txt
318
319 if __name__ == "__main__" :
320     #fichier = 'D:/Eficas_dev/Tests/zzzz100a.comm'
321     fichier = 'U:/Eficas_dev/Tests/test_eval.comm'
322     texte = open(fichier,'r').read()
323     txt = PARSEUR_PYTHON(texte).get_texte()
324     print txt
325