1*b1cdbd2cSJim Jagielski# *************************************************************
2*b1cdbd2cSJim Jagielski#
3*b1cdbd2cSJim Jagielski#  Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski#  or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski#  distributed with this work for additional information
6*b1cdbd2cSJim Jagielski#  regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski#  to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski#  "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski#  with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski#
11*b1cdbd2cSJim Jagielski#    http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski#
13*b1cdbd2cSJim Jagielski#  Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski#  software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski#  KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski#  specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski#  under the License.
19*b1cdbd2cSJim Jagielski#
20*b1cdbd2cSJim Jagielski# *************************************************************
21*b1cdbd2cSJim Jagielski
22*b1cdbd2cSJim Jagielskiimport sys, os.path
23*b1cdbd2cSJim Jagielskifrom globals import *
24*b1cdbd2cSJim Jagielskiimport macroparser
25*b1cdbd2cSJim Jagielski
26*b1cdbd2cSJim Jagielskiclass EOF(Exception):
27*b1cdbd2cSJim Jagielski    def __init__ (self):
28*b1cdbd2cSJim Jagielski        pass
29*b1cdbd2cSJim Jagielski
30*b1cdbd2cSJim Jagielski    def str (self):
31*b1cdbd2cSJim Jagielski        return "end of file"
32*b1cdbd2cSJim Jagielski
33*b1cdbd2cSJim Jagielskiclass BOF(Exception):
34*b1cdbd2cSJim Jagielski    def __init__ (self):
35*b1cdbd2cSJim Jagielski        pass
36*b1cdbd2cSJim Jagielski
37*b1cdbd2cSJim Jagielski    def str (self):
38*b1cdbd2cSJim Jagielski        return "beginning of file"
39*b1cdbd2cSJim Jagielski
40*b1cdbd2cSJim Jagielski
41*b1cdbd2cSJim Jagielskidef removeHeaderQuotes (orig):
42*b1cdbd2cSJim Jagielski    if len(orig) <= 2:
43*b1cdbd2cSJim Jagielski        return orig
44*b1cdbd2cSJim Jagielski    elif orig[0] == orig[-1] == '"':
45*b1cdbd2cSJim Jagielski        return orig[1:-1]
46*b1cdbd2cSJim Jagielski    elif orig[0] == '<' and orig[-1] == '>':
47*b1cdbd2cSJim Jagielski        return orig[1:-1]
48*b1cdbd2cSJim Jagielski
49*b1cdbd2cSJim Jagielski    return orig
50*b1cdbd2cSJim Jagielski
51*b1cdbd2cSJim Jagielski
52*b1cdbd2cSJim Jagielskidef dumpTokens (tokens, toError=False):
53*b1cdbd2cSJim Jagielski
54*b1cdbd2cSJim Jagielski    scope = 0
55*b1cdbd2cSJim Jagielski    indent = "    "
56*b1cdbd2cSJim Jagielski    line = ''
57*b1cdbd2cSJim Jagielski    chars = ''
58*b1cdbd2cSJim Jagielski
59*b1cdbd2cSJim Jagielski    for token in tokens:
60*b1cdbd2cSJim Jagielski        if token in '{<':
61*b1cdbd2cSJim Jagielski            if len(line) > 0:
62*b1cdbd2cSJim Jagielski                chars += indent*scope + line + "\n"
63*b1cdbd2cSJim Jagielski                line = ''
64*b1cdbd2cSJim Jagielski            chars += indent*scope + token + "\n"
65*b1cdbd2cSJim Jagielski            scope += 1
66*b1cdbd2cSJim Jagielski
67*b1cdbd2cSJim Jagielski        elif token in '}>':
68*b1cdbd2cSJim Jagielski            if len(line) > 0:
69*b1cdbd2cSJim Jagielski                chars += indent*scope + line + "\n"
70*b1cdbd2cSJim Jagielski                line = ''
71*b1cdbd2cSJim Jagielski            scope -= 1
72*b1cdbd2cSJim Jagielski            chars += indent*scope + token
73*b1cdbd2cSJim Jagielski
74*b1cdbd2cSJim Jagielski        elif token == ';':
75*b1cdbd2cSJim Jagielski            if len(line) > 0:
76*b1cdbd2cSJim Jagielski                chars += indent*scope + line + ";\n"
77*b1cdbd2cSJim Jagielski                line = ''
78*b1cdbd2cSJim Jagielski            else:
79*b1cdbd2cSJim Jagielski                chars += ";\n"
80*b1cdbd2cSJim Jagielski        elif len(token) > 0:
81*b1cdbd2cSJim Jagielski            line += token + ' '
82*b1cdbd2cSJim Jagielski
83*b1cdbd2cSJim Jagielski    if len(line) > 0:
84*b1cdbd2cSJim Jagielski        chars += line
85*b1cdbd2cSJim Jagielski    chars += "\n"
86*b1cdbd2cSJim Jagielski    if toError:
87*b1cdbd2cSJim Jagielski        sys.stderr.write(chars)
88*b1cdbd2cSJim Jagielski    else:
89*b1cdbd2cSJim Jagielski        sys.stdout.write(chars)
90*b1cdbd2cSJim Jagielski
91*b1cdbd2cSJim Jagielski
92*b1cdbd2cSJim Jagielskiclass HeaderData(object):
93*b1cdbd2cSJim Jagielski    def __init__ (self):
94*b1cdbd2cSJim Jagielski        self.defines = {}
95*b1cdbd2cSJim Jagielski        self.tokens = []
96*b1cdbd2cSJim Jagielski
97*b1cdbd2cSJim Jagielski
98*b1cdbd2cSJim Jagielskiclass SrcLexer(object):
99*b1cdbd2cSJim Jagielski    """Lexicographical analyzer for .src format.
100*b1cdbd2cSJim Jagielski
101*b1cdbd2cSJim JagielskiThe role of a lexer is to parse the source file and break it into
102*b1cdbd2cSJim Jagielskiappropriate tokens.  Such tokens are later passed to a parser to
103*b1cdbd2cSJim Jagielskibuild the syntax tree.
104*b1cdbd2cSJim Jagielski"""
105*b1cdbd2cSJim Jagielski    headerCache = {}
106*b1cdbd2cSJim Jagielski
107*b1cdbd2cSJim Jagielski    VISIBLE = 0
108*b1cdbd2cSJim Jagielski    INVISIBLE_PRE = 1
109*b1cdbd2cSJim Jagielski    INVISIBLE_POST = 2
110*b1cdbd2cSJim Jagielski
111*b1cdbd2cSJim Jagielski    def __init__ (self, chars, filepath = None):
112*b1cdbd2cSJim Jagielski        self.filepath = filepath
113*b1cdbd2cSJim Jagielski        self.parentLexer = None
114*b1cdbd2cSJim Jagielski        self.chars = chars
115*b1cdbd2cSJim Jagielski        self.bufsize = len(self.chars)
116*b1cdbd2cSJim Jagielski
117*b1cdbd2cSJim Jagielski        # TODO: use parameters for this
118*b1cdbd2cSJim Jagielski        # Properties that can be copied.
119*b1cdbd2cSJim Jagielski        self.headerDict = dict ()
120*b1cdbd2cSJim Jagielski        self.debug = False
121*b1cdbd2cSJim Jagielski        self.debugMacro = False
122*b1cdbd2cSJim Jagielski        self.includeDirs = list ()
123*b1cdbd2cSJim Jagielski        self.expandHeaders = True
124*b1cdbd2cSJim Jagielski        self.inMacroDefine = False
125*b1cdbd2cSJim Jagielski        self.stopOnHeader = False
126*b1cdbd2cSJim Jagielski
127*b1cdbd2cSJim Jagielski    def copyProperties (self, other):
128*b1cdbd2cSJim Jagielski        """Copy properties from another instance of SrcLexer."""
129*b1cdbd2cSJim Jagielski
130*b1cdbd2cSJim Jagielski        # TODO: use parameters for this
131*b1cdbd2cSJim Jagielski        self.headerDict = other.headerDict
132*b1cdbd2cSJim Jagielski        self.debug = other.debug
133*b1cdbd2cSJim Jagielski        self.debugMacro = other.debugMacro
134*b1cdbd2cSJim Jagielski        self.includeDirs = other.includeDirs[:]
135*b1cdbd2cSJim Jagielski        self.expandHeaders = other.expandHeaders
136*b1cdbd2cSJim Jagielski        self.inMacroDefine = other.inMacroDefine
137*b1cdbd2cSJim Jagielski        self.stopOnHeader = other.stopOnHeader
138*b1cdbd2cSJim Jagielski
139*b1cdbd2cSJim Jagielski    def init (self):
140*b1cdbd2cSJim Jagielski        self.firstNonBlank = ''
141*b1cdbd2cSJim Jagielski        self.token = ''
142*b1cdbd2cSJim Jagielski        self.tokens = []
143*b1cdbd2cSJim Jagielski        self.defines = {}
144*b1cdbd2cSJim Jagielski        self.visibilityStack = []
145*b1cdbd2cSJim Jagielski
146*b1cdbd2cSJim Jagielski    def getTokens (self):
147*b1cdbd2cSJim Jagielski        return self.tokens
148*b1cdbd2cSJim Jagielski
149*b1cdbd2cSJim Jagielski    def getDefines (self):
150*b1cdbd2cSJim Jagielski        return self.defines
151*b1cdbd2cSJim Jagielski
152*b1cdbd2cSJim Jagielski    def nextPos (self, i):
153*b1cdbd2cSJim Jagielski        while True:
154*b1cdbd2cSJim Jagielski            i += 1
155*b1cdbd2cSJim Jagielski            try:
156*b1cdbd2cSJim Jagielski                c = self.chars[i]
157*b1cdbd2cSJim Jagielski            except IndexError:
158*b1cdbd2cSJim Jagielski                raise EOF
159*b1cdbd2cSJim Jagielski
160*b1cdbd2cSJim Jagielski            if ord(c) in [0x0D]:
161*b1cdbd2cSJim Jagielski                continue
162*b1cdbd2cSJim Jagielski            break
163*b1cdbd2cSJim Jagielski        return i
164*b1cdbd2cSJim Jagielski
165*b1cdbd2cSJim Jagielski    def prevPos (self, i):
166*b1cdbd2cSJim Jagielski        while True:
167*b1cdbd2cSJim Jagielski            i -= 1
168*b1cdbd2cSJim Jagielski            try:
169*b1cdbd2cSJim Jagielski                c = self.chars[i]
170*b1cdbd2cSJim Jagielski            except IndexError:
171*b1cdbd2cSJim Jagielski                raise BOF
172*b1cdbd2cSJim Jagielski
173*b1cdbd2cSJim Jagielski            if ord(c) in [0x0D]:
174*b1cdbd2cSJim Jagielski                continue
175*b1cdbd2cSJim Jagielski            break
176*b1cdbd2cSJim Jagielski        return i
177*b1cdbd2cSJim Jagielski
178*b1cdbd2cSJim Jagielski    def isCodeVisible (self):
179*b1cdbd2cSJim Jagielski        if len(self.visibilityStack) == 0:
180*b1cdbd2cSJim Jagielski            return True
181*b1cdbd2cSJim Jagielski        for item in self.visibilityStack:
182*b1cdbd2cSJim Jagielski            if item != SrcLexer.VISIBLE:
183*b1cdbd2cSJim Jagielski                return False
184*b1cdbd2cSJim Jagielski        return True
185*b1cdbd2cSJim Jagielski
186*b1cdbd2cSJim Jagielski    def tokenize (self):
187*b1cdbd2cSJim Jagielski        self.init()
188*b1cdbd2cSJim Jagielski
189*b1cdbd2cSJim Jagielski        i = 0
190*b1cdbd2cSJim Jagielski        while True:
191*b1cdbd2cSJim Jagielski            c = self.chars[i]
192*b1cdbd2cSJim Jagielski
193*b1cdbd2cSJim Jagielski            if self.firstNonBlank == '' and not c in [' ', "\n", "\t"]:
194*b1cdbd2cSJim Jagielski                # Store the first non-blank in a line.
195*b1cdbd2cSJim Jagielski                self.firstNonBlank = c
196*b1cdbd2cSJim Jagielski            elif c == "\n":
197*b1cdbd2cSJim Jagielski                self.firstNonBlank = ''
198*b1cdbd2cSJim Jagielski
199*b1cdbd2cSJim Jagielski            if c == '#':
200*b1cdbd2cSJim Jagielski                i = self.pound(i)
201*b1cdbd2cSJim Jagielski            elif c == '/':
202*b1cdbd2cSJim Jagielski                i = self.slash(i)
203*b1cdbd2cSJim Jagielski            elif c == "\n":
204*b1cdbd2cSJim Jagielski                i = self.lineBreak(i)
205*b1cdbd2cSJim Jagielski            elif c == '"':
206*b1cdbd2cSJim Jagielski                i = self.doubleQuote(i)
207*b1cdbd2cSJim Jagielski            elif c in [' ', "\t"]:
208*b1cdbd2cSJim Jagielski                i = self.blank(i)
209*b1cdbd2cSJim Jagielski            elif c in ";()[]{}<>,=+-*":
210*b1cdbd2cSJim Jagielski                # Any outstanding single-character token.
211*b1cdbd2cSJim Jagielski                i = self.anyToken(i, c)
212*b1cdbd2cSJim Jagielski            elif self.isCodeVisible():
213*b1cdbd2cSJim Jagielski                self.token += c
214*b1cdbd2cSJim Jagielski
215*b1cdbd2cSJim Jagielski            try:
216*b1cdbd2cSJim Jagielski                i = self.nextPos(i)
217*b1cdbd2cSJim Jagielski            except EOF:
218*b1cdbd2cSJim Jagielski                break
219*b1cdbd2cSJim Jagielski
220*b1cdbd2cSJim Jagielski        if len(self.token):
221*b1cdbd2cSJim Jagielski            self.tokens.append(self.token)
222*b1cdbd2cSJim Jagielski
223*b1cdbd2cSJim Jagielski        if not self.parentLexer and self.debug:
224*b1cdbd2cSJim Jagielski            progress ("-"*68 + "\n")
225*b1cdbd2cSJim Jagielski            progress ("All defines found in this translation unit:\n")
226*b1cdbd2cSJim Jagielski            keys = sorted(self.defines.keys())
227*b1cdbd2cSJim Jagielski            for key in keys:
228*b1cdbd2cSJim Jagielski                progress ("@ %s\n"%key)
229*b1cdbd2cSJim Jagielski
230*b1cdbd2cSJim Jagielski    def dumpTokens (self, toError=False):
231*b1cdbd2cSJim Jagielski        dumpTokens(self.tokens, toError)
232*b1cdbd2cSJim Jagielski
233*b1cdbd2cSJim Jagielski
234*b1cdbd2cSJim Jagielski    def maybeAddToken (self):
235*b1cdbd2cSJim Jagielski        if len(self.token) > 0:
236*b1cdbd2cSJim Jagielski            self.tokens.append(self.token)
237*b1cdbd2cSJim Jagielski            self.token = ''
238*b1cdbd2cSJim Jagielski
239*b1cdbd2cSJim Jagielski
240*b1cdbd2cSJim Jagielski    #--------------------------------------------------------------------
241*b1cdbd2cSJim Jagielski    # character handlers
242*b1cdbd2cSJim Jagielski
243*b1cdbd2cSJim Jagielski    def blank (self, i):
244*b1cdbd2cSJim Jagielski        if not self.isCodeVisible():
245*b1cdbd2cSJim Jagielski            return i
246*b1cdbd2cSJim Jagielski
247*b1cdbd2cSJim Jagielski        self.maybeAddToken()
248*b1cdbd2cSJim Jagielski        return i
249*b1cdbd2cSJim Jagielski
250*b1cdbd2cSJim Jagielski
251*b1cdbd2cSJim Jagielski    def pound (self, i):
252*b1cdbd2cSJim Jagielski
253*b1cdbd2cSJim Jagielski        if self.inMacroDefine:
254*b1cdbd2cSJim Jagielski            return i
255*b1cdbd2cSJim Jagielski
256*b1cdbd2cSJim Jagielski        if not self.firstNonBlank == '#':
257*b1cdbd2cSJim Jagielski            return i
258*b1cdbd2cSJim Jagielski
259*b1cdbd2cSJim Jagielski        self.maybeAddToken()
260*b1cdbd2cSJim Jagielski        # We are in preprocessing mode.
261*b1cdbd2cSJim Jagielski
262*b1cdbd2cSJim Jagielski        # Get the macro command name '#<command> .....'
263*b1cdbd2cSJim Jagielski
264*b1cdbd2cSJim Jagielski        command, define, buf = '', '', ''
265*b1cdbd2cSJim Jagielski        firstNonBlank = False
266*b1cdbd2cSJim Jagielski        while True:
267*b1cdbd2cSJim Jagielski            try:
268*b1cdbd2cSJim Jagielski                i = self.nextPos(i)
269*b1cdbd2cSJim Jagielski                c = self.chars[i]
270*b1cdbd2cSJim Jagielski                if c == '\\' and self.chars[self.nextPos(i)] == "\n":
271*b1cdbd2cSJim Jagielski                    i = self.nextPos(i)
272*b1cdbd2cSJim Jagielski                    continue
273*b1cdbd2cSJim Jagielski            except EOF:
274*b1cdbd2cSJim Jagielski                break
275*b1cdbd2cSJim Jagielski
276*b1cdbd2cSJim Jagielski            if c == "\n":
277*b1cdbd2cSJim Jagielski                if len(buf) > 0 and len(command) == 0:
278*b1cdbd2cSJim Jagielski                    command = buf
279*b1cdbd2cSJim Jagielski                i = self.prevPos(i)
280*b1cdbd2cSJim Jagielski                break
281*b1cdbd2cSJim Jagielski            elif c in [' ', "\t"]:
282*b1cdbd2cSJim Jagielski                if not firstNonBlank:
283*b1cdbd2cSJim Jagielski                    # Ignore any leading blanks after the '#'.
284*b1cdbd2cSJim Jagielski                    continue
285*b1cdbd2cSJim Jagielski
286*b1cdbd2cSJim Jagielski                if len(command) == 0:
287*b1cdbd2cSJim Jagielski                    command = buf
288*b1cdbd2cSJim Jagielski                    buf = ''
289*b1cdbd2cSJim Jagielski                else:
290*b1cdbd2cSJim Jagielski                    buf += ' '
291*b1cdbd2cSJim Jagielski            elif c == '(':
292*b1cdbd2cSJim Jagielski                if len(buf) > 0 and len(command) == 0:
293*b1cdbd2cSJim Jagielski                    command = buf
294*b1cdbd2cSJim Jagielski                buf += c
295*b1cdbd2cSJim Jagielski            else:
296*b1cdbd2cSJim Jagielski                if not firstNonBlank:
297*b1cdbd2cSJim Jagielski                    firstNonBlank = True
298*b1cdbd2cSJim Jagielski                buf += c
299*b1cdbd2cSJim Jagielski
300*b1cdbd2cSJim Jagielski        if command == 'define':
301*b1cdbd2cSJim Jagielski            self.handleMacroDefine(buf)
302*b1cdbd2cSJim Jagielski        elif command == 'include':
303*b1cdbd2cSJim Jagielski            self.handleMacroInclude(buf)
304*b1cdbd2cSJim Jagielski        elif command == 'ifdef':
305*b1cdbd2cSJim Jagielski            defineName = buf.strip()
306*b1cdbd2cSJim Jagielski            if defineName in self.defines:
307*b1cdbd2cSJim Jagielski                self.visibilityStack.append(SrcLexer.VISIBLE)
308*b1cdbd2cSJim Jagielski            else:
309*b1cdbd2cSJim Jagielski                self.visibilityStack.append(SrcLexer.INVISIBLE_PRE)
310*b1cdbd2cSJim Jagielski
311*b1cdbd2cSJim Jagielski        elif command == 'ifndef':
312*b1cdbd2cSJim Jagielski            defineName = buf.strip()
313*b1cdbd2cSJim Jagielski            if defineName in self.defines:
314*b1cdbd2cSJim Jagielski                self.visibilityStack.append(SrcLexer.INVISIBLE_PRE)
315*b1cdbd2cSJim Jagielski            else:
316*b1cdbd2cSJim Jagielski                self.visibilityStack.append(SrcLexer.VISIBLE)
317*b1cdbd2cSJim Jagielski
318*b1cdbd2cSJim Jagielski        elif command == 'if':
319*b1cdbd2cSJim Jagielski            if self.evalCodeVisibility(buf):
320*b1cdbd2cSJim Jagielski                self.visibilityStack.append(SrcLexer.VISIBLE)
321*b1cdbd2cSJim Jagielski            else:
322*b1cdbd2cSJim Jagielski                self.visibilityStack.append(SrcLexer.INVISIBLE_PRE)
323*b1cdbd2cSJim Jagielski
324*b1cdbd2cSJim Jagielski        elif command == 'elif':
325*b1cdbd2cSJim Jagielski            if len(self.visibilityStack) == 0:
326*b1cdbd2cSJim Jagielski                raise ParseError ('')
327*b1cdbd2cSJim Jagielski
328*b1cdbd2cSJim Jagielski            if self.visibilityStack[-1] == SrcLexer.VISIBLE:
329*b1cdbd2cSJim Jagielski                self.visibilityStack[-1] = SrcLexer.INVISIBLE_POST
330*b1cdbd2cSJim Jagielski            elif self.visibilityStack[-1] == SrcLexer.INVISIBLE_PRE:
331*b1cdbd2cSJim Jagielski                # Evaluate only if the current visibility is false.
332*b1cdbd2cSJim Jagielski                if self.evalCodeVisibility(buf):
333*b1cdbd2cSJim Jagielski                    self.visibilityStack[-1] = SrcLexer.VISIBLE
334*b1cdbd2cSJim Jagielski
335*b1cdbd2cSJim Jagielski        elif command == 'else':
336*b1cdbd2cSJim Jagielski            if len(self.visibilityStack) == 0:
337*b1cdbd2cSJim Jagielski                raise ParseError ('')
338*b1cdbd2cSJim Jagielski
339*b1cdbd2cSJim Jagielski            if self.visibilityStack[-1] == SrcLexer.VISIBLE:
340*b1cdbd2cSJim Jagielski                self.visibilityStack[-1] = SrcLexer.INVISIBLE_POST
341*b1cdbd2cSJim Jagielski            if self.visibilityStack[-1] == SrcLexer.INVISIBLE_PRE:
342*b1cdbd2cSJim Jagielski                self.visibilityStack[-1] = SrcLexer.VISIBLE
343*b1cdbd2cSJim Jagielski
344*b1cdbd2cSJim Jagielski        elif command == 'endif':
345*b1cdbd2cSJim Jagielski            if len(self.visibilityStack) == 0:
346*b1cdbd2cSJim Jagielski                raise ParseError ('')
347*b1cdbd2cSJim Jagielski            self.visibilityStack.pop()
348*b1cdbd2cSJim Jagielski
349*b1cdbd2cSJim Jagielski        elif command == 'undef':
350*b1cdbd2cSJim Jagielski            pass
351*b1cdbd2cSJim Jagielski        elif command in ['error', 'pragma']:
352*b1cdbd2cSJim Jagielski            pass
353*b1cdbd2cSJim Jagielski        else:
354*b1cdbd2cSJim Jagielski            print("'%s' '%s'"%(command, buf))
355*b1cdbd2cSJim Jagielski            print(self.filepath)
356*b1cdbd2cSJim Jagielski            sys.exit(0)
357*b1cdbd2cSJim Jagielski
358*b1cdbd2cSJim Jagielski        return i
359*b1cdbd2cSJim Jagielski
360*b1cdbd2cSJim Jagielski
361*b1cdbd2cSJim Jagielski    def evalCodeVisibility (self, buf):
362*b1cdbd2cSJim Jagielski        try:
363*b1cdbd2cSJim Jagielski            return eval(buf)
364*b1cdbd2cSJim Jagielski        except:
365*b1cdbd2cSJim Jagielski            return True
366*b1cdbd2cSJim Jagielski
367*b1cdbd2cSJim Jagielski    def handleMacroDefine (self, buf):
368*b1cdbd2cSJim Jagielski
369*b1cdbd2cSJim Jagielski        mparser = macroparser.MacroParser(buf)
370*b1cdbd2cSJim Jagielski        mparser.debug = self.debugMacro
371*b1cdbd2cSJim Jagielski        mparser.parse()
372*b1cdbd2cSJim Jagielski        macro = mparser.getMacro()
373*b1cdbd2cSJim Jagielski        if macro:
374*b1cdbd2cSJim Jagielski            self.defines[macro.name] = macro
375*b1cdbd2cSJim Jagielski
376*b1cdbd2cSJim Jagielski    def handleMacroInclude (self, buf):
377*b1cdbd2cSJim Jagielski
378*b1cdbd2cSJim Jagielski        # Strip excess string if any.
379*b1cdbd2cSJim Jagielski        pos = buf.find(' ')
380*b1cdbd2cSJim Jagielski        if pos >= 0:
381*b1cdbd2cSJim Jagielski            buf = buf[:pos]
382*b1cdbd2cSJim Jagielski        headerSub = removeHeaderQuotes(buf)
383*b1cdbd2cSJim Jagielski
384*b1cdbd2cSJim Jagielski        if not self.expandHeaders:
385*b1cdbd2cSJim Jagielski            # We don't want to expand headers.  Bail out.
386*b1cdbd2cSJim Jagielski            if self.debug:
387*b1cdbd2cSJim Jagielski                progress ("%s ignored\n"%headerSub)
388*b1cdbd2cSJim Jagielski            return
389*b1cdbd2cSJim Jagielski
390*b1cdbd2cSJim Jagielski        defines = {}
391*b1cdbd2cSJim Jagielski        headerPath = None
392*b1cdbd2cSJim Jagielski        for includeDir in self.includeDirs:
393*b1cdbd2cSJim Jagielski            hpath = includeDir + '/' + headerSub
394*b1cdbd2cSJim Jagielski            if os.path.isfile(hpath) and hpath != self.filepath:
395*b1cdbd2cSJim Jagielski                headerPath = hpath
396*b1cdbd2cSJim Jagielski                break
397*b1cdbd2cSJim Jagielski
398*b1cdbd2cSJim Jagielski        if not headerPath:
399*b1cdbd2cSJim Jagielski            error("included header file " + headerSub + " not found\n", self.stopOnHeader)
400*b1cdbd2cSJim Jagielski            return
401*b1cdbd2cSJim Jagielski
402*b1cdbd2cSJim Jagielski        if self.debug:
403*b1cdbd2cSJim Jagielski            progress ("%s found\n"%headerPath)
404*b1cdbd2cSJim Jagielski
405*b1cdbd2cSJim Jagielski        if headerPath in self.headerDict:
406*b1cdbd2cSJim Jagielski            if self.debug:
407*b1cdbd2cSJim Jagielski                progress ("%s already included\n"%headerPath)
408*b1cdbd2cSJim Jagielski            return
409*b1cdbd2cSJim Jagielski
410*b1cdbd2cSJim Jagielski        if headerPath in SrcLexer.headerCache:
411*b1cdbd2cSJim Jagielski            if self.debug:
412*b1cdbd2cSJim Jagielski                progress ("%s in cache\n"%headerPath)
413*b1cdbd2cSJim Jagielski            for key in list(SrcLexer.headerCache[headerPath].defines.keys()):
414*b1cdbd2cSJim Jagielski                self.defines[key] = SrcLexer.headerCache[headerPath].defines[key]
415*b1cdbd2cSJim Jagielski            return
416*b1cdbd2cSJim Jagielski
417*b1cdbd2cSJim Jagielski        chars = open(headerPath, 'r').read()
418*b1cdbd2cSJim Jagielski        mclexer = SrcLexer(chars, headerPath)
419*b1cdbd2cSJim Jagielski        mclexer.copyProperties(self)
420*b1cdbd2cSJim Jagielski        mclexer.parentLexer = self
421*b1cdbd2cSJim Jagielski        mclexer.tokenize()
422*b1cdbd2cSJim Jagielski        hdrData = HeaderData()
423*b1cdbd2cSJim Jagielski        hdrData.tokens = mclexer.getTokens()
424*b1cdbd2cSJim Jagielski        headerDefines = mclexer.getDefines()
425*b1cdbd2cSJim Jagielski        for key in list(headerDefines.keys()):
426*b1cdbd2cSJim Jagielski            defines[key] = headerDefines[key]
427*b1cdbd2cSJim Jagielski            hdrData.defines[key] = headerDefines[key]
428*b1cdbd2cSJim Jagielski
429*b1cdbd2cSJim Jagielski        self.headerDict[headerPath] = True
430*b1cdbd2cSJim Jagielski        SrcLexer.headerCache[headerPath] = hdrData
431*b1cdbd2cSJim Jagielski
432*b1cdbd2cSJim Jagielski        # Update the list of headers that have already been expaneded.
433*b1cdbd2cSJim Jagielski        for key in list(mclexer.headerDict.keys()):
434*b1cdbd2cSJim Jagielski            self.headerDict[key] = True
435*b1cdbd2cSJim Jagielski
436*b1cdbd2cSJim Jagielski        if self.debug:
437*b1cdbd2cSJim Jagielski            progress ("defines found in header %s:\n"%headerSub)
438*b1cdbd2cSJim Jagielski            for key in list(defines.keys()):
439*b1cdbd2cSJim Jagielski                progress ("  '%s'\n"%key)
440*b1cdbd2cSJim Jagielski
441*b1cdbd2cSJim Jagielski        for key in list(defines.keys()):
442*b1cdbd2cSJim Jagielski            self.defines[key] = defines[key]
443*b1cdbd2cSJim Jagielski
444*b1cdbd2cSJim Jagielski
445*b1cdbd2cSJim Jagielski    def slash (self, i):
446*b1cdbd2cSJim Jagielski        if not self.isCodeVisible():
447*b1cdbd2cSJim Jagielski            return i
448*b1cdbd2cSJim Jagielski
449*b1cdbd2cSJim Jagielski        if i < self.bufsize - 1 and self.chars[i+1] == '/':
450*b1cdbd2cSJim Jagielski            # Parse line comment.
451*b1cdbd2cSJim Jagielski            line = ''
452*b1cdbd2cSJim Jagielski            i += 2
453*b1cdbd2cSJim Jagielski            while i < self.bufsize:
454*b1cdbd2cSJim Jagielski                c = self.chars[i]
455*b1cdbd2cSJim Jagielski                if ord(c) in [0x0A, 0x0D]:
456*b1cdbd2cSJim Jagielski                    return i - 1
457*b1cdbd2cSJim Jagielski                line += c
458*b1cdbd2cSJim Jagielski                i += 1
459*b1cdbd2cSJim Jagielski            self.token = ''
460*b1cdbd2cSJim Jagielski        elif i < self.bufsize - 1 and self.chars[i+1] == '*':
461*b1cdbd2cSJim Jagielski            comment = ''
462*b1cdbd2cSJim Jagielski            i += 2
463*b1cdbd2cSJim Jagielski            while i < self.bufsize:
464*b1cdbd2cSJim Jagielski                c = self.chars[i]
465*b1cdbd2cSJim Jagielski                if c == '/' and self.chars[i-1] == '*':
466*b1cdbd2cSJim Jagielski                    return i
467*b1cdbd2cSJim Jagielski                comment += c
468*b1cdbd2cSJim Jagielski                i += 1
469*b1cdbd2cSJim Jagielski        else:
470*b1cdbd2cSJim Jagielski            return self.anyToken(i, '/')
471*b1cdbd2cSJim Jagielski
472*b1cdbd2cSJim Jagielski        return i
473*b1cdbd2cSJim Jagielski
474*b1cdbd2cSJim Jagielski
475*b1cdbd2cSJim Jagielski    def lineBreak (self, i):
476*b1cdbd2cSJim Jagielski        if not self.isCodeVisible():
477*b1cdbd2cSJim Jagielski            return i
478*b1cdbd2cSJim Jagielski
479*b1cdbd2cSJim Jagielski        self.maybeAddToken()
480*b1cdbd2cSJim Jagielski
481*b1cdbd2cSJim Jagielski        return i
482*b1cdbd2cSJim Jagielski
483*b1cdbd2cSJim Jagielski
484*b1cdbd2cSJim Jagielski    def doubleQuote (self, i):
485*b1cdbd2cSJim Jagielski        if not self.isCodeVisible():
486*b1cdbd2cSJim Jagielski            return i
487*b1cdbd2cSJim Jagielski
488*b1cdbd2cSJim Jagielski        literal = ''
489*b1cdbd2cSJim Jagielski        i += 1
490*b1cdbd2cSJim Jagielski        while i < self.bufsize:
491*b1cdbd2cSJim Jagielski            c = self.chars[i]
492*b1cdbd2cSJim Jagielski            if c == '"':
493*b1cdbd2cSJim Jagielski                self.tokens.append('"'+literal+'"')
494*b1cdbd2cSJim Jagielski                break
495*b1cdbd2cSJim Jagielski            literal += c
496*b1cdbd2cSJim Jagielski            i += 1
497*b1cdbd2cSJim Jagielski
498*b1cdbd2cSJim Jagielski        return i
499*b1cdbd2cSJim Jagielski
500*b1cdbd2cSJim Jagielski
501*b1cdbd2cSJim Jagielski    def anyToken (self, i, token):
502*b1cdbd2cSJim Jagielski        if not self.isCodeVisible():
503*b1cdbd2cSJim Jagielski            return i
504*b1cdbd2cSJim Jagielski
505*b1cdbd2cSJim Jagielski        self.maybeAddToken()
506*b1cdbd2cSJim Jagielski        self.token = token
507*b1cdbd2cSJim Jagielski        self.maybeAddToken()
508*b1cdbd2cSJim Jagielski        return i
509