]> SALOME platform Git repositories - tools/eficas.git/blob - Traducteur/parseur.py
Salome HOME
5b4a223fa5de0857a098f2b6d44c599ea581fd0a
[tools/eficas.git] / Traducteur / parseur.py
1 # -*- coding: utf-8 -*-
2 import re,string
3 import compiler
4
5 debug=0
6
7 escapedQuotesRE = re.compile(r"(\\\\|\\\"|\\\')")
8 stringsAndCommentsRE =  \
9       re.compile("(\"\"\".*?\"\"\"|'''.*?'''|\"[^\"]*\"|\'[^\']*\'|#.*?\n)", re.DOTALL)
10 allchars = string.maketrans("", "")
11 allcharsExceptNewline = allchars[: allchars.index('\n')]+allchars[allchars.index('\n')+1:]
12 allcharsExceptNewlineTranstable = string.maketrans(allcharsExceptNewline, '*'*len(allcharsExceptNewline))
13
14 def maskStringsAndComments(src):
15     """Remplace tous les caracteres dans commentaires et strings par des * """
16     src = escapedQuotesRE.sub("**", src)
17     allstrings = stringsAndCommentsRE.split(src)
18     # every odd element is a string or comment
19     for i in xrange(1, len(allstrings), 2):
20         if allstrings[i].startswith("'''")or allstrings[i].startswith('"""'):
21             allstrings[i] = allstrings[i][:3]+ \
22                            allstrings[i][3:-3].translate(allcharsExceptNewlineTranstable)+ \
23                            allstrings[i][-3:]
24         else:
25             allstrings[i] = allstrings[i][0]+ \
26                            allstrings[i][1:-1].translate(allcharsExceptNewlineTranstable)+ \
27                            allstrings[i][-1]
28
29     return "".join(allstrings)
30
31 #un nombre queconque de blancs,un nom,des blancs
32 pattern_oper   = re.compile(r"^\s*(.*?=\s*)?([a-zA-Z_]\w*)(\s*)(\()(.*)",re.DOTALL)
33 pattern_proc   = re.compile(r"^\s*([a-zA-Z_]\w*)(\s*)(\()(.*)",re.DOTALL)
34
35 implicitContinuationChars = (('(', ')'), ('[', ']'), ('{', '}'))
36 linecontinueRE = re.compile(r"\\\s*(#.*)?$")
37 emptyHangingBraces = [0,0,0,0,0]
38
39 class UnbalancedBracesException: pass
40
41 class Node:
42     def __init__(self):
43         self.childNodes=[]
44
45     def addChild(self,node):
46         self.childNodes.append(node)
47
48
49 class FactNode(Node):pass
50 class JDCNode(Node):
51     def __init__(self,src):
52         Node.__init__(self)
53         self.src=src
54
55 class Command(Node):
56     def __init__(self,name,lineno,colno,firstparen):
57         Node.__init__(self)
58         self.name=name
59         self.lineno=lineno
60         self.colno=colno
61         self.firstparen=firstparen
62
63 class Keyword(Node):
64     def __init__(self,name,lineno,colno,endline,endcol):
65         Node.__init__(self)
66         self.name=name
67         self.lineno=lineno
68         self.colno=colno
69         self.endline=endline
70         self.endcol=endcol
71
72     def getText(self,jdc):
73         if self.endline > self.lineno:
74             lignecourante=self.lineno + 1 
75             debut=jdc.getLines()[self.lineno-1][self.colno:]
76             fin  = jdc.getLines()[self.endline-1][:self.endcol]
77             texte=debut
78             lignecourante=self.lineno + 1 
79             while  lignecourante > self.endline  :
80                 texte = texte + jdc.getLines()[lignecourante]
81                 lignecourante = lignecourante + 1
82             if chaineBlanche(fin) == 0 :  
83                texte=texte + fin
84             if texte[-1] == "\n" :
85                texte=texte[0:-1]
86         else:
87             texte = jdc.getLines()[self.lineno-1][self.colno:self.endcol]
88         return texte
89
90 def chaineBlanche(texte) :
91 # retourne 1 si la chaine est composee de " "
92 # retourne 0 sinon
93     bool = 1 ;
94     for i in range(len(texte)) :
95         if texte[i] != " " : bool = 0
96     return bool
97
98 def printNode(node):
99     if hasattr(node,'name'):
100         print node.name
101     else:
102         print "pas de nom pour:",node
103     for c in node.childNodes:
104         printNode(c)
105
106 def parser(src,atraiter):
107     """Parse le texte src et retourne un arbre syntaxique (root).
108
109        Cet arbre syntaxique a comme noeuds (childNodes) les commandes à traiter (liste atraiter)
110     """
111     lines=src.splitlines(1)
112     maskedSrc=maskStringsAndComments(src)
113     maskedLines=maskedSrc.splitlines(1)
114
115     root=JDCNode(src)
116
117     # (a) dans un premier temps on extrait les commandes et on les insère dans un arbre (root) 
118     # les noeuds fils sont stockés dans root.childNodes (liste)
119     lineno=0
120     for line in maskedLines:
121         lineno=lineno+1
122         if debug:print "line",lineno,":",line
123         m=pattern_proc.match(line)
124         if m and (m.group(1) in atraiter):
125             if debug:print m.start(3),m.end(3),m.start(4)
126             root.addChild(Command(m.group(1),lineno,m.start(1),m.end(3)))
127         else:
128             m=pattern_oper.match(line)
129             if m and (m.group(2) in atraiter):
130                 root.addChild(Command(m.group(2),lineno,m.start(2),m.end(4)))
131
132     #(b) dans un deuxième temps , on récupère le texte complet de la commande jusqu'à la
133     # dernière parenthèse fermante
134
135     #iterateur sur les lignes physiques masquées
136     iterlines=iter(maskedLines)
137
138     linenum=0
139     for c in root.childNodes:
140         lineno=c.lineno
141         colno=c.colno # début de la commande
142         while linenum < lineno:
143             line=iterlines.next()
144             linenum=linenum+1
145             if linenum != lineno:
146                 if debug:print "line %s:"%linenum, line
147         tmp = []
148         hangingBraces = list(emptyHangingBraces)
149         hangingComments = 0
150         while 1:
151             # update hanging braces
152             for i in range(len(implicitContinuationChars)):
153                 contchar = implicitContinuationChars[i]
154                 numHanging = hangingBraces[i]
155
156                 hangingBraces[i] = numHanging+line.count(contchar[0]) - \
157                                 line.count(contchar[1])
158
159             hangingComments ^= line.count('"""') % 2
160             hangingComments ^= line.count("'''") % 2
161     
162             if hangingBraces[0] < 0 or hangingBraces[1] < 0 or hangingBraces[2] < 0:
163                 raise UnbalancedBracesException()
164
165             if linecontinueRE.search(line):
166                 tmp.append(lines[linenum-1])
167             elif hangingBraces != emptyHangingBraces:
168                 tmp.append(lines[linenum-1])
169             elif hangingComments:
170                 tmp.append(lines[linenum-1])
171             else:
172                 tmp.append(lines[linenum-1])
173                 src="".join(tmp)
174                 c.src=src
175                 c.endline=linenum
176                 decal=len(line)-line.rindex(')')
177                 c.lastparen=len(src)-decal
178                 if debug:print "logical line %s %s:" % (c.lineno,c.endline),src
179                 break
180             line=iterlines.next()
181             linenum=linenum+1
182
183     return root
184
185
186 def lastparen(src):
187     """Retourne la position de la derniere parenthese fermante dans src a partir du debut de la string
188
189        La string doit contenir la premiere parenthese ouvrante
190     """
191     src=maskStringsAndComments(src)
192     level=0
193     i,n=0,len(src)
194     while i < n:
195         ch=src[i]
196         i=i+1
197         if ch in ('(','['):
198             level=level+1
199         if ch in (')',']'):
200             if level == 0:
201                 raise UnbalancedBracesException()
202             level=level-1
203             if level == 0:
204                 #derniere parenthese fermante
205                 return i
206
207 def lastparen2(src):
208     """Retourne la position de la derniere parenthese fermante dans src a partir du debut de la string
209
210        La string ne contient pas la premiere parenthese ouvrante
211     """
212     src=maskStringsAndComments(src)
213     level=1
214     i,n=0,len(src)
215     while i < n:
216         ch=src[i]
217         i=i+1
218         if ch in ('(','['):
219             level=level+1
220         if ch in (')',']'):
221             if level == 0:
222                 raise UnbalancedBracesException()
223             level=level-1
224             if level == 0:
225                 #derniere parenthese fermante
226                 return i
227