# -*- coding: utf-8 -*-
-# Copyright (C) 2007-2013 EDF R&D
+# Copyright (C) 2007-2021 EDF R&D
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
from __future__ import absolute_import
from __future__ import print_function
try :
- from builtins import str
- from builtins import range
- from builtins import object
+ from builtins import str
+ from builtins import object
except :
- pass
+ pass
import sys,string,re
import traceback
from Extensions.i18n import tr
-from six.moves import range
escapedQuotesRE = re.compile(r"(\\\\|\\\"|\\\')")
stringsAndCommentsRE = \
#stringsAndCommentsRE = \
# re.compile(u"(\"\"\".*\"\"\"|'''.*'''|\"[^\"]*\"|\'[^\']*\'|#.*\n)", re.DOTALL)
import six
-if six.PY2 :
+if six.PY2 :
allchars = string.maketrans(u"", "")
allcharsExceptNewline = allchars[: allchars.index('\n')]+allchars[allchars.index('\n')+1:]
allcharsExceptNewlineTranstable = string.maketrans(allcharsExceptNewline, '*'*len(allcharsExceptNewline))
-else :
+else :
allchars=bytes.maketrans(b"",b"")
allcharsExceptNewline = allchars[: allchars.index(b'\n')]+allchars[allchars.index(b'\n')+1:]
allcharsExceptNewlineTranstable = bytes.maketrans(allcharsExceptNewline, b'*'*len(allcharsExceptNewline))
def maskStringsAndComments(src):
"""Masque tous les caracteres de src contenus dans des commentaires ou des strings multilignes (triples
quotes et guillemets.
- Le masquage est realise en remplacant les caracteres par des *
+ Le masquage est realise en remplacant les caracteres par des *
Attention : cette fonction doit etre utilisee sur un texte complet et pas ligne par ligne
"""
# remplace les \\, les \" les \' par **
# supprime toutes les chaines ou commentaires ,y compris multiligne i
-# entre 3 ou 1 simples ou doubles quotes (ouvrantes fermantes) ou #
+# entre 3 ou 1 simples ou doubles quotes (ouvrantes fermantes) ou #
# laisse les non fermantes ou non ouvrantes
# on prend 1 sur 2 en raison du split qui donne python, commentaire, python, commentaire...
linecontinueRE = re.compile(r"\\\s*(#.*)?$")
emptyHangingBraces = [0,0,0,0,0]
-class ParserException(Exception): pass
+class parserException(Exception): pass
class FatalError(Exception): pass
#commentaire double precede d'un nombre quelconque de blancs (pas multiligne)
)
""",re.VERBOSE|re.MULTILINE)
-def construit_genea(texte,liste_mc):
+def construitGenea(texte,listeMc):
"""
Retourne un dictionnaire dont les cles sont des reels et les valeurs sont leurs representations textuelles.
Realise un filtrage sur les reels :
- Ne garde que les reels pour lesquels str ne donne pas une bonne representation.
- - Ne garde que les reels derriere un argument keyword dont le nom est dans liste_mc
+ - Ne garde que les reels derriere un argument keyword dont le nom est dans listeMc
>>> 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),
... #POMPE_PRIMA._BOUCLE_N._2_ELEMENT_NUMERO:0239
... h=_F(x=34.6,y=-1)'''
- >>> construit_genea(s,['a','x'])
+ >>> construitGenea(s,['a','x'])
{0.000213: '21.3e-5'}
"""
d={}
#argument keyword
mot=m[:-1]
else:
- if mot not in liste_mc:continue
+ if mot not in listeMc:continue
#valeur
key=eval(m)
if str(key) != m: d[key]=m
self.texte = ''
pere.l_objets.append(self)
- def set_text(self,texte):
+ def setText(self,texte):
self.texte = texte
- def append_text(self,texte):
+ def appendText(self,texte):
"""
Ajoute texte a self.texte en mettant un retour chariot a la fin de texte
"""
#s='COMMENTAIRE(u"""'+self.texte+'""")\n\n'
#return s
- def append_text(self,texte):
+ def appendText(self,texte):
"""
Ajoute texte a self.texte en enlevant le # initial
"""
# le diese n'est pas sur le premier caractere
amont,aval = texte.split('#',1) # on decoupe suivant la premiere occurrence de #
self.texte = self.texte +amont + aval
-
+
class COMMANDE(ENTITE_JDC):
def __str__(self):
Retourne self.texte
"""
return self.texte+'\n'
-
- def get_nb_par(self):
+
+ def getNbPar(self):
"""
Retourne la difference entre le nombre de parentheses ouvrantes
et le nombre de parentheses fermantes presentes dans self.texte
class AFFECTATION(ENTITE_JDC):
- def append_text(self,texte):
+ def appendText(self,texte):
"""
Ajoute texte a self.texte en enlevant tout retour chariot et tout point virgule
PN et tout commentaire
if texte[-1] == '\n' : texte = texte[0:-1].rstrip()
if texte[-1] == ';' : texte = texte[0:-1].rstrip()
self.texte = self.texte+texte+'\n'
-
+
def __str__(self):
"""
Retourne une expression de l'affectation comprehensible par ACCAS
class COMMANDE_COMMENTARISEE(ENTITE_JDC):
- def append_text(self,texte):
+ def appendText(self,texte):
"""
Ajoute texte a self.texte en enlevant les doubles commentaires
"""
class AFFECTATION_EVAL(ENTITE_JDC):
- def append_text(self,texte):
+ def appendText(self,texte):
"""
Ajoute texte a self.texte en enlevant tout retour chariot
"""
if texte[-1] == '\n' : texte = texte[1:-1]
self.texte = self.texte+texte
-
+
def __str__(self):
"""
Retourne une expression du parametre EVAL comprehensible par ACCAS
if valeur[-1] == '\n': valeur = valeur[:-1]
valeur = valeur.strip()
return nom+' = PARAMETRE_EVAL(nom=\''+nom+'\',valeur=\''+valeur+'\')\n\n'
-
+
class PARSEUR_PYTHON(object):
"""
- Cette classe sert a generer un objet PARSEUR_PYTHON qui realise l'analyse d'un texte
+ Cette classe sert a generer un objet PARSEUR_PYTHON qui realise l'analyse d'un texte
representant un JDC Python en distinguant :
- les commentaires inter commandes
- les affectations
pattern_eval = re.compile(r'^(EVAL)([ \t\r\f\v]*)\(([\w\W]*)')
pattern_ligne_vide = re.compile(r'^[\t\r\f\v\n]+')
pattern_name = re.compile(r'[a-zA-Z_]\w*')
-
+
def __init__(self,texte):
self.texte = texte
self.l_objets=None
- self.appli=None
+ self.appliEficas=None
- def is_affectation(self,texte):
+ def isAffectation(self,texte):
"""
Methode booleenne qui retourne 1 si le texte est celui d'une affectation dans un jeu de commandes
Aster, 0 sinon
if m.end() != len(s):return 0
return 1
- def is_eval(self,texte):
+ def isEval(self,texte):
"""
Methode booleenne qui retourne 1 si le texte est celui d'une affectation de type EVAL
dans un jeu de commandes Aster, 0 sinon
return 1
else:
return 0
-
- def is_commande(self,texte):
+
+ def isCommande(self,texte):
"""
Methode booleenne qui retourne 1 si le texte est celui d'une commande dans un jeu de commandes
Aster, 0 sinon
else:
return 0
- def is_modification_catalogue(self,texte) :
+ def isModificationCatalogue(self,texte) :
if self.pattern_commande.match(texte):
- return 1
+ return 1
def analyse(self):
"""
hangingComments ^= line.count('"""') % 2
hangingComments ^= line.count(u"'''") % 2
#print (hangingComments,hangingBraces)
- if hangingBraces[0] < 0 or hangingBraces[1] < 0 or hangingBraces[2] < 0:
- raise ParserException()
+ if hangingBraces[0] < 0 or hangingBraces[1] < 0 or hangingBraces[2] < 0:
+ raise parserException()
if ligne.strip() == '':
# il s'agit d'un saut de ligne
# on a un objet commentarise a l'interieur d'une commande
# --> non traite pour l'instant : on l'ajoute simplement a la commande courante comme
# un commentaire ordinaire
- commande_courante.append_text(ligne)
+ commande_courante.appendText(ligne)
elif commande_commentarisee_courante :
# commande_commentarisee en cours : on ajoute la ligne
- commande_commentarisee_courante.append_text(ligne)
+ commande_commentarisee_courante.appendText(ligne)
# on a 2 commandes commentarisees de suite
if pattern_finComments.match(ligne) :
- commande_commentarisee_courante = None
+ commande_commentarisee_courante = None
else:
# debut de commande commentarisee : on cree un objet commande_commentarisee_courante
commande_commentarisee_courante = COMMANDE_COMMENTARISEE(self)
- commande_commentarisee_courante.append_text(ligne)
+ commande_commentarisee_courante.appendText(ligne)
#on passe a la ligne suivante
continue
if commande_courante :
# il s'agit d'un commentaire a l'interieur d'une commande --> on ne fait rien de special
- #on l'ajoute au texte de la commande
- commande_courante.append_text(ligne)
+ #on l'ajoute au texte de la commande
+ commande_courante.appendText(ligne)
elif commentaire_courant :
# il s'agit de la nieme ligne d'un commentaire entre deux commandes
# --> on ajoute cette ligne au commentaire courant
- commentaire_courant.append_text(ligne)
+ commentaire_courant.appendText(ligne)
else :
# il s'agit d'un nouveau commentaire entre deux commandes
# --> on le cree et il devient le commentaire courant
commentaire_courant = COMMENTAIRE(self)
- commentaire_courant.append_text(ligne)
+ commentaire_courant.appendText(ligne)
#on passe a la ligne suivante
continue
if commande_courante :
#on a une commande en cours. On l'enrichit ou on la termine
- commande_courante.append_text(ligne)
+ commande_courante.appendText(ligne)
if not linecontinueRE.search(line) \
and (hangingBraces == emptyHangingBraces) \
and not hangingComments:
- #la commande est terminee
- self.analyse_reel(commande_courante.texte)
+ #la commande est terminee
+ self.analyseReel(commande_courante.texte)
commande_courante = None
#on passe a la ligne suivante
if affectation_courante != None :
#poursuite d'une affectation
- affectation_courante.append_text(ligne)
+ affectation_courante.appendText(ligne)
if not linecontinueRE.search(line) \
and (hangingBraces == emptyHangingBraces) \
and not hangingComments:
# il peut s'agir d'une commande ou d'une affectation ...
# ou d'un EVAL !!!
- if self.is_eval(ligne):
+ if self.isEval(ligne):
# --> affectation de type EVAL
if affectation_courante : affectation_courante = None
affectation = AFFECTATION_EVAL(self)
- affectation.append_text(ligne)
+ affectation.appendText(ligne)
#on passe a la ligne suivante
continue
- if self.is_affectation(ligne):
+ if self.isAffectation(ligne):
#print( '--> affectation')
text=ligne
#traitement des commentaires en fin de ligne
if compos > 2:
#commentaire en fin de ligne
#on cree un nouveau commentaire avant le parametre
- COMMENTAIRE(self).append_text(ligne[compos:])
+ COMMENTAIRE(self).appendText(ligne[compos:])
text=ligne[:compos]
#si plusieurs instructions separees par des ; sur la meme ligne
inspos=line.find(u";")
sur la meme ligne : %s", ligne))
affectation_courante = AFFECTATION(self)
- affectation_courante.append_text(text)
+ affectation_courante.appendText(text)
if not linecontinueRE.search(line) \
and (hangingBraces == emptyHangingBraces) \
and not hangingComments:
#on passe a la ligne suivante
continue
- if self.is_commande(ligne):
+ if self.isCommande(ligne):
# --> nouvelle commande
affectation_courante = None
commande_courante = COMMANDE(self)
- commande_courante.append_text(ligne)
+ commande_courante.appendText(ligne)
#si la commande est complete, on la termine
if not linecontinueRE.search(line) \
and (hangingBraces == emptyHangingBraces) \
and not hangingComments:
- #la commande est terminee
- self.analyse_reel(commande_courante.texte)
+ #la commande est terminee
+ self.analyseReel(commande_courante.texte)
commande_courante = None
#on passe a la ligne suivante
continue
-
+
def enleve (self,texte) :
"""Supprime de texte tous les caracteres blancs, fins de ligne, tabulations
Le nouveau texte est retourne
i=0
chaine=""
while (i<len(texte)):
- if (texte[i] == " " or texte[i] == "\n" or texte[i] == "\t") :
- i=i+1
- else :
- chaine=chaine+texte[i]
- i=i+1
- return chaine
-
- def construit_genea(self,texte):
+ if (texte[i] == " " or texte[i] == "\n" or texte[i] == "\t") :
+ i=i+1
+ else :
+ chaine=chaine+texte[i]
+ i=i+1
+ return chaine
+
+ def construitGenea(self,texte):
indiceC=0
mot=""
dict_reel_concept={}
# traitement pour chaque caractere
- while (indiceC < len(texte)):
- c=texte[indiceC]
- if ( c == "," or c == "(u" or c == ")"):
- mot=""
- elif ( c== "="):
- #on doit trouver derriere soit une valeur soit une parenthese
- valeur=""
- nouvelindice=indiceC+1
- if texte[nouvelindice] != "(u":
- #pas de parenthese ouvrante derriere un signe =, on a une valeur.
- while ( texte[nouvelindice] != "," and texte[nouvelindice] != ")"):
- valeur=valeur+texte[nouvelindice]
- nouvelindice=nouvelindice+1
- if nouvelindice == len(texte) :
- nouvelindice=nouvelindice -1
- break
- if mot in self.appli.liste_simp_reel:
- if valeur[0] != "'":
- try :
- clef=eval(valeur)
- if str(clef) != str(valeur) :
- dict_reel_concept[clef]=valeur
- except :
- pass
- mot=""
- indiceC=nouvelindice
- else:
- #parenthese ouvrante derriere un signe =, on a un tuple de valeur ou de mots cles facteurs.
- # s agit -il d un tuple
- if texte[nouvelindice+1] != "(u":
- #le suivant n'est pas une parenthese ouvrante : on a un tuple de valeurs ou un mot cle facteur
- tuple=False
- #on avance jusqu'a la fin du tuple de valeurs ou jusqu'a la fin du premier mot cle simple
- #contenu dans le mot cle facteur
- while ( texte[nouvelindice] != "="):
- if texte[nouvelindice] == ")" :
- tuple=True
- break
- else :
- nouvelindice=nouvelindice+1
- if nouvelindice == len(texte) :
- nouvelindice=nouvelindice -1
- break
- if tuple :
- #cas du tuple de valeurs
- valeur=texte[indiceC+1:nouvelindice+1]
- indiceC=nouvelindice+1
- if mot in self.appli.liste_simp_reel:
- valeur=valeur[1:-1]
- for val in valeur.split(',') :
- # Attention la derniere valeur est""
- try :
- if val[0] != "'":
- clef=eval(val)
- if str(clef) != str(val) :
- dict_reel_concept[clef]=val
- except :
- pass
- mot=""
- # ou de ( imbriquees
- else :
- #cas du mocle facteur simple ou
+ while (indiceC < len(texte)):
+ c=texte[indiceC]
+ if ( c == "," or c == "(u" or c == ")"):
+ mot=""
+ elif ( c== "="):
+ #on doit trouver derriere soit une valeur soit une parenthese
+ valeur=""
+ nouvelindice=indiceC+1
+ if texte[nouvelindice] != "(u":
+ #pas de parenthese ouvrante derriere un signe =, on a une valeur.
+ while ( texte[nouvelindice] != "," and texte[nouvelindice] != ")"):
+ valeur=valeur+texte[nouvelindice]
+ nouvelindice=nouvelindice+1
+ if nouvelindice == len(texte) :
+ nouvelindice=nouvelindice -1
+ break
+ if mot in self.appliEficas.liste_simp_reel:
+ if valeur[0] != "'":
+ try :
+ clef=eval(valeur)
+ if str(clef) != str(valeur) :
+ dict_reel_concept[clef]=valeur
+ except :
+ pass
mot=""
- else :
- mot=mot+texte[indiceC]
- indiceC=indiceC+1
+ indiceC=nouvelindice
+ else:
+ #parenthese ouvrante derriere un signe =, on a un tuple de valeur ou de mots cles facteurs.
+ # s agit -il d un tuple
+ if texte[nouvelindice+1] != "(u":
+ #le suivant n'est pas une parenthese ouvrante : on a un tuple de valeurs ou un mot cle facteur
+ tuple=False
+ #on avance jusqu'a la fin du tuple de valeurs ou jusqu'a la fin du premier mot cle simple
+ #contenu dans le mot cle facteur
+ while ( texte[nouvelindice] != "="):
+ if texte[nouvelindice] == ")" :
+ tuple=True
+ break
+ else :
+ nouvelindice=nouvelindice+1
+ if nouvelindice == len(texte) :
+ nouvelindice=nouvelindice -1
+ break
+ if tuple :
+ #cas du tuple de valeurs
+ valeur=texte[indiceC+1:nouvelindice+1]
+ indiceC=nouvelindice+1
+ if mot in self.appliEficas.liste_simp_reel:
+ valeur=valeur[1:-1]
+ for val in valeur.split(',') :
+ # Attention la derniere valeur est""
+ try :
+ if val[0] != "'":
+ clef=eval(val)
+ if str(clef) != str(val) :
+ dict_reel_concept[clef]=val
+ except :
+ pass
+ mot=""
+ # ou de ( imbriquees
+ else :
+ #cas du mocle facteur simple ou
+ mot=""
+ else :
+ mot=mot+texte[indiceC]
+ indiceC=indiceC+1
# traitement du dernier inutile
- # c est un ;
+ # c est un ;
return dict_reel_concept
- def analyse_reel(self,commande) :
+ def analyseReel(self,commande) :
nomConcept=None
# On verifie qu on a bien un OPER
# et pas une MACRO
if commande.find(u"=") > commande.find(u"(u") :
- return
+ return
if commande.find(u"=") > 0:
- #epure1=self.enleve(commande)
- epure1=pattern_blancs.sub(u"",commande)
- nomConcept,corps=epure1.split(u"=",1)
- epure2=corps.replace(u"_F(u","(u")
- #nomConcept=epure1.split(u"=")[0]
- #index=epure1.find(u"=")
- #epure2=epure1[index+1:len(epure1)].replace(u"_F(u","(u")
- #dict_reel_concept=self.construit_genea(epure2)
- if self.appli:
- dict_reel_concept=construit_genea(epure2,self.appli.liste_simp_reel)
- else:
- dict_reel_concept={}
+ #epure1=self.enleve(commande)
+ epure1=pattern_blancs.sub(u"",commande)
+ nomConcept,corps=epure1.split(u"=",1)
+ epure2=corps.replace(u"_F(u","(u")
+ #nomConcept=epure1.split(u"=")[0]
+ #index=epure1.find(u"=")
+ #epure2=epure1[index+1:len(epure1)].replace(u"_F(u","(u")
+ #dict_reel_concept=self.construitGenea(epure2)
+ if self.appliEficas:
+ dict_reel_concept=construitGenea(epure2,self.appliEficas.liste_simp_reel)
+ else:
+ dict_reel_concept={}
if nomConcept == "sansnom" :
- nomConcept = ""
+ nomConcept = ""
if nomConcept !=None :
- if len(dict_reel_concept) != 0:
- self.appli.dict_reels[nomConcept]=dict_reel_concept
+ if len(dict_reel_concept) != 0:
+ self.appliEficas.dict_reels[nomConcept]=dict_reel_concept
- def get_texte(self,appli=None):
+ def getTexte(self,appliEficas=None):
"""
Retourne le texte issu de l'analyse
"""
- self.appli=appli
+ self.appliEficas=appliEficas
try:
#if 1:
if not self.l_objets : self.analyse()
for obj in self.l_objets:
txt = txt+str(obj)
#else :
- except ParserException:
+ except parserException:
#Impossible de convertir le texte, on le retourne tel que
txt=self.texte
return txt
def test():
- #import parseur_python
- import doctest
- doctest.testmod(parseur_python)
+ #import parseur_python
+ import doctest
+ doctest.testmod(parseur_python)
if __name__ == "__main__" :
import time
#fichier = 'D:/Eficas_dev/Tests/zzzz100a.comm'
#fichier = 'U:/Eficas_dev/Tests/test_eval.comm'
- texte = open(fichier,'r').read()
- class appli(object):
- dict_reels={}
- liste_simp_reel=["VALE","VALE_C","GROUP_MA","RAYON"]
- a=appli()
+ with open(fichier) as fd:
+ texte = fd.read()
+ class appliEficas(object):
+ dict_reels={}
+ liste_simp_reel=["VALE","VALE_C","GROUP_MA","RAYON"]
+ a=appliEficas()
compile(txt, '<string>', 'exec')
print((a.dict_reels))