Exemple #1
0
class TableManager:
  def __init__(self, filename=None):
    super(TableManager, self).__init__()
    self.table = SymbolTable()

    self.line_counts = [0]
    self.scope_names = ['global']

    self.numscopes = {}

    if filename:
      self.load_file(filename)

  def __str__(self):
    artsy = '*' * 10
    return '{} Symbol Table for {} {}\n{}'.format(artsy, self.filename, artsy, self.table)

  def load_file(self, filename):
    self.filename = filename

    with open(filename) as f:
      for line in f:
        self.parse_line(line)

    return True

  #returns True is a record was successfully inserted into the symbol table
  def _insert_one(self, label_name, var_type, adds=None):
    label_key = (self.scope_names[-1], label_name)
    _data = {
      'var_type': var_type,
      'line_count': self.line_counts[-1]
    }
    if adds:
      _data.update(adds)
    if not self.table.lookup(label_key) and label_name not in ck.keywords:
      self.table.insert(label_key, **_data)
      return True

  def parse_line(self, line):
    #ignore blank lines
    if not line.strip():
      return

    #check if scope should be initialized or finalized, the line variable is going to be screwed with
    if '{' in line:
      self.table.initialize_scope()
      curr_scope = self.table.scope_number
      self.line_counts.append(0)

      if curr_scope in self.numscopes:
        self.numscopes[curr_scope] += 1
      else:
        self.numscopes[curr_scope] = 0
      self.scope_names.append('{}.{}'.format(curr_scope, self.numscopes[curr_scope]))

      should_initialize = True
    else:
      should_initialize = False

    if '}' in line:
      should_finalize = True
    else:
      should_finalize = False

    #determine if a function is defined and get parameters from functions
    is_function = False
    if '(' in line:
      line = line.replace('(', ' ( ').replace(')', ' ) ')
      if ';' not in line and line.split()[0] not in ck.flowkeys:
        #function definitions are lines that have an open parens
        # and don't have a semicolon
        # AND the first token is not a flow of control keyword
        line, params = line.split('(')
        is_function = True
        param_tokens = [ x.strip() for x in params.rstrip(' {)\n').split(',') if x ]

    #insert new labels into the table
    if is_function or line.split()[0] in ['void', 'int', 'char', 'for'] or line.split()[0] in ck.varmods:
      #handle pointer nonsense
      if '*' in line:
        line = line.replace('*', '')
        pointer = True
      else:
        pointer = False
      head, tail = line.split(maxsplit=1)

      #ignore any/all variable modifiers
      while head in ck.varmods:
        head, tail = tail.split(maxsplit=1)

      #first token of var type
      if head in ['void','int','char']:
        if is_function:
          #insert function name
          word = tail.strip()

          #if a scope was initialized this line, we need to use the correct name
          if should_initialize:
            real_scope = -2
          else:
            real_scope = -1

          if not self.table.lookup(( self.scope_names[real_scope], word)) and word not in ck.keywords:
            self.table.insert(( self.scope_names[real_scope], word), 'function', self.line_counts[real_scope], num_parameters=len(param_tokens), parameter_name_and_type=param_tokens, return_type=head)
            self.scope_names[-1] = '{} - level {}'.format(word, self.table.scope_number)

          #insert function parameters
          for declare in param_tokens:
            pointer = '*' in declare

            var_type, label_name = ''.join(c for c in declare if c not in set(string.punctuation)).split()
            if pointer:
              var_type += '*'

            if self._insert_one(label_name, var_type):
              pass
        else:
          words = [ x.strip() for x in tail.split(',') if x ];

          #become a pointer to the var
          if pointer:
            head += '*'

          #insert the (possibly) comma-delimited set of declared variables
          for word in words:

            extra_data = None
            #handle the array of it all
            if '[' in word and ']' in word:
              dimension_bounds = []
              head = '[' + head + ']'
              word, _, tail = word.partition('[')

              while True:
                dimension, _, tail = tail.partition(']')
                dimension_bounds.append(dimension)

                if not tail:
                  break
                else:
                  tail = tail[1:]

              extra_data = {
                'number_of_dimensions': len(dimension_bounds),
                'upper_bounds_of_dimensions' : dimension_bounds
              }

            word = ''.join(c for c in word if c not in set(string.punctuation)).split()[0]
            if self._insert_one(word, head, extra_data):
              pass

    #handle close brace work
    if should_finalize:
      self.table.finalize_scope()
      self.line_counts.pop()
      self.scope_names.pop()

    for i,c in enumerate(self.line_counts):
      self.line_counts[i] += 1