Salome HOME
Merge V9 dans Master
[tools/eficas.git] / convert / parseur_python.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2017   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 construitGenea(texte,listeMc):
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 listeMc
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        >>> construitGenea(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 listeMc: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 setText(self,texte):
161         self.texte = texte
162
163     def appendText(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 appendText(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 getNbPar(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 appendText(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 appendText(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 appendText(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-zA-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 isAffectation(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         print (texte)
307         if '=' not in texte : return 0
308         if self.pattern_commande.match(texte):
309             # cas d'une procedure ...
310             return 0
311         amont,aval = texte.split('=',1)
312         aval = aval.strip()
313
314
315         if self.pattern_commande.match(aval):
316             return 0
317         else:
318             s= amont.strip()
319             m= self.pattern_name.match(s)
320             if m is None : return 0
321             if m.start() != 0 :return 0
322             if m.end() != len(s):return 0
323             return 1
324
325     def isEval(self,texte):
326         """
327         Methode booleenne qui retourne 1 si le texte est celui d'une affectation de type EVAL
328         dans un jeu de commandes Aster, 0 sinon
329         """
330         if '=' not in texte : return 0
331         if self.pattern_commande.match(texte):
332             # cas d'une procedure ...
333             return 0
334         amont,aval = texte.split('=',1)
335         aval = aval.strip()
336         if not self.pattern_commande.match(aval) : return 0
337         if self.pattern_eval.match(aval):
338             return 1
339         else:
340             return 0
341             
342     def isCommande(self,texte):
343         """
344         Methode booleenne qui retourne 1 si le texte est celui d'une commande dans un jeu de commandes
345         Aster, 0 sinon
346         """
347         if self.pattern_commande.match(texte):
348             # cas d'une procedure ...
349             return 1
350         # A ce stade il faut avoir un OPER ou une MACRO, bref un '=' !
351         if '=' not in texte : return 0
352         # on a un texte de la forme xxxx = yyyyy
353         # --> reste a analyser yyyy
354         amont,aval = texte.split('=',1)
355         aval = aval.strip()
356         if self.pattern_commande.match(aval):
357             return 1
358         else:
359             return 0
360
361     def isModificationCatalogue(self,texte) :
362         if self.pattern_commande.match(texte):
363            return 1
364
365     def analyse(self):
366         """
367         Eclate la chaine self.texte en self.l_objets une liste lignes d'instructions
368         et de commentaires (parmi lesquels des instructions "commentarisees").
369         """
370         l_lignes = self.texte.split('\n')
371         commentaire_courant             = None
372         commande_courante               = None
373         affectation_courante            = None
374         commande_commentarisee_courante = None
375         self.l_objets = []
376
377         #initialisation du nombre de parentheses non fermees et de commentaires non termines
378         #Attention a reinitialiser en fin de ligne logique
379         #Une ligne logique peut s'etendre sur plusieurs lignes physiques avec des caracteres de continuation
380         #explicites ou implicites
381         hangingBraces = list(emptyHangingBraces)
382         hangingComments = 0
383
384         #Masquage des commentaires et strings multilignes
385         srcMasked=maskStringsAndComments('\n'.join(l_lignes))
386         masked_lines=srcMasked.split('\n')
387         lineno=0
388
389         for ligne in l_lignes :
390             line=masked_lines[lineno]
391             lineno=lineno+1
392             #print ("ligne:",line)
393             # mise a jour du nombre total de parentheses ouvertes (non fermees)
394             # et du nombre de commentaires non termines
395             for i in range(len(implicitContinuationChars)):
396                 contchar = implicitContinuationChars[i]
397                 numHanging = hangingBraces[i]
398                 hangingBraces[i] = numHanging+line.count(contchar[0]) - line.count(contchar[1])
399
400             hangingComments ^= line.count('"""') % 2
401             hangingComments ^= line.count(u"'''") % 2
402             #print (hangingComments,hangingBraces)
403             if hangingBraces[0] < 0 or hangingBraces[1] < 0 or hangingBraces[2] < 0: 
404                 raise parserException()
405
406             if ligne.strip() == '':
407                 # il s'agit d'un saut de ligne
408                 # --> on l'ignore
409                 continue
410
411             if pattern_2comments.match(ligne):
412                 #on a trouve une commande commentarisee : double commentaire sans rien devant a part des blancs
413                 if commentaire_courant:
414                     #Si un commentaire ordinaire est en cours on le termine
415                     commentaire_courant = None
416
417                 if commande_courante :
418                     # on a un objet commentarise a l'interieur d'une commande
419                     # --> non traite pour l'instant : on l'ajoute simplement a la commande courante comme
420                     # un commentaire ordinaire
421                     commande_courante.appendText(ligne)
422                 elif commande_commentarisee_courante :
423                     # commande_commentarisee en cours : on ajoute la ligne
424                     commande_commentarisee_courante.appendText(ligne)
425                     # on a 2 commandes commentarisees de suite
426                     if pattern_finComments.match(ligne) :
427                        commande_commentarisee_courante = None
428                 else:
429                     # debut de commande commentarisee : on cree un objet commande_commentarisee_courante
430                     commande_commentarisee_courante = COMMANDE_COMMENTARISEE(self)
431                     commande_commentarisee_courante.appendText(ligne)
432
433                 #on passe a la ligne suivante
434                 continue
435
436             if pattern_comment.match(ligne):
437                 #commentaire ordinaire avec seulement des blancs devant
438                 if commande_commentarisee_courante :
439                     # commande_commentarisee en cours : on la clot
440                     commande_commentarisee_courante = None
441
442                 if commande_courante :
443                     # il s'agit d'un commentaire a l'interieur d'une commande --> on ne fait rien de special
444                     #on l'ajoute au texte de la commande 
445                     commande_courante.appendText(ligne)
446                 elif commentaire_courant :
447                     # il s'agit de la nieme ligne d'un commentaire entre deux commandes
448                     # --> on ajoute cette ligne au commentaire courant
449                     commentaire_courant.appendText(ligne)
450                 else :
451                     # il s'agit d'un nouveau commentaire entre deux commandes
452                     # --> on le cree et il devient le commentaire courant
453                     commentaire_courant = COMMENTAIRE(self)
454                     commentaire_courant.appendText(ligne)
455
456                 #on passe a la ligne suivante
457                 continue
458
459             # la ligne contient des donnees autre qu'un eventuel commentaire
460             if commentaire_courant :
461                 # on clot un eventuel commentaire courant
462                 commentaire_courant = None
463
464             if commande_commentarisee_courante :
465                 # on clot une eventuelle commande commentarisee courante
466                 commande_commentarisee_courante = None
467
468             if commande_courante :
469                 #on a une commande en cours. On l'enrichit ou on la termine
470                 commande_courante.appendText(ligne)
471                 if not linecontinueRE.search(line) \
472                    and (hangingBraces == emptyHangingBraces) \
473                    and not hangingComments:
474                     #la commande est terminee 
475                     self.analyseReel(commande_courante.texte)
476                     commande_courante = None
477
478                 #on passe a la ligne suivante
479                 continue
480
481             if affectation_courante != None :
482                 #poursuite d'une affectation
483                 affectation_courante.appendText(ligne)
484                 if not linecontinueRE.search(line) \
485                    and (hangingBraces == emptyHangingBraces) \
486                    and not hangingComments:
487                     #L'affectation est terminee
488                     affectation_courante=None
489                 #on passe a la ligne suivante
490                 continue
491
492             # il peut s'agir d'une commande ou d'une affectation ...
493             # ou d'un EVAL !!!
494             if self.isEval(ligne):
495                 # --> affectation de type EVAL
496                 if affectation_courante : affectation_courante = None
497                 affectation = AFFECTATION_EVAL(self)
498                 affectation.appendText(ligne)
499                 #on passe a la ligne suivante
500                 continue
501
502             if self.isAffectation(ligne):
503                 #print( '--> affectation')
504                 text=ligne
505                 #traitement des commentaires en fin de ligne
506                 compos=line.find(u"#")
507                 if compos > 2:
508                     #commentaire en fin de ligne
509                     #on cree un nouveau commentaire avant le parametre
510                     COMMENTAIRE(self).appendText(ligne[compos:])
511                     text=ligne[:compos]
512                 #si plusieurs instructions separees par des ; sur la meme ligne
513                 inspos=line.find(u";")
514                 if inspos > 2:
515                     #on garde seulement la premiere partie de la ligne
516                     #si on a que des blancs apres le point virgule
517                     if text[inspos:].strip() == ";":
518                         text=text[:inspos]
519                     else:
520                         raise FatalError(tr("Eficas ne peut pas traiter plusieurs instructions \
521                                                  sur la meme ligne : %s", ligne))
522
523                 affectation_courante = AFFECTATION(self)
524                 affectation_courante.appendText(text)
525                 if not linecontinueRE.search(line) \
526                    and (hangingBraces == emptyHangingBraces) \
527                    and not hangingComments:
528                     #L'affectation est terminee
529                     affectation_courante=None
530                 #on passe a la ligne suivante
531                 continue
532
533             if self.isCommande(ligne):
534                 # --> nouvelle commande
535                 affectation_courante = None
536                 commande_courante = COMMANDE(self)
537                 commande_courante.appendText(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.analyseReel(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 construitGenea(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 analyseReel(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.construitGenea(epure2)
654            if self.appli:
655              dict_reel_concept=construitGenea(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 getTexte(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))