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