Salome HOME
chgt copyright
[tools/eficas.git] / convert / parseur_python.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2021   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         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 isEval(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 isCommande(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 isModificationCatalogue(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.appendText(ligne)
421                 elif commande_commentarisee_courante :
422                     # commande_commentarisee en cours : on ajoute la ligne
423                     commande_commentarisee_courante.appendText(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.appendText(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.appendText(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.appendText(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.appendText(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.appendText(ligne)
470                 if not linecontinueRE.search(line) \
471                    and (hangingBraces == emptyHangingBraces) \
472                    and not hangingComments:
473                     #la commande est terminee 
474                     self.analyseReel(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.appendText(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.isEval(ligne):
494                 # --> affectation de type EVAL
495                 if affectation_courante : affectation_courante = None
496                 affectation = AFFECTATION_EVAL(self)
497                 affectation.appendText(ligne)
498                 #on passe a la ligne suivante
499                 continue
500
501             if self.isAffectation(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).appendText(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.appendText(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.isCommande(ligne):
533                 # --> nouvelle commande
534                 affectation_courante = None
535                 commande_courante = COMMANDE(self)
536                 commande_courante.appendText(ligne)
537                 #si la commande est complete, on la termine
538                 if not linecontinueRE.search(line) \
539                    and (hangingBraces == emptyHangingBraces) \
540                    and not hangingComments:
541                     #la commande est terminee 
542                     self.analyseReel(commande_courante.texte)
543                     commande_courante = None
544                 #on passe a la ligne suivante
545                 continue
546
547  
548     def enleve (self,texte) :
549         """Supprime de texte tous les caracteres blancs, fins de ligne, tabulations
550            Le nouveau texte est retourne
551         """
552         i=0
553         chaine=""
554         while (i<len(texte)):
555           if (texte[i] == " " or texte[i] == "\n" or texte[i] == "\t") :
556              i=i+1
557           else :
558              chaine=chaine+texte[i]
559              i=i+1
560         return chaine 
561             
562     def construitGenea(self,texte):
563         indiceC=0
564         mot=""
565         dict_reel_concept={}
566
567         # traitement pour chaque caractere
568         while (indiceC < len(texte)): 
569            c=texte[indiceC]
570            if ( c == "," or c == "(u" or c == ")"):
571               mot=""
572            elif ( c== "="):
573               #on doit trouver derriere soit une valeur soit une parenthese
574               valeur=""
575               nouvelindice=indiceC+1
576               if texte[nouvelindice] != "(u":
577                  #pas de parenthese ouvrante derriere un signe =, on a une valeur.
578                  while ( texte[nouvelindice] != "," and texte[nouvelindice] != ")"):
579                     valeur=valeur+texte[nouvelindice]
580                     nouvelindice=nouvelindice+1
581                     if nouvelindice == len(texte) :
582                         nouvelindice=nouvelindice -1
583                         break
584                  if mot in self.appli.liste_simp_reel:
585                     if valeur[0] != "'":
586                        try :
587                          clef=eval(valeur)
588                          if str(clef) != str(valeur) :
589                             dict_reel_concept[clef]=valeur
590                        except :
591                          pass
592                  mot=""
593                  indiceC=nouvelindice
594               else:
595                  #parenthese ouvrante derriere un signe =, on a un tuple de valeur ou de mots cles facteurs.
596                  # s agit -il d un tuple 
597                  if texte[nouvelindice+1] != "(u":
598                     #le suivant n'est pas une parenthese ouvrante : on a un tuple de valeurs ou un mot cle facteur
599                     tuple=False
600                     #on avance jusqu'a la fin du tuple de valeurs ou jusqu'a la fin du premier mot cle simple
601                     #contenu dans le mot cle facteur
602                     while ( texte[nouvelindice] != "="):
603                        if texte[nouvelindice] == ")" :
604                           tuple=True
605                           break
606                        else :
607                           nouvelindice=nouvelindice+1
608                           if nouvelindice == len(texte) :
609                              nouvelindice=nouvelindice -1
610                              break
611                     if tuple :
612                        #cas du tuple de valeurs
613                        valeur=texte[indiceC+1:nouvelindice+1]
614                        indiceC=nouvelindice+1 
615                        if mot in self.appli.liste_simp_reel:
616                           valeur=valeur[1:-1]
617                           for val in valeur.split(',') :
618                           # Attention la derniere valeur est""
619                              try :
620                                 if val[0] != "'":
621                                   clef=eval(val)
622                                   if str(clef) != str(val) :
623                                      dict_reel_concept[clef]=val
624                              except :
625                                   pass
626                        mot=""
627                # ou de ( imbriquees
628                  else :
629                     #cas du mocle facteur simple ou 
630                     mot=""
631            else :
632               mot=mot+texte[indiceC]
633            indiceC=indiceC+1
634         # traitement du dernier inutile
635         # c est un ; 
636         return dict_reel_concept
637
638     def analyseReel(self,commande) :
639         nomConcept=None
640         # On verifie qu on a bien un OPER
641         # et pas une MACRO
642         if commande.find(u"=") > commande.find(u"(u") :
643            return
644         if commande.find(u"=") > 0:
645            #epure1=self.enleve(commande)
646            epure1=pattern_blancs.sub(u"",commande)
647            nomConcept,corps=epure1.split(u"=",1)
648            epure2=corps.replace(u"_F(u","(u")
649            #nomConcept=epure1.split(u"=")[0]
650            #index=epure1.find(u"=")
651            #epure2=epure1[index+1:len(epure1)].replace(u"_F(u","(u")
652            #dict_reel_concept=self.construitGenea(epure2)
653            if self.appli:
654              dict_reel_concept=construitGenea(epure2,self.appli.liste_simp_reel)
655            else:
656              dict_reel_concept={}
657         if nomConcept == "sansnom" :
658            nomConcept = ""
659         if nomConcept !=None :
660            if len(dict_reel_concept) != 0:
661               self.appli.dict_reels[nomConcept]=dict_reel_concept
662
663     def getTexte(self,appli=None):
664         """
665         Retourne le texte issu de l'analyse
666         """
667         self.appli=appli
668         try:
669         #if 1:
670             if not self.l_objets : self.analyse()
671             txt=''
672             for obj in self.l_objets:
673                 txt = txt+str(obj)
674         #else :
675         except  parserException:
676             #Impossible de convertir le texte, on le retourne tel que
677             txt=self.texte
678         return txt
679
680 def test():
681   #import parseur_python
682   import doctest
683   doctest.testmod(parseur_python)
684
685
686 if __name__ == "__main__" :
687     import time
688     #fichier = 'D:/Eficas_dev/Tests/zzzz100a.comm'
689     #fichier = 'U:/Eficas_dev/Tests/test_eval.comm'
690     texte = open(fichier,'r').read()
691     class appli(object):
692        dict_reels={}
693        liste_simp_reel=["VALE","VALE_C","GROUP_MA","RAYON"]
694     a=appli()
695
696     compile(txt, '<string>', 'exec')
697     print((a.dict_reels))