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