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