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