Module protogen
[hide private]
[frames] | no frames]

Source Code for Module protogen

  1  #!/usr/bin/env python 
  2  ### BITPIM 
  3  ### 
  4  ### Copyright (C) 2003-2004 Roger Binns <rogerb@rogerbinns.com> 
  5  ### 
  6  ### This program is free software; you can redistribute it and/or modify 
  7  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  8  ### 
  9  ### $Id: protogen.py 4772 2010-01-02 06:10:24Z djpham $ 
 10   
 11  "Generate Python code from packet descriptions" 
 12  from __future__ import with_statement 
 13  import contextlib 
 14  import tokenize 
 15  import sys 
 16  import token 
 17  import cStringIO 
 18  import os 
 19   
20 -class protoerror(Exception):
21
22 - def __init__(self, desc, token):
23 Exception.__init__(self,desc) 24 self.desc=desc 25 self.token=token
26
27 - def __repr__(self):
28 str=self.desc+"\nLine "+`self.token[2][0]`+":\n" 29 str+=self.token[4] 30 str+=" "*self.token[2][1]+"^\n" 31 str+=`self.token[:4]` 32 return str
33
34 - def __str__(self):
35 return self.__repr__()
36
37 -class protogentokenizer:
38 # A section enclosed in %{ ... }%. One item follows which is the string 39 LITERAL="LITERAL" 40 41 # The start of a packet. 42 # Followed by name, generatordict (as a string), userspecced dict (as a string), a comment (or None) 43 PACKETSTART="PACKETSTART" 44 45 # End of a packet. Nothing follows 46 PACKETEND="PACKETEND" 47 48 # Start of an 'if' section. Followed by condition as string including trailing ':' 49 CONDITIONALSTART="CONDITIONALSTART" 50 51 # start if an 'else' or 'elif' section. 52 CONDITIONALRESTART="CONDITIONALRESTART" 53 54 # End of an 'if' section. Nothing follows 55 CONDITIONALEND="CONDITIONALEND" 56 57 # An actual field. Followed by name, size [-1 means unknown size], type, generatordict, userspecced dict, comment, modifiers 58 FIELD="FIELD" 59 60 # Embedded codes: similar to LITERAL, but defined inside a PACKET. 61 CODE="CODE" 62 63 # An assertion (validity check). Followed by string of assertion expression 64 ASSERTION="ASSERTION" 65 66 STATE_TOPLEVEL="STATE_TOPLEVEL" 67 STATE_PACKET="STATE_PACKET" 68 STATE_CONDITIONAL="STATE_CONDITIONAL" 69 70
71 - def __init__(self, tokenizer, autogennamebase):
72 self.tokenizer=tokenizer 73 self.pb=[] # pushback list from what we are tokenizing 74 self.state=[self.STATE_TOPLEVEL] # state stack 75 self.packetstack=[] # packets being described stack 76 self.resultspb=[] # our results pushback stack 77 self.lines=[None] # no zeroth line 78 self.autogennamebase=autogennamebase 79 self.deferredpackets=[] # used for nested packets
80
81 - def _getautogenname(self, line):
82 return self.autogennamebase+`line`
83
84 - def _lookahead(self, howfar=1):
85 "Returns a token howfar ahead" 86 assert howfar>=1 87 while len(self.pb)<howfar: 88 self.pb.append(self._realnext()) 89 return self.pb[howfar-1]
90
91 - def _realnext(self):
92 "Gets the next token from our input, ignoring the pushback list" 93 while True: 94 t=self.tokenizer.next() 95 t=(token.tok_name[t[0]],)+t[1:] 96 97 # we grab a copy of any lines we see for the first time 98 if len(self.lines)==t[2][0]: 99 ll=t[4].split('\n') 100 self.lines.extend(ll[:-1]) 101 elif t[3][0]>len(self.lines): 102 # multiline token 103 ll=t[4].split('\n') 104 ll=ll[:-1] 105 for i,l in zip(range(t[2][0],t[3][0]+1), ll): 106 # we may already have the line, hence the conditional 107 if len(self.lines)==i: 108 self.lines.append(l) 109 110 if t[0]=='NL': 111 t=('NEWLINE',)+t[1:] 112 if t[0]!='COMMENT': 113 break 114 # print "next:",t 115 return t
116
117 - def _nextignorenl(self):
118 "Gets next token ignoring newlines" 119 while True: 120 t=self._next() 121 if t[0]!='NEWLINE': 122 return t
123
124 - def _next(self):
125 "Gets next token from our input, looking in pushback list" 126 if len(self.pb): 127 t=self.pb[0] 128 self.pb=self.pb[1:] 129 return t 130 return self._realnext()
131
132 - def _consumenl(self):
133 "consumes any newlines" 134 while True: 135 t=self._lookahead() 136 if t[0]!='NEWLINE': 137 break 138 self._next()
139
140 - def _getuptoeol(self):
141 """Returns everything up to newline as a string. If end of line has backslash before it then 142 next line is returned as well""" 143 t=self._lookahead() 144 res=self._getline(t[2][0])[t[2][1]:] 145 while True: 146 while t[0]!='NEWLINE': 147 t=self._next() 148 if res[-2]!='\\': 149 break 150 t=self._next() 151 res+=self._getline(t[2][0]) 152 return res
153
154 - def _getline(self, line):
155 return self.lines[line]
156
157 - def __iter__(self):
158 return self
159
160 - def next(self):
161 res=None 162 if len(self.resultspb): 163 res=self.resultspb.pop() 164 165 if self.state[-1]==self.STATE_TOPLEVEL: 166 if res is not None: 167 return res 168 169 # any deferred packets? 170 if len(self.deferredpackets): 171 res=self.deferredpackets[0] 172 self.deferredpackets=self.deferredpackets[1:] 173 return res 174 175 # outermost level in file 176 t=self._lookahead() 177 if t[0]=='NEWLINE': 178 self._next() # consume 179 return self.next() 180 if t[0]=='OP' and t[1]=='%': 181 return (self.LITERAL, self._getliteral()) 182 if t[0]=='NAME' and t[1]=='PACKET': 183 return self._processpacketheader() 184 if t[0]=='ENDMARKER': 185 raise StopIteration() 186 raise protoerror("Unexpected token", t) 187 188 if self.state[-1]==self.STATE_PACKET or self.state[-1]==self.STATE_CONDITIONAL: 189 # describing fields in a packet 190 if res is None: 191 res=self._processpacketfield() 192 # flatten nested packets 193 if res[0]==self.PACKETSTART: 194 q=[res] 195 while True: 196 res=self.next() 197 q.append(res) 198 if res[0]==self.PACKETEND: 199 break 200 self.deferredpackets.extend(q) 201 return self.next() 202 # normal 203 return res 204 205 raise protoerror("Unexpected state", self._lookahead())
206
207 - def _getliteral(self):
208 "Returns the section enclosed in %{ ... }%. The %{ and }% must be on lines by themselves." 209 t=self._next() 210 if t[0]!='OP' or t[1]!='%': 211 raise protoerror("Expecting '%{'", t) 212 t=self._next() 213 if t[0]!='OP' or t[1]!='{': 214 raise protoerror("Expecting '%{'", t) 215 t=self._next() 216 if t[0]!='NEWLINE': 217 raise protoerror("Expecting newline", t) 218 # now in middle of literal 219 res="" 220 lastline=-1 221 while True: 222 t=self._lookahead() 223 t2=self._lookahead(2) 224 if t[0]=='OP' and t[1]=='%' and \ 225 t2[0]=='OP' and t2[1]=='}': 226 self._next() # consume % 227 self._next() # consume } 228 t=self._next() 229 if t[0]!='NEWLINE': 230 raise protoerror("Expecting newline",t) 231 break 232 t=self._next() 233 res+=t[4] 234 lastline=t[2][0] 235 while self._lookahead()[2][0]==lastline: 236 # consume all tokens on the same line 237 self._next() 238 return res
239
240 - def _getdict(self):
241 """Returns a text string representing a dict. If the next token is 242 not a dict start then None is returned""" 243 res=None 244 t=self._lookahead() 245 if t[0]!='OP' or t[1]!="{": 246 return res 247 res="" 248 t=self._next() 249 start=t[2] 250 mostrecent=t # to aid in debugging 251 nest=1 252 while nest>0: 253 t=self._next() 254 if t[0]=='OP' and t[1]=='}': 255 nest-=1 256 continue 257 if t[0]=='OP' and t[1]=='{': 258 mostrecent=t 259 nest+=1 260 continue 261 if t[0]=='DEDENT' or t[0]=='INDENT' or t[0]=='ENDMARKER': 262 raise protoerror("Unterminated '{'", mostrecent) 263 264 end=t[3] 265 for line in range(start[0], end[0]+1): 266 l=self._getline(line) 267 if line==end[0]: 268 l=l[:end[1]] 269 if line==start[0]: 270 l=l[start[1]:] 271 res+=l 272 273 return res
274
275 - def _processpacketheader(self):
276 t=self._next() 277 if t[0]!='NAME': 278 raise protoerror("expecting 'PACKET'", t) 279 thedict=self._getdict() 280 t=self._next() 281 # class name 282 themodifiers="" 283 while t[0]=='OP': 284 themodifiers+=t[1] 285 t=self._next() 286 if t[0]!='NAME': 287 raise protoerror("expecting packet name", t) 288 thename=t[1] 289 t=self._next() 290 if t[0]!='OP' and t[1]!=':': 291 raise protoerror("expecting ':'", t) 292 293 # we now have to see an indent and an option string in either order, with newlines ignored 294 thecomment=None 295 seenindent=False 296 while True: 297 t=self._lookahead() 298 if t[0]=='NEWLINE': 299 self._next() 300 continue 301 if t[0]=='STRING': 302 if thecomment is not None: 303 raise protoerror("Duplicate string comment", t) 304 thecomment=self._next()[1] 305 continue 306 if t[0]=='INDENT': 307 if seenindent: 308 raise protoerror("Unexpected repeat indent", t) 309 seenindent=True 310 self._next() 311 continue 312 break 313 314 if not seenindent: 315 raise protoerror("Expecting an indent", t) 316 self._consumenl() 317 # ok, now pointing to packet data 318 self.state.append(self.STATE_PACKET) 319 self.packetstack.append( (thename, thedict, thecomment, themodifiers) ) 320 return self.PACKETSTART, thename, None, thedict, thecomment, themodifiers
321
322 - def _processpacketfield(self):
323 """Read in one packet field""" 324 self._consumenl() 325 t=self._lookahead() 326 327 if t[0]=='DEDENT': 328 # consume 329 self._next() 330 # pop a packet 331 x=self.state.pop() 332 if x==self.STATE_CONDITIONAL: 333 # check if this is an else if elif 334 t=self._lookahead() 335 if t[0]=='NAME' and t[1] in ('else', 'elif'): 336 self.state.append(self.STATE_CONDITIONAL) 337 else: 338 return (self.CONDITIONALEND,) 339 else: 340 return (self.PACKETEND,) 341 342 if t[0]=='OP' and t[1]=='%': 343 # embedded codes 344 return self.CODE, self._getliteral() 345 346 # Size 347 if t[0]=='NUMBER': 348 self._next() 349 thesize=int(t[1]) 350 elif t[0]=='OP' and t[1]=='*': 351 self._next() 352 thesize=-1 353 elif t[0]=='NAME' and t[1].upper()=='P': 354 self._next() 355 thesize='P' 356 elif t[0]=='NAME' and t[1].upper()=='A': 357 self._next() 358 return self.ASSERTION, self._getuptoeol() 359 elif t[0]=='NAME' and t[1]=='if': 360 str=self._getuptoeol() 361 self._consumenl() 362 t=self._next() 363 if t[0]!='INDENT': 364 raise protoerror("Expecting an indent after if ...: statement", t) 365 self.state.append(self.STATE_CONDITIONAL) 366 return (self.CONDITIONALSTART, str) 367 elif t[0]=='NAME' and t[1] in ('elif', 'else'): 368 str=self._getuptoeol() 369 self._consumenl() 370 t=self._next() 371 if t[0]!='INDENT': 372 raise protoerror("Expecting an indent after else: or elif ...: statement", t) 373 if self.state[-1]!=self.STATE_CONDITIONAL: 374 raise protoerror('An if must precede an else or elif.', t) 375 return (self.CONDITIONALRESTART, str) 376 else: 377 raise protoerror("Expecting field size as an integer, *, P, A or 'if' statement", t) 378 379 # Type 380 t=self._next() 381 if t[0]!='NAME': 382 raise protoerror("Expecting field type", t) 383 thetype=t[1] 384 385 # a dot and another type (first was module)? 386 t=self._lookahead() 387 if t[0]=='OP' and t[1]=='.': 388 self._next() 389 t=self._next() 390 if t[0]!='NAME': 391 raise protoerror("Expecting a name after . in field type", t) 392 thetype+="."+t[1] 393 394 # Optional dict 395 thedict=self._getdict() 396 397 # Name 398 themodifiers="" 399 t=self._next() 400 while t[0]=='OP': 401 themodifiers+=t[1] 402 t=self._next() 403 thevisible=t[0]=='NAME' 404 if thevisible: 405 thename=t[1] 406 else: 407 # Anonymous, invisible field 408 thename=self._getautogenname(t[2][0]) 409 410 # A colon (anonymous inner struct), newline, or string description 411 thedesc=None 412 t=self._lookahead() 413 if t[0]=='OP' and t[1]==':': 414 # consume : 415 self._next() 416 417 seenindent=False 418 419 # optional newline 420 self._consumenl() 421 # optional description 422 t=self._lookahead() 423 if t[0]=='STRING': 424 thedesc=t[1] 425 t=self._next() 426 elif t[0]=='INDENT': 427 seenindent=True 428 self._next() 429 # optional newline 430 self._consumenl() 431 # there should be an indent 432 if not seenindent: 433 t=self._next() 434 if t[0]!='INDENT': 435 raise protoerror("Expected an indent after : based field", t) 436 437 # put new packet on results pushback 438 autoclass=self._getautogenname(t[2][0]) 439 self.resultspb.append( (self.PACKETSTART, autoclass, None, None, "'Anonymous inner class'", "") ) 440 self.state.append(self.STATE_PACKET) 441 442 return self.FIELD, thename, thesize, thetype, "{'elementclass': "+autoclass+"}", \ 443 thedict, thedesc, themodifiers, thevisible 444 445 # optional string 446 if t[0]=='STRING': 447 thedesc=t[1] 448 self._next() 449 # optional newline 450 self._consumenl() 451 # the string this time on the next line? 452 if thedesc is None: 453 t=self._lookahead() 454 if t[0]=='STRING': 455 thedesc=t[1] 456 self._next() 457 self._consumenl() 458 # return what have digested .. 459 return self.FIELD, thename, thesize, thetype, None, thedict, thedesc,\ 460 themodifiers, thevisible
461
462 -def indent(level=1):
463 return " "*level
464 465
466 -class codegen:
467 - def __init__(self, tokenizer):
468 self.tokenizer=tokenizer
469
470 - def gencode(self):
471 tokens=self.tokenizer 472 out=cStringIO.StringIO() 473 474 print >>out, "# THIS FILE IS AUTOMATICALLY GENERATED. EDIT THE SOURCE FILE NOT THIS ONE" 475 476 for t in tokens: 477 if t[0]==tokens.LITERAL: 478 out.write(t[1]) 479 continue 480 if t[0]==tokens.PACKETSTART: 481 classdetails=t 482 classfields=[] 483 classcodes=[] 484 continue 485 if t[0]==tokens.PACKETEND: 486 self.genclasscode(out, classdetails, classfields, classcodes) 487 continue 488 if t[0]==tokens.CODE: 489 classcodes.append(t) 490 else: 491 classfields.append(t) 492 493 return out.getvalue()
494
495 - def genclasscode(self, out, namestuff, fields, codes):
496 classname=namestuff[1] 497 tokens=self.tokenizer 498 _read_only='-' in namestuff[5] 499 print >>out, "class %s(BaseProtogenClass):" % (classname,) 500 if namestuff[4] is not None: 501 print >>out, indent()+namestuff[4] 502 if _read_only: 503 print >>out, indent(1)+"# Read-From-Buffer-Only Class" 504 # fields 505 fieldlist=[f[1] for f in fields if f[0]==tokens.FIELD and f[8]] 506 507 print >>out, indent(1)+"__fields="+`fieldlist` 508 print >>out, "" 509 510 511 # Constructor 512 print >>out, indent()+"def __init__(self, *args, **kwargs):" 513 print >>out, indent(2)+"dict={}" 514 if namestuff[2] is not None: 515 print >>out, indent(2)+"# Default generator arguments" 516 print >>out, indent(2)+"dict.update("+namestuff[2]+")" 517 if namestuff[3] is not None: 518 print >>out, indent(2)+"# User specified arguments in the packet description" 519 print >>out, indent(2)+"dict.update("+namestuff[3]+")" 520 print >>out, indent(2)+"# What was supplied to this function" 521 print >>out, indent(2)+"dict.update(kwargs)" 522 print >>out, indent(2)+"# Parent constructor" 523 print >>out, indent(2)+"super(%s,self).__init__(**dict)"%(namestuff[1],) 524 print >>out, indent(2)+"if self.__class__ is %s:" % (classname,) 525 print >>out, indent(3)+"self._update(args,dict)" 526 print >>out, "\n" 527 # getfields 528 print >>out, indent()+"def getfields(self):" 529 print >>out, indent(2)+"return self.__fields" 530 print >>out, "\n" 531 # update function 532 print >>out, indent()+"def _update(self, args, kwargs):" 533 print >>out, indent(2)+"super(%s,self)._update(args,kwargs)"%(namestuff[1],) 534 print >>out, indent(2)+"keys=kwargs.keys()" 535 print >>out, indent(2)+"for key in keys:" 536 print >>out, indent(3)+"if key in self.__fields:" 537 print >>out, indent(4)+"setattr(self, key, kwargs[key])" 538 print >>out, indent(4)+"del kwargs[key]" 539 print >>out, indent(2)+"# Were any unrecognized kwargs passed in?" 540 print >>out, indent(2)+"if __debug__:" 541 print >>out, indent(3)+"self._complainaboutunusedargs(%s,kwargs)" % (namestuff[1],) 542 # if only field, pass stuff on to it 543 if len(fields)==1: 544 print >>out, indent(2)+"if len(args):" 545 # we can't use makefield as we have to make a new dict 546 d=[] 547 if f[2]>=0: 548 d.append("{'sizeinbytes': "+`f[2]`+"}") 549 for xx in 4,5: 550 if f[xx] is not None: 551 d.append(f[xx]) 552 for dd in d: assert dd[0]=="{" and dd[-1]=='}' 553 d=[dd[1:-1] for dd in d] 554 print >>out, indent(3)+"dict2={%s}" % (", ".join(d),) 555 print >>out, indent(3)+"dict2.update(kwargs)" 556 print >>out, indent(3)+"kwargs=dict2" 557 print >>out, indent(3)+"self.__field_%s=%s(*args,**dict2)" % (f[1],f[3]) 558 # else error if any args 559 else: 560 print >>out, indent(2)+"if len(args): raise TypeError('Unexpected arguments supplied: '+`args`)" 561 print >>out, indent(2)+"# Make all P fields that haven't already been constructed" 562 for f in fields: 563 if f[0]==tokens.FIELD and f[2]=='P': 564 ## print >>out, indent(2)+"if getattr(self, '__field_"+f[1]+"', None) is None:" 565 print >>out, indent(2)+"try: self.__field_"+f[1] 566 print >>out, indent(2)+"except:" 567 self.makefield(out, 3, f) 568 569 print >>out, "\n" 570 571 # Write to a buffer 572 i=2 573 print >>out, indent()+"def writetobuffer(self,buf,autolog=True,logtitle=\"<written data>\"):" 574 print >>out, indent(i)+"'Writes this packet to the supplied buffer'" 575 if _read_only: 576 print >>out, indent(i)+"raise NotImplementedError" 577 else: 578 print >>out, indent(i)+"self._bufferstartoffset=buf.getcurrentoffset()" 579 for f in fields: 580 if f[0]==tokens.FIELD and f[2]!='P': 581 if '+' in f[7]: 582 print >>out, indent(i)+"try: self.__field_%s" % (f[1],) 583 print >>out, indent(i)+"except:" 584 self.makefield(out, i+1, f, isreading=False) 585 print >>out, indent(i)+"self.__field_"+f[1]+".writetobuffer(buf)" 586 elif f[0]==tokens.CONDITIONALSTART: 587 print >>out, indent(i)+f[1] 588 i+=1 589 elif f[0]==tokens.CONDITIONALRESTART: 590 print >>out, indent(i-1)+f[1] 591 elif f[0]==tokens.CONDITIONALEND: 592 i-=1 593 assert i==2 594 print >>out, indent(2)+"self._bufferendoffset=buf.getcurrentoffset()" 595 print >>out, indent(2)+"if autolog and self._bufferstartoffset==0: self.autologwrite(buf, logtitle=logtitle)" 596 print >>out, "\n" 597 598 # Read from a buffer 599 print >>out, indent()+"def readfrombuffer(self,buf,autolog=True,logtitle=\"<read data>\"):" 600 print >>out, indent(2)+"'Reads this packet from the supplied buffer'" 601 i=2 602 print >>out, indent(2)+"self._bufferstartoffset=buf.getcurrentoffset()" 603 print >>out, indent(2)+"if autolog and self._bufferstartoffset==0: self.autologread(buf, logtitle=logtitle)" 604 for f in fields: 605 if f[0]==tokens.FIELD: 606 if f[2]=='P': 607 continue 608 if _read_only and not f[8]: 609 # anonymous field, use temp field instead 610 print >>out, indent(i)+self._maketempfieldstr(f)+".readfrombuffer(buf)" 611 else: 612 self.makefield(out, i, f) 613 print >>out, indent(i)+"self.__field_%s.readfrombuffer(buf)" % (f[1],) 614 elif f[0]==tokens.CONDITIONALSTART: 615 print >>out, indent(i)+f[1] 616 i+=1 617 elif f[0]==tokens.CONDITIONALRESTART: 618 print >>out, indent(i-1)+f[1] 619 elif f[0]==tokens.CONDITIONALEND: 620 i-=1 621 assert i==2 622 print >>out, indent(2)+"self._bufferendoffset=buf.getcurrentoffset()" 623 print >>out, "\n" 624 625 # Setup each field as a property 626 for f in fields: 627 if f[0]==tokens.FIELD and f[8]: 628 # get 629 print >>out, indent()+"def __getfield_%s(self):" % (f[1],) 630 if '+' in f[7]: 631 print >>out, indent(2)+"try: self.__field_%s" % (f[1],) 632 print >>out, indent(2)+"except:" 633 self.makefield(out, 3, f) 634 print >>out, indent(2)+"return self.__field_%s.getvalue()\n" % (f[1],) 635 # set 636 print >>out, indent()+"def __setfield_%s(self, value):" % (f[1],) 637 print >>out, indent(2)+"if isinstance(value,%s):" % (f[3],) 638 print >>out, indent(3)+"self.__field_%s=value" % (f[1],) 639 print >>out, indent(2)+"else:" 640 self.makefield(out, 3, f, "value,", isreading=False) 641 print >>out, "" 642 # del 643 print >>out, indent()+"def __delfield_%s(self): del self.__field_%s\n" % (f[1], f[1]) 644 # Make it a property 645 print >>out, indent()+"%s=property(__getfield_%s, __setfield_%s, __delfield_%s, %s)\n" % (f[1], f[1], f[1], f[1], f[6]) 646 if '++' in f[7]: 647 # allow setting attributes 648 print >>out, indent()+"def ss_pb_count_respset_%s_attr(self, **kwargs):"%f[1] 649 print >>out, indent(2)+"self.%s"%f[1] 650 print >>out, indent(2)+"self.__field_%s.update(**kwargs)\n"%f[1] 651 652 # we are a container 653 print >>out, indent()+"def iscontainer(self):" 654 print >>out, indent(2)+"return True\n" 655 656 print >>out, indent()+"def containerelements(self):" 657 i=2 658 _pass_flg= { i: True } 659 for f in fields: 660 if f[0]==tokens.FIELD and f[8]: 661 print >>out, indent(i)+"yield ('%s', self.__field_%s, %s)" % (f[1], f[1], f[6]) 662 _pass_flg[i]=False 663 elif f[0]==tokens.CONDITIONALSTART: 664 print >>out, indent(i)+f[1] 665 _pass_flg[i]=False 666 i+=1 667 _pass_flg[i]=True 668 elif f[0]==tokens.CONDITIONALRESTART: 669 if _pass_flg[i]: 670 print >>out, indent(i)+"pass" 671 else: 672 _pass_flg[i]=True 673 print >>out, indent(i-1)+f[1] 674 elif f[0]==tokens.CONDITIONALEND: 675 if _pass_flg[i]: 676 print >>out, indent(i)+"pass" 677 i-=1 678 assert i==2 679 680 # generate embeded codes 681 print >>out 682 for _l in codes: 683 print >>out, _l[1] 684 685 print >>out, "\n\n"
686
687 - def makefield(self, out, indentamount, field, args="", isreading=True):
688 d=[] 689 if field[2]!='P' and field[2]>=0: 690 d.append("{'sizeinbytes': "+`field[2]`+"}") 691 if not (isreading and '*' in field[7]): 692 for xx in 4,5: 693 if field[xx] is not None: 694 d.append(field[xx]) 695 696 for dd in d: 697 assert dd[0]=='{' and dd[-1]=='}' 698 699 if len(d)==0: 700 print >>out, indent(indentamount)+"self.__field_%s=%s(%s)" % (field[1], field[3], args) 701 return 702 703 d=[dd[1:-1] for dd in d] 704 dd="{"+", ".join(d)+"}" 705 print >>out, indent(indentamount)+"self.__field_%s=%s(%s**%s)" % (field[1], field[3], args, dd)
706
707 - def _maketempfieldstr(self, field, args='', isreading=True):
708 # create and return string that creates a temporary field 709 d=[] 710 if field[2]!='P' and field[2]>=0: 711 d.append("{'sizeinbytes': "+`field[2]`+"}") 712 if not (isreading and '*' in field[7]): 713 for xx in 4,5: 714 if field[xx] is not None: 715 d.append(field[xx]) 716 717 for dd in d: 718 assert dd[0]=='{' and dd[-1]=='}' 719 720 if len(d)==0: 721 return "%s(%s)" % (fields[3], args) 722 723 d=[dd[1:-1] for dd in d] 724 dd="{"+", ".join(d)+"}" 725 return "%s(%s**%s)" % (field[3], args, dd)
726 727
728 -def processfile(inputfilename, outputfilename):
729 print "Processing",inputfilename,"to",outputfilename 730 fn=os.path.basename(outputfilename) 731 fn=os.path.splitext(fn)[0] 732 with contextlib.nested(file(inputfilename, "rtU"), 733 file(outputfilename, "wt")) as (f, f2): 734 tokens=tokenize.generate_tokens(f.readline) 735 tt=protogentokenizer(tokens, "_gen_"+fn+"_") 736 cg=codegen(tt) 737 f2.write(cg.gencode())
738 739 if __name__=='__main__': 740 if len(sys.argv)>3 or (len(sys.argv)==2 and sys.argv[1]=="--help"): 741 print "protogen compiles all .p files in this directory to .py" 742 print "protogen foo.p compiles foo.p to foo.py" 743 print "protogen foo.p bar.py compiles foo.p to bar.py" 744 sys.exit(1) 745 elif len(sys.argv)==3: 746 processfile(sys.argv[1], sys.argv[2]) 747 elif len(sys.argv)==2: 748 processfile(sys.argv[1], sys.argv[1]+"y") 749 elif len(sys.argv)==1: 750 import glob 751 for f in glob.glob("*.p"): 752 processfile(f, f+"y") 753 for f in glob.glob("phones/*.p"): 754 processfile(f, f+"y") 755