let rec compile_global_expression expr = match expr with
    Ast.SynFunctionDeclare (dt, name, arglist) -> [NoteFunction name]
  | Ast.SynRemotableFunctionDeclare (dt, name, arglist) -> []
  | Ast.SynFunctionDefine ((dt, name, arglist), expr_list) -> 
        compile_function_definition name arglist expr_list
  | Ast.SynTemplatedDeclare (_,expr) -> compile_global_expression expr
  | Ast.SynTemplatedDefine (_,expr) -> compile_global_expression expr
  | Ast.SynStructDeclare sdecl -> []
  | Ast.SynGlobalEnumDeclare edecl -> []
  | Ast.SynGlobalVarDeclare vdecl -> 
      (match vdecl with
           Ast.SynVarDeclareNoInit (dt,v) -> 
             let dt_result = compile_datatype_init dt in
             let _ = init_buffer := !init_buffer @ dt_result @ [SetVar v] in
               [DeclareGlobal v]
         | _ -> raise_compile_error ["Unexpected compile error: cannot initialize a variable in the global scope."])                          
  | Ast.SynStateMachine _ ->
      raise_compile_error ["Unexpected compile error: source-to-source compilation of state machine failed."]
  | Ast.SynInclude data -> 
      match !data with
          Ast.IncludeAst ast -> compile_global_expression_list ast
        | Ast.IncludeFileName s -> 
            raise_compile_error ["Unexpected compile error: include ";s;" was not typechecked properly."]
            
(** Compile a global expression list *)

and compile_global_expression_list src_prog = 
  match src_prog with
      cur::rest -> 
        let curbuf = compile_global_expression cur in
        let restbuf = compile_global_expression_list rest in
          curbuf@restbuf
    | [] -> []

(** Compile a source program to IR representation, including the init buffer *)

and compile_ir src_prog =
  try
    let _ = init_buffer := [] in
    let init_label = make_label "INIT" in
    let program_result = compile_global_expression_list src_prog in
      [Instruction (Annotation (concat ["init ";init_label]))]
      @ program_result
      @ [Instruction (Annotation (concat ["function ";init_label;" 0"]));
         Instruction (Label (init_label))]
      @ !init_buffer
      @ [Instruction Return]
  with
      Ircompile_error s ->
        let _ = output_string stderr s in
        let _ = output_string stderr "\n" in
        let _ = flush stderr in
          raise (Ircompile_error s)