Changeset 1144 for proto/RE2PBS


Ignore:
Timestamp:
Apr 22, 2011, 2:00:48 AM (8 years ago)
Author:
ksherdy
Message:

Add Factory class to prevent name conflicts. Add debug support. Enforce Generator interface methods. Add incremental cursor strategy.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • proto/RE2PBS/bin/re2pbs.py

    r1142 r1144  
    1212    def debug(self):
    1313      print 'Debug node.'
     14
     15# TODO - Implement RE alternation.
    1416
    1517#
     
    5456    def debug(self):
    5557      return 'Single() -> (%s)' % (self.codepoint)
    56      
    57 class Generator:
    58     ''' Regular Expression generator for parallel bit streams interface and helpers.'''
    59     def __init__(self):
    60       pass   
    61    
    62     def make_init_stmts(self, strm):
    63       pass
    64    
    65     def make_match_stmts(self, strm, quantifier, follow_strm=None):
    66       pass
    67    
    68     def make_optional_stmts(self, strm, follow_strm=None):
    69       pass
    70    
    71     def make_kleene_star_stmts(self, strm, follow_strm=None):
    72       pass
    73    
    74     def make_kleene_cross_stmts(self, strm, follow_strm=None):
    75       pass
    76 
    77     def make_single_stmts(self, follow_strm=None):
    78       pass
    79      
    80     @classmethod
    81     def indent(cls, level):
    82       return ''.join(['\n' for i in range(0, level)])
    83      
     58
     59class PabloCode:
     60    """ Methods to generate and format Pablo prototype statements and code. """
    8461    @classmethod
    8562    def Assign(cls, lhs, rhs):
     
    9269    @classmethod
    9370    def Nand(cls, lhs, rhs):
    94       return '(' + lhs + ')' + ' ~& (' + rhs + ')'
     71      return '(' + lhs + ')' + ' &~ (' + rhs + ')'
    9572     
    9673    @classmethod       
     
    10077    @classmethod
    10178    def Advance(cls, strm):
    102       return 'Advance(%s)' % (strm)
     79      return 'bitutil.Advance(%s)' % (strm)
    10380   
    10481    @classmethod
    10582    def ScanThru(cls, cursor, strm):
    106       return 'ScanThru(%s,%s)' % (cursor, strm)
    107    
    108 class FollowCheck(Generator):
    109    
    110     ''' Regular expression stream generator.'''
    111     def __init__(self, cursor = 'cursor', error = 'error', level=0):
    112       self.indent = self.indent(level)
    113       self.cursor = cursor
    114       self.error = error
    115    
     83      return 'bitutil.ScanThru(%s,%s)' % (cursor, strm)
     84
     85    @classmethod
     86    def indent(cls, level):
     87      return ''.join(['\t' for i in range(0, level)])
     88     
     89class GeneratorFactory:
     90    """ Parallel bit stream equation generator factory class.
     91        Use this class create parallel bit stream class instances to
     92        ensure that emitted cursor and error stream identifiers are unique.
     93    """
     94    def __init__(self):
     95      self.count = 0
     96           
     97    def build_post_validator(self, level=0, cursor = 'cursor', error = 'error'):
     98      self.count = self.count + 1
     99      cursor += '_' + str(self.count)
     100      error += '_' + str(self.count)
     101      return PostValidator(level, cursor, error)
     102
     103    def build_pre_validator(self, level=0, cursor = 'cursor', error = 'error'):
     104      self.count = self.count + 1
     105      cursor += '_' + str(self.count)
     106      error += '_' + str(self.count)
     107      return PreValidator(level, cursor, error)
     108
     109import sys
     110
     111class Generator:
     112    """ Parallel bit streams equation generator base class."""
     113    def __init__(self, level=0, cursor='cursor', error='error'):
     114      self.indent_level = PabloCode.indent(level)
     115     
     116      self.cursor_count = -1
     117      self.cursor_base = cursor
     118      self.cursor = self.next_cursor()
     119     
     120      self.error_count = -1   
     121      self.error_base = error
     122      self.error = self.next_error()
     123         
     124    def next_cursor(self):
     125        self.cursor_count = self.cursor_count + 1
     126        self.cursor = self.cursor_base + '_' + str(self.cursor_count)
     127        return self.cursor
     128       
     129    def next_error(self):         
     130        self.error_count = self.error_count + 1
     131        self.error = self.error_base + '_' + str(self.error_count)
     132        return self.error
     133       
     134    def make_lexical_items(self, strm_lst):
     135        strms = ""
     136        for strm in strm_lst:
     137          strms += self.indent_level + PabloCode.Assign(strm,'0')  +'\n'         
     138        return strms 
     139     
    116140    def make_init_stmts(self, strm):
    117       code = self.indent  + self.Assign(self.error, '0') + '\n'
    118       code += self.indent + self.Assign(self.cursor, self.Nand(strm, self.Advance(strm)))  + '\n'
    119       return code
    120    
    121     def make_match_stmts(self, strm, quantifier=None, follow_strm=None):
     141      print self.__class__.__name__ + ' not implemented.'
     142      sys.exit(1)
     143   
     144    def make_match_stmts(self, strm, quantifier, follow_set_strm=None):
     145      print self.__class__.__name__ + ' not implemented.'
     146      sys.exit(1)
     147   
     148    def make_optional_stmts(self, strm, follow_set_strm=None):
     149      print self.__class__.__name__ + ' not implemented.'
     150      sys.exit(1)
     151   
     152    def make_kleene_star_stmts(self, strm, follow_set_strm=None):
     153      print self.__class__.__name__ + ' not implemented.'
     154      sys.exit(1)
     155   
     156    def make_kleene_cross_stmts(self, strm, follow_set_strm=None):
     157      print self.__class__.__name__ + ' not implemented.'
     158      sys.exit(1)
     159
     160    def make_single_stmts(self, strm, follow_set_strm=None):
     161      print self.__class__.__name__ + ' not implemented.'
     162      sys.exit(1)
     163     
     164    def make_finalization_stmts(self): 
     165      print self.__class__.__name__ + ' not implemented.'
     166      sys.exit(1)
     167     
     168    def make_debug_stmts(self):
     169      print self.__class__.__name__ + ' not implemented.'
     170      sys.exit(1)
     171     
     172class PostValidator(Generator):
     173   
     174    """ Regular expression stream generator utilizing a post-validation strategy,
     175        i.e. Advance cursor(s). Validate.
     176       
     177        This approach requires regular expression symbol lookahead to
     178        determine 'Follow' lexical item streams for the identification of errors.
     179    """
     180       
     181#       TODO
     182#
     183#       (1) Implemeent method definition: make_follow_set_strm .
     184#       (2) Add post validation error handling & deletion of cursor positions in error.
     185#       (3) Add debug code.
     186#
     187
     188    def __init__(self, level=0, cursor='cursor', error='error'):
     189      Generator.__init__(self, level, cursor, error)
     190   
     191    def make_init_stmts(self, strm):
     192      code = self.indent_level  + PabloCode.Assign(self.error, '0') + '\n'
     193      code += self.indent_level + PabloCode.Assign(self.cursor, PabloCode.Nand(strm, PabloCode.Advance(strm)))  + '\n'
     194      return code
     195   
     196    def make_match_stmts(self, strm, quantifier=None, follow_set_strm=None):
    122197      if quantifier == '?':
    123         return self.make_optional_stmts(strm, follow_strm)
     198        return self.make_optional_stmts(strm, follow_set_strm)
    124199      elif quantifier == '+':
    125         return self.make_kleene_cross_stmts(strm, follow_strm)
     200        return self.make_kleene_cross_stmts(strm, follow_set_strm)
    126201      elif quantifier == '*':
    127         return self.make_kleene_star_stmts(strm, follow_strm)
     202        return self.make_kleene_star_stmts(strm, follow_set_strm)
    128203      else:
    129         return self.make_single_stmts(follow_strm)
    130        
    131     def make_single_stmts(self, follow_strm=None):
    132       code = self.indent + self.Assign(self.cursor, self.Advance(self.cursor)) + '\n'
    133       if(follow_strm != None):
    134             code += self.OrEq(self.error, self.Nand(self.cursor, follow_strm)) + '\n'
    135       return code
    136 
    137     def make_optional_stmts(self, strm, follow_strm=None):
    138       code = self.indent + self.Assign(self.cursor, self.ScanThru(self.cursor, self.And(strm, self.cursor))) + '\n'
    139       if(follow_strm != None):
    140             code += self.OrEq(self.error, self.Nand(self.cursor, follow_strm)) + '\n'
    141       return code
    142    
    143     def make_kleene_star_stmts(self, strm, follow_strm=None):
    144       code = self.indent + self.Assign(self.cursor, self.ScanThru(self.cursor, strm)) + '\n'
    145       if(follow_strm != None):
    146             code += self.OrEq(self.error, self.Nand(self.cursor, follow_strm)) + '\n'
    147       return code
    148    
    149     def make_kleene_cross_stmts(self, strm, follow_strm=None):
     204        return self.make_single_stmts(strm, follow_set_strm)
     205       
     206    def make_single_stmts(self, strm, follow_set_strm=None):
     207      """ Cursor = Advance(Cursor)                      # C = C + C
     208          Error  = Cursor &~ FollowSet(Strm)            # E = C &~ F
     209          Cursor = Cursor &~ Error                      # C = C &~ E
     210      """
     211      code = self.indent_level + PabloCode.Assign(self.cursor, PabloCode.Advance(self.cursor)) + '\n'
     212      if(follow_set_strm != None):
     213            code += self.indent_level + PabloCode.OrEq(self.error, PabloCode.Nand(self.cursor, follow_set_strm)) + '\n'
     214      return code
     215
     216    def make_optional_stmts(self, strm, follow_set_strm=None):
     217      """ Temp   = Cursor                                       # T = C
     218          Cursor = ScanThru(Cursor, (Strm & Cursor))            # C = ScanThru(C,(S & C)) OR C = C | Advance(C&S), this eliminates internal ScanThru addition.
     219          Error  = Cursor1 &~ Temp &~ FollowSet(Strm)           # E = C &~ T &~ F, since C &~ (T | F)
     220      """
     221      code = self.indent_level + PabloCode.Assign(self.cursor, PabloCode.ScanThru(self.cursor, PabloCode.And(self.cursor, strm))) + '\n'
     222      if(follow_set_strm != None):
     223            code += self.indent_level + PabloCode.OrEq(self.error, PabloCode.Nand(self.cursor, follow_set_strm)) + '\n'
     224      return code
     225   
     226    def make_kleene_star_stmts(self, strm, follow_set_strm=None):
     227      """ Temp   = Cursor                                       # T  = C
     228          Cursor = ScanThru(Cursor, Strm)                       # C  = ScanThru(C,S)         
     229          Error  = Cursor1 &~ Temp &~ FollowSet(Strm)           # E  = C &~ T &~ F, since C &~ (T | F)
     230      """
     231      code = self.indent_level + PabloCode.Assign(self.cursor, PabloCode.ScanThru(self.cursor, strm)) + '\n'
     232      if(follow_set_strm != None):
     233            code += self.indent_level + PabloCode.OrEq(self.error, PabloCode.Nand(self.cursor, follow_set_strm)) + '\n'
     234      return code
     235   
     236    def make_kleene_cross_stmts(self, strm, follow_set_strm=None):
     237      #code = self.make_single_stmts(strm)
     238      code = self.make_kleene_star_stmts(strm, follow_set_strm)
     239      return code
     240
     241class PreValidator(Generator):
     242   
     243    """ Regular expression stream generator using a pre-validation strategy,
     244        i.e. Validate. Advance cursor(s). """
     245
     246    def __init__(self, level=0, cursor='cursor', error='error', debug=True):
     247      Generator.__init__(self, level, cursor, error)
     248           
     249      self.debug = debug
     250      if (self.debug):
     251        self.re2pbs_debug_generator = DebugGenerator()
     252   
     253    def make_init_stmts(self, strm):
     254      code = []
     255
     256      #----- op 1 -----
     257      op = self.indent_level  + PabloCode.Assign(self.error, '0')
     258      code.append(op)
     259
     260      if (self.debug):
     261                self.re2pbs_debug_generator.add_stmt('Init')
     262                self.re2pbs_debug_generator.add_stmt(op, self.error)
     263
     264      #----- op 2 -----
     265      op = self.indent_level + PabloCode.Assign(self.cursor, PabloCode.Nand(strm, PabloCode.Advance(strm)))
     266      code.append(op)
     267
     268      if (self.debug):
     269                self.re2pbs_debug_generator.add_stmt(strm, strm)
     270                self.re2pbs_debug_generator.add_stmt(op, self.cursor)
     271
     272      return '\n'.join(code) + '\n'
     273   
     274    def make_match_stmts(self, strm, quantifier=None, follow_set_strm=None):
     275      if quantifier == '?':
     276        return self.make_optional_stmts(strm, follow_set_strm)
     277      elif quantifier == '+':
     278        return self.make_kleene_cross_stmts(strm, follow_set_strm)
     279      elif quantifier == '*':
     280        return self.make_kleene_star_stmts(strm, follow_set_strm)
     281      else:
     282        return self.make_single_stmts(strm, follow_set_strm)
     283       
     284    def make_single_stmts(self, strm, follow_set_strm=None):     
     285      # E = C &~ S
     286      # C = C &~ E
     287      # C = Advance(C)
     288
     289      code = []
     290     
     291      #----- op 1 -----
     292      if (self.debug):
     293                self.re2pbs_debug_generator.add_stmt('Single Character')
     294                self.re2pbs_debug_generator.add_stmt(self.cursor, self.cursor)
     295                self.re2pbs_debug_generator.add_stmt(strm, strm)
     296     
     297      cursor = self.cursor
     298      op = self.indent_level + PabloCode.Assign(self.next_error(), PabloCode.Nand(cursor, strm))
     299      code.append(op)
     300
     301      if (self.debug):
     302                self.re2pbs_debug_generator.add_stmt(op, self.error)
     303
     304
     305      #----- op 2 -----
     306      cursor = self.cursor
     307      op = self.indent_level + PabloCode.Assign(self.next_cursor(), PabloCode.Nand(cursor, self.error))
     308      code.append(op)
     309
     310      if (self.debug):
     311                self.re2pbs_debug_generator.add_stmt(op, self.cursor)
     312
     313      #----- op 3 -----
     314      cursor = self.cursor
     315      op = self.indent_level + PabloCode.Assign(self.next_cursor(), PabloCode.Advance(cursor))
     316      code.append(op)
     317
     318      if (self.debug):
     319                self.re2pbs_debug_generator.add_stmt(op, self.cursor)
     320
     321
     322      return '\n'.join(code) + '\n'
     323
     324    def make_optional_stmts(self, strm, follow_set_strm=None):
     325      # C = ScanThru(C, (C & S))
     326      code = []     
     327
     328      #----- op 1 -----
     329      if (self.debug):
     330                self.re2pbs_debug_generator.add_stmt('Optional Character')
     331                self.re2pbs_debug_generator.add_stmt(self.cursor, self.cursor)
     332                self.re2pbs_debug_generator.add_stmt(strm, strm)
     333
     334      cursor = self.cursor
     335      op = self.indent_level + PabloCode.Assign(self.next_cursor(), PabloCode.ScanThru(self.cursor, PabloCode.And(cursor, strm)))
     336      code.append(op)
     337
     338      if (self.debug):
     339                self.re2pbs_debug_generator.add_stmt(op, self.cursor)
     340
     341      return '\n'.join(code) + '\n'
     342   
     343    def make_kleene_star_stmts(self, strm, follow_set_strm=None):
     344      # C = ScanThru(C, S)
     345      code = []
     346
     347      #----- op 1 -----
     348      if (self.debug):
     349                self.re2pbs_debug_generator.add_stmt('Kleene Star')
     350                self.re2pbs_debug_generator.add_stmt(self.cursor, self.cursor)
     351                self.re2pbs_debug_generator.add_stmt(strm, strm)
     352
     353      cursor = self.cursor
     354      op = self.indent_level + PabloCode.Assign(self.next_cursor(), PabloCode.ScanThru(cursor, strm))
     355      code.append(op)
     356
     357      if (self.debug):
     358                self.re2pbs_debug_generator.add_stmt(op, self.cursor)
     359
     360      return '\n'.join(code) + '\n'
     361   
     362    def make_kleene_cross_stmts(self, strm, follow_set_strm=None):
     363      # E = C &~ S
     364      # C = C &~ E
     365      # C = Advance(C)
     366      # C = ScanThru(C, S)
     367      code = ''     
     368
     369      if (self.debug):
     370                self.re2pbs_debug_generator.add_stmt('Kleene Cross')
     371
    150372      code = self.make_single_stmts(strm)
    151       code += self.make_kleene_star_stmts(strm, follow_strm)
    152       return code
    153            
     373      code += self.make_kleene_star_stmts(strm, follow_set_strm)
     374     
     375      return code
     376     
     377    def make_finalization_stmts(self):
     378     
     379      code = []
     380       
     381      if self.error_count > 0:
     382              op = self.indent_level + PabloCode.Assign(self.next_error(), self.error_base + '_' + str(0))
     383              code.append(op)
     384
     385              if (self.debug):
     386                        self.re2pbs_debug_generator.add_stmt(op, self.error)
     387
     388
     389      for i in range(1, self.error_count):
     390              op = self.indent_level + PabloCode.OrEq(self.error, self.error_base + '_' + str(i))
     391              code.append(op)
     392
     393              if (self.debug):
     394                        self.re2pbs_debug_generator.add_stmt(op, self.error)
     395             
     396      return '\n'.join(code) + '\n'
     397
     398
     399    def make_debug_stmts(self):     
     400      code = ""
     401      if(self.debug):
     402        code = self.re2pbs_debug_generator.make_debug_stmts()
     403
     404      return code
     405       
     406class DebugGenerator:
     407    def __init__(self, level=0):
     408      self.header = 'bitutil.print_aligned_streams([(\'Input Data\', u8data), \n'
     409      self.footer = '])'
     410      self.indent_level = PabloCode.indent(level)
     411      self.stmts = []
     412 
     413    def add_stmt(self, label, strm=0):
     414      stmt = self.indent_level + '(\'%s\', bitutil.bitstream2string(%s, lgth+1))' % (label, strm)
     415      self.stmts.append(stmt)
     416     
     417    def make_debug_stmts(self):
     418      return self.indent_level + self.header + ',\n'.join(self.stmts) + self.footer + '\n'
     419
     420def readfile(filename):
     421      f = open(filename, 'r')
     422      contents = f.read()
     423      f.close()
     424      return contents
     425
     426def writefile(filename, contents):
     427      f=open(filename, 'w')
     428      f.write(contents)
     429      f.close()
     430     
     431import string     
     432     
     433class Program:
     434  def __init__(self, prototype='prototype.py', template = "prototype_template.py"):
     435      self.prototype = prototype
     436      self.template = template
     437      self.contents = readfile(template)     
     438   
     439  def generate(self, lex_strms, cc_code, pbs_code, pbs_debug=''):   
     440      self.contents = string.replace(self.contents, '@lex_strms', lex_strms)
     441      self.contents = string.replace(self.contents, '@cc_code', cc_code)
     442      self.contents = string.replace(self.contents, '@pbs_code', pbs_code)
     443      self.contents = string.replace(self.contents, '@pbs_code', pbs_debug)
     444      writefile(self.prototype, self.contents)
     445
    154446def test():
    155     emitter = FollowCheck()
    156     print emitter.make_init_stmts('lex.Ampersand')                              # init Atom '&'
    157     print emitter.make_match_stmts('lex.Ampersand', None, 'lex.Hash')           # at   Atom '&' expect Atom - '#'
    158     print emitter.make_match_stmts('lex.Hash', None, 'lex.Digit')               # at   Atom '#' expect Atom '[0-9]'
    159     print emitter.make_match_stmts('lex.Digit', '+', 'lex.Semi')               
    160              
     447   
     448    factory = GeneratorFactory()
     449   
     450    re2pbs_code_generator = factory.build_pre_validator()
     451    pbs_code = re2pbs_code_generator.make_init_stmts('lex.Ampersand')                           # init   '&'
     452    pbs_code += re2pbs_code_generator.make_match_stmts('lex.Ampersand', None, 'lex.Hash')               # expect '&'
     453    pbs_code += re2pbs_code_generator.make_match_stmts('lex.Hash', None, 'lex.Digit')                   # expect '#'
     454    pbs_code += re2pbs_code_generator.make_match_stmts('lex.Digit', '+', 'lex.Semi')                    # expect '[0-9]'
     455    pbs_code += re2pbs_code_generator.make_match_stmts('lex.Semi', None, None)                  # expect ';'   
     456    pbs_code += re2pbs_code_generator.make_finalization_stmts()
     457
     458    re2pbs_code_generator = factory.build_pre_validator()
     459    pbs_code +=  re2pbs_code_generator.make_init_stmts('lex.Ampersand')                         # init   '&'
     460    pbs_code +=  re2pbs_code_generator.make_match_stmts('lex.Ampersand', None, None)            # expect '&'
     461    pbs_code +=  re2pbs_code_generator.make_match_stmts('lex.Hash', None, None)                 # expect '#'
     462    pbs_code +=  re2pbs_code_generator.make_match_stmts('lex.x', None, None)                    # expect 'x'
     463    pbs_code +=  re2pbs_code_generator.make_match_stmts('lex.Digit', '+', None)                 # expect '[0-9]'   
     464    pbs_code +=  re2pbs_code_generator.make_match_stmts('lex.Semi', None, None)                 # expect ';'
     465    pbs_code += re2pbs_code_generator.make_finalization_stmts()
     466
     467    print pbs_code
     468    print re2pbs_code_generator.make_debug_stmts()
     469
     470
    161471if __name__ == "__main__":
    162472    test()
    163473 
    164    
    165    
    166    
Note: See TracChangeset for help on using the changeset viewer.