let rec string_of_global_expression expr = match expr with
    SynFunctionDeclare (dt,s,arglist) -> 
      concat [string_of_datatype dt;" ";s;"(";string_of_arglist arglist;");\n"]
  | SynRemotableFunctionDeclare (dt,s,arglist) ->
      concat ["remotable ";string_of_datatype dt;" ";s;"(";string_of_arglist arglist;");\n"]
  | SynTemplatedDeclare (slist,gexpr) ->
      concat ["template <";string_of_string_list slist;">\n"; string_of_global_expression gexpr]
  | SynFunctionDefine ((dt,s,arglist),expr_list) ->
      concat [string_of_datatype dt;" ";s;"(";string_of_arglist arglist;") {\n";string_of_expr_list expr_list;"}\n"]
  | SynTemplatedDefine (slist,gexpr) ->
      concat ["template <";string_of_string_list slist;">\n"; string_of_global_expression gexpr]
  | SynStructDeclare (sname,vdecl_list) ->
      concat ["struct ";sname;" {\n";string_of_var_declare_list vdecl_list;"};\n"]
  | SynGlobalEnumDeclare (ename,slist) ->
      concat ["enum ";ename;" {";string_of_string_list slist;"};\n"]
  | SynGlobalVarDeclare vdecl ->
      concat [string_of_var_declare vdecl;";\n"]
  | SynInclude include_data ->
      concat ["include \"";string_of_include !include_data;"\"\n"]
  | SynStateMachine _ ->
      raise (Failure "Source-to-source FSM compilation did not occur (code 2).")

and string_of_arglist arglist = match arglist with
    (dt,vname)::[] -> concat [string_of_datatype dt;" ";vname]
  | (dt,vname)::rest -> concat [string_of_datatype dt;" ";vname;", "]
  | [] -> ""

and string_of_datatype dt = match dt with
    SynIntType -> "int"
  | SynFloatType -> "float"
  | SynStringType -> "string"
  | SynBoolType -> "bool"
  | SynVoidType -> "void"
  | SynEnumOrStructType (sname,_) -> sname
  | SynArrayType (t,vprod) -> concat [string_of_datatype t;" array [";string_of_value_producer vprod;"]"]
  | SynListType t -> concat [string_of_datatype t;" list"]
  | SynRefType t -> concat [string_of_datatype t;" ref"]
  | SynArrowType (dt_list,t) -> concat ["(";string_of_datatype_list dt_list;") -> ";string_of_datatype t]

and string_of_string_list slist = match slist with
    cur::[] -> cur
  | cur::rest -> concat [cur;", ";string_of_string_list rest]
  | [] -> ""


and string_of_expr_list expr_list = match expr_list with
    expr::rest -> concat [string_of_expr expr;string_of_expr_list rest]
  | [] -> ""

and string_of_var_declare_list vdecl_list = match vdecl_list with
    vdecl::[] -> concat [string_of_var_declare vdecl]
  | vdecl::rest -> concat [string_of_var_declare vdecl;", ";string_of_var_declare_list rest]
  | [] -> ""

and string_of_var_declare vdecl = match vdecl with
    SynVarDeclareNoInit (dt,name) -> 
      concat [string_of_datatype dt;" ";name]
  | SynVarDeclareWithInit (dt,name,vprod) -> 
      concat [string_of_datatype dt;" ";name;" = ";string_of_value_producer vprod]

and string_of_include data = match data with
    IncludeFileName s -> s
  | _ -> raise (Failure "Source-to-source FSM compilation did not occur (code 1).")

and string_of_value_producer vprod = match vprod with
    SynValue v -> 
      string_of_value v
  | SynFunctionCallValue funcall ->
      string_of_function_call funcall
  | SynVarIdentifier vident ->
      string_of_variable_identifier vident 
  | SynBinop (vprod1,binop,vprod2) ->
      concat [string_of_value_producer vprod1;" "; string_of_binop binop;" "; string_of_value_producer vprod2]
  | SynPrefixUnop (op,vprod) ->
      concat [string_of_unop op;" ";string_of_value_producer vprod]
  | SynParenthesized vprod ->
      concat ["(";string_of_value_producer vprod;")"]
  | SynArrayValueProducer vprod_list ->
      concat ["{";string_of_value_producer_list vprod_list ",";"}"]
  | SynListValueProducer lval_prod ->
      string_of_list_value_producer lval_prod 

and string_of_datatype_list dt_list = match dt_list with
    cur::[] -> string_of_datatype cur
  | cur::rest -> concat [string_of_datatype cur; string_of_datatype_list rest]
  | [] -> ""

