1*cdf0e10cSrcweirimport sys 2*cdf0e10cSrcweirfrom globals import * 3*cdf0e10cSrcweirimport srclexer 4*cdf0e10cSrcweir 5*cdf0e10cSrcweir# simple name translation map 6*cdf0e10cSrcweirpostTransMap = {"ok-button": "okbutton", 7*cdf0e10cSrcweir "cancel-button": "cancelbutton", 8*cdf0e10cSrcweir "help-button": "helpbutton"} 9*cdf0e10cSrcweir 10*cdf0e10cSrcweirdef transName (name): 11*cdf0e10cSrcweir """Translate a mixed-casing name to dash-separated name. 12*cdf0e10cSrcweir 13*cdf0e10cSrcweirTranslate a mixed-casing name (e.g. MyLongName) to a dash-separated name 14*cdf0e10cSrcweir(e.g. my-long-name). 15*cdf0e10cSrcweir""" 16*cdf0e10cSrcweir def isUpper (c): 17*cdf0e10cSrcweir return c >= 'A' and c <= 'Z' 18*cdf0e10cSrcweir 19*cdf0e10cSrcweir newname = '' 20*cdf0e10cSrcweir parts = [] 21*cdf0e10cSrcweir buf = '' 22*cdf0e10cSrcweir for c in name: 23*cdf0e10cSrcweir if isUpper(c) and len(buf) > 1: 24*cdf0e10cSrcweir parts.append(buf) 25*cdf0e10cSrcweir buf = c 26*cdf0e10cSrcweir else: 27*cdf0e10cSrcweir buf += c 28*cdf0e10cSrcweir 29*cdf0e10cSrcweir if len(buf) > 0: 30*cdf0e10cSrcweir parts.append(buf) 31*cdf0e10cSrcweir 32*cdf0e10cSrcweir first = True 33*cdf0e10cSrcweir for part in parts: 34*cdf0e10cSrcweir if first: 35*cdf0e10cSrcweir first = False 36*cdf0e10cSrcweir else: 37*cdf0e10cSrcweir newname += '-' 38*cdf0e10cSrcweir newname += part.lower() 39*cdf0e10cSrcweir 40*cdf0e10cSrcweir # special-case mapping ... 41*cdf0e10cSrcweir if 0: #postTransMap.has_key(newname): 42*cdf0e10cSrcweir newname = postTransMap[newname] 43*cdf0e10cSrcweir 44*cdf0e10cSrcweir return newname 45*cdf0e10cSrcweir 46*cdf0e10cSrcweir 47*cdf0e10cSrcweirdef transValue (value): 48*cdf0e10cSrcweir """Translate certain values. 49*cdf0e10cSrcweir 50*cdf0e10cSrcweirExamples of translated values include TRUE -> true, FALSE -> false. 51*cdf0e10cSrcweir""" 52*cdf0e10cSrcweir if value.lower() in ["true", "false"]: 53*cdf0e10cSrcweir value = value.lower() 54*cdf0e10cSrcweir return value 55*cdf0e10cSrcweir 56*cdf0e10cSrcweir 57*cdf0e10cSrcweirdef renameAttribute (name, elemName): 58*cdf0e10cSrcweir 59*cdf0e10cSrcweir # TODO: all manner of evil special cases ... 60*cdf0e10cSrcweir if elemName == 'metric-field' and name == 'spin-size': 61*cdf0e10cSrcweir return 'step-size' 62*cdf0e10cSrcweir 63*cdf0e10cSrcweir return name 64*cdf0e10cSrcweir 65*cdf0e10cSrcweir 66*cdf0e10cSrcweirclass Statement(object): 67*cdf0e10cSrcweir """Container to hold information for a single statement. 68*cdf0e10cSrcweir 69*cdf0e10cSrcweirEach statement consists of the left-hand-side token(s), and right-hand-side 70*cdf0e10cSrcweirtokens, separated by a '=' token. This class stores the information on the 71*cdf0e10cSrcweirleft-hand-side tokens. 72*cdf0e10cSrcweir""" 73*cdf0e10cSrcweir def __init__ (self): 74*cdf0e10cSrcweir self.leftTokens = [] 75*cdf0e10cSrcweir self.leftScope = None 76*cdf0e10cSrcweir 77*cdf0e10cSrcweir 78*cdf0e10cSrcweirclass MacroExpander(object): 79*cdf0e10cSrcweir def __init__ (self, tokens, defines): 80*cdf0e10cSrcweir self.tokens = tokens 81*cdf0e10cSrcweir self.defines = defines 82*cdf0e10cSrcweir 83*cdf0e10cSrcweir def expand (self): 84*cdf0e10cSrcweir self.pos = 0 85*cdf0e10cSrcweir while self.pos < len(self.tokens): 86*cdf0e10cSrcweir self.expandToken() 87*cdf0e10cSrcweir 88*cdf0e10cSrcweir def expandToken (self): 89*cdf0e10cSrcweir token = self.tokens[self.pos] 90*cdf0e10cSrcweir if not self.defines.has_key(token): 91*cdf0e10cSrcweir self.pos += 1 92*cdf0e10cSrcweir return 93*cdf0e10cSrcweir 94*cdf0e10cSrcweir macro = self.defines[token] 95*cdf0e10cSrcweir nvars = len(macro.vars.keys()) 96*cdf0e10cSrcweir if nvars == 0: 97*cdf0e10cSrcweir # Simple expansion 98*cdf0e10cSrcweir self.tokens[self.pos:self.pos+1] = macro.tokens 99*cdf0e10cSrcweir return 100*cdf0e10cSrcweir else: 101*cdf0e10cSrcweir # Expansion with arguments. 102*cdf0e10cSrcweir values, lastPos = self.parseValues() 103*cdf0e10cSrcweir newtokens = [] 104*cdf0e10cSrcweir for mtoken in macro.tokens: 105*cdf0e10cSrcweir if macro.vars.has_key(mtoken): 106*cdf0e10cSrcweir # variable 107*cdf0e10cSrcweir pos = macro.vars[mtoken] 108*cdf0e10cSrcweir valtokens = values[pos] 109*cdf0e10cSrcweir for valtoken in valtokens: 110*cdf0e10cSrcweir newtokens.append(valtoken) 111*cdf0e10cSrcweir else: 112*cdf0e10cSrcweir # not a variable 113*cdf0e10cSrcweir newtokens.append(mtoken) 114*cdf0e10cSrcweir 115*cdf0e10cSrcweir self.tokens[self.pos:self.pos+lastPos+1] = newtokens 116*cdf0e10cSrcweir 117*cdf0e10cSrcweir 118*cdf0e10cSrcweir def parseValues (self): 119*cdf0e10cSrcweir """Parse tokens to get macro function variable values. 120*cdf0e10cSrcweir 121*cdf0e10cSrcweirBe aware that there is an implicit quotes around the text between the open 122*cdf0e10cSrcweirparen, the comma(s), and the close paren. For instance, if a macro is defined 123*cdf0e10cSrcweiras FOO(a, b) and is used as FOO(one two three, and four), then the 'a' must be 124*cdf0e10cSrcweirreplaced with 'one two three', and the 'b' replaced with 'and four'. In other 125*cdf0e10cSrcweirwords, whitespace does not end a token. 126*cdf0e10cSrcweir 127*cdf0e10cSrcweir""" 128*cdf0e10cSrcweir values = [] 129*cdf0e10cSrcweir i = 1 130*cdf0e10cSrcweir scope = 0 131*cdf0e10cSrcweir value = [] 132*cdf0e10cSrcweir while True: 133*cdf0e10cSrcweir try: 134*cdf0e10cSrcweir tk = self.tokens[self.pos+i] 135*cdf0e10cSrcweir except IndexError: 136*cdf0e10cSrcweir progress ("error parsing values (%d)\n"%i) 137*cdf0e10cSrcweir for j in xrange(0, i): 138*cdf0e10cSrcweir print self.tokens[self.pos+j], 139*cdf0e10cSrcweir print '' 140*cdf0e10cSrcweir srclexer.dumpTokens(self.tokens) 141*cdf0e10cSrcweir srclexer.dumpTokens(self.newtokens) 142*cdf0e10cSrcweir print "tokens expanded so far:" 143*cdf0e10cSrcweir for tk in self.expandedTokens: 144*cdf0e10cSrcweir print "-"*20 145*cdf0e10cSrcweir print tk 146*cdf0e10cSrcweir srclexer.dumpTokens(self.defines[tk].tokens) 147*cdf0e10cSrcweir sys.exit(1) 148*cdf0e10cSrcweir if tk == '(': 149*cdf0e10cSrcweir value = [] 150*cdf0e10cSrcweir scope += 1 151*cdf0e10cSrcweir elif tk == ',': 152*cdf0e10cSrcweir values.append(value) 153*cdf0e10cSrcweir value = [] 154*cdf0e10cSrcweir elif tk == ')': 155*cdf0e10cSrcweir scope -= 1 156*cdf0e10cSrcweir values.append(value) 157*cdf0e10cSrcweir value = [] 158*cdf0e10cSrcweir if scope == 0: 159*cdf0e10cSrcweir break 160*cdf0e10cSrcweir else: 161*cdf0e10cSrcweir raise ParseError ('') 162*cdf0e10cSrcweir else: 163*cdf0e10cSrcweir value.append(tk) 164*cdf0e10cSrcweir i += 1 165*cdf0e10cSrcweir 166*cdf0e10cSrcweir return values, i 167*cdf0e10cSrcweir 168*cdf0e10cSrcweir def getTokens (self): 169*cdf0e10cSrcweir return self.tokens 170*cdf0e10cSrcweir 171*cdf0e10cSrcweir 172*cdf0e10cSrcweirclass SrcParser(object): 173*cdf0e10cSrcweir 174*cdf0e10cSrcweir def __init__ (self, tokens, defines = None): 175*cdf0e10cSrcweir self.tokens = tokens 176*cdf0e10cSrcweir self.defines = defines 177*cdf0e10cSrcweir self.debug = False 178*cdf0e10cSrcweir self.onlyExpandMacros = False 179*cdf0e10cSrcweir 180*cdf0e10cSrcweir def init (self): 181*cdf0e10cSrcweir self.elementStack = [RootNode()] 182*cdf0e10cSrcweir self.stmtData = Statement() 183*cdf0e10cSrcweir self.tokenBuf = [] 184*cdf0e10cSrcweir self.leftTokens = [] 185*cdf0e10cSrcweir 186*cdf0e10cSrcweir # Expand defined macros. 187*cdf0e10cSrcweir if self.debug: 188*cdf0e10cSrcweir progress ("-"*68+"\n") 189*cdf0e10cSrcweir for key in self.defines.keys(): 190*cdf0e10cSrcweir progress ("define: %s\n"%key) 191*cdf0e10cSrcweir 192*cdf0e10cSrcweir self.expandMacro() 193*cdf0e10cSrcweir self.tokenSize = len(self.tokens) 194*cdf0e10cSrcweir 195*cdf0e10cSrcweir def expandMacro (self): 196*cdf0e10cSrcweir macroExp = MacroExpander(self.tokens, self.defines) 197*cdf0e10cSrcweir macroExp.expand() 198*cdf0e10cSrcweir self.tokens = macroExp.getTokens() 199*cdf0e10cSrcweir if self.onlyExpandMacros: 200*cdf0e10cSrcweir srclexer.dumpTokens(self.tokens) 201*cdf0e10cSrcweir sys.exit(0) 202*cdf0e10cSrcweir 203*cdf0e10cSrcweir def parse (self): 204*cdf0e10cSrcweir """Parse it! 205*cdf0e10cSrcweir 206*cdf0e10cSrcweirThis is the main loop for the parser. This is where it all begins and ends. 207*cdf0e10cSrcweir""" 208*cdf0e10cSrcweir self.init() 209*cdf0e10cSrcweir 210*cdf0e10cSrcweir i = 0 211*cdf0e10cSrcweir while i < self.tokenSize: 212*cdf0e10cSrcweir tk = self.tokens[i] 213*cdf0e10cSrcweir if tk == '{': 214*cdf0e10cSrcweir i = self.openBrace(i) 215*cdf0e10cSrcweir elif tk == '}': 216*cdf0e10cSrcweir i = self.closeBrace(i) 217*cdf0e10cSrcweir elif tk == ';': 218*cdf0e10cSrcweir i = self.semiColon(i) 219*cdf0e10cSrcweir elif tk == '=': 220*cdf0e10cSrcweir i = self.assignment(i) 221*cdf0e10cSrcweir else: 222*cdf0e10cSrcweir self.tokenBuf.append(tk) 223*cdf0e10cSrcweir 224*cdf0e10cSrcweir i += 1 225*cdf0e10cSrcweir 226*cdf0e10cSrcweir return self.elementStack[0] 227*cdf0e10cSrcweir 228*cdf0e10cSrcweir #------------------------------------------------------------------------- 229*cdf0e10cSrcweir # Token Handlers 230*cdf0e10cSrcweir 231*cdf0e10cSrcweir """ 232*cdf0e10cSrcweirEach token handler takes the current token position and returns the position 233*cdf0e10cSrcweirof the last token processed. For the most part, the current token position 234*cdf0e10cSrcweirand the last processed token are one and the same, in which case the handler 235*cdf0e10cSrcweircan simply return the position value it receives without incrementing it. 236*cdf0e10cSrcweir 237*cdf0e10cSrcweirIf you need to read ahead to process more tokens than just the current token, 238*cdf0e10cSrcweirmake sure that the new token position points to the last token that has been 239*cdf0e10cSrcweirprocessed, not the next token that has not yet been processed. This is 240*cdf0e10cSrcweirbecause the main loop increments the token position when it returns from the 241*cdf0e10cSrcweirhandler. 242*cdf0e10cSrcweir""" 243*cdf0e10cSrcweir 244*cdf0e10cSrcweir # assignment token '=' 245*cdf0e10cSrcweir def assignment (self, i): 246*cdf0e10cSrcweir self.leftTokens = self.tokenBuf[:] 247*cdf0e10cSrcweir if self.stmtData.leftScope == None: 248*cdf0e10cSrcweir # Keep track of lhs data in case of compound statement. 249*cdf0e10cSrcweir self.stmtData.leftTokens = self.tokenBuf[:] 250*cdf0e10cSrcweir self.stmtData.leftScope = len(self.elementStack) - 1 251*cdf0e10cSrcweir 252*cdf0e10cSrcweir self.tokenBuf = [] 253*cdf0e10cSrcweir return i 254*cdf0e10cSrcweir 255*cdf0e10cSrcweir # open brace token '{' 256*cdf0e10cSrcweir def openBrace (self, i): 257*cdf0e10cSrcweir bufSize = len(self.tokenBuf) 258*cdf0e10cSrcweir leftSize = len(self.leftTokens) 259*cdf0e10cSrcweir obj = None 260*cdf0e10cSrcweir if bufSize == 0 and leftSize > 0: 261*cdf0e10cSrcweir # Name = { ... 262*cdf0e10cSrcweir obj = Element(self.leftTokens[0]) 263*cdf0e10cSrcweir 264*cdf0e10cSrcweir elif bufSize > 0 and leftSize == 0: 265*cdf0e10cSrcweir # Type Name { ... 266*cdf0e10cSrcweir wgtType = self.tokenBuf[0] 267*cdf0e10cSrcweir wgtRID = None 268*cdf0e10cSrcweir if bufSize >= 2: 269*cdf0e10cSrcweir wgtRID = self.tokenBuf[1] 270*cdf0e10cSrcweir obj = Element(wgtType, wgtRID) 271*cdf0e10cSrcweir 272*cdf0e10cSrcweir else: 273*cdf0e10cSrcweir # LeftName = Name { ... 274*cdf0e10cSrcweir obj = Element(self.leftTokens[0]) 275*cdf0e10cSrcweir obj.setAttr("type", self.tokenBuf[0]) 276*cdf0e10cSrcweir 277*cdf0e10cSrcweir obj.name = transName(obj.name) 278*cdf0e10cSrcweir 279*cdf0e10cSrcweir if obj.name == 'string-list': 280*cdf0e10cSrcweir i = self.parseStringList(i) 281*cdf0e10cSrcweir elif obj.name == 'filter-list': 282*cdf0e10cSrcweir i = self.parseFilterList(i, obj) 283*cdf0e10cSrcweir else: 284*cdf0e10cSrcweir self.elementStack[-1].appendChild(obj) 285*cdf0e10cSrcweir self.elementStack.append(obj) 286*cdf0e10cSrcweir 287*cdf0e10cSrcweir self.tokenBuf = [] 288*cdf0e10cSrcweir self.leftTokens = [] 289*cdf0e10cSrcweir 290*cdf0e10cSrcweir return i 291*cdf0e10cSrcweir 292*cdf0e10cSrcweir # close brace token '}' 293*cdf0e10cSrcweir def closeBrace (self, i): 294*cdf0e10cSrcweir if len(self.tokenBuf) > 0: 295*cdf0e10cSrcweir if self.debug: 296*cdf0e10cSrcweir print self.tokenBuf 297*cdf0e10cSrcweir raise ParseError ('') 298*cdf0e10cSrcweir self.elementStack.pop() 299*cdf0e10cSrcweir return i 300*cdf0e10cSrcweir 301*cdf0e10cSrcweir # semi colon token ';' 302*cdf0e10cSrcweir def semiColon (self, i): 303*cdf0e10cSrcweir stackSize = len(self.elementStack) 304*cdf0e10cSrcweir scope = stackSize - 1 305*cdf0e10cSrcweir if len(self.tokenBuf) == 0: 306*cdf0e10cSrcweir pass 307*cdf0e10cSrcweir elif scope == 0: 308*cdf0e10cSrcweir # We are not supposed to have any statment in global scope. 309*cdf0e10cSrcweir # Just ignore this statement. 310*cdf0e10cSrcweir pass 311*cdf0e10cSrcweir else: 312*cdf0e10cSrcweir # Statement within a scope. Import it as an attribute for the 313*cdf0e10cSrcweir # current element. 314*cdf0e10cSrcweir elem = self.elementStack[-1] 315*cdf0e10cSrcweir 316*cdf0e10cSrcweir name = "none" 317*cdf0e10cSrcweir if len(self.leftTokens) > 0: 318*cdf0e10cSrcweir # Use the leftmost token as the name for now. If we need to 319*cdf0e10cSrcweir # do more complex parsing of lhs, add more code here. 320*cdf0e10cSrcweir name = self.leftTokens[0] 321*cdf0e10cSrcweir name = transName(name) 322*cdf0e10cSrcweir 323*cdf0e10cSrcweir if name == 'pos': 324*cdf0e10cSrcweir i = self.parsePosAttr(i) 325*cdf0e10cSrcweir elif name == 'size': 326*cdf0e10cSrcweir i = self.parseSizeAttr(i) 327*cdf0e10cSrcweir elif len (self.tokenBuf) == 1: 328*cdf0e10cSrcweir # Simple value 329*cdf0e10cSrcweir value = transValue(self.tokenBuf[0]) 330*cdf0e10cSrcweir name = renameAttribute(name, elem.name) 331*cdf0e10cSrcweir elem.setAttr(name, value) 332*cdf0e10cSrcweir 333*cdf0e10cSrcweir if not self.stmtData.leftScope == None and self.stmtData.leftScope < scope: 334*cdf0e10cSrcweir # This is a nested scope within a statement. Do nothing for now. 335*cdf0e10cSrcweir pass 336*cdf0e10cSrcweir 337*cdf0e10cSrcweir if self.stmtData.leftScope == scope: 338*cdf0e10cSrcweir # end of (nested) statement. 339*cdf0e10cSrcweir self.stmtData.leftScope = None 340*cdf0e10cSrcweir 341*cdf0e10cSrcweir self.tokenBuf = [] 342*cdf0e10cSrcweir self.leftTokens = [] 343*cdf0e10cSrcweir 344*cdf0e10cSrcweir return i 345*cdf0e10cSrcweir 346*cdf0e10cSrcweir def parseStringList (self, i): 347*cdf0e10cSrcweir 348*cdf0e10cSrcweir i += 1 349*cdf0e10cSrcweir while i < self.tokenSize: 350*cdf0e10cSrcweir tk = self.tokens[i] 351*cdf0e10cSrcweir if tk == '}': 352*cdf0e10cSrcweir break 353*cdf0e10cSrcweir i += 1 354*cdf0e10cSrcweir 355*cdf0e10cSrcweir return i 356*cdf0e10cSrcweir 357*cdf0e10cSrcweir def parseFilterList (self, i, obj): 358*cdf0e10cSrcweir self.elementStack[-1].appendChild(obj) 359*cdf0e10cSrcweir self.elementStack.append(obj) 360*cdf0e10cSrcweir 361*cdf0e10cSrcweir return i 362*cdf0e10cSrcweir 363*cdf0e10cSrcweir def parsePosAttr (self, i): 364*cdf0e10cSrcweir 365*cdf0e10cSrcweir # MAP_APPFONT ( 6 , 5 ) 366*cdf0e10cSrcweir elem = self.elementStack[-1] 367*cdf0e10cSrcweir x, y = self.parseMapAppfont(self.tokenBuf) 368*cdf0e10cSrcweir elem.setAttr("x", x) 369*cdf0e10cSrcweir elem.setAttr("y", y) 370*cdf0e10cSrcweir 371*cdf0e10cSrcweir return i 372*cdf0e10cSrcweir 373*cdf0e10cSrcweir def parseSizeAttr (self, i): 374*cdf0e10cSrcweir 375*cdf0e10cSrcweir # MAP_APPFONT ( 6 , 5 ) 376*cdf0e10cSrcweir elem = self.elementStack[-1] 377*cdf0e10cSrcweir width, height = self.parseMapAppfont(self.tokenBuf) 378*cdf0e10cSrcweir elem.setAttr("width", width) 379*cdf0e10cSrcweir elem.setAttr("height", height) 380*cdf0e10cSrcweir 381*cdf0e10cSrcweir return i 382*cdf0e10cSrcweir 383*cdf0e10cSrcweir def parseMapAppfont (self, tokens): 384*cdf0e10cSrcweir values = [] 385*cdf0e10cSrcweir scope = 0 386*cdf0e10cSrcweir val = '' 387*cdf0e10cSrcweir for tk in tokens: 388*cdf0e10cSrcweir if tk == '(': 389*cdf0e10cSrcweir scope += 1 390*cdf0e10cSrcweir if scope == 1: 391*cdf0e10cSrcweir val = '' 392*cdf0e10cSrcweir else: 393*cdf0e10cSrcweir val += tk 394*cdf0e10cSrcweir elif tk == ')': 395*cdf0e10cSrcweir scope -= 1 396*cdf0e10cSrcweir if scope == 0: 397*cdf0e10cSrcweir if len(val) == 0: 398*cdf0e10cSrcweir raise ParseError ('') 399*cdf0e10cSrcweir values.append(val) 400*cdf0e10cSrcweir break 401*cdf0e10cSrcweir else: 402*cdf0e10cSrcweir val += tk 403*cdf0e10cSrcweir elif tk == ',': 404*cdf0e10cSrcweir if len(val) == 0: 405*cdf0e10cSrcweir raise ParseError ('') 406*cdf0e10cSrcweir values.append(val) 407*cdf0e10cSrcweir val = '' 408*cdf0e10cSrcweir elif scope > 0: 409*cdf0e10cSrcweir val += tk 410*cdf0e10cSrcweir 411*cdf0e10cSrcweir if len(values) != 2: 412*cdf0e10cSrcweir raise ParseError ('') 413*cdf0e10cSrcweir 414*cdf0e10cSrcweir return eval(values[0]), eval(values[1]) 415*cdf0e10cSrcweir 416*cdf0e10cSrcweir 417