code: def precompile(ex, signature=(), context={}):
      
      types = dict(signature)
      input_order = [name for (name, type_) in signature]
  
      if isinstance(ex, (str, unicode)):
          ex = stringToExpression(ex, types, context)
  
      # the AST is like the expression, but the node objects don't have
      # any odd interpretations
  
      ast = expressionToAST(ex)
  
      if ex.astType != 'op':
          ast = ASTNode('op', value='copy', astKind=ex.astKind, children=(ast,))
  
      ast = typeCompileAst(ast)
  
      aliases = collapseDuplicateSubtrees(ast)
  
      assignLeafRegisters(ast.allOf('raw'), Immediate)
      assignLeafRegisters(ast.allOf('variable', 'constant'), Register)
      assignBranchRegisters(ast.allOf('op'), Register)
  
      # assign registers for aliases
      for a in aliases:
          a.reg = a.value.reg
  
      input_order = getInputOrder(ast, input_order)
      constants_order, constants = getConstants(ast)
  
      if isReduction(ast):
          ast.reg.temporary = False
  
      optimizeTemporariesAllocation(ast)
  
      ast.reg.temporary = False
      r_output = 0
      ast.reg.n = 0
  
      r_inputs = r_output + 1
      r_constants = setOrderedRegisterNumbers(input_order, r_inputs)
      r_temps = setOrderedRegisterNumbers(constants_order, r_constants)
      r_end, tempsig = setRegisterNumbersForTemporaries(ast, r_temps)
  
      threeAddrProgram = convertASTtoThreeAddrForm(ast)
      input_names = tuple([a.value for a in input_order])
      signature = ''.join(type_to_typecode[types.get(x, default_type)]
                          for x in input_names)
      return threeAddrProgram, signature, tempsig, constants, input_names
docs: Compile the expression to an intermediate form.