1*cdf0e10cSrcweir
2*cdf0e10cSrcweirimport sys
3*cdf0e10cSrcweirfrom globals import *
4*cdf0e10cSrcweirimport srclexer
5*cdf0e10cSrcweir
6*cdf0e10cSrcweirclass MacroParser(object):
7*cdf0e10cSrcweir
8*cdf0e10cSrcweir    def __init__ (self, buf):
9*cdf0e10cSrcweir        self.buffer = buf
10*cdf0e10cSrcweir        self.macro = None
11*cdf0e10cSrcweir        self.debug = False
12*cdf0e10cSrcweir
13*cdf0e10cSrcweir    def parse (self):
14*cdf0e10cSrcweir        """
15*cdf0e10cSrcweirA macro with arguments must have its open paren immediately following
16*cdf0e10cSrcweirits name without any whitespace.
17*cdf0e10cSrcweir"""
18*cdf0e10cSrcweir        if self.debug:
19*cdf0e10cSrcweir            print "-"*68
20*cdf0e10cSrcweir            print "parsing '%s'"%self.buffer
21*cdf0e10cSrcweir
22*cdf0e10cSrcweir        i = 0
23*cdf0e10cSrcweir        bufSize = len(self.buffer)
24*cdf0e10cSrcweir        name, buf = '', ''
25*cdf0e10cSrcweir        while i < bufSize:
26*cdf0e10cSrcweir            c = self.buffer[i]
27*cdf0e10cSrcweir            if c in [' ', "\t"] and len(name) == 0:
28*cdf0e10cSrcweir                # This is a simple macro with no arguments.
29*cdf0e10cSrcweir                name = buf
30*cdf0e10cSrcweir                vars = []
31*cdf0e10cSrcweir                content = self.buffer[i:]
32*cdf0e10cSrcweir                self.setMacro(name, vars, content)
33*cdf0e10cSrcweir                return
34*cdf0e10cSrcweir            elif c == '(' and len(name) == 0:
35*cdf0e10cSrcweir                # This one has arguments.
36*cdf0e10cSrcweir                name = buf
37*cdf0e10cSrcweir                buf = self.buffer[i:]
38*cdf0e10cSrcweir                vars, content = self.parseArgs(buf)
39*cdf0e10cSrcweir                self.setMacro(name, vars, content)
40*cdf0e10cSrcweir                return
41*cdf0e10cSrcweir            else:
42*cdf0e10cSrcweir                buf += c
43*cdf0e10cSrcweir                i += 1
44*cdf0e10cSrcweir
45*cdf0e10cSrcweir    def parseArgs (self, buffer):
46*cdf0e10cSrcweir        """Parse arguments.
47*cdf0e10cSrcweir
48*cdf0e10cSrcweirThe buffer is expected to be formatted like '(a, b, c)' where the first
49*cdf0e10cSrcweircharacter is the open paren.
50*cdf0e10cSrcweir"""
51*cdf0e10cSrcweir        scope = 0
52*cdf0e10cSrcweir        buf = ''
53*cdf0e10cSrcweir        vars = []
54*cdf0e10cSrcweir        content = ''
55*cdf0e10cSrcweir        bufSize = len(buffer)
56*cdf0e10cSrcweir        i = 0
57*cdf0e10cSrcweir        while i < bufSize:
58*cdf0e10cSrcweir            c = buffer[i]
59*cdf0e10cSrcweir            if c == '(':
60*cdf0e10cSrcweir                scope += 1
61*cdf0e10cSrcweir            elif c == ')':
62*cdf0e10cSrcweir                scope -= 1
63*cdf0e10cSrcweir                if len(buf) > 0:
64*cdf0e10cSrcweir                    vars.append(buf)
65*cdf0e10cSrcweir                if scope == 0:
66*cdf0e10cSrcweir                    break
67*cdf0e10cSrcweir            elif c == ',':
68*cdf0e10cSrcweir                if len(buf) == 0:
69*cdf0e10cSrcweir                    raise globals.ParseError ('')
70*cdf0e10cSrcweir                vars.append(buf)
71*cdf0e10cSrcweir                buf = ''
72*cdf0e10cSrcweir            elif c in " \t" and scope > 0:
73*cdf0e10cSrcweir                pass
74*cdf0e10cSrcweir            else:
75*cdf0e10cSrcweir                buf += c
76*cdf0e10cSrcweir
77*cdf0e10cSrcweir            i += 1
78*cdf0e10cSrcweir
79*cdf0e10cSrcweir        if scope > 0:
80*cdf0e10cSrcweir            raise globals.ParseError ('')
81*cdf0e10cSrcweir
82*cdf0e10cSrcweir        return vars, buffer[i+1:]
83*cdf0e10cSrcweir
84*cdf0e10cSrcweir
85*cdf0e10cSrcweir    def setMacro (self, name, vars, content):
86*cdf0e10cSrcweir        if self.debug:
87*cdf0e10cSrcweir            print "-"*68
88*cdf0e10cSrcweir            print "name: %s"%name
89*cdf0e10cSrcweir            for var in vars:
90*cdf0e10cSrcweir                print "var: %s"%var
91*cdf0e10cSrcweir            if len(vars) == 0:
92*cdf0e10cSrcweir                print "no vars"
93*cdf0e10cSrcweir            print "content: '%s'"%content
94*cdf0e10cSrcweir
95*cdf0e10cSrcweir        if len(content) > 0:
96*cdf0e10cSrcweir            self.macro = Macro(name)
97*cdf0e10cSrcweir            for i in xrange(0, len(vars)):
98*cdf0e10cSrcweir                self.macro.vars[vars[i]] = i
99*cdf0e10cSrcweir
100*cdf0e10cSrcweir            # tokinize it using lexer.
101*cdf0e10cSrcweir            mclexer = srclexer.SrcLexer(content)
102*cdf0e10cSrcweir            mclexer.expandHeaders = False
103*cdf0e10cSrcweir            mclexer.inMacroDefine = True
104*cdf0e10cSrcweir            mclexer.tokenize()
105*cdf0e10cSrcweir            self.macro.tokens = mclexer.getTokens()
106*cdf0e10cSrcweir            if self.debug:
107*cdf0e10cSrcweir                print self.macro.tokens
108*cdf0e10cSrcweir
109*cdf0e10cSrcweir            if not self.isValidMacro(self.macro):
110*cdf0e10cSrcweir                self.macro = None
111*cdf0e10cSrcweir
112*cdf0e10cSrcweir        if self.debug:
113*cdf0e10cSrcweir            if self.macro != None:
114*cdf0e10cSrcweir                print "macro registered!"
115*cdf0e10cSrcweir            else:
116*cdf0e10cSrcweir                print "macro not registered"
117*cdf0e10cSrcweir
118*cdf0e10cSrcweir    def isValidMacro (self, macro):
119*cdf0e10cSrcweir
120*cdf0e10cSrcweir        n = len(macro.tokens)
121*cdf0e10cSrcweir        if n == 0:
122*cdf0e10cSrcweir            return False
123*cdf0e10cSrcweir        elif len(macro.name) > 4 and macro.name[1:4] == 'ID_':
124*cdf0e10cSrcweir            # We don't want to expand macros like HID_, SID_, WID_, etc.
125*cdf0e10cSrcweir            return False
126*cdf0e10cSrcweir        return True
127*cdf0e10cSrcweir
128*cdf0e10cSrcweir
129*cdf0e10cSrcweir    def getMacro (self):
130*cdf0e10cSrcweir        return self.macro
131