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.
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.
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.
20 # ======================================================================
24 def __init__(self,pere):
26 pere.l_objets.append(self)
28 def set_text(self,texte):
31 def append_text(self,texte):
33 Ajoute texte à self.texte en mettant un retour chariot à la fin de texte
36 self.texte = self.texte +texte
38 class COMMENTAIRE(ENTITE_JDC):
42 Retourne une chaîne de caractères représentants self
43 sous une forme interprétable par EFICAS
45 s='COMMENTAIRE("""'+self.texte+'""")\n\n'
48 def append_text(self,texte):
50 Ajoute texte à self.texte en enlevant le # initial
54 self.texte = self.texte+texte[1:]
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
60 class COMMANDE(ENTITE_JDC):
66 return self.texte+'\n'
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
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')
78 for ligne in l_lignes:
79 ligne = string.split(ligne,'#')[0]
80 nb = nb + (string.count(ligne,'(')-string.count(ligne,')'))
83 class AFFECTATION(ENTITE_JDC):
85 def append_text(self,texte):
87 Ajoute texte à self.texte en enlevant tout retour chariot et tout point virgule
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
95 Retourne une expression de l'affectation compréhensible par ACCAS
96 et exploitable par EFICAS
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'
104 class COMMANDE_COMMENTARISEE(ENTITE_JDC):
106 def append_text(self,texte):
108 Ajoute texte à self.texte en enlevant les doubles commentaires
110 texte = string.strip(texte)
111 texte = string.strip(texte[2:])
112 self.texte = self.texte+(len(self.texte)>0)*'\n'+texte
116 Retourne une expression de la commande commentarisée compréhensible par ACCAS
117 et exploitable par EFICAS
119 return "COMMANDE_COMM(texte='''"+self.texte+"''')\n"
121 class AFFECTATION_EVAL(ENTITE_JDC):
123 def append_text(self,texte):
125 Ajoute texte à self.texte en enlevant tout retour chariot
127 if texte[-1] == '\n' : texte = texte[1:-1]
128 self.texte = self.texte+texte
132 Retourne une expression du paramètre EVAL compréhensible par ACCAS
133 et exploitable par EFICAS
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'
141 class PARSEUR_PYTHON:
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
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]+')
153 def __init__(self,texte):
157 def is_affectation(self,texte):
159 Méthode booléenne qui retourne 1 si le texte est celui d'une affectation dans un jeu de commandes
162 if '=' not in texte : return 0
163 if self.pattern_commande.match(texte):
164 # cas d'une procédure ...
166 amont,aval = string.split(texte,'=',1)
167 aval = string.strip(aval)
168 if self.pattern_commande.match(aval):
173 def is_eval(self,texte):
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
178 if '=' not in texte : return 0
179 if self.pattern_commande.match(texte):
180 # cas d'une procédure ...
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):
190 def is_commande(self,texte):
192 Méthode booléenne qui retourne 1 si le texte est celui d'une commande dans un jeu de commandes
195 if self.pattern_commande.match(texte):
196 # cas d'une procédure ...
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):
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").
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
222 for ligne in l_lignes :
224 if string.strip(ligne) == '':
225 # il s'agit d'un saut de ligne
229 liste = string.split(ligne,'##',1)
231 # on a trouvé un double commentaire dans la ligne
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)
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
254 # on a un double commentaire en fin de ligne
255 # --> pour l'instant on ne fait rien
257 new_ligne = string.split(ligne,'#')[0] # on enlève toute la partie commentaire de la ligne
258 new_ligne = string.strip(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)
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)
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
284 # il peut s'agir d'une commande ou d'une affectation ...
285 # ou de la poursuite d'une affectation !!!!!
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):
294 affectation_courante = AFFECTATION(self)
295 affectation_courante.append_text(ligne)
296 elif self.is_commande(new_ligne):
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
305 #--> poursuite d'une affectation
306 affectation_courante.append_text(ligne)
311 Retourne le texte issu de l'analyse
313 if not self.l_objets : self.analyse()
315 for obj in self.l_objets:
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()