5 # simple name translation map
6 postTransMap
= {"ok-button": "okbutton",
7 "cancel-button": "cancelbutton",
8 "help-button": "helpbutton"}
11 """Translate a mixed-casing name to dash-separated name.
13 Translate a mixed-casing name (e.g. MyLongName) to a dash-separated name
17 return c
>= 'A' and c
<= 'Z'
23 if isUpper(c
) and len(buf
) > 1:
38 newname
+= part
.lower()
40 # special-case mapping ...
41 if 0: #postTransMap.has_key(newname):
42 newname
= postTransMap
[newname
]
47 def transValue (value
):
48 """Translate certain values.
50 Examples of translated values include TRUE -> true, FALSE -> false.
52 if value
.lower() in ["true", "false"]:
57 def renameAttribute (name
, elemName
):
59 # TODO: all manner of evil special cases ...
60 if elemName
== 'metric-field' and name
== 'spin-size':
66 class Statement(object):
67 """Container to hold information for a single statement.
69 Each statement consists of the left-hand-side token(s), and right-hand-side
70 tokens, separated by a '=' token. This class stores the information on the
71 left-hand-side tokens.
78 class MacroExpander(object):
79 def __init__ (self
, tokens
, defines
):
81 self
.defines
= defines
85 while self
.pos
< len(self
.tokens
):
88 def expandToken (self
):
89 token
= self
.tokens
[self
.pos
]
90 if not self
.defines
.has_key(token
):
94 macro
= self
.defines
[token
]
95 nvars
= len(macro
.vars.keys())
98 self
.tokens
[self
.pos
:self
.pos
+1] = macro
.tokens
101 # Expansion with arguments.
102 values
, lastPos
= self
.parseValues()
104 for mtoken
in macro
.tokens
:
105 if macro
.vars.has_key(mtoken
):
107 pos
= macro
.vars[mtoken
]
108 valtokens
= values
[pos
]
109 for valtoken
in valtokens
:
110 newtokens
.append(valtoken
)
113 newtokens
.append(mtoken
)
115 self
.tokens
[self
.pos
:self
.pos
+lastPos
+1] = newtokens
118 def parseValues (self
):
119 """Parse tokens to get macro function variable values.
121 Be aware that there is an implicit quotes around the text between the open
122 paren, the comma(s), and the close paren. For instance, if a macro is defined
123 as FOO(a, b) and is used as FOO(one two three, and four), then the 'a' must be
124 replaced with 'one two three', and the 'b' replaced with 'and four'. In other
125 words, whitespace does not end a token.
134 tk
= self
.tokens
[self
.pos
+i
]
136 progress ("error parsing values (%d)\n"%i)
137 for j
in xrange(0, i
):
138 print self
.tokens
[self
.pos
+j
],
140 srclexer
.dumpTokens(self
.tokens
)
141 srclexer
.dumpTokens(self
.newtokens
)
142 print "tokens expanded so far:"
143 for tk
in self
.expandedTokens
:
146 srclexer
.dumpTokens(self
.defines
[tk
].tokens
)
161 raise ParseError ('')
168 def getTokens (self
):
172 class SrcParser(object):
174 def __init__ (self
, tokens
, defines
= None):
176 self
.defines
= defines
178 self
.onlyExpandMacros
= False
181 self
.elementStack
= [RootNode()]
182 self
.stmtData
= Statement()
186 # Expand defined macros.
188 progress ("-"*68+"\n")
189 for key
in self
.defines
.keys():
190 progress ("define: %s\n"%key
)
193 self
.tokenSize
= len(self
.tokens
)
195 def expandMacro (self
):
196 macroExp
= MacroExpander(self
.tokens
, self
.defines
)
198 self
.tokens
= macroExp
.getTokens()
199 if self
.onlyExpandMacros
:
200 srclexer
.dumpTokens(self
.tokens
)
206 This is the main loop for the parser. This is where it all begins and ends.
211 while i
< self
.tokenSize
:
214 i
= self
.openBrace(i
)
216 i
= self
.closeBrace(i
)
218 i
= self
.semiColon(i
)
220 i
= self
.assignment(i
)
222 self
.tokenBuf
.append(tk
)
226 return self
.elementStack
[0]
228 #-------------------------------------------------------------------------
232 Each token handler takes the current token position and returns the position
233 of the last token processed. For the most part, the current token position
234 and the last processed token are one and the same, in which case the handler
235 can simply return the position value it receives without incrementing it.
237 If you need to read ahead to process more tokens than just the current token,
238 make sure that the new token position points to the last token that has been
239 processed, not the next token that has not yet been processed. This is
240 because the main loop increments the token position when it returns from the
244 # assignment token '='
245 def assignment (self
, i
):
246 self
.leftTokens
= self
.tokenBuf
[:]
247 if self
.stmtData
.leftScope
== None:
248 # Keep track of lhs data in case of compound statement.
249 self
.stmtData
.leftTokens
= self
.tokenBuf
[:]
250 self
.stmtData
.leftScope
= len(self
.elementStack
) - 1
255 # open brace token '{'
256 def openBrace (self
, i
):
257 bufSize
= len(self
.tokenBuf
)
258 leftSize
= len(self
.leftTokens
)
260 if bufSize
== 0 and leftSize
> 0:
262 obj
= Element(self
.leftTokens
[0])
264 elif bufSize
> 0 and leftSize
== 0:
266 wgtType
= self
.tokenBuf
[0]
269 wgtRID
= self
.tokenBuf
[1]
270 obj
= Element(wgtType
, wgtRID
)
273 # LeftName = Name { ...
274 obj
= Element(self
.leftTokens
[0])
275 obj
.setAttr("type", self
.tokenBuf
[0])
277 obj
.name
= transName(obj
.name
)
279 if obj
.name
== 'string-list':
280 i
= self
.parseStringList(i
)
281 elif obj
.name
== 'filter-list':
282 i
= self
.parseFilterList(i
, obj
)
284 self
.elementStack
[-1].appendChild(obj
)
285 self
.elementStack
.append(obj
)
292 # close brace token '}'
293 def closeBrace (self
, i
):
294 if len(self
.tokenBuf
) > 0:
297 raise ParseError ('')
298 self
.elementStack
.pop()
301 # semi colon token ';'
302 def semiColon (self
, i
):
303 stackSize
= len(self
.elementStack
)
304 scope
= stackSize
- 1
305 if len(self
.tokenBuf
) == 0:
308 # We are not supposed to have any statment in global scope.
309 # Just ignore this statement.
312 # Statement within a scope. Import it as an attribute for the
314 elem
= self
.elementStack
[-1]
317 if len(self
.leftTokens
) > 0:
318 # Use the leftmost token as the name for now. If we need to
319 # do more complex parsing of lhs, add more code here.
320 name
= self
.leftTokens
[0]
321 name
= transName(name
)
324 i
= self
.parsePosAttr(i
)
326 i
= self
.parseSizeAttr(i
)
327 elif len (self
.tokenBuf
) == 1:
329 value
= transValue(self
.tokenBuf
[0])
330 name
= renameAttribute(name
, elem
.name
)
331 elem
.setAttr(name
, value
)
333 if not self
.stmtData
.leftScope
== None and self
.stmtData
.leftScope
< scope
:
334 # This is a nested scope within a statement. Do nothing for now.
337 if self
.stmtData
.leftScope
== scope
:
338 # end of (nested) statement.
339 self
.stmtData
.leftScope
= None
346 def parseStringList (self
, i
):
349 while i
< self
.tokenSize
:
357 def parseFilterList (self
, i
, obj
):
358 self
.elementStack
[-1].appendChild(obj
)
359 self
.elementStack
.append(obj
)
363 def parsePosAttr (self
, i
):
365 # MAP_APPFONT ( 6 , 5 )
366 elem
= self
.elementStack
[-1]
367 x
, y
= self
.parseMapAppfont(self
.tokenBuf
)
373 def parseSizeAttr (self
, i
):
375 # MAP_APPFONT ( 6 , 5 )
376 elem
= self
.elementStack
[-1]
377 width
, height
= self
.parseMapAppfont(self
.tokenBuf
)
378 elem
.setAttr("width", width
)
379 elem
.setAttr("height", height
)
383 def parseMapAppfont (self
, tokens
):
398 raise ParseError ('')
405 raise ParseError ('')
412 raise ParseError ('')
414 return eval(values
[0]), eval(values
[1])