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