and string_of_expr expr = match expr with
    SynVarDeclare vdecl -> 
      concat [string_of_var_declare vdecl;";\n"]
  | SynEnumDeclare (ename,slist) ->
      concat ["enum ";ename;" {";string_of_string_list slist;"};\n"]
  | SynVarAssign vasgn -> 
      concat [string_of_var_assign vasgn;";\n"]
  | SynCond cond ->
      concat [string_of_conditional cond;"\n"]
  | SynLoop loop ->
      concat [string_of_loop loop;"\n"]
  | SynFunctionCall funcall ->
      concat [string_of_function_call funcall;";\n"]
  | SynReturnStatement ret ->
      concat [string_of_return_statement ret;";\n"]
  | SynBreak -> "break;\n"
  | SynContinue -> "continue;\n";

and string_of_value value = match value with
    SynIntValue i -> string_of_int i
  | SynFloatValue f -> string_of_float f
  | SynStringValue s -> s
  | SynBoolValue b -> if b then "true" else "false"

and string_of_function_call funcall = match funcall with
    SynLocalCall (foo,vprod_list,_) ->
      concat [foo;"(";string_of_value_producer_list vprod_list ",";")"]
  | SynRemoteCall (foo,vprod_list,retvar) ->
      concat ["!(";foo;"(";string_of_value_producer_list vprod_list ",";"), ";string_of_variable_identifier retvar;")"]
  | SynRemoteCallNoResult (foo,vprod_list) ->
      concat ["!(";foo;"(";string_of_value_producer_list vprod_list ",";")"]

and string_of_variable_identifier vident = match vident with
    SynVarName s -> s
  | SynStructOrEnumValue (vident,s,_) ->
      concat [string_of_variable_identifier vident;".";s]
  | SynArrayCell (vident,vprod) ->
      concat [string_of_variable_identifier vident;"[";string_of_value_producer vprod;"]"]

and string_of_unop op = match op with
    SynUnopNot -> "not"
  | SynUnopCar -> "car"
  | SynUnopCdr -> "cdr"
  | SynUnopTrunc -> "trunc"
  | SynUnopDeref -> "$"
  | SynUnopNeg -> "-"
  | SynUnopNull -> "null"

and string_of_value_producer_list vprod_list del = match vprod_list with
    cur::[] -> 
      string_of_value_producer cur
  | cur::rest -> 
      concat [string_of_value_producer cur;del;" ";string_of_value_producer_list rest del]
  | [] -> ""
    
and string_of_list_value_producer vprod = match vprod with
    SynListNil dt -> 
      concat ["nil[";string_of_datatype dt;"]"]
  | SynListList vp_lst ->
      concat ["[";string_of_value_producer_list vp_lst ";";"]"]
  | SynListCons (vp1,vp2) ->
      concat [string_of_value_producer vp1;"::";string_of_value_producer vp2]

and string_of_var_assign vasgn = match vasgn with
    SynVarAssignment (vident,vprod) ->
      concat [string_of_variable_identifier vident;" = ";string_of_value_producer vprod]
  | SynVarModify (vident,binop,vprod) -> 
      concat [string_of_variable_identifier vident;" ";string_of_binop binop;"= ";string_of_value_producer vprod]

and string_of_conditional cond = match cond with
    SynIf (vprod,expr_list) ->
      concat ["if (";string_of_value_producer vprod;") {\n";string_of_expr_list expr_list;"}\n"]
  | SynIfCase (vprod,expr_list,continued_cond) ->
      concat ["if (";string_of_value_producer vprod;") {\n";string_of_expr_list expr_list;"}\n";string_of_continued_conditional continued_cond]

and string_of_continued_conditional cond = match cond with
    SynFinalElse expr_list ->
      concat ["else {\n";string_of_expr_list expr_list;"}\n"]
  | SynElse cond ->
      concat ["else ";string_of_conditional cond]

and string_of_loop loop = match loop with
    SynWhile (vprod,expr_list) ->
      concat ["while (";string_of_value_producer vprod;") {\n";string_of_expr_list expr_list;"}\n"]
  | SynFor (expr_init,vprod,expr_step,expr_list) ->
      concat ["for (";string_of_expr expr_init;string_of_value_producer vprod;";\n";string_of_expr expr_step;") {\n";string_of_expr_list expr_list;"}\n"]
  | SynDoWhile (expr_list,vprod) ->
      concat ["do {\n";string_of_expr_list expr_list;"} while (";string_of_value_producer vprod;")"]

and string_of_return_statement ret = match ret with
    SynVoidReturn -> "return"
  | SynValueReturn vprod ->
      concat ["return ";string_of_value_producer vprod]

and string_of_binop op = match op with
    SynBinopAnd -> "and"
  | SynBinopOr -> "or"
  | SynBinopAdd -> "add"
  | SynBinopSub -> "sub"
  | SynBinopMul -> "mul"
  | SynBinopDiv -> "div"
  | SynBinopIDiv -> "idiv"
  | SynBinopMod -> "mod"
  | SynBinopConcat -> "concat"
  | SynBinopCons -> "::"
  | SynCompLt -> "<"
  | SynCompGt -> ">"
  | SynCompLte -> "<="
  | SynCompGte -> ">="
  | SynCompEq -> "="
  | SynCompNeq -> "!="