Salome HOME
fin portage python 3
[tools/eficas.git] / convert / parseur_python.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2013   EDF R&D
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20 from __future__ import absolute_import
21 from __future__ import print_function
22 try :
23   from builtins import str
24   from builtins import range
25   from builtins import object
26 except :
27   pass
28 import sys,string,re
29 import traceback
30 from Extensions.i18n import tr
31 from six.moves import range
32
33 escapedQuotesRE = re.compile(r"(\\\\|\\\"|\\\')")
34 stringsAndCommentsRE =  \
35       re.compile(u"(\"\"\".*?\"\"\"|'''.*?'''|\"[^\"]*\"|\'[^\']*\'|#.*?\n)", re.DOTALL)
36 #stringsAndCommentsRE =  \
37 #      re.compile(u"(\"\"\".*\"\"\"|'''.*'''|\"[^\"]*\"|\'[^\']*\'|#.*\n)", re.DOTALL)
38 import six
39 if six.PY2 : 
40     allchars = string.maketrans(u"", "")
41     allcharsExceptNewline = allchars[: allchars.index('\n')]+allchars[allchars.index('\n')+1:]
42     allcharsExceptNewlineTranstable = string.maketrans(allcharsExceptNewline, '*'*len(allcharsExceptNewline))
43 else : 
44     allchars=bytes.maketrans(b"",b"")
45     allcharsExceptNewline = allchars[: allchars.index(b'\n')]+allchars[allchars.index(b'\n')+1:]
46     allcharsExceptNewlineTranstable = bytes.maketrans(allcharsExceptNewline, b'*'*len(allcharsExceptNewline))
47
48 #if sys.platform[0:5]=="linux" :
49 #   allcharsExceptNewlineTranstable = string.maketrans(allcharsExceptNewline, '*'*len(allcharsExceptNewline))
50 #elif sys.platform[0:3]=="win" :
51 #   allcharsExceptNewlineTranstable = dict((ord(char), u'*') for char in allcharsExceptNewline)#
52 #else :
53 #   allcharsExceptNewlineTranstable = string.maketrans(allcharsExceptNewline, '*'*len(allcharsExceptNewline))
54
55 def maskStringsAndComments(src):
56     """Masque tous les caracteres de src contenus dans des commentaires ou des strings multilignes (triples
57        quotes et guillemets.
58        Le masquage est realise en remplacant les caracteres par des * 
59        Attention : cette fonction doit etre utilisee sur un texte complet et pas ligne par ligne
60     """
61 # remplace les \\, les \" les \'  par **
62 # supprime toutes les chaines ou commentaires ,y compris multiligne i
63 # entre 3 ou 1 simples ou doubles quotes (ouvrantes fermantes) ou # 
64 # laisse les non fermantes ou non ouvrantes
65 # on prend 1 sur 2 en raison du split qui donne python, commentaire, python, commentaire...
66
67     src = escapedQuotesRE.sub("**", src)
68     allstrings = stringsAndCommentsRE.split(src)
69
70     # on a une liste d elements constituee successivement de  (string, comment)
71     for i in range(1, len(allstrings), 2):
72         if allstrings[i].startswith(u"'''")or allstrings[i].startswith('"""'):
73             allstrings[i] = allstrings[i][:3]+ \
74                             allstrings[i][3:-3].translate(allcharsExceptNewlineTranstable)+ \
75                             allstrings[i][-3:]
76         else:
77             allstrings[i] = allstrings[i][0]+ \
78                             allstrings[i][1:-1].translate(allcharsExceptNewlineTranstable)+ \
79                             allstrings[i][-1]
80
81     return "".join(allstrings)
82
83 implicitContinuationChars = (('(', ')'), ('[', ']'), ('{', '}'))
84 linecontinueRE = re.compile(r"\\\s*(#.*)?$")
85 emptyHangingBraces = [0,0,0,0,0]
86
87 class ParserException(Exception): pass
88 class FatalError(Exception): pass
89
90 #commentaire double precede d'un nombre quelconque de blancs (pas multiligne)
91 pattern_2comments   = re.compile(r"^\s*##.*")
92 pattern_finComments = re.compile("^\s*##Fin Commentaire")
93 #commentaire standard precede d'un nombre quelconque de blancs (pas multiligne)
94 pattern_comment   = re.compile(r"^\s*#.*")
95 #fin de ligne ; suivi d'un nombre quelconque de blancs (pas multiligne)
96 pattern_fin   = re.compile(r"; *$")
97 #pattern pour supprimer les blancs, tabulations et fins de ligne
98 pattern_blancs = re.compile(r"[ \t\r\f\v]")
99 #pattern_blancs = re.compile(r"[\s\n]")
100 number_kw_pattern=re.compile(r"""
101 (
102     #groupe nombre decimal
103     (?:
104         #signe : on ignore le signe +
105         [-]?
106         #groupe (avec ?: n'apparait pas en tant que groupe dans le resultat)
107         (?:
108             #mantisse forme entiere.fractionnaire
109             \d+(?:\.\d*)?
110             |
111             #ou forme .fractionnaire
112             \.\d+
113         )
114         (?:[eE][+-]?\d+)?
115     )
116     |
117     #argument keyword
118     [a-zA-Z_]\w*=
119 )
120 """,re.VERBOSE|re.MULTILINE)
121
122 def construit_genea(texte,liste_mc):
123     """
124        Retourne un dictionnaire dont les cles sont des reels et les valeurs sont leurs representations textuelles.
125
126        Realise un filtrage sur les reels :
127
128          - Ne garde que les reels pour lesquels str ne donne pas une bonne representation.
129          - Ne garde que les reels derriere un argument keyword dont le nom est dans liste_mc
130
131        >>> s = '''a=+21.3e-5*85,b=-.1234,c=81.6   , d= -8 , e=_F(x=342.67,y=-1), f=+1.1, g=(1.3,-5,1.54E-3),
132        ... #POMPE_PRIMA._BOUCLE_N._2_ELEMENT_NUMERO:0239
133        ... h=_F(x=34.6,y=-1)'''
134        >>> construit_genea(s,['a','x'])
135        {0.000213: '21.3e-5'}
136     """
137     d={}
138     mot=""
139     #on masque les strings et commentaires pour ne pas identifier de faux reels
140     for m in number_kw_pattern.findall(maskStringsAndComments(texte)):
141         if m[-1] == '=':
142             #argument keyword
143             mot=m[:-1]
144         else:
145             if mot not in liste_mc:continue
146             #valeur
147             key=eval(m)
148             if str(key) != m: d[key]=m
149     return d
150
151
152 class ENTITE_JDC(object) :
153     """Classe de base pour tous les objets crees lors de la conversion
154        Tout objet derive est enregistre aupres de son pere a sa creation
155     """
156     def __init__(self,pere):
157         self.texte = ''
158         pere.l_objets.append(self)
159
160     def set_text(self,texte):
161         self.texte = texte
162
163     def append_text(self,texte):
164         """
165         Ajoute texte a self.texte en mettant un retour chariot a la fin de texte
166         """
167         texte = texte+'\n'
168         self.texte = self.texte +texte
169
170     def __str__(self):
171         return self.texte
172
173 class COMMENTAIRE(ENTITE_JDC):
174
175     def __str__(self):
176         """
177         Retourne une chaine de caracteres representants self
178         sous une forme interpretable par EFICAS
179         """
180         t=repr(self.texte)
181         return "COMMENTAIRE(u"+t+")\n"
182
183         #s='COMMENTAIRE(u"""'+self.texte+'""")\n\n'
184         #return s
185
186     def append_text(self,texte):
187         """
188         Ajoute texte a self.texte en enlevant le # initial
189         """
190         texte = texte+'\n'
191         if texte[0] == '#':
192             self.texte = self.texte+texte[1:]
193         else:
194             # le diese n'est pas sur le premier caractere
195             amont,aval = texte.split('#',1) # on decoupe suivant la premiere occurrence de #
196             self.texte = self.texte +amont + aval
197         
198 class COMMANDE(ENTITE_JDC):
199
200     def __str__(self):
201         """
202         Retourne self.texte
203         """
204         return self.texte+'\n'
205         
206     def get_nb_par(self):
207         """
208         Retourne la difference entre le nombre de parentheses ouvrantes
209         et le nombre de parentheses fermantes presentes dans self.texte
210         Peut donc retourner un entier negatif
211         """
212         # faire attention aux commentaires contenus dans self.texte
213         # qui peuvent eux-memes contenir des parentheses !!!!
214         l_lignes = self.texte.split('\n')
215         nb = 0
216         for ligne in l_lignes:
217             ligne = ligne.split('#')[0]
218             #nb = nb + (string.count(ligne,'(')-string.count(ligne,')'))
219
220             nb = nb + ( ligne.count('(') - ligne.count(')') )
221         return nb
222
223 class AFFECTATION(ENTITE_JDC):
224
225     def append_text(self,texte):
226         """
227         Ajoute texte a self.texte en enlevant tout retour chariot et tout point virgule
228         PN et tout commentaire
229         """
230         if texte[-1] == '\n' : texte = texte[0:-1].rstrip()
231         if texte[-1] == ';'  : texte = texte[0:-1].rstrip()
232         self.texte = self.texte+texte+'\n'
233         
234     def __str__(self):
235         """
236         Retourne une expression de l'affectation comprehensible par ACCAS
237         et exploitable par EFICAS
238         """
239         nom,valeur = self.texte.split('=',1)
240         n = nom.rstrip()
241         nom = n.lstrip()
242         if valeur[-1] == '\n': valeur = valeur[:-1]
243         return n + ' = PARAMETRE(nom=\''+nom+'\',valeur='+valeur+')\n'
244
245 class COMMANDE_COMMENTARISEE(ENTITE_JDC):
246
247     def append_text(self,texte):
248         """
249         Ajoute texte a self.texte en enlevant les doubles commentaires
250         """
251         texte = texte.strip()
252         texte = texte[2:].strip()
253         self.texte = self.texte+(len(self.texte)>0)*'\n'+texte
254
255     def __str__(self):
256         """
257         Retourne une expression de la commande commentarisee comprehensible par ACCAS
258         et exploitable par EFICAS
259         """
260         return "COMMANDE_COMM(texte="+repr(self.texte)+")\n"
261         #return "COMMANDE_COMM(texte='''"+self.texte+"''')\n"
262
263 class AFFECTATION_EVAL(ENTITE_JDC):
264
265     def append_text(self,texte):
266         """
267         Ajoute texte a self.texte en enlevant tout retour chariot
268         """
269         if texte[-1] == '\n' : texte = texte[1:-1]
270         self.texte = self.texte+texte
271         
272     def __str__(self):
273         """
274         Retourne une expression du parametre EVAL comprehensible par ACCAS
275         et exploitable par EFICAS
276         """
277         nom,valeur = self.texte.split('=',1)
278         nom = nom.strip()
279         if valeur[-1] == '\n': valeur = valeur[:-1]
280         valeur = valeur.strip()
281         return nom+' = PARAMETRE_EVAL(nom=\''+nom+'\',valeur=\''+valeur+'\')\n\n'
282         
283 class PARSEUR_PYTHON(object):
284     """
285     Cette classe sert a generer un objet PARSEUR_PYTHON qui realise l'analyse d'un texte 
286     representant un JDC Python en distinguant :
287       - les commentaires inter commandes
288       - les affectations
289       - les commandes
290     """
291     pattern_commande   = re.compile(r'^([A-Z][A-Z0-9_]+)([ \t\r\f\v]*)\(([\w\W]*)')
292     pattern_eval       = re.compile(r'^(EVAL)([ \t\r\f\v]*)\(([\w\W]*)')
293     pattern_ligne_vide = re.compile(r'^[\t\r\f\v\n]+')
294     pattern_name       = re.compile(r'[a-zA-Z_]\w*')
295     
296     def __init__(self,texte):
297         self.texte = texte
298         self.l_objets=None
299         self.appli=None
300
301     def is_affectation(self,texte):
302         """
303         Methode booleenne qui retourne 1 si le texte est celui d'une affectation dans un jeu de commandes
304         Aster, 0 sinon
305         """
306         if '=' not in texte : return 0
307         if self.pattern_commande.match(texte):
308             # cas d'une procedure ...
309             return 0
310         amont,aval = texte.split('=',1)
311         aval = aval.strip()
312
313
314         if self.pattern_commande.match(aval):
315             return 0
316         else:
317             s= amont.strip()
318             m= self.pattern_name.match(s)
319             if m is None : return 0
320             if m.start() != 0 :return 0
321             if m.end() != len(s):return 0
322             return 1
323
324     def is_eval(self,texte):
325         """
326         Methode booleenne qui retourne 1 si le texte est celui d'une affectation de type EVAL
327         dans un jeu de commandes Aster, 0 sinon
328         """
329         if '=' not in texte : return 0
330         if self.pattern_commande.match(texte):
331             # cas d'une procedure ...
332             return 0
333         amont,aval = texte.split('=',1)
334         aval = aval.strip()
335         if not self.pattern_commande.match(aval) : return 0
336         if self.pattern_eval.match(aval):
337             return 1
338         else:
339             return 0
340             
341     def is_commande(self,texte):
342         """
343         Methode booleenne qui retourne 1 si le texte est celui d'une commande dans un jeu de commandes
344         Aster, 0 sinon
345         """
346         if self.pattern_commande.match(texte):
347             # cas d'une procedure ...
348             return 1
349         # A ce stade il faut avoir un OPER ou une MACRO, bref un '=' !
350         if '=' not in texte : return 0
351         # on a un texte de la forme xxxx = yyyyy
352         # --> reste a analyser yyyy
353         amont,aval = texte.split('=',1)
354         aval = aval.strip()
355         if self.pattern_commande.match(aval):
356             return 1
357         else:
358             return 0
359
360     def is_modification_catalogue(self,texte) :
361         if self.pattern_commande.match(texte):
362            return 1
363
364     def analyse(self):
365         """
366         Eclate la chaine self.texte en self.l_objets une liste lignes d'instructions
367         et de commentaires (parmi lesquels des instructions "commentarisees").
368         """
369         l_lignes = self.texte.split('\n')
370         commentaire_courant             = None
371         commande_courante               = None
372         affectation_courante            = None
373         commande_commentarisee_courante = None
374         self.l_objets = []
375
376         #initialisation du nombre de parentheses non fermees et de commentaires non termines
377         #Attention a reinitialiser en fin de ligne logique
378         #Une ligne logique peut s'etendre sur plusieurs lignes physiques avec des caracteres de continuation
379         #explicites ou implicites
380         hangingBraces = list(emptyHangingBraces)
381         hangingComments = 0
382
383         #Masquage des commentaires et strings multilignes
384         srcMasked=maskStringsAndComments('\n'.join(l_lignes))
385         masked_lines=srcMasked.split('\n')
386         lineno=0
387
388         for ligne in l_lignes :
389             line=masked_lines[lineno]
390             lineno=lineno+1
391             #print ("ligne:",line)
392             # mise a jour du nombre total de parentheses ouvertes (non fermees)
393             # et du nombre de commentaires non termines
394             for i in range(len(implicitContinuationChars)):
395                 contchar = implicitContinuationChars[i]
396                 numHanging = hangingBraces[i]
397                 hangingBraces[i] = numHanging+line.count(contchar[0]) - line.count(contchar[1])
398
399             hangingComments ^= line.count('"""') % 2
400             hangingComments ^= line.count(u"'''") % 2
401             #print (hangingComments,hangingBraces)
402             if hangingBraces[0] < 0 or hangingBraces[1] < 0 or hangingBraces[2] < 0: 
403                 raise ParserException()
404
405             if ligne.strip() == '':
406                 # il s'agit d'un saut de ligne
407                 # --> on l'ignore
408                 continue
409
410             if pattern_2comments.match(ligne):
411                 #on a trouve une commande commentarisee : double commentaire sans rien devant a part des blancs
412                 if commentaire_courant:
413                     #Si un commentaire ordinaire est en cours on le termine
414                     commentaire_courant = None
415
416                 if commande_courante :
417                     # on a un objet commentarise a l'interieur d'une commande
418                     # --> non traite pour l'instant : on l'ajoute simplement a la commande courante comme
419                     # un commentaire ordinaire
420                     commande_courante.append_text(ligne)
421                 elif commande_commentarisee_courante :
422                     # commande_commentarisee en cours : on ajoute la ligne
423                     commande_commentarisee_courante.append_text(ligne)
424                     # on a 2 commandes commentarisees de suite
425                     if pattern_finComments.match(ligne) :
426                        commande_commentarisee_courante = None
427                 else:
428                     # debut de commande commentarisee : on cree un objet commande_commentarisee_courante
429                     commande_commentarisee_courante = COMMANDE_COMMENTARISEE(self)
430                     commande_commentarisee_courante.append_text(ligne)
431
432                 #on passe a la ligne suivante
433                 continue
434
435             if pattern_comment.match(ligne):
436                 #commentaire ordinaire avec seulement des blancs devant
437                 if commande_commentarisee_courante :
438                     # commande_commentarisee en cours : on la clot
439                     commande_commentarisee_courante = None
440
441                 if commande_courante :
442                     # il s'agit d'un commentaire a l'interieur d'une commande --> on ne fait rien de special
443                     #on l'ajoute au texte de la commande 
444                     commande_courante.append_text(ligne)
445                 elif commentaire_courant :
446                     # il s'agit de la nieme ligne d'un commentaire entre deux commandes
447                     # --> on ajoute cette ligne au commentaire courant
448                     commentaire_courant.append_text(ligne)
449                 else :
450                     # il s'agit d'un nouveau commentaire entre deux commandes
451                     # --> on le cree et il devient le commentaire courant
452                     commentaire_courant = COMMENTAIRE(self)
453                     commentaire_courant.append_text(ligne)
454
455                 #on passe a la ligne suivante
456                 continue
457
458             # la ligne contient des donnees autre qu'un eventuel commentaire
459             if commentaire_courant :
460                 # on clot un eventuel commentaire courant
461                 commentaire_courant = None
462
463             if commande_commentarisee_courante :
464                 # on clot une eventuelle commande commentarisee courante
465                 commande_commentarisee_courante = None
466
467             if commande_courante :
468                 #on a une commande en cours. On l'enrichit ou on la termine
469                 commande_courante.append_text(ligne)
470                 if not linecontinueRE.search(line) \
471                    and (hangingBraces == emptyHangingBraces) \
472                    and not hangingComments:
473                     #la commande est terminee 
474                     self.analyse_reel(commande_courante.texte)
475                     commande_courante = None
476
477                 #on passe a la ligne suivante
478                 continue
479
480             if affectation_courante != None :
481                 #poursuite d'une affectation
482                 affectation_courante.append_text(ligne)
483                 if not linecontinueRE.search(line) \
484                    and (hangingBraces == emptyHangingBraces) \
485                    and not hangingComments:
486                     #L'affectation est terminee
487                     affectation_courante=None
488                 #on passe a la ligne suivante
489                 continue
490
491             # il peut s'agir d'une commande ou d'une affectation ...
492             # ou d'un EVAL !!!
493             if self.is_eval(ligne):
494                 # --> affectation de type EVAL
495                 if affectation_courante : affectation_courante = None
496                 affectation = AFFECTATION_EVAL(self)
497                 affectation.append_text(ligne)
498                 #on passe a la ligne suivante
499                 continue
500
501             if self.is_affectation(ligne):
502                 #print( '--> affectation')
503                 text=ligne
504                 #traitement des commentaires en fin de ligne
505                 compos=line.find(u"#")
506                 if compos > 2:
507                     #commentaire en fin de ligne
508                     #on cree un nouveau commentaire avant le parametre
509                     COMMENTAIRE(self).append_text(ligne[compos:])
510                     text=ligne[:compos]
511                 #si plusieurs instructions separees par des ; sur la meme ligne
512                 inspos=line.find(u";")
513                 if inspos > 2:
514                     #on garde seulement la premiere partie de la ligne
515                     #si on a que des blancs apres le point virgule
516                     if text[inspos:].strip() == ";":
517                         text=text[:inspos]
518                     else:
519                         raise FatalError(tr("Eficas ne peut pas traiter plusieurs instructions \
520                                                  sur la meme ligne : %s", ligne))
521
522                 affectation_courante = AFFECTATION(self)
523                 affectation_courante.append_text(text)
524                 if not linecontinueRE.search(line) \
525                    and (hangingBraces == emptyHangingBraces) \
526                    and not hangingComments:
527                     #L'affectation est terminee
528                     affectation_courante=None
529                 #on passe a la ligne suivante
530                 continue
531
532             if self.is_commande(ligne):
533                 # --> nouvelle commande
534                 #print ('nouvelle commande')
535                 affectation_courante = None
536                 commande_courante = COMMANDE(self)
537                 commande_courante.append_text(ligne)
538                 #si la commande est complete, on la termine
539                 if not linecontinueRE.search(line) \
540                    and (hangingBraces == emptyHangingBraces) \
541                    and not hangingComments:
542                     #la commande est terminee 
543                     self.analyse_reel(commande_courante.texte)
544                     commande_courante = None
545                 #on passe a la ligne suivante
546                 continue
547
548  
549     def enleve (self,texte) :
550         """Supprime de texte tous les caracteres blancs, fins de ligne, tabulations
551            Le nouveau texte est retourne
552         """
553         i=0
554         chaine=""
555         while (i<len(texte)):
556           if (texte[i] == " " or texte[i] == "\n" or texte[i] == "\t") :
557              i=i+1
558           else :
559              chaine=chaine+texte[i]
560              i=i+1
561         return chaine 
562             
563     def construit_genea(self,texte):
564         indiceC=0
565         mot=""
566         dict_reel_concept={}
567
568         # traitement pour chaque caractere
569         while (indiceC < len(texte)): 
570            c=texte[indiceC]
571            if ( c == "," or c == "(u" or c == ")"):
572               mot=""
573            elif ( c== "="):
574               #on doit trouver derriere soit une valeur soit une parenthese
575               valeur=""
576               nouvelindice=indiceC+1
577               if texte[nouvelindice] != "(u":
578                  #pas de parenthese ouvrante derriere un signe =, on a une valeur.
579                  while ( texte[nouvelindice] != "," and texte[nouvelindice] != ")"):
580                     valeur=valeur+texte[nouvelindice]
581                     nouvelindice=nouvelindice+1
582                     if nouvelindice == len(texte) :
583                         nouvelindice=nouvelindice -1
584                         break
585                  if mot in self.appli.liste_simp_reel:
586                     if valeur[0] != "'":
587                        try :
588                          clef=eval(valeur)
589                          if str(clef) != str(valeur) :
590                             dict_reel_concept[clef]=valeur
591                        except :
592                          pass
593                  mot=""
594                  indiceC=nouvelindice
595               else:
596                  #parenthese ouvrante derriere un signe =, on a un tuple de valeur ou de mots cles facteurs.
597                  # s agit -il d un tuple 
598                  if texte[nouvelindice+1] != "(u":
599                     #le suivant n'est pas une parenthese ouvrante : on a un tuple de valeurs ou un mot cle facteur
600                     tuple=False
601                     #on avance jusqu'a la fin du tuple de valeurs ou jusqu'a la fin du premier mot cle simple
602                     #contenu dans le mot cle facteur
603                     while ( texte[nouvelindice] != "="):
604                        if texte[nouvelindice] == ")" :
605                           tuple=True
606                           break
607                        else :
608                           nouvelindice=nouvelindice+1
609                           if nouvelindice == len(texte) :
610                              nouvelindice=nouvelindice -1
611                              break
612                     if tuple :
613                        #cas du tuple de valeurs
614                        valeur=texte[indiceC+1:nouvelindice+1]
615                        indiceC=nouvelindice+1 
616                        if mot in self.appli.liste_simp_reel:
617                           valeur=valeur[1:-1]
618                           for val in valeur.split(',') :
619                           # Attention la derniere valeur est""
620                              try :
621                                 if val[0] != "'":
622                                   clef=eval(val)
623                                   if str(clef) != str(val) :
624                                      dict_reel_concept[clef]=val
625                              except :
626                                   pass
627                        mot=""
628                # ou de ( imbriquees
629                  else :
630                     #cas du mocle facteur simple ou 
631                     mot=""
632            else :
633               mot=mot+texte[indiceC]
634            indiceC=indiceC+1
635         # traitement du dernier inutile
636         # c est un ; 
637         return dict_reel_concept
638
639     def analyse_reel(self,commande) :
640         nomConcept=None
641         # On verifie qu on a bien un OPER
642         # et pas une MACRO
643         if commande.find(u"=") > commande.find(u"(u") :
644            return
645         if commande.find(u"=") > 0:
646            #epure1=self.enleve(commande)
647            epure1=pattern_blancs.sub(u"",commande)
648            nomConcept,corps=epure1.split(u"=",1)
649            epure2=corps.replace(u"_F(u","(u")
650            #nomConcept=epure1.split(u"=")[0]
651            #index=epure1.find(u"=")
652            #epure2=epure1[index+1:len(epure1)].replace(u"_F(u","(u")
653            #dict_reel_concept=self.construit_genea(epure2)
654            if self.appli:
655              dict_reel_concept=construit_genea(epure2,self.appli.liste_simp_reel)
656            else:
657              dict_reel_concept={}
658         if nomConcept == "sansnom" :
659            nomConcept = ""
660         if nomConcept !=None :
661            if len(dict_reel_concept) != 0:
662               self.appli.dict_reels[nomConcept]=dict_reel_concept
663
664     def get_texte(self,appli=None):
665         """
666         Retourne le texte issu de l'analyse
667         """
668         self.appli=appli
669         try:
670         #if 1:
671             if not self.l_objets : self.analyse()
672             txt=''
673             for obj in self.l_objets:
674                 txt = txt+str(obj)
675         #else :
676         except  ParserException:
677             #Impossible de convertir le texte, on le retourne tel que
678             txt=self.texte
679         return txt
680
681 def test():
682   #import parseur_python
683   import doctest
684   doctest.testmod(parseur_python)
685
686
687 if __name__ == "__main__" :
688     import time
689     #fichier = 'D:/Eficas_dev/Tests/zzzz100a.comm'
690     #fichier = 'U:/Eficas_dev/Tests/test_eval.comm'
691     texte = open(fichier,'r').read()
692     class appli(object):
693        dict_reels={}
694        liste_simp_reel=["VALE","VALE_C","GROUP_MA","RAYON"]
695     a=appli()
696
697     compile(txt, '<string>', 'exec')
698     print((a.dict_reels))