1*cdf0e10cSrcweirimport sys
2*cdf0e10cSrcweirfrom globals import *
3*cdf0e10cSrcweirimport srclexer
4*cdf0e10cSrcweir
5*cdf0e10cSrcweir# simple name translation map
6*cdf0e10cSrcweirpostTransMap = {"ok-button": "okbutton",
7*cdf0e10cSrcweir                "cancel-button": "cancelbutton",
8*cdf0e10cSrcweir                "help-button": "helpbutton"}
9*cdf0e10cSrcweir
10*cdf0e10cSrcweirdef transName (name):
11*cdf0e10cSrcweir    """Translate a mixed-casing name to dash-separated name.
12*cdf0e10cSrcweir
13*cdf0e10cSrcweirTranslate a mixed-casing name (e.g. MyLongName) to a dash-separated name
14*cdf0e10cSrcweir(e.g. my-long-name).
15*cdf0e10cSrcweir"""
16*cdf0e10cSrcweir    def isUpper (c):
17*cdf0e10cSrcweir        return c >= 'A' and c <= 'Z'
18*cdf0e10cSrcweir
19*cdf0e10cSrcweir    newname = ''
20*cdf0e10cSrcweir    parts = []
21*cdf0e10cSrcweir    buf = ''
22*cdf0e10cSrcweir    for c in name:
23*cdf0e10cSrcweir        if isUpper(c) and len(buf) > 1:
24*cdf0e10cSrcweir            parts.append(buf)
25*cdf0e10cSrcweir            buf = c
26*cdf0e10cSrcweir        else:
27*cdf0e10cSrcweir            buf += c
28*cdf0e10cSrcweir
29*cdf0e10cSrcweir    if len(buf) > 0:
30*cdf0e10cSrcweir        parts.append(buf)
31*cdf0e10cSrcweir
32*cdf0e10cSrcweir    first = True
33*cdf0e10cSrcweir    for part in parts:
34*cdf0e10cSrcweir        if first:
35*cdf0e10cSrcweir            first = False
36*cdf0e10cSrcweir        else:
37*cdf0e10cSrcweir            newname += '-'
38*cdf0e10cSrcweir        newname += part.lower()
39*cdf0e10cSrcweir
40*cdf0e10cSrcweir    # special-case mapping ...
41*cdf0e10cSrcweir    if 0: #postTransMap.has_key(newname):
42*cdf0e10cSrcweir        newname = postTransMap[newname]
43*cdf0e10cSrcweir
44*cdf0e10cSrcweir    return newname
45*cdf0e10cSrcweir
46*cdf0e10cSrcweir
47*cdf0e10cSrcweirdef transValue (value):
48*cdf0e10cSrcweir    """Translate certain values.
49*cdf0e10cSrcweir
50*cdf0e10cSrcweirExamples of translated values include TRUE -> true, FALSE -> false.
51*cdf0e10cSrcweir"""
52*cdf0e10cSrcweir    if value.lower() in ["true", "false"]:
53*cdf0e10cSrcweir        value = value.lower()
54*cdf0e10cSrcweir    return value
55*cdf0e10cSrcweir
56*cdf0e10cSrcweir
57*cdf0e10cSrcweirdef renameAttribute (name, elemName):
58*cdf0e10cSrcweir
59*cdf0e10cSrcweir    # TODO: all manner of evil special cases ...
60*cdf0e10cSrcweir    if elemName == 'metric-field' and name == 'spin-size':
61*cdf0e10cSrcweir        return 'step-size'
62*cdf0e10cSrcweir
63*cdf0e10cSrcweir    return name
64*cdf0e10cSrcweir
65*cdf0e10cSrcweir
66*cdf0e10cSrcweirclass Statement(object):
67*cdf0e10cSrcweir    """Container to hold information for a single statement.
68*cdf0e10cSrcweir
69*cdf0e10cSrcweirEach statement consists of the left-hand-side token(s), and right-hand-side
70*cdf0e10cSrcweirtokens, separated by a '=' token.  This class stores the information on the
71*cdf0e10cSrcweirleft-hand-side tokens.
72*cdf0e10cSrcweir"""
73*cdf0e10cSrcweir    def __init__ (self):
74*cdf0e10cSrcweir        self.leftTokens = []
75*cdf0e10cSrcweir        self.leftScope = None
76*cdf0e10cSrcweir
77*cdf0e10cSrcweir
78*cdf0e10cSrcweirclass MacroExpander(object):
79*cdf0e10cSrcweir    def __init__ (self, tokens, defines):
80*cdf0e10cSrcweir        self.tokens = tokens
81*cdf0e10cSrcweir        self.defines = defines
82*cdf0e10cSrcweir
83*cdf0e10cSrcweir    def expand (self):
84*cdf0e10cSrcweir        self.pos = 0
85*cdf0e10cSrcweir        while self.pos < len(self.tokens):
86*cdf0e10cSrcweir            self.expandToken()
87*cdf0e10cSrcweir
88*cdf0e10cSrcweir    def expandToken (self):
89*cdf0e10cSrcweir        token = self.tokens[self.pos]
90*cdf0e10cSrcweir        if not self.defines.has_key(token):
91*cdf0e10cSrcweir            self.pos += 1
92*cdf0e10cSrcweir            return
93*cdf0e10cSrcweir
94*cdf0e10cSrcweir        macro = self.defines[token]
95*cdf0e10cSrcweir        nvars = len(macro.vars.keys())
96*cdf0e10cSrcweir        if nvars == 0:
97*cdf0e10cSrcweir            # Simple expansion
98*cdf0e10cSrcweir            self.tokens[self.pos:self.pos+1] = macro.tokens
99*cdf0e10cSrcweir            return
100*cdf0e10cSrcweir        else:
101*cdf0e10cSrcweir            # Expansion with arguments.
102*cdf0e10cSrcweir            values, lastPos = self.parseValues()
103*cdf0e10cSrcweir            newtokens = []
104*cdf0e10cSrcweir            for mtoken in macro.tokens:
105*cdf0e10cSrcweir                if macro.vars.has_key(mtoken):
106*cdf0e10cSrcweir                    # variable
107*cdf0e10cSrcweir                    pos = macro.vars[mtoken]
108*cdf0e10cSrcweir                    valtokens = values[pos]
109*cdf0e10cSrcweir                    for valtoken in valtokens:
110*cdf0e10cSrcweir                        newtokens.append(valtoken)
111*cdf0e10cSrcweir                else:
112*cdf0e10cSrcweir                    # not a variable
113*cdf0e10cSrcweir                    newtokens.append(mtoken)
114*cdf0e10cSrcweir
115*cdf0e10cSrcweir            self.tokens[self.pos:self.pos+lastPos+1] = newtokens
116*cdf0e10cSrcweir
117*cdf0e10cSrcweir
118*cdf0e10cSrcweir    def parseValues (self):
119*cdf0e10cSrcweir        """Parse tokens to get macro function variable values.
120*cdf0e10cSrcweir
121*cdf0e10cSrcweirBe aware that there is an implicit quotes around the text between the open
122*cdf0e10cSrcweirparen, the comma(s), and the close paren.  For instance, if a macro is defined
123*cdf0e10cSrcweiras FOO(a, b) and is used as FOO(one two three, and four), then the 'a' must be
124*cdf0e10cSrcweirreplaced with 'one two three', and the 'b' replaced with 'and four'.  In other
125*cdf0e10cSrcweirwords, whitespace does not end a token.
126*cdf0e10cSrcweir
127*cdf0e10cSrcweir"""
128*cdf0e10cSrcweir        values = []
129*cdf0e10cSrcweir        i = 1
130*cdf0e10cSrcweir        scope = 0
131*cdf0e10cSrcweir        value = []
132*cdf0e10cSrcweir        while True:
133*cdf0e10cSrcweir            try:
134*cdf0e10cSrcweir                tk = self.tokens[self.pos+i]
135*cdf0e10cSrcweir            except IndexError:
136*cdf0e10cSrcweir                progress ("error parsing values (%d)\n"%i)
137*cdf0e10cSrcweir                for j in xrange(0, i):
138*cdf0e10cSrcweir                    print self.tokens[self.pos+j],
139*cdf0e10cSrcweir                print ''
140*cdf0e10cSrcweir                srclexer.dumpTokens(self.tokens)
141*cdf0e10cSrcweir                srclexer.dumpTokens(self.newtokens)
142*cdf0e10cSrcweir                print "tokens expanded so far:"
143*cdf0e10cSrcweir                for tk in self.expandedTokens:
144*cdf0e10cSrcweir                    print "-"*20
145*cdf0e10cSrcweir                    print tk
146*cdf0e10cSrcweir                    srclexer.dumpTokens(self.defines[tk].tokens)
147*cdf0e10cSrcweir                sys.exit(1)
148*cdf0e10cSrcweir            if tk == '(':
149*cdf0e10cSrcweir                value = []
150*cdf0e10cSrcweir                scope += 1
151*cdf0e10cSrcweir            elif tk == ',':
152*cdf0e10cSrcweir                values.append(value)
153*cdf0e10cSrcweir                value = []
154*cdf0e10cSrcweir            elif tk == ')':
155*cdf0e10cSrcweir                scope -= 1
156*cdf0e10cSrcweir                values.append(value)
157*cdf0e10cSrcweir                value = []
158*cdf0e10cSrcweir                if scope == 0:
159*cdf0e10cSrcweir                    break
160*cdf0e10cSrcweir                else:
161*cdf0e10cSrcweir                    raise ParseError ('')
162*cdf0e10cSrcweir            else:
163*cdf0e10cSrcweir                value.append(tk)
164*cdf0e10cSrcweir            i += 1
165*cdf0e10cSrcweir
166*cdf0e10cSrcweir        return values, i
167*cdf0e10cSrcweir
168*cdf0e10cSrcweir    def getTokens (self):
169*cdf0e10cSrcweir        return self.tokens
170*cdf0e10cSrcweir
171*cdf0e10cSrcweir
172*cdf0e10cSrcweirclass SrcParser(object):
173*cdf0e10cSrcweir
174*cdf0e10cSrcweir    def __init__ (self, tokens, defines = None):
175*cdf0e10cSrcweir        self.tokens = tokens
176*cdf0e10cSrcweir        self.defines = defines
177*cdf0e10cSrcweir        self.debug = False
178*cdf0e10cSrcweir        self.onlyExpandMacros = False
179*cdf0e10cSrcweir
180*cdf0e10cSrcweir    def init (self):
181*cdf0e10cSrcweir        self.elementStack = [RootNode()]
182*cdf0e10cSrcweir        self.stmtData = Statement()
183*cdf0e10cSrcweir        self.tokenBuf = []
184*cdf0e10cSrcweir        self.leftTokens = []
185*cdf0e10cSrcweir
186*cdf0e10cSrcweir        # Expand defined macros.
187*cdf0e10cSrcweir        if self.debug:
188*cdf0e10cSrcweir            progress ("-"*68+"\n")
189*cdf0e10cSrcweir            for key in self.defines.keys():
190*cdf0e10cSrcweir                progress ("define: %s\n"%key)
191*cdf0e10cSrcweir
192*cdf0e10cSrcweir        self.expandMacro()
193*cdf0e10cSrcweir        self.tokenSize = len(self.tokens)
194*cdf0e10cSrcweir
195*cdf0e10cSrcweir    def expandMacro (self):
196*cdf0e10cSrcweir        macroExp = MacroExpander(self.tokens, self.defines)
197*cdf0e10cSrcweir        macroExp.expand()
198*cdf0e10cSrcweir        self.tokens = macroExp.getTokens()
199*cdf0e10cSrcweir        if self.onlyExpandMacros:
200*cdf0e10cSrcweir            srclexer.dumpTokens(self.tokens)
201*cdf0e10cSrcweir            sys.exit(0)
202*cdf0e10cSrcweir
203*cdf0e10cSrcweir    def parse (self):
204*cdf0e10cSrcweir        """Parse it!
205*cdf0e10cSrcweir
206*cdf0e10cSrcweirThis is the main loop for the parser.  This is where it all begins and ends.
207*cdf0e10cSrcweir"""
208*cdf0e10cSrcweir        self.init()
209*cdf0e10cSrcweir
210*cdf0e10cSrcweir        i = 0
211*cdf0e10cSrcweir        while i < self.tokenSize:
212*cdf0e10cSrcweir            tk = self.tokens[i]
213*cdf0e10cSrcweir            if tk == '{':
214*cdf0e10cSrcweir                i = self.openBrace(i)
215*cdf0e10cSrcweir            elif tk == '}':
216*cdf0e10cSrcweir                i = self.closeBrace(i)
217*cdf0e10cSrcweir            elif tk == ';':
218*cdf0e10cSrcweir                i = self.semiColon(i)
219*cdf0e10cSrcweir            elif tk == '=':
220*cdf0e10cSrcweir                i = self.assignment(i)
221*cdf0e10cSrcweir            else:
222*cdf0e10cSrcweir                self.tokenBuf.append(tk)
223*cdf0e10cSrcweir
224*cdf0e10cSrcweir            i += 1
225*cdf0e10cSrcweir
226*cdf0e10cSrcweir        return self.elementStack[0]
227*cdf0e10cSrcweir
228*cdf0e10cSrcweir    #-------------------------------------------------------------------------
229*cdf0e10cSrcweir    # Token Handlers
230*cdf0e10cSrcweir
231*cdf0e10cSrcweir    """
232*cdf0e10cSrcweirEach token handler takes the current token position and returns the position
233*cdf0e10cSrcweirof the last token processed.  For the most part, the current token position
234*cdf0e10cSrcweirand the last processed token are one and the same, in which case the handler
235*cdf0e10cSrcweircan simply return the position value it receives without incrementing it.
236*cdf0e10cSrcweir
237*cdf0e10cSrcweirIf you need to read ahead to process more tokens than just the current token,
238*cdf0e10cSrcweirmake sure that the new token position points to the last token that has been
239*cdf0e10cSrcweirprocessed, not the next token that has not yet been processed.  This is
240*cdf0e10cSrcweirbecause the main loop increments the token position when it returns from the
241*cdf0e10cSrcweirhandler.
242*cdf0e10cSrcweir"""
243*cdf0e10cSrcweir
244*cdf0e10cSrcweir    # assignment token '='
245*cdf0e10cSrcweir    def assignment (self, i):
246*cdf0e10cSrcweir        self.leftTokens = self.tokenBuf[:]
247*cdf0e10cSrcweir        if self.stmtData.leftScope == None:
248*cdf0e10cSrcweir            # Keep track of lhs data in case of compound statement.
249*cdf0e10cSrcweir            self.stmtData.leftTokens = self.tokenBuf[:]
250*cdf0e10cSrcweir            self.stmtData.leftScope = len(self.elementStack) - 1
251*cdf0e10cSrcweir
252*cdf0e10cSrcweir        self.tokenBuf = []
253*cdf0e10cSrcweir        return i
254*cdf0e10cSrcweir
255*cdf0e10cSrcweir    # open brace token '{'
256*cdf0e10cSrcweir    def openBrace (self, i):
257*cdf0e10cSrcweir        bufSize = len(self.tokenBuf)
258*cdf0e10cSrcweir        leftSize = len(self.leftTokens)
259*cdf0e10cSrcweir        obj = None
260*cdf0e10cSrcweir        if bufSize == 0 and leftSize > 0:
261*cdf0e10cSrcweir            # Name = { ...
262*cdf0e10cSrcweir            obj = Element(self.leftTokens[0])
263*cdf0e10cSrcweir
264*cdf0e10cSrcweir        elif bufSize > 0 and leftSize == 0:
265*cdf0e10cSrcweir            # Type Name { ...
266*cdf0e10cSrcweir            wgtType = self.tokenBuf[0]
267*cdf0e10cSrcweir            wgtRID = None
268*cdf0e10cSrcweir            if bufSize >= 2:
269*cdf0e10cSrcweir                wgtRID = self.tokenBuf[1]
270*cdf0e10cSrcweir            obj = Element(wgtType, wgtRID)
271*cdf0e10cSrcweir
272*cdf0e10cSrcweir        else:
273*cdf0e10cSrcweir            # LeftName = Name { ...
274*cdf0e10cSrcweir            obj = Element(self.leftTokens[0])
275*cdf0e10cSrcweir            obj.setAttr("type", self.tokenBuf[0])
276*cdf0e10cSrcweir
277*cdf0e10cSrcweir        obj.name = transName(obj.name)
278*cdf0e10cSrcweir
279*cdf0e10cSrcweir        if obj.name == 'string-list':
280*cdf0e10cSrcweir            i = self.parseStringList(i)
281*cdf0e10cSrcweir        elif obj.name == 'filter-list':
282*cdf0e10cSrcweir            i = self.parseFilterList(i, obj)
283*cdf0e10cSrcweir        else:
284*cdf0e10cSrcweir            self.elementStack[-1].appendChild(obj)
285*cdf0e10cSrcweir            self.elementStack.append(obj)
286*cdf0e10cSrcweir
287*cdf0e10cSrcweir        self.tokenBuf = []
288*cdf0e10cSrcweir        self.leftTokens = []
289*cdf0e10cSrcweir
290*cdf0e10cSrcweir        return i
291*cdf0e10cSrcweir
292*cdf0e10cSrcweir    # close brace token '}'
293*cdf0e10cSrcweir    def closeBrace (self, i):
294*cdf0e10cSrcweir        if len(self.tokenBuf) > 0:
295*cdf0e10cSrcweir            if self.debug:
296*cdf0e10cSrcweir                print self.tokenBuf
297*cdf0e10cSrcweir            raise ParseError ('')
298*cdf0e10cSrcweir        self.elementStack.pop()
299*cdf0e10cSrcweir        return i
300*cdf0e10cSrcweir
301*cdf0e10cSrcweir    # semi colon token ';'
302*cdf0e10cSrcweir    def semiColon (self, i):
303*cdf0e10cSrcweir        stackSize = len(self.elementStack)
304*cdf0e10cSrcweir        scope = stackSize - 1
305*cdf0e10cSrcweir        if len(self.tokenBuf) == 0:
306*cdf0e10cSrcweir            pass
307*cdf0e10cSrcweir        elif scope == 0:
308*cdf0e10cSrcweir            # We are not supposed to have any statment in global scope.
309*cdf0e10cSrcweir            # Just ignore this statement.
310*cdf0e10cSrcweir            pass
311*cdf0e10cSrcweir        else:
312*cdf0e10cSrcweir            # Statement within a scope.  Import it as an attribute for the
313*cdf0e10cSrcweir            # current element.
314*cdf0e10cSrcweir            elem = self.elementStack[-1]
315*cdf0e10cSrcweir
316*cdf0e10cSrcweir            name = "none"
317*cdf0e10cSrcweir            if len(self.leftTokens) > 0:
318*cdf0e10cSrcweir                # Use the leftmost token as the name for now.  If we need to
319*cdf0e10cSrcweir                # do more complex parsing of lhs, add more code here.
320*cdf0e10cSrcweir                name = self.leftTokens[0]
321*cdf0e10cSrcweir                name = transName(name)
322*cdf0e10cSrcweir
323*cdf0e10cSrcweir            if name == 'pos':
324*cdf0e10cSrcweir                i = self.parsePosAttr(i)
325*cdf0e10cSrcweir            elif name == 'size':
326*cdf0e10cSrcweir                i = self.parseSizeAttr(i)
327*cdf0e10cSrcweir            elif len (self.tokenBuf) == 1:
328*cdf0e10cSrcweir                # Simple value
329*cdf0e10cSrcweir                value = transValue(self.tokenBuf[0])
330*cdf0e10cSrcweir                name = renameAttribute(name, elem.name)
331*cdf0e10cSrcweir                elem.setAttr(name, value)
332*cdf0e10cSrcweir
333*cdf0e10cSrcweir            if not self.stmtData.leftScope == None and self.stmtData.leftScope < scope:
334*cdf0e10cSrcweir                # This is a nested scope within a statement.  Do nothing for now.
335*cdf0e10cSrcweir                pass
336*cdf0e10cSrcweir
337*cdf0e10cSrcweir        if self.stmtData.leftScope == scope:
338*cdf0e10cSrcweir            # end of (nested) statement.
339*cdf0e10cSrcweir            self.stmtData.leftScope = None
340*cdf0e10cSrcweir
341*cdf0e10cSrcweir        self.tokenBuf = []
342*cdf0e10cSrcweir        self.leftTokens = []
343*cdf0e10cSrcweir
344*cdf0e10cSrcweir        return i
345*cdf0e10cSrcweir
346*cdf0e10cSrcweir    def parseStringList (self, i):
347*cdf0e10cSrcweir
348*cdf0e10cSrcweir        i += 1
349*cdf0e10cSrcweir        while i < self.tokenSize:
350*cdf0e10cSrcweir            tk = self.tokens[i]
351*cdf0e10cSrcweir            if tk == '}':
352*cdf0e10cSrcweir                break
353*cdf0e10cSrcweir            i += 1
354*cdf0e10cSrcweir
355*cdf0e10cSrcweir        return i
356*cdf0e10cSrcweir
357*cdf0e10cSrcweir    def parseFilterList (self, i, obj):
358*cdf0e10cSrcweir        self.elementStack[-1].appendChild(obj)
359*cdf0e10cSrcweir        self.elementStack.append(obj)
360*cdf0e10cSrcweir
361*cdf0e10cSrcweir        return i
362*cdf0e10cSrcweir
363*cdf0e10cSrcweir    def parsePosAttr (self, i):
364*cdf0e10cSrcweir
365*cdf0e10cSrcweir        # MAP_APPFONT ( 6 , 5 )
366*cdf0e10cSrcweir        elem = self.elementStack[-1]
367*cdf0e10cSrcweir        x, y = self.parseMapAppfont(self.tokenBuf)
368*cdf0e10cSrcweir        elem.setAttr("x", x)
369*cdf0e10cSrcweir        elem.setAttr("y", y)
370*cdf0e10cSrcweir
371*cdf0e10cSrcweir        return i
372*cdf0e10cSrcweir
373*cdf0e10cSrcweir    def parseSizeAttr (self, i):
374*cdf0e10cSrcweir
375*cdf0e10cSrcweir        # MAP_APPFONT ( 6 , 5 )
376*cdf0e10cSrcweir        elem = self.elementStack[-1]
377*cdf0e10cSrcweir        width, height = self.parseMapAppfont(self.tokenBuf)
378*cdf0e10cSrcweir        elem.setAttr("width", width)
379*cdf0e10cSrcweir        elem.setAttr("height", height)
380*cdf0e10cSrcweir
381*cdf0e10cSrcweir        return i
382*cdf0e10cSrcweir
383*cdf0e10cSrcweir    def parseMapAppfont (self, tokens):
384*cdf0e10cSrcweir        values = []
385*cdf0e10cSrcweir        scope = 0
386*cdf0e10cSrcweir        val = ''
387*cdf0e10cSrcweir        for tk in tokens:
388*cdf0e10cSrcweir            if tk == '(':
389*cdf0e10cSrcweir                scope += 1
390*cdf0e10cSrcweir                if scope == 1:
391*cdf0e10cSrcweir                    val = ''
392*cdf0e10cSrcweir                else:
393*cdf0e10cSrcweir                    val += tk
394*cdf0e10cSrcweir            elif tk == ')':
395*cdf0e10cSrcweir                scope -= 1
396*cdf0e10cSrcweir                if scope == 0:
397*cdf0e10cSrcweir                    if len(val) == 0:
398*cdf0e10cSrcweir                        raise ParseError ('')
399*cdf0e10cSrcweir                    values.append(val)
400*cdf0e10cSrcweir                    break
401*cdf0e10cSrcweir                else:
402*cdf0e10cSrcweir                    val += tk
403*cdf0e10cSrcweir            elif tk == ',':
404*cdf0e10cSrcweir                if len(val) == 0:
405*cdf0e10cSrcweir                    raise ParseError ('')
406*cdf0e10cSrcweir                values.append(val)
407*cdf0e10cSrcweir                val = ''
408*cdf0e10cSrcweir            elif scope > 0:
409*cdf0e10cSrcweir                val += tk
410*cdf0e10cSrcweir
411*cdf0e10cSrcweir        if len(values) != 2:
412*cdf0e10cSrcweir            raise ParseError ('')
413*cdf0e10cSrcweir
414*cdf0e10cSrcweir        return eval(values[0]), eval(values[1])
415*cdf0e10cSrcweir
416*cdf0e10cSrcweir
417