From 7d0d9001b51651ea82238626b6f043fac0c24514 Mon Sep 17 00:00:00 2001 From: Christian Caremoli <> Date: Mon, 24 Apr 2006 12:51:42 +0000 Subject: [PATCH] ajout traducteur syntaxique --- Traducteur/jdcparser.py | 34 +++++++ Traducteur/load.py | 49 ++++++++++ Traducteur/log.py | 8 ++ Traducteur/mocles.py | 127 ++++++++++++++++++++++++ Traducteur/parseur.py | 199 ++++++++++++++++++++++++++++++++++++++ Traducteur/removemocle.py | 49 ++++++++++ Traducteur/renamemocle.py | 34 +++++++ Traducteur/toto.comm | 74 ++++++++++++++ Traducteur/utils.py | 24 +++++ Traducteur/visiteur.py | 61 ++++++++++++ 10 files changed, 659 insertions(+) create mode 100644 Traducteur/jdcparser.py create mode 100644 Traducteur/load.py create mode 100644 Traducteur/log.py create mode 100644 Traducteur/mocles.py create mode 100644 Traducteur/parseur.py create mode 100644 Traducteur/removemocle.py create mode 100644 Traducteur/renamemocle.py create mode 100644 Traducteur/toto.comm create mode 100644 Traducteur/utils.py create mode 100644 Traducteur/visiteur.py diff --git a/Traducteur/jdcparser.py b/Traducteur/jdcparser.py new file mode 100644 index 00000000..8e450b67 --- /dev/null +++ b/Traducteur/jdcparser.py @@ -0,0 +1,34 @@ +import log + +from load import getJDC +from mocles import parseKeywords +import removemocle +import renamemocle + +atraiter=("DEBUT","LIRE_MAILLAGE","AFFE_MODELE","DEFI_GROUP", + "AFFE_MATERIAU","DEFI_MATERIAU","STAT_NONLINE", + ) + +filename="toto.comm" +jdc=getJDC(filename,atraiter) +root=jdc.root + +#Parse les mocles des commandes +parseKeywords(root) + +removemocle.removemocleinfact(jdc,"AFFE_MATERIAU","AFFE","TOUT") +removemocle.removemocle(jdc,"STAT_NONLINE","SOLVEUR") +renamemocle.renamemocleinfact(jdc,"AFFE_MODELE","AFFE","PHENOMENE","TOTO") +renamemocle.renamemocleinfact(jdc,"AFFE_MODELE","AFFE","MODELISATION","TITI") +renamemocle.renamemocleinfact(jdc,"DEFI_GROUP","CREA_GROUP_NO","GROUP_MA","TUTU") +removemocle.removemocle(jdc,"LIRE_MAILLAGE","INFO") +removemocle.removemocle(jdc,"LIRE_MAILLAGE","UNITE") +renamemocle.renamemocle(jdc,"DEFI_MATERIAU","ELAS","ELASTIC") +renamemocle.renamemocle(jdc,"AFFE_MATERIAU","MAILLAGE","MAILL") +removemocle.removemocleinfact(jdc,"STAT_NONLINE","SOLV","METHOD") +removemocle.removemocle(jdc,"STAT_NONLINE","AFFE") + + +f=open("tutu.comm",'w') +f.write(jdc.getSource()) +f.close() diff --git a/Traducteur/load.py b/Traducteur/load.py new file mode 100644 index 00000000..90757c07 --- /dev/null +++ b/Traducteur/load.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- + +import os +import parseur +from mocles import parseKeywords + +atraiter=("DEBUT","LIRE_MAILLAGE","AFFE_MODELE","DEFI_GROUP", + "AFFE_MATERIAU","DEFI_MATERIAU", + ) + +JDCdict={} + +class JDC: + """Cet objet conserve toutes les informations relatives à un fichier de commandes .comm""" + def __init__(self,filename,src,atraiter): + self.filename = os.path.abspath(filename) + self.atraiter=atraiter + self.init(src,atraiter) + + def init(self,src,atraiter): + self.root=parseur.parser(src,atraiter) + self.lines=src.splitlines(1) + + def parseKeywords(self): + parseKeywords(self.root) + + def reset(self,src): + self.init(src,self.atraiter) + self.parseKeywords() + + def getSource(self): + return "".join(self.getLines()) + + def getLine(self,linenum): + return self.getLines()[linenum-1] + + def getLines(self): + return self.lines + +def getJDC(filename,atraiter=atraiter): + jdc=JDCdict.get(filename) + if not jdc: + f=open(filename) + src=f.read() + f.close() + jdc=JDC(filename,src,atraiter) + JDCdict[filename]=jdc + return jdc + diff --git a/Traducteur/log.py b/Traducteur/log.py new file mode 100644 index 00000000..04994338 --- /dev/null +++ b/Traducteur/log.py @@ -0,0 +1,8 @@ +import logging +logger=logging.getLogger() +hdlr=logging.FileHandler('convert.log','w') +#formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') +formatter = logging.Formatter('%(levelname)s: %(message)s') +hdlr.setFormatter(formatter) +logger.addHandler(hdlr) +logger.setLevel(logging.INFO) diff --git a/Traducteur/mocles.py b/Traducteur/mocles.py new file mode 100644 index 00000000..f9429ad8 --- /dev/null +++ b/Traducteur/mocles.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- + +import compiler +import types +from parseur import Keyword,FactNode,lastparen,lastparen2 +from visiteur import KeywordFinder,visitor +from utils import indexToCoordinates + +debug=0 + +def parseFact(match,c,kw): + submatch=match[2] + lastpar=match[0]+lastparen(c.src[match[0]:]) + if type(submatch[0][0]) ==types.IntType: + #mot cle facteur isolé + no=FactNode() + kw.addChild(no) + for ii in range(len(submatch)-1): + e=submatch[ii] + x,y=indexToCoordinates(c.src,e[0]) + lineno=y+c.lineno + colno=x + x,y=indexToCoordinates(c.src,submatch[ii+1][0]) + endline=y+c.lineno + endcol=x + no.addChild(Keyword(e[1],lineno,colno,endline,endcol)) + #last one + e=submatch[-1] + x,y=indexToCoordinates(c.src,e[0]) + lineno=y+c.lineno + colno=x + x,y=indexToCoordinates(c.src,lastpar-1) + endline=y+c.lineno + endcol=x + no.addChild(Keyword(e[1],lineno,colno,endline,endcol)) + else: + #mot cle facteur multiple + ii=0 + for l in submatch: + lastpar=l[0][0]+lastparen2(c.src[l[0][0]:]) + ii=ii+1 + no=FactNode() + kw.addChild(no) + for j in range(len(l)-1): + e=l[j] + x,y=indexToCoordinates(c.src,e[0]) + lineno=y+c.lineno + colno=x + x,y=indexToCoordinates(c.src,l[j+1][0]) + endline=y+c.lineno + endcol=x + no.addChild(Keyword(e[1],lineno,colno,endline,endcol)) + #last one + e=l[-1] + x,y=indexToCoordinates(c.src,e[0]) + lineno=y+c.lineno + colno=x + x,y=indexToCoordinates(c.src,lastpar-1) + endline=y+c.lineno + endcol=x + no.addChild(Keyword(e[1],lineno,colno,endline,endcol)) + + +def parseKeywords(root): + """A partir d'un arbre contenant des commandes, ajoute les noeuds fils correspondant aux mocles + de la commande + """ + matchFinder=KeywordFinder() + + for c in root.childNodes: + ast=compiler.parse(c.src) + #print ast + matchFinder.reset(c.src) + visitor.walk(ast, matchFinder) + #print matchFinder.matches + if len(matchFinder.matches) > 1: + #plusieurs mocles trouvés : un mocle commence au début du keyword (matchFinder.matches[i][0]) + # et finit juste avant le keyword suivant (matchFinder.matches[i+1][0]]) + for i in range(len(matchFinder.matches)-1): + if debug:print "texte:",c.src[matchFinder.matches[i][0]:matchFinder.matches[i+1][0]] + x,y=indexToCoordinates(c.src,matchFinder.matches[i][0]) + lineno=y+c.lineno + colno=x + x,y=indexToCoordinates(c.src,matchFinder.matches[i+1][0]) + endline=y+c.lineno + endcol=x + if debug:print matchFinder.matches[i][0],matchFinder.matches[i][1],lineno,colno,endline,endcol + kw=Keyword(matchFinder.matches[i][1],lineno,colno,endline,endcol) + c.addChild(kw) + submatch= matchFinder.matches[i][2] + if submatch: + parseFact(matchFinder.matches[i],c,kw) + #dernier mocle : il commence au debut du dernier keyword (matchFinder.matches[i+1][0]) et + #finit avant la parenthese fermante de la commande (c.lastparen) + if debug:print "texte:",c.src[matchFinder.matches[i+1][0]:c.lastparen] + x,y=indexToCoordinates(c.src,matchFinder.matches[i+1][0]) + lineno=y+c.lineno + colno=x + x,y=indexToCoordinates(c.src,c.lastparen) + endline=y+c.lineno + endcol=x + if debug:print matchFinder.matches[i+1][0],matchFinder.matches[i+1][1],lineno,colno,endline,endcol + kw=Keyword(matchFinder.matches[i+1][1],lineno,colno,endline,endcol) + c.addChild(kw) + submatch= matchFinder.matches[i+1][2] + if submatch: + parseFact(matchFinder.matches[i+1],c,kw) + + elif len(matchFinder.matches) == 1: + #un seul mocle trouve : il commence au début du keyword (matchFinder.matches[0][0]) et + #finit juste avant la parenthese fermante de la commande (c.lastparen) + if debug:print "texte:",c.src[matchFinder.matches[0][0]:c.lastparen] + x,y=indexToCoordinates(c.src,matchFinder.matches[0][0]) + lineno=y+c.lineno + colno=x + x,y=indexToCoordinates(c.src,c.lastparen) + endline=y+c.lineno + endcol=x + if debug:print matchFinder.matches[0][0],matchFinder.matches[0][1],lineno,colno,endline,endcol + kw=Keyword(matchFinder.matches[0][1],lineno,colno,endline,endcol) + c.addChild(kw) + submatch= matchFinder.matches[0][2] + if submatch: + parseFact(matchFinder.matches[0],c,kw) + else: + pass + diff --git a/Traducteur/parseur.py b/Traducteur/parseur.py new file mode 100644 index 00000000..54f5861a --- /dev/null +++ b/Traducteur/parseur.py @@ -0,0 +1,199 @@ +# -*- coding: utf-8 -*- +import re,string +import compiler + +debug=0 + +escapedQuotesRE = re.compile(r"(\\\\|\\\"|\\\')") +stringsAndCommentsRE = \ + re.compile("(\"\"\".*?\"\"\"|'''.*?'''|\"[^\"]*\"|\'[^\']*\'|#.*?\n)", re.DOTALL) +allchars = string.maketrans("", "") +allcharsExceptNewline = allchars[: allchars.index('\n')]+allchars[allchars.index('\n')+1:] +allcharsExceptNewlineTranstable = string.maketrans(allcharsExceptNewline, '*'*len(allcharsExceptNewline)) + +def maskStringsAndComments(src): + """Remplace tous les caracteres dans commentaires et strings par des * """ + src = escapedQuotesRE.sub("**", src) + allstrings = stringsAndCommentsRE.split(src) + # every odd element is a string or comment + for i in xrange(1, len(allstrings), 2): + if allstrings[i].startswith("'''")or allstrings[i].startswith('"""'): + allstrings[i] = allstrings[i][:3]+ \ + allstrings[i][3:-3].translate(allcharsExceptNewlineTranstable)+ \ + allstrings[i][-3:] + else: + allstrings[i] = allstrings[i][0]+ \ + allstrings[i][1:-1].translate(allcharsExceptNewlineTranstable)+ \ + allstrings[i][-1] + + return "".join(allstrings) + +#un nombre queconque de blancs,un nom,des blancs +pattern_oper = re.compile(r"^\s*(.*?=\s*)?([a-zA-Z_]\w*)(\s*)(\()(.*)",re.DOTALL) +pattern_proc = re.compile(r"^\s*([a-zA-Z_]\w*)(\s*)(\()(.*)",re.DOTALL) + +implicitContinuationChars = (('(', ')'), ('[', ']'), ('{', '}')) +linecontinueRE = re.compile(r"\\\s*(#.*)?$") +emptyHangingBraces = [0,0,0,0,0] + +class UnbalancedBracesException: pass + +class Node: + def __init__(self): + self.childNodes=[] + + def addChild(self,node): + self.childNodes.append(node) + +class FactNode(Node):pass +class JDCNode(Node): + def __init__(self,src): + Node.__init__(self) + self.src=src + +class Command(Node): + def __init__(self,name,lineno,colno,firstparen): + Node.__init__(self) + self.name=name + self.lineno=lineno + self.colno=colno + self.firstparen=firstparen + +class Keyword(Node): + def __init__(self,name,lineno,colno,endline,endcol): + Node.__init__(self) + self.name=name + self.lineno=lineno + self.colno=colno + self.endline=endline + self.endcol=endcol + +def printNode(node): + if hasattr(node,'name'): + print node.name + else: + print "pas de nom pour:",node + for c in node.childNodes: + printNode(c) + +def parser(src,atraiter): + """Parse le texte src et retourne un arbre syntaxique (root). + + Cet arbre syntaxique a comme noeuds (childNodes) les commandes à traiter (liste atraiter) + """ + lines=src.splitlines(1) + maskedSrc=maskStringsAndComments(src) + #print maskedSrc + maskedLines=maskedSrc.splitlines(1) + + root=JDCNode(src) + + # (a) dans un premier temps on extrait les commandes et on les insère dans un arbre (root) + # les noeuds fils sont stockés dans root.childNodes (liste) + lineno=0 + for line in maskedLines: + lineno=lineno+1 + if debug:print "line",lineno,":",line + m=pattern_proc.match(line) + if m and (m.group(1) in atraiter): + if debug:print m.start(3),m.end(3),m.start(4) + root.addChild(Command(m.group(1),lineno,m.start(1),m.end(3))) + else: + m=pattern_oper.match(line) + if m and (m.group(2) in atraiter): + root.addChild(Command(m.group(2),lineno,m.start(2),m.end(4))) + + #(b) dans un deuxième temps , on récupère le texte complet de la commande jusqu'à la + # dernière parenthèse fermante + + #iterateur sur les lignes physiques masquées + iterlines=iter(maskedLines) + + linenum=0 + for c in root.childNodes: + lineno=c.lineno + colno=c.colno # début de la commande + while linenum < lineno: + line=iterlines.next() + linenum=linenum+1 + if linenum != lineno: + if debug:print "line %s:"%linenum, line + tmp = [] + hangingBraces = list(emptyHangingBraces) + hangingComments = 0 + while 1: + # update hanging braces + for i in range(len(implicitContinuationChars)): + contchar = implicitContinuationChars[i] + numHanging = hangingBraces[i] + hangingBraces[i] = numHanging+line.count(contchar[0]) - \ + line.count(contchar[1]) + + hangingComments ^= line.count('"""') % 2 + hangingComments ^= line.count("'''") % 2 + + if hangingBraces[0] < 0 or hangingBraces[1] < 0 or hangingBraces[2] < 0: + raise UnbalancedBracesException() + + if linecontinueRE.search(line): + tmp.append(lines[linenum-1]) + elif hangingBraces != emptyHangingBraces: + tmp.append(lines[linenum-1]) + elif hangingComments: + tmp.append(lines[linenum-1]) + else: + tmp.append(lines[linenum-1]) + src="".join(tmp) + c.src=src + c.endline=linenum + decal=len(line)-line.rindex(')') + c.lastparen=len(src)-decal + if debug:print "logical line %s %s:" % (c.lineno,c.endline),src + break + line=iterlines.next() + linenum=linenum+1 + + return root + + +def lastparen(src): + """Retourne la position de la derniere parenthese fermante dans src a partir du debut de la string + + La string doit contenir la premiere parenthese ouvrante + """ + src=maskStringsAndComments(src) + level=0 + i,n=0,len(src) + while i < n: + ch=src[i] + i=i+1 + if ch in ('(','['): + level=level+1 + if ch in (')',']'): + if level == 0: + raise UnbalancedBracesException() + level=level-1 + if level == 0: + #derniere parenthese fermante + return i + +def lastparen2(src): + """Retourne la position de la derniere parenthese fermante dans src a partir du debut de la string + + La string ne contient pas la premiere parenthese ouvrante + """ + src=maskStringsAndComments(src) + level=1 + i,n=0,len(src) + while i < n: + ch=src[i] + i=i+1 + if ch in ('(','['): + level=level+1 + if ch in (')',']'): + if level == 0: + raise UnbalancedBracesException() + level=level-1 + if level == 0: + #derniere parenthese fermante + return i diff --git a/Traducteur/removemocle.py b/Traducteur/removemocle.py new file mode 100644 index 00000000..66fabd79 --- /dev/null +++ b/Traducteur/removemocle.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +import logging +from parseur import FactNode + +debug=1 +#on n'a qu'un mocle par commande. On peut donc supprimer le mocle sans trop de précautions (a part iterer a l'envers sur les commandes) +#avant de supprimer un autre mocle, on remet à jour l'arbre syntaxique (lineno,colno,etc.) +def removemocle(jdc,command,mocle): + #on itere sur les commandes a l'envers pour ne pas polluer les numeros de ligne avec les modifications + commands= jdc.root.childNodes[:] + commands.reverse() + for c in commands: + if c.name != command:continue + for mc in c.childNodes: + if mc.name != mocle:continue + removemc(jdc,c,mc) + + jdc.reset(jdc.getSource()) + +def removemc(jdc,c,mc): + if debug:print "Suppression de:",c.name,mc.name,mc.lineno,mc.colno,mc.endline,mc.endcol + logging.info("Suppression de: %s, %s, %s, %s, %d, %d",c.name,mc.name,mc.lineno,mc.colno,mc.endline,mc.endcol) + if mc.endline > mc.lineno: + if debug:print "mocle sur plusieurs lignes--%s--" % jdc.getLines()[mc.lineno-1][mc.colno:] + jdc.getLines()[mc.lineno-1]=jdc.getLines()[mc.lineno-1][:mc.colno] + jdc.getLines()[mc.endline-1]=jdc.getLines()[mc.endline-1][mc.endcol:] + #attention : supprimer les lignes à la fin + jdc.getLines()[mc.lineno:mc.endline-1]=[] + else: + if debug:print "mocle sur une ligne--%s--" % jdc.getLines()[mc.lineno-1][mc.colno:mc.endcol] + s=jdc.getLines()[mc.lineno-1] + jdc.getLines()[mc.lineno-1]=s[:mc.colno]+s[mc.endcol:] + +def removemocleinfact(jdc,command,fact,mocle): + #on itere sur les commandes a l'envers pour ne pas polluer les numeros de ligne avec les modifications + commands= jdc.root.childNodes[:] + commands.reverse() + for c in commands: + if c.name != command:continue + for mc in c.childNodes: + if mc.name != fact:continue + l=mc.childNodes[:] + l.reverse() + for ll in l: + for n in ll.childNodes: + if n.name != mocle:continue + removemc(jdc,c,n) + + jdc.reset(jdc.getSource()) diff --git a/Traducteur/renamemocle.py b/Traducteur/renamemocle.py new file mode 100644 index 00000000..2c98e6f6 --- /dev/null +++ b/Traducteur/renamemocle.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +import logging +from parseur import FactNode +debug=0 +#on n'a qu'un mocle par commande. +#en fin de traitement, on remet à jour l'arbre syntaxique (lineno,colno,etc.) +def renamemocle(jdc,command,mocle,new_name): + for c in jdc.root.childNodes: + if c.name != command:continue + for mc in c.childNodes: + if mc.name != mocle:continue + if debug:print "Renommage de:",c.name,mc.name,mc.lineno,mc.colno + logging.info("Renommage de: %s, %s, %s, %s en %s",c.name,mc.name,mc.lineno,mc.colno,new_name) + s=jdc.getLines()[mc.lineno-1] + jdc.getLines()[mc.lineno-1]=s[:mc.colno]+new_name+s[mc.colno+len(mocle):] + + jdc.reset(jdc.getSource()) + +def renamemocleinfact(jdc,command,fact,mocle,new_name): + for c in jdc.root.childNodes: + if c.name != command:continue + for mc in c.childNodes: + if mc.name != fact:continue + l=mc.childNodes[:] + #on itere a l'envers + l.reverse() + for ll in l: + for n in ll.childNodes: + if n.name != mocle:continue + s=jdc.getLines()[n.lineno-1] + jdc.getLines()[n.lineno-1]=s[:n.colno]+new_name+s[n.colno+len(mocle):] + + jdc.reset(jdc.getSource()) + diff --git a/Traducteur/toto.comm b/Traducteur/toto.comm new file mode 100644 index 00000000..fbd94a1a --- /dev/null +++ b/Traducteur/toto.comm @@ -0,0 +1,74 @@ +DEBUT() + +MAIL=LIRE_MAILLAGE( ) + +# +# DEFINITION DES GROUPES DE NOEUDS +MAIL=DEFI_GROUP( reuse=MAIL, MAILLAGE=MAIL,CREA_GROUP_NO=( + _F( GROUP_MA = 'ENCAST'), + _F( GROUP_MA = 'CONT_PR'), + _F( GROUP_MA = ( 'B', 'SECT_MED', ))) + ) + +MAIL=DEFI_GROUP( CREA_GROUP_NO=[ + _F( GROUP_MA = 'ENCAST',INFO=2), + _F( GROUP_MA = 'CONT_PR'), + _F( GROUP_MA = ( 'B', 'SECT_MED', ))] + ) +# +# DEFINITION DU MODELE +MODELE=AFFE_MODELE( MAILLAGE=MAIL, + AFFE=_F( TOUT = 'OUI', + PHENOMENE = 'MECANIQUE', + MODELISATION = 'AXIS_FOURIER') ) + +# +# DEFINITION DU MATERIAU +ACIER=DEFI_MATERIAU( ELAS= _F( E = 2.1E11, NU = 0.3, + ALPHA = 1.E-5, RHO = 7800.) #comment + #comment + ) + +# +# ATTRIBUTION DU MATERIAU +CHMAT=AFFE_MATERIAU( MAILLAGE =MAIL, + AFFE=_F( TOUT = 'OUI', + MATER = ACIER) ) +CHMAT2=AFFE_MATERIAU( MAILLAGE =MAIL, + AFFE=(_F( TOUT = 'OUI', MATER = ACIER), + _F( TOUT = 'OUI', MATER = ACIER), + _F( TOUT = 'OUI', MATER = ACIER), + ) + ) +STAT_NONLINE(SOLVEUR=_F(METHOD="FRONT", + PREC=1.E-3)) +STAT_NONLINE(SOLV=_F(METHOD="FRONT", + PREC=1.E-3), + AFFE=(_F( TOUT = 'OUI', MATER = ACIER), + _F( TOUT = 'OUI', MATER = ACIER), + _F( TOUT = 'OUI', MATER = ACIER), + ) + ) + +MA=LIRE_MAILLAGE(UNITE=20,INFO=2,TEXT="""aaaa( +bbb""") +""" +MOO=AFFE_MODELE() +""" +MO=AFFE_MODELE(MAILLAGE=MA, + INFO=2, + ) +#LIRE_MAILLAGE() +MA2=LIRE_MAILLAGE(UNITE=21) +MA3 = LIRE_MAILLAGE ( #comment ( ] + UNITE=23, + ) +MA4 = LIRE_MAILLAGE ( #commentaire commande + UNITE + = + 24 + ,INFO=2 #commentaire mocle INFO + ) #commentaire fin commande +M5=LIRE_MAILLAGE ( #comment commande +) +a[2*(i+1)]=LIRE_MAILLAGE(UNITE=21) diff --git a/Traducteur/utils.py b/Traducteur/utils.py new file mode 100644 index 00000000..e14e310a --- /dev/null +++ b/Traducteur/utils.py @@ -0,0 +1,24 @@ +import re + +def indexToCoordinates(src, index): + """return le numero de la colonne (x) et le numero de la ligne (y) dans src""" + y = src[: index].count("\n") + startOfLineIdx = src.rfind("\n", 0, index)+1 + x = index-startOfLineIdx + return x, y + +def linetodict(line): + """Transforme une ligne (string) en un dictionnaire de mots repérés par le numéro de la colonne""" + + words = re.split("(\w+)", line) + h = {};i = 0 + for word in words: + h[i] = word + i+=len(word) + return h + +def dicttoline(d): + """Transformation inverse: à partir d'un dictionnaire retourne une ligne""" + cols = d.keys() + cols.sort() + return "".join([d[colno]for colno in cols]) diff --git a/Traducteur/visiteur.py b/Traducteur/visiteur.py new file mode 100644 index 00000000..b06ac8e3 --- /dev/null +++ b/Traducteur/visiteur.py @@ -0,0 +1,61 @@ +import re +from compiler import visitor + +class MatchFinder: + """Visiteur de base : gestion des matches """ + def reset(self,line): + self.matches = [] + self.words = re.split("(\w+)", line) # every other one is a non word + self.positions = [] + i = 0 + for word in self.words: + self.positions.append(i) + i+=len(word) + self.index = 0 + + def popWordsUpTo(self, word): + if word == "*": + return # won't be able to find this + posInWords = self.words.index(word) + idx = self.positions[posInWords] + self.words = self.words[posInWords+1:] + self.positions = self.positions[posInWords+1:] + + def appendMatch(self,name): + idx = self.getNextIndexOfWord(name) + self.matches.append((idx, name)) + + def getNextIndexOfWord(self,name): + return self.positions[self.words.index(name)] + + +class KeywordFinder(MatchFinder): + """Visiteur pour les keywords d'une commande """ + + def visitKeyword(self,node): + idx = self.getNextIndexOfWord(node.name) + #self.appendMatch(node.name) + self.popWordsUpTo(node.name) + prevmatches=self.matches + self.matches = [] + for child in node.getChildNodes(): + self.visit(child) + prevmatches.append((idx, node.name,self.matches)) + self.matches=prevmatches + + def visitTuple(self,node): + matchlist=[] + for child in node.getChildNodes(): + self.matches = [] + self.visit(child) + if self.matches: + #Pour eviter les tuples et listes ordinaires, on ne garde que les visites fructueuses + matchlist.append(self.matches) + self.matches=matchlist + + visitList=visitTuple + + def visitName(self,node): + self.popWordsUpTo(node.name) + def visitAssName(self,node): + self.popWordsUpTo(node.name) -- 2.39.2