Exemplo n.º 1
0
def interpreter(input_path="exampleInput.c",debugging=False):
  ### STEP 0:declaration of (global) variables and preprocessing ###

  # Declarate variables
  global func_table,main_flow,current_scope,flow_stack,jump_to_new_func, ret_val,current_scope, memory, isError, debug

  program_end = False

  # Set debugging mode
  if debugging:
    debug=True

  # Make AST
  with open(input_path,'r') as outfile:
    result=cparse().parse(
      input=outfile.read(),
      lexer=clex(),
      tracking=True
    )

  if debug:
    print(result)

  # in case of Syntax error -> end program  
  if result==None:
    isError=True
    return
    
  # Make function table
  for i in range(len(result)):
    if result[i][0] == "func":
      ast = result[i]
      if len(ast[3]) == 1 and ast[3][0] == "void":
        func_table[ast[2]] = {'ret_type':ast[1], 'param_num': 0, 'param_list': [], 'flow_graph': None}
      else:
        func_table[ast[2]] = {'name':ast[2], 'ret_type':ast[1], 'param_num': len(ast[3]), 'param_list': ast[3], 'flow_graph':None}

  # make symbol table
  # sub 1: Convert scope list to Scope objects 
  Scope_list=list(map(lambda x: Scope(x),scope_list_ext(input_path=input_path)))
  # sub 2: Find parent scope for each scopes
  # note: Scope_list[0] is always global scope(see scope_list_ext)
  for i in range(1,len(Scope_list)):
      for j in range(i):
        if (Scope_list[j].start_line <= Scope_list[i].start_line and Scope_list[j].end_line >= Scope_list[i].end_line):
          Scope_list[i].parent_scope = Scope_list[j]
  
  current_scope = Scope_list[0]

  scope_start_line = []
  scope_end_line = []
  for output in Scope_list:
    scope_start_line.append(output.start_line)
    scope_end_line.append(output.end_line)
  scope_start_line.reverse()
  scope_end_line.reverse()
  Scope_list.reverse()

  # Print Scope (for debugging)
  if debug:
    print("** SCOPE LIST **")
    for output in Scope_list:
      print(output)
    print(scope_start_line)
    print("** FUNCTION TABLE: dictionary of dictionaries **")
    print(func_table)

  # make flow graph for each functions
  for i in range(len(result)):
    if result[i][0] == 'func':
      ast = result[i]
      ast_scope = ast[5]
      statement_list = ast[4]

      func_flow = make_flow(ast, ast_scope, statement_list)
      if ast[2] in func_table.keys():
        func_table[ast[2]]['flow_graph'] = func_flow

      if ast[2] == 'main':
        main_flow = func_flow

  # Make memory structure
  compute_static_allocation(result)
  memory = Memory()

  ### STEP 1:main loop ###
  syntax=re.compile(r"(\Anext( (0|[1-9]\d*))?\Z)|(\Aprint [A-Za-z_]\w*(\[\d*\])?\Z)|(\Atrace [A-Za-z_]\w*\Z)|(\Aquit\Z)|(\Amem\Z)")
  while True:
    global current_address
    cmd = input(">> ").strip()

    #Catch incorrect syntax
    if syntax.match(cmd) is None:
      if (cmd[0:4] == "next"):
        print("Incorrect command usage: try 'next [lines]'")
      elif (cmd[0:5] == "print") or (cmd[0:5] == "trace"):
        print("Invalid typing of the variable name")
      else:
        print("Wrong expression!!\n <code syntax>\n")
        print((" next\n"
              " next <integer>\n"
              " print <ID>\n"
              " trace <ID>\n"
              " quit\n"))
      continue

    #instruction handler
    if (cmd[0:4] == "next"):
      if (len(cmd) == 4):
        line_num = 1
      else:
        line_num = int(cmd[5:])
      
      for i in range(line_num):
        if program_end:
          break
        
        if debug:
          print("line", main_flow.lineno, main_flow.statement)

        try:
          if (main_flow.statement is None):
            prev_scope = None
            if main_flow.lineno in scope_start_line:
              scope_copy = copy.deepcopy(Scope_list[scope_start_line.index(main_flow.lineno)])
              prev_scope = current_scope
              current_scope = scope_copy
              if debug:
                print("Change scope to", current_scope)
              if jump_to_new_func:
                # save parameter to new symbol_table
                params = func_table[new_func]['param_list']
                for k in range(func_table[new_func]['param_num']):
                  if type(params[k][1]) is tuple:
                    current_scope.symbol_table[params[k][1][1]] = {'address': current_address, 'type': params[k][0]+"arr", 'value':[param_pass[k]], 'history':[(main_flow.lineno, param_pass_addr.pop(0))]}
                    current_address += 4
                  else:
                    current_scope.symbol_table[params[k][1]] = {'address': current_address, 'type':params[k][0] , 'value':[param_pass[k]], 'history':[(main_flow.lineno, param_pass[k])]}
                    current_address += 4
                if debug:
                  current_scope.print_symboltable()
                jump_to_new_func = False
              else:
                current_scope.parent_scope = prev_scope
            elif main_flow.lineno in scope_end_line:
              prev_scope = current_scope
              current_scope = current_scope.parent_scope
              if debug:
                print("Change scope to", current_scope)
            
            main_flow = main_flow.next_node
            
            if (main_flow is None):
              current_scope = prev_scope
              print("End of program")
              program_end = True

          elif main_flow.statement[0] == 'declare':
            for j in range(len(main_flow.statement[2])):
              if type(main_flow.statement[2][j]) is tuple:  
                if (main_flow.statement[2][j][0] == 'TIMES'):  # declaration of pointer
                  current_scope.symbol_table[main_flow.statement[2][j][1]] = {"address": current_address, "type":main_flow.statement[1]+"ptr", "value":['N/A'], "size":0, "history": [(main_flow.statement[-1], 'N/A')]}
                  current_address += 4
                else:    # declaration of array
                  current_scope.symbol_table[main_flow.statement[2][j][0]] = {"address": current_address, "type":main_flow.statement[1]+"arr", "size":int(main_flow.statement[2][j][1]), "value":[['N/A' for k in range(int(main_flow.statement[2][j][1]))]], "history": [(main_flow.statement[-1], current_address)]}
                  current_address += 4 * int(main_flow.statement[2][j][1])
              else:
                current_scope.symbol_table[main_flow.statement[2][j]] = {"address": current_address, "type":main_flow.statement[1], "value":['N/A'], "history": [(main_flow.statement[-1], 'N/A')]}
                current_address += 4
            if debug:
              current_scope.print_symboltable()
            main_flow = main_flow.next_node

          elif main_flow.statement[0] == 'assign':
            assign_value(main_flow.statement[1], main_flow.statement[3], current_scope, main_flow.statement[-1])
            if debug:
              current_scope.print_symboltable()
              current_scope.parent_scope.print_symboltable()
            if jump_to_new_func == False:
              main_flow = main_flow.next_node

          elif main_flow.statement[0] == 'FOR':
            if main_flow.visited:
              if main_flow.statement[4][0] in current_scope.symbol_table.keys():
                if main_flow.statement[4][1] == '++':
                  assign_value(main_flow.statement[4][0], get_value(main_flow.statement[4][0],current_scope)+1, current_scope, main_flow.statement[4][2])
                elif main_flow.statement[4][1] == '--':
                  assign_value(main_flow.statement[4][0], get_value(main_flow.statement[4][0],current_scope)-1, current_scope, main_flow.statement[4][2])
              if (get_value(main_flow.statement[3][0], current_scope) < get_value(main_flow.statement[3][2],current_scope)):
                main_flow = main_flow.next_node_branch
              else:
                main_flow.visited = False
                main_flow = main_flow.next_node
            else:
              assign_value(main_flow.statement[2][1], main_flow.statement[2][3], current_scope, main_flow.statement[2][-1])
              main_flow.visited = True
              if (calc_value(main_flow.statement[3], current_scope)):
                main_flow = main_flow.next_node_branch
              else:
                main_flow = main_flow.next_node
            
            if debug:
              current_scope.print_symboltable()

          elif main_flow.statement[0] == 'IF':
            if main_flow.visited:
              main_flow.visited = False
              main_flow = main_flow.next_node
            else:
              main_flow.visited = True
              if calc_value(main_flow.statement[2], current_scope):
                main_flow = main_flow.next_node_branch
              else:
                if main_flow.next_node_branch2 is not None:
                  main_flow = main_flow.next_node_branch2
                else:
                  main_flow.visited = False
                  main_flow = main_flow.next_node

          elif main_flow.statement[0] == 'WHILE':
            if calc_value(main_flow.statement[2], current_scope):
              main_flow = main_flow.next_node_branch
            else:
              main_flow = main_flow.next_node

          elif main_flow.statement[0] == 'RETURN':
            if len(main_flow.statement) > 2: # if there is a return value
              ret_val = calc_value(main_flow.statement[1], current_scope)
              if debug:
                print("Return value: ", ret_val)

            if len(flow_stack) != 0:
              ret_addr = flow_stack.pop()
              main_flow = ret_addr[0]
              current_scope = ret_addr[1]
            else:
              print("End of program")
              program_end = True

          elif main_flow.statement[0] == 'printf':
            print_string = None
            if "%f" in main_flow.statement[1][0]:
              print_string = main_flow.statement[1][0][1:-1].replace('%f', str(calc_value(main_flow.statement[1][1], current_scope)))
            elif "%d" in main_flow.statement[1][0]:
              print_string = main_flow.statement[1][0][1:-1].replace('%d', str(calc_value(main_flow.statement[1][1], current_scope)))
            else:  # printf(const char*)
              print_string = main_flow.statement[1][0][1:-1]
            print(print_string.replace(r'\n', '\n'), end="")
            main_flow = main_flow.next_node

          elif main_flow.statement[0] == 'free':
            target_scope = memory.free(int(current_scope.symbol_table[main_flow.statement[1][0]]['history'][-1][1]))
            target_scope.symbol_table[main_flow.statement[1][0]]['history'].append((main_flow.lineno, 'N/A'))
            main_flow = main_flow.next_node
          
          elif main_flow.statement[0] in current_scope.symbol_table.keys():
            if main_flow.statement[1] == '++':
              assign_value(main_flow.statement[0], get_value(main_flow.statement[0],current_scope)+1, current_scope, main_flow.statement[2])
            elif main_flow.statement[1] == '--':
              assign_value(main_flow.statement[0], get_value(main_flow.statement[0],current_scope)-1, current_scope, main_flow.statement[2])
            main_flow = main_flow.next_node
        except:
          print("Run-time error: line", main_flow.lineno)
          isError=True
          break
        if isError:
          break
      
    elif (cmd[0:5] == "trace"):
      if len(cmd) == 5:  # No parameter
        pass
      else:
        print_trace(cmd[6:], current_scope)
    elif (cmd[0:5] == "print"):
      if len(cmd) == 5:  # No parameter
        pass
      else:
        print_value(cmd[6:], current_scope)
    elif (cmd[0:4] == "quit"):
      break
    elif (cmd[0:3] == "mem"):
      print("Dynamic allocation : {}, {}".format(memory.num_used_fragment, memory.total_memory - memory.free_memory))
    else:
      print("Exception!")
    if isError:
      break