19f22d7c2SAndrew Rist# *************************************************************
29f22d7c2SAndrew Rist#
39f22d7c2SAndrew Rist#  Licensed to the Apache Software Foundation (ASF) under one
49f22d7c2SAndrew Rist#  or more contributor license agreements.  See the NOTICE file
59f22d7c2SAndrew Rist#  distributed with this work for additional information
69f22d7c2SAndrew Rist#  regarding copyright ownership.  The ASF licenses this file
79f22d7c2SAndrew Rist#  to you under the Apache License, Version 2.0 (the
89f22d7c2SAndrew Rist#  "License"); you may not use this file except in compliance
99f22d7c2SAndrew Rist#  with the License.  You may obtain a copy of the License at
109f22d7c2SAndrew Rist#
119f22d7c2SAndrew Rist#    http://www.apache.org/licenses/LICENSE-2.0
129f22d7c2SAndrew Rist#
139f22d7c2SAndrew Rist#  Unless required by applicable law or agreed to in writing,
149f22d7c2SAndrew Rist#  software distributed under the License is distributed on an
159f22d7c2SAndrew Rist#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
169f22d7c2SAndrew Rist#  KIND, either express or implied.  See the License for the
179f22d7c2SAndrew Rist#  specific language governing permissions and limitations
189f22d7c2SAndrew Rist#  under the License.
199f22d7c2SAndrew Rist#
209f22d7c2SAndrew Rist# *************************************************************
219f22d7c2SAndrew Rist
22cdf0e10cSrcweir
23cdf0e10cSrcweirimport sys
24cdf0e10cSrcweirfrom globals import *
25cdf0e10cSrcweirimport srclexer
26cdf0e10cSrcweir
27cdf0e10cSrcweirclass MacroParser(object):
28cdf0e10cSrcweir
29cdf0e10cSrcweir    def __init__ (self, buf):
30cdf0e10cSrcweir        self.buffer = buf
31cdf0e10cSrcweir        self.macro = None
32cdf0e10cSrcweir        self.debug = False
33cdf0e10cSrcweir
34cdf0e10cSrcweir    def parse (self):
35cdf0e10cSrcweir        """
36*ae54856bSPedro GiffuniA macro with arguments must have its open paren immediately following
37cdf0e10cSrcweirits name without any whitespace.
38cdf0e10cSrcweir"""
39cdf0e10cSrcweir        if self.debug:
40cdf0e10cSrcweir            print "-"*68
41cdf0e10cSrcweir            print "parsing '%s'"%self.buffer
42cdf0e10cSrcweir
43cdf0e10cSrcweir        i = 0
44cdf0e10cSrcweir        bufSize = len(self.buffer)
45cdf0e10cSrcweir        name, buf = '', ''
46cdf0e10cSrcweir        while i < bufSize:
47cdf0e10cSrcweir            c = self.buffer[i]
48cdf0e10cSrcweir            if c in [' ', "\t"] and len(name) == 0:
49cdf0e10cSrcweir                # This is a simple macro with no arguments.
50cdf0e10cSrcweir                name = buf
51cdf0e10cSrcweir                vars = []
52cdf0e10cSrcweir                content = self.buffer[i:]
53cdf0e10cSrcweir                self.setMacro(name, vars, content)
54cdf0e10cSrcweir                return
55cdf0e10cSrcweir            elif c == '(' and len(name) == 0:
56cdf0e10cSrcweir                # This one has arguments.
57cdf0e10cSrcweir                name = buf
58cdf0e10cSrcweir                buf = self.buffer[i:]
59cdf0e10cSrcweir                vars, content = self.parseArgs(buf)
60cdf0e10cSrcweir                self.setMacro(name, vars, content)
61cdf0e10cSrcweir                return
62cdf0e10cSrcweir            else:
63cdf0e10cSrcweir                buf += c
64cdf0e10cSrcweir                i += 1
65cdf0e10cSrcweir
66cdf0e10cSrcweir    def parseArgs (self, buffer):
67cdf0e10cSrcweir        """Parse arguments.
68cdf0e10cSrcweir
69*ae54856bSPedro GiffuniThe buffer is expected to be formatted like '(a, b, c)' where the first
70cdf0e10cSrcweircharacter is the open paren.
71cdf0e10cSrcweir"""
72cdf0e10cSrcweir        scope = 0
73cdf0e10cSrcweir        buf = ''
74cdf0e10cSrcweir        vars = []
75cdf0e10cSrcweir        content = ''
76cdf0e10cSrcweir        bufSize = len(buffer)
77cdf0e10cSrcweir        i = 0
78cdf0e10cSrcweir        while i < bufSize:
79cdf0e10cSrcweir            c = buffer[i]
80cdf0e10cSrcweir            if c == '(':
81cdf0e10cSrcweir                scope += 1
82cdf0e10cSrcweir            elif c == ')':
83cdf0e10cSrcweir                scope -= 1
84cdf0e10cSrcweir                if len(buf) > 0:
85cdf0e10cSrcweir                    vars.append(buf)
86cdf0e10cSrcweir                if scope == 0:
87cdf0e10cSrcweir                    break
88cdf0e10cSrcweir            elif c == ',':
89cdf0e10cSrcweir                if len(buf) == 0:
90cdf0e10cSrcweir                    raise globals.ParseError ('')
91cdf0e10cSrcweir                vars.append(buf)
92cdf0e10cSrcweir                buf = ''
93cdf0e10cSrcweir            elif c in " \t" and scope > 0:
94cdf0e10cSrcweir                pass
95cdf0e10cSrcweir            else:
96cdf0e10cSrcweir                buf += c
97cdf0e10cSrcweir
98cdf0e10cSrcweir            i += 1
99cdf0e10cSrcweir
100cdf0e10cSrcweir        if scope > 0:
101cdf0e10cSrcweir            raise globals.ParseError ('')
102cdf0e10cSrcweir
103cdf0e10cSrcweir        return vars, buffer[i+1:]
104cdf0e10cSrcweir
105cdf0e10cSrcweir
106cdf0e10cSrcweir    def setMacro (self, name, vars, content):
107cdf0e10cSrcweir        if self.debug:
108cdf0e10cSrcweir            print "-"*68
109cdf0e10cSrcweir            print "name: %s"%name
110cdf0e10cSrcweir            for var in vars:
111cdf0e10cSrcweir                print "var: %s"%var
112cdf0e10cSrcweir            if len(vars) == 0:
113cdf0e10cSrcweir                print "no vars"
114cdf0e10cSrcweir            print "content: '%s'"%content
115cdf0e10cSrcweir
116cdf0e10cSrcweir        if len(content) > 0:
117cdf0e10cSrcweir            self.macro = Macro(name)
118cdf0e10cSrcweir            for i in xrange(0, len(vars)):
119cdf0e10cSrcweir                self.macro.vars[vars[i]] = i
120cdf0e10cSrcweir
121cdf0e10cSrcweir            # tokinize it using lexer.
122cdf0e10cSrcweir            mclexer = srclexer.SrcLexer(content)
123cdf0e10cSrcweir            mclexer.expandHeaders = False
124cdf0e10cSrcweir            mclexer.inMacroDefine = True
125cdf0e10cSrcweir            mclexer.tokenize()
126cdf0e10cSrcweir            self.macro.tokens = mclexer.getTokens()
127cdf0e10cSrcweir            if self.debug:
128cdf0e10cSrcweir                print self.macro.tokens
129*ae54856bSPedro Giffuni
130cdf0e10cSrcweir            if not self.isValidMacro(self.macro):
131cdf0e10cSrcweir                self.macro = None
132cdf0e10cSrcweir
133cdf0e10cSrcweir        if self.debug:
134cdf0e10cSrcweir            if self.macro != None:
135cdf0e10cSrcweir                print "macro registered!"
136cdf0e10cSrcweir            else:
137cdf0e10cSrcweir                print "macro not registered"
138cdf0e10cSrcweir
139cdf0e10cSrcweir    def isValidMacro (self, macro):
140cdf0e10cSrcweir
141cdf0e10cSrcweir        n = len(macro.tokens)
142cdf0e10cSrcweir        if n == 0:
143cdf0e10cSrcweir            return False
144cdf0e10cSrcweir        elif len(macro.name) > 4 and macro.name[1:4] == 'ID_':
145cdf0e10cSrcweir            # We don't want to expand macros like HID_, SID_, WID_, etc.
146cdf0e10cSrcweir            return False
147cdf0e10cSrcweir        return True
148cdf0e10cSrcweir
149cdf0e10cSrcweir
150cdf0e10cSrcweir    def getMacro (self):
151cdf0e10cSrcweir        return self.macro
152