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