
(********************************************************************)
(*                                                                  *)
(*  expr_utl.s7i  Functions for the internal C expressions.         *)
(*  Copyright (C) 1990 - 1994, 2004 - 2015  Thomas Mertes           *)
(*                                                                  *)
(*  This file is part of the Seed7 compiler.                        *)
(*                                                                  *)
(*  This program is free software; you can redistribute it and/or   *)
(*  modify it under the terms of the GNU General Public License as  *)
(*  published by the Free Software Foundation; either version 2 of  *)
(*  the License, or (at your option) any later version.             *)
(*                                                                  *)
(*  This program is distributed in the hope that it will be useful, *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of  *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   *)
(*  GNU General Public License for more details.                    *)
(*                                                                  *)
(*  You should have received a copy of the GNU General Public       *)
(*  License along with this program; if not, write to the           *)
(*  Free Software Foundation, Inc., 51 Franklin Street,             *)
(*  Fifth Floor, Boston, MA  02110-1301, USA.                       *)
(*                                                                  *)
(********************************************************************)


var boolean_obj_hash: function_pointer_declared is boolean_obj_hash.EMPTY_HASH;


const func string: create_name (in reference: current_object) is func

  result
    var string: expr is "o_";
  local
    var string: raw_name is "";
  begin
    raw_name := str(current_object);
    expr &:= str(objNumber(current_object));
    expr &:= "_";
    expr &:= striToUtf8(raw_name);
  end func;


const proc: create_name (in reference: current_object, inout string: expr) is func

  local
    var string: raw_name is "";
    var string: name is "";
  begin
    raw_name := str(current_object);
    name := getName(raw_name);
    expr &:= str(objNumber(current_object));
    if name <> "" then
      expr &:= "_";
      expr &:= name;
    end if;
    if raw_name <> "" then
      expr &:= "/*";
      expr &:= striToUtf8(raw_name);
      expr &:= "*/";
    end if;
  end func;


const proc: create_name2 (in reference: current_object, inout string: expr) is func

  local
    var string: raw_name is "";
    var string: name is "";
  begin
    raw_name := str(current_object);
    name := getName(raw_name);
    expr &:= str(objNumber(current_object));
    if name <> "" then
      expr &:= "_";
      expr &:= name;
    end if;
    if raw_name <> "" then
      expr &:= "/ ";
      expr &:= striToUtf8(raw_name);
    end if;
  end func;


const proc: create_name (in reference: current_object, in integer: object_number,
    inout string: expr) is func

  local
    var string: raw_name is "";
    var string: name is "";
  begin
    raw_name := str(current_object);
    name := getName(raw_name);
    expr &:= str(object_number);
    if name <> "" then
      expr &:= "_";
      expr &:= name;
    end if;
    if raw_name <> "" then
      expr &:= "/*";
      expr &:= raw_name;
      expr &:= "*/";
    end if;
  end func;


const proc: process_expr (in reference: current_expression, inout expr_type: c_expr) is forward;
const proc: process_call_by_name_expr (in var reference: current_expression, inout expr_type: c_expr) is forward;


const proc: prepare_typed_result (in type: aType, inout expr_type: c_expr) is func

  begin
    incr(c_expr.temp_num);
    c_expr.result_name := "tmp_";
    c_expr.result_name &:= str(c_expr.temp_num);
    c_expr.result_decl := type_name(aType);
    c_expr.result_decl &:= " tmp_";
    c_expr.result_decl &:= str(c_expr.temp_num);
    c_expr.result_decl &:= " = (";
    c_expr.result_decl &:= type_name(aType);
    c_expr.result_decl &:= ")(NULL);\n";
    process_destr_declaration(aType, global_c_expr);
    process_destr_call(aType, c_expr.result_name, c_expr.result_free);
    c_expr.result_to_null := c_expr.result_name;
    c_expr.result_to_null &:= " = (";
    c_expr.result_to_null &:= type_name(aType);
    c_expr.result_to_null &:= ")(NULL);\n";
    c_expr.result_intro := "(tmp_";
    c_expr.result_intro &:= str(c_expr.temp_num);
    c_expr.result_intro &:= "=(";
    c_expr.result_intro &:= type_name(aType);
    c_expr.result_intro &:= ")(";
    c_expr.result_finish := "))";
  end func;


const proc: prepare_bigint_result (inout expr_type: c_expr) is func

  begin
    incr(c_expr.temp_num);
    c_expr.result_name := "tmp_";
    c_expr.result_name &:= str(c_expr.temp_num);
    c_expr.result_decl := "bigIntType tmp_";
    c_expr.result_decl &:= str(c_expr.temp_num);
    c_expr.result_decl &:= " = NULL;\n";
    c_expr.result_free := "bigDestr(tmp_";
    c_expr.result_free &:= str(c_expr.temp_num);
    c_expr.result_free &:= ");\n";
    c_expr.result_to_null := c_expr.result_name;
    c_expr.result_to_null &:= " = NULL;\n";
    c_expr.result_intro := "(tmp_";
    c_expr.result_intro &:= str(c_expr.temp_num);
    c_expr.result_intro &:= "=";
    c_expr.result_finish := ")";
  end func;


const proc: prepare_list_result (in type: list_type, inout expr_type: c_expr) is func

  begin
    incr(c_expr.temp_num);
    c_expr.result_name := "tmp_";
    c_expr.result_name &:= str(c_expr.temp_num);
    c_expr.result_decl := type_name(list_type);
    c_expr.result_decl &:= " tmp_";
    c_expr.result_decl &:= str(c_expr.temp_num);
    c_expr.result_decl &:= " = (";
    c_expr.result_decl &:= type_name(list_type);
    c_expr.result_decl &:= ")(NULL);\n";
    c_expr.result_free := "rflDestr(tmp_";
    c_expr.result_free &:= str(c_expr.temp_num);
    c_expr.result_free &:= ");\n";
    c_expr.result_to_null := c_expr.result_name;
    c_expr.result_to_null &:= " = (";
    c_expr.result_to_null &:= type_name(list_type);
    c_expr.result_to_null &:= ")(NULL);\n";
    c_expr.result_intro := "(tmp_";
    c_expr.result_intro &:= str(c_expr.temp_num);
    c_expr.result_intro &:= "=(";
    c_expr.result_intro &:= type_name(list_type);
    c_expr.result_intro &:= ")(";
    c_expr.result_finish := "))";
  end func;


const proc: prepare_set_result (in type: set_type, inout expr_type: c_expr) is func

  begin
    incr(c_expr.temp_num);
    c_expr.result_name := "tmp_";
    c_expr.result_name &:= str(c_expr.temp_num);
    c_expr.result_decl := type_name(set_type);
    c_expr.result_decl &:= " tmp_";
    c_expr.result_decl &:= str(c_expr.temp_num);
    c_expr.result_decl &:= " = (";
    c_expr.result_decl &:= type_name(set_type);
    c_expr.result_decl &:= ")(NULL);\n";
    c_expr.result_free := "setDestr(tmp_";
    c_expr.result_free &:= str(c_expr.temp_num);
    c_expr.result_free &:= ");\n";
    c_expr.result_to_null := c_expr.result_name;
    c_expr.result_to_null &:= " = (";
    c_expr.result_to_null &:= type_name(set_type);
    c_expr.result_to_null &:= ")(NULL);\n";
    c_expr.result_intro := "(tmp_";
    c_expr.result_intro &:= str(c_expr.temp_num);
    c_expr.result_intro &:= "=(";
    c_expr.result_intro &:= type_name(set_type);
    c_expr.result_intro &:= ")(";
    c_expr.result_finish := "))";
  end func;


const proc: prepare_stri_result (inout expr_type: c_expr) is func

  begin
    incr(c_expr.temp_num);
    c_expr.result_name := "tmp_";
    c_expr.result_name &:= str(c_expr.temp_num);
    c_expr.result_decl := "striType tmp_";
    c_expr.result_decl &:= str(c_expr.temp_num);
    c_expr.result_decl &:= " = NULL;\n";
    c_expr.result_free := "strDestr(tmp_";
    c_expr.result_free &:= str(c_expr.temp_num);
    c_expr.result_free &:= ");\n";
    c_expr.result_to_null := c_expr.result_name;
    c_expr.result_to_null &:= " = NULL;\n";
    c_expr.result_intro := "(tmp_";
    c_expr.result_intro &:= str(c_expr.temp_num);
    c_expr.result_intro &:= "=";
    c_expr.result_finish := ")";
  end func;


const proc: prepare_bstri_result (inout expr_type: c_expr) is func

  begin
    incr(c_expr.temp_num);
    c_expr.result_name := "tmp_";
    c_expr.result_name &:= str(c_expr.temp_num);
    c_expr.result_decl := "bstriType tmp_";
    c_expr.result_decl &:= str(c_expr.temp_num);
    c_expr.result_decl &:= " = NULL;\n";
    c_expr.result_free := "bstDestr(tmp_";
    c_expr.result_free &:= str(c_expr.temp_num);
    c_expr.result_free &:= ");\n";
    c_expr.result_to_null := c_expr.result_name;
    c_expr.result_to_null &:= " = NULL;\n";
    c_expr.result_intro := "(tmp_";
    c_expr.result_intro &:= str(c_expr.temp_num);
    c_expr.result_intro &:= "=";
    c_expr.result_finish := ")";
  end func;


const proc: prepare_prog_result (inout expr_type: c_expr) is func

  begin
    incr(c_expr.temp_num);
    c_expr.result_name := "tmp_";
    c_expr.result_name &:= str(c_expr.temp_num);
    c_expr.result_decl := "progType tmp_";
    c_expr.result_decl &:= str(c_expr.temp_num);
    c_expr.result_decl &:= " = NULL;\n";
    c_expr.result_free := "prgDestr(tmp_";
    c_expr.result_free &:= str(c_expr.temp_num);
    c_expr.result_free &:= ");\n";
    c_expr.result_to_null := c_expr.result_name;
    c_expr.result_to_null &:= " = NULL;\n";
    c_expr.result_intro := "(tmp_";
    c_expr.result_intro &:= str(c_expr.temp_num);
    c_expr.result_intro &:= "=";
    c_expr.result_finish := ")";
  end func;


const proc: prepare_win_result (inout expr_type: c_expr) is func

  begin
    incr(c_expr.temp_num);
    c_expr.result_name := "tmp_";
    c_expr.result_name &:= str(c_expr.temp_num);
    c_expr.result_decl := "winType tmp_";
    c_expr.result_decl &:= str(c_expr.temp_num);
    c_expr.result_decl &:= " = NULL;\n";
    c_expr.result_free := "drwDestr(tmp_";
    c_expr.result_free &:= str(c_expr.temp_num);
    c_expr.result_free &:= ");\n";
    c_expr.result_to_null := c_expr.result_name;
    c_expr.result_to_null &:= " = NULL;\n";
    c_expr.result_intro := "(tmp_";
    c_expr.result_intro &:= str(c_expr.temp_num);
    c_expr.result_intro &:= "=";
    c_expr.result_finish := ")";
  end func;


const proc: prepare_process_result (inout expr_type: c_expr) is func

  begin
    incr(c_expr.temp_num);
    c_expr.result_name := "tmp_";
    c_expr.result_name &:= str(c_expr.temp_num);
    c_expr.result_decl := "processType tmp_";
    c_expr.result_decl &:= str(c_expr.temp_num);
    c_expr.result_decl &:= " = NULL;\n";
    c_expr.result_free := "pcsDestr(tmp_";
    c_expr.result_free &:= str(c_expr.temp_num);
    c_expr.result_free &:= ");\n";
    c_expr.result_to_null := c_expr.result_name;
    c_expr.result_to_null &:= " = NULL;\n";
    c_expr.result_intro := "(tmp_";
    c_expr.result_intro &:= str(c_expr.temp_num);
    c_expr.result_intro &:= "=";
    c_expr.result_finish := ")";
  end func;


const proc: prepareAnyParamTemporarys (in reference: aParam,
    inout expr_type: c_param, inout expr_type: c_expr) is func

  begin
    c_param.temp_num := c_expr.temp_num;
    process_expr(aParam, c_param);
    c_expr.temp_num := c_param.temp_num;
    c_expr.temp_decls &:= c_param.temp_decls;
    c_expr.temp_assigns &:= c_param.temp_assigns;
    c_expr.temp_frees &:= c_param.temp_frees;
    c_expr.temp_to_null &:= c_param.temp_to_null;
  end func;


const proc: prepareCallByNameParamTemporarys (in reference: aParam,
    inout expr_type: c_param, inout expr_type: c_expr) is func

  begin
    c_param.temp_num := c_expr.temp_num;
    process_call_by_name_expr(aParam, c_param);
    c_expr.temp_num := c_param.temp_num;
    c_expr.temp_decls &:= c_param.temp_decls;
    c_expr.temp_assigns &:= c_param.temp_assigns;
    c_expr.temp_frees &:= c_param.temp_frees;
    c_expr.temp_to_null &:= c_param.temp_to_null;
  end func;


const proc: getAnyParamToExpr (in expr_type: c_param, inout expr_type: c_expr) is func

  begin
    if c_param.expr <> "" then
      c_expr.expr &:= c_param.expr;
    else
      c_expr.temp_decls &:= c_param.result_decl;
      c_expr.temp_frees &:= c_param.result_free;
      c_expr.temp_to_null &:= c_param.result_to_null;
      c_expr.expr &:= c_param.result_intro;
      c_expr.expr &:= c_param.result_expr;
      c_expr.expr &:= c_param.result_finish;
    end if;
  end func;


const proc: getAnyParamToExpr (in reference: aParam, inout expr_type: c_expr) is func

  local
    var expr_type: c_param is expr_type.value;
  begin
    prepareAnyParamTemporarys(aParam, c_param, c_expr);
    getAnyParamToExpr(c_param, c_expr);
  end func;


const proc: getAnyParamToResultExpr (in expr_type: c_param, inout expr_type: c_expr) is func

  begin
    if c_param.expr <> "" then
      c_expr.result_expr &:= c_param.expr;
    else
      c_expr.temp_decls &:= c_param.result_decl;
      c_expr.temp_frees &:= c_param.result_free;
      c_expr.temp_to_null &:= c_param.result_to_null;
      c_expr.result_expr &:= c_param.result_intro;
      c_expr.result_expr &:= c_param.result_expr;
      c_expr.result_expr &:= c_param.result_finish;
    end if;
  end func;


const proc: getAnyParamToResultExpr (in reference: aParam, inout expr_type: c_expr) is func

  local
    var expr_type: c_param is expr_type.value;
  begin
    prepareAnyParamTemporarys(aParam, c_param, c_expr);
    getAnyParamToResultExpr(c_param, c_expr);
  end func;


const proc: getStdParamToResultExpr (in reference: aParam, inout expr_type: c_expr) is func

  local
    var expr_type: c_param is expr_type.value;
  begin
    prepareAnyParamTemporarys(aParam, c_param, c_expr);
    c_expr.result_expr &:= c_param.expr;
  end func;


const proc: getGenericValue (in reference: current_expression,
    inout expr_type: c_expr) is func

  local
    var type: result_type is void;
    var string: temp_name is "";
  begin
    result_type := getExprResultType(current_expression);
    if result_type in typeCategory and typeCategory[result_type] = FLOATOBJECT or
        not ccConf.LITTLE_ENDIAN_INTTYPE then
      incr(c_expr.temp_num);
      temp_name := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "const_rtlValueUnion ";
      c_expr.temp_decls &:= temp_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= "(";
      c_expr.expr &:= temp_name;
      c_expr.expr &:= ".";
      c_expr.expr &:= raw_type_value(result_type);
      c_expr.expr &:= "=";
      process_expr(current_expression, c_expr);
      c_expr.expr &:= ",";
      c_expr.expr &:= temp_name;
      c_expr.expr &:= ".genericValue)";
    else
      c_expr.expr &:= "(genericType)(";
      process_expr(current_expression, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: getGenericValue (in type: variableType, in string: variableName,
    inout expr_type: c_expr) is func

  local
    var string: temp_name is "";
  begin
    if variableType in typeCategory and typeCategory[variableType] = FLOATOBJECT or
        not ccConf.LITTLE_ENDIAN_INTTYPE then
      incr(c_expr.temp_num);
      temp_name := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "const_rtlValueUnion ";
      c_expr.temp_decls &:= temp_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= "(";
      c_expr.expr &:= temp_name;
      c_expr.expr &:= ".";
      c_expr.expr &:= raw_type_value(variableType);
      c_expr.expr &:= "=";
      c_expr.expr &:= variableName;
      c_expr.expr &:= ",";
      c_expr.expr &:= temp_name;
      c_expr.expr &:= ".genericValue)";
    else
      c_expr.expr &:= "(genericType)(";
      c_expr.expr &:= variableName;
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: getGenericValueOfVariableObject (in reference: variableObject,
    inout expr_type: c_expr) is func

  local
    var type: result_type is void;
    var string: temp_name is "";
  begin
    result_type := getType(variableObject);
    if result_type in typeCategory and typeCategory[result_type] = FLOATOBJECT or
        not ccConf.LITTLE_ENDIAN_INTTYPE then
      incr(c_expr.temp_num);
      temp_name := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "const_rtlValueUnion ";
      c_expr.temp_decls &:= temp_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= "(";
      c_expr.expr &:= temp_name;
      c_expr.expr &:= ".";
      c_expr.expr &:= raw_type_value(result_type);
      c_expr.expr &:= "=o_";
      create_name(variableObject, c_expr.expr);
      c_expr.expr &:= ",";
      c_expr.expr &:= temp_name;
      c_expr.expr &:= ".genericValue)";
    else
      c_expr.expr &:= "(genericType)(o_";
      create_name(variableObject, c_expr.expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: getCreatedValueAsGeneric (in type: param_type, in expr_type: c_param,
    inout expr_type: c_expr) is func

  local
    var string: temp_name is "";
  begin
    if param_type in typeCategory and typeCategory[param_type] = FLOATOBJECT or
        not ccConf.LITTLE_ENDIAN_INTTYPE then
      incr(c_expr.temp_num);
      temp_name := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "rtlValueUnion ";
      c_expr.temp_decls &:= temp_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= "(";
      c_expr.expr &:= temp_name;
      c_expr.expr &:= ".";
      c_expr.expr &:= raw_type_value(param_type);
      c_expr.expr &:= "=";
      if c_param.result_expr <> "" then
        c_expr.expr &:= c_param.result_expr;
      else
        process_create_declaration(param_type, global_c_expr);
        process_create_call(param_type, c_param.expr, c_expr.expr);
      end if;
      c_expr.expr &:= ",";
      c_expr.expr &:= temp_name;
      c_expr.expr &:= ".genericValue)";
    elsif c_param.result_expr <> "" then
      c_expr.expr &:= c_param.result_expr;
    else
      process_create_declaration(param_type, global_c_expr);
      process_create_call(param_type, c_param.expr, c_expr.expr);
    end if;
  end func;


const proc: getCreatedValueAsGeneric (in reference: aParam, inout expr_type: c_expr) is func

  local
    var expr_type: c_param is expr_type.value;
    var type: param_type is void;
  begin
    param_type := getExprResultType(aParam);
    prepareAnyParamTemporarys(aParam, c_param, c_expr);
    getCreatedValueAsGeneric(param_type, c_param, c_expr);
  end func;


const proc: getGenericValueToResultExpr (in reference: current_expression,
    inout expr_type: c_expr) is func

  local
    var type: result_type is void;
    var string: temp_name is "";
  begin
    result_type := getExprResultType(current_expression);
    if result_type in typeCategory and typeCategory[result_type] = FLOATOBJECT or
        not ccConf.LITTLE_ENDIAN_INTTYPE then
      incr(c_expr.temp_num);
      temp_name := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "const_rtlValueUnion ";
      c_expr.temp_decls &:= temp_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.result_expr &:= "(";
      c_expr.result_expr &:= temp_name;
      c_expr.result_expr &:= ".";
      c_expr.result_expr &:= raw_type_value(result_type);
      c_expr.result_expr &:= "=";
      getAnyParamToResultExpr(current_expression, c_expr);
      c_expr.result_expr &:= ",";
      c_expr.result_expr &:= temp_name;
      c_expr.result_expr &:= ".genericValue)";
    else
      c_expr.result_expr &:= "(genericType)(";
      getAnyParamToResultExpr(current_expression, c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: getGenericTemporaryToResultExpr (in type: param_type, in expr_type: c_param,
    inout expr_type: c_expr) is func

  local
    var string: temp_name is "";
  begin
    if param_type in typeCategory and typeCategory[param_type] = FLOATOBJECT or
        not ccConf.LITTLE_ENDIAN_INTTYPE then
      incr(c_expr.temp_num);
      temp_name := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "rtlValueUnion ";
      c_expr.temp_decls &:= temp_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.result_expr &:= "(";
      c_expr.result_expr &:= temp_name;
      c_expr.result_expr &:= ".";
      c_expr.result_expr &:= raw_type_value(param_type);
      c_expr.result_expr &:= "=";
      if c_param.result_expr <> "" then
        c_expr.result_expr &:= c_param.result_expr;
      else
        process_create_declaration(param_type, global_c_expr);
        process_create_call(param_type, c_param.expr, c_expr.result_expr);
      end if;
      c_expr.result_expr &:= ",";
      c_expr.result_expr &:= temp_name;
      c_expr.result_expr &:= ".genericValue)";
    elsif c_param.result_expr <> "" then
      c_expr.result_expr &:= c_param.result_expr;
    else
      process_create_declaration(param_type, global_c_expr);
      process_create_call(param_type, c_param.expr, c_expr.result_expr);
    end if;
  end func;


const proc: getGenericTemporaryToResultExpr (in reference: aParam, inout expr_type: c_expr) is func

  local
    var expr_type: c_param is expr_type.value;
    var type: param_type is void;
  begin
    param_type := getExprResultType(aParam);
    prepareAnyParamTemporarys(aParam, c_param, c_expr);
    getGenericTemporaryToResultExpr(param_type, c_param, c_expr);
  end func;


const proc: getTemporaryToResultExpr (in type: param_type, in expr_type: c_param,
    inout expr_type: c_expr) is func

  local
    var string: temp_name is "";
  begin
    if param_type in typeCategory and typeCategory[param_type] = FLOATOBJECT then
      incr(c_expr.temp_num);
      temp_name := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "rtlValueUnion ";
      c_expr.temp_decls &:= temp_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.result_expr &:= "(";
      c_expr.result_expr &:= temp_name;
      c_expr.result_expr &:= ".floatValue=";
      c_expr.result_expr &:= c_param.expr;
      c_expr.result_expr &:= ",";
      c_expr.result_expr &:= temp_name;
      c_expr.result_expr &:= ".genericValue)";
    elsif c_param.result_expr <> "" then
      c_expr.result_expr &:= c_param.result_expr;
    else
      process_create_declaration(param_type, global_c_expr);
      process_create_call(param_type, c_param.expr, c_expr.result_expr);
    end if;
  end func;


const proc: getTemporaryToResultExpr (in reference: aParam, inout expr_type: c_expr) is func

  local
    var expr_type: c_param is expr_type.value;
    var type: param_type is void;
  begin
    param_type := getExprResultType(aParam);
    prepareAnyParamTemporarys(aParam, c_param, c_expr);
    getTemporaryToResultExpr(param_type, c_param, c_expr);
  end func;


const proc: doLocalDeclsOfStatement (in expr_type: statement, inout expr_type: c_expr) is func

  begin
    if statement.temp_decls <> "" then
      setDiagnosticLine(c_expr);
      c_expr.expr &:= "{\n";
      appendWithDiagnostic(statement.temp_decls, c_expr);
      appendWithDiagnostic(statement.temp_assigns, c_expr);
      appendWithDiagnostic(statement.expr, c_expr);
      appendWithDiagnostic(statement.temp_frees, c_expr);
      appendWithDiagnostic(statement.result_free, c_expr);
      setDiagnosticLine(c_expr);
      c_expr.expr &:= "}\n";
    else
      appendWithDiagnostic(statement.temp_assigns, c_expr);
      appendWithDiagnostic(statement.expr, c_expr);
      appendWithDiagnostic(statement.temp_frees, c_expr);
      appendWithDiagnostic(statement.result_free, c_expr);
    end if;
  end func;


const func string: defineTempVariable (in string: typeName, in string: namePrefix,
    inout expr_type: c_expr) is func

  result
    var string: variableName is "";
  begin
    incr(c_expr.temp_num);
    variableName := namePrefix & str(c_expr.temp_num);
    c_expr.temp_decls &:= typeName;
    c_expr.temp_decls &:= " ";
    c_expr.temp_decls &:= variableName;
    c_expr.temp_decls &:= ";\n";
  end func;


const func string: defineTempVariable (in string: typeName, in string: namePrefix,
    in string: initValue, inout expr_type: c_expr) is func

  result
    var string: variableName is "";
  begin
    incr(c_expr.temp_num);
    variableName := namePrefix & str(c_expr.temp_num);
    c_expr.temp_decls &:= typeName;
    c_expr.temp_decls &:= " ";
    c_expr.temp_decls &:= variableName;
    c_expr.temp_decls &:= ";\n";
    c_expr.expr &:= variableName;
    c_expr.expr &:= "=";
    c_expr.expr &:= initValue;
    c_expr.expr &:= ",";
  end func;


const func boolean: isNormalVariable (in reference: a_param) is
  return category(a_param) in {TYPEOBJECT, INTOBJECT, BIGINTOBJECT,
      CHAROBJECT, STRIOBJECT, BSTRIOBJECT, ARRAYOBJECT, HASHOBJECT,
      STRUCTOBJECT, INTERFACEOBJECT, SETOBJECT, FILEOBJECT,
      SOCKETOBJECT, POLLOBJECT, LISTOBJECT, FLOATOBJECT, WINOBJECT,
      PROCESSOBJECT, REFOBJECT, REFLISTOBJECT, ACTOBJECT, VALUEPARAMOBJECT,
      REFPARAMOBJECT, RESULTOBJECT, LOCALVOBJECT, PROGOBJECT};


const func string: normalVariable (in reference: aParam, inout expr_type: c_expr) is func

  result
    var string: varName is "";
  local
    var expr_type: c_param is expr_type.value;
  begin
    prepareAnyParamTemporarys(aParam, c_param, c_expr);
    varName := "(" & c_param.expr & ")";
  end func;


const func string: getTempVariable (in string: typeName, in string: namePrefix,
    in string: initValue, inout expr_type: c_expr) is func

  result
    var string: variableName is "";
  begin
    incr(c_expr.temp_num);
    variableName := namePrefix & str(c_expr.temp_num);
    c_expr.temp_decls &:= typeName;
    c_expr.temp_decls &:= " ";
    c_expr.temp_decls &:= variableName;
    c_expr.temp_decls &:= ";\n";
    if initValue <> "" then
      c_expr.expr &:= variableName;
      c_expr.expr &:= "=";
      c_expr.expr &:= initValue;
      c_expr.expr &:= ",";
    end if;
  end func;


const func string: getTempVariable (in string: typeName, in string: namePrefix,
    in reference: param1, inout expr_type: c_expr) is func

  result
    var string: variableName is "";
  begin
    incr(c_expr.temp_num);
    variableName := namePrefix & str(c_expr.temp_num);
    c_expr.temp_decls &:= typeName;
    c_expr.temp_decls &:= " ";
    c_expr.temp_decls &:= variableName;
    c_expr.temp_decls &:= ";\n";
    c_expr.expr &:= variableName;
    c_expr.expr &:= "=";
    getAnyParamToExpr(param1, c_expr);
    c_expr.expr &:= ",";
  end func;


const func string: getParameterAsVariable (in string: typeName, in string: namePrefix,
    in reference: param1, inout expr_type: c_expr) is func

  result
    var string: variableName is "";
  begin
    if isNormalVariable(param1) then
      variableName := normalVariable(param1, c_expr);
    else
      variableName := getTempVariable(typeName, namePrefix, param1, c_expr);
    end if;
  end func;


const func reference: getParameterAsVariable (in reference: param1,
    inout expr_type: c_expr) is func

  result
    var reference: variableObject is NIL;
  local
    var type: resultType is void;
  begin
    if isNormalVariable(param1) then
      variableObject := param1;
    else
      resultType := getType(param1);
      if isFunc(resultType) or isVarfunc(resultType) then
        resultType := resultType(resultType);
      end if;
      variableObject := allocVar(resultType, typeCategory[resultType]);
      incr(c_expr.temp_num);
      c_expr.temp_decls &:= type_name(getType(variableObject));
      c_expr.temp_decls &:= " o_";
      create_name(variableObject, c_expr.temp_decls);
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= " o_";
      create_name(variableObject, c_expr.expr);
      c_expr.expr &:= "=";
      getAnyParamToExpr(param1, c_expr);
      c_expr.expr &:= ";\n";
    end if;
  end func;


const func string: getReference (in string: typeName, in string: namePrefix,
    in reference: param1, inout expr_type: c_expr) is func

  result
    var string: variableName is "";
  begin
    incr(c_expr.temp_num);
    variableName := namePrefix & str(c_expr.temp_num);
    c_expr.temp_decls &:= typeName;
    c_expr.temp_decls &:= " *";
    c_expr.temp_decls &:= variableName;
    c_expr.temp_decls &:= ";\n";
    c_expr.expr &:= variableName;
    c_expr.expr &:= "=&(";
    getAnyParamToExpr(param1, c_expr);
    c_expr.expr &:= "),";
    variableName := "(*" & variableName & ")";
  end func;


const func string: getParameterAsReference (in string: typeName, in string: namePrefix,
    in reference: param1, inout expr_type: c_expr) is func

  result
    var string: variableName is "";
  begin
    if isNormalVariable(param1) then
      variableName := normalVariable(param1, c_expr);
    else
      variableName := getReference(typeName, namePrefix, param1, c_expr);
    end if;
  end func;


const func string: defineTempConstant (in string: typeName, in string: namePrefix,
    in reference: param1, inout expr_type: c_expr) is func
  result
    var string: variableName is "";
  local
    var expr_type: param_expr is expr_type.value;
  begin
    incr(c_expr.temp_num);
    variableName := namePrefix & str(c_expr.temp_num);
    param_expr.temp_num := c_expr.temp_num;
    process_expr(param1, param_expr);
    c_expr.temp_num := param_expr.temp_num;
    c_expr.temp_decls &:= typeName;
    c_expr.temp_decls &:= " ";
    c_expr.temp_decls &:= variableName;
    if param_expr.temp_frees <> "" then
      c_expr.temp_decls &:= ";\n";
      c_expr.temp_assigns &:= "{\n";
      c_expr.temp_assigns &:= param_expr.temp_decls;
      c_expr.temp_assigns &:= param_expr.temp_assigns;
      c_expr.temp_assigns &:= variableName;
      c_expr.temp_assigns &:= "=";
      c_expr.temp_assigns &:= param_expr.expr;
      c_expr.temp_assigns &:= ";\n";
      c_expr.temp_assigns &:= param_expr.temp_frees;
      c_expr.temp_assigns &:= "}\n";
    elsif param_expr.temp_decls <> "" or param_expr.temp_assigns <> "" then
      c_expr.temp_decls &:= ";\n";
      c_expr.temp_decls &:= param_expr.temp_decls;
      c_expr.temp_assigns &:= param_expr.temp_assigns;
      c_expr.temp_assigns &:= variableName;
      c_expr.temp_assigns &:= "=";
      c_expr.temp_assigns &:= param_expr.expr;
      c_expr.temp_assigns &:= ";\n";
    else
      c_expr.temp_decls &:= "=";
      c_expr.temp_decls &:= param_expr.expr;
      c_expr.temp_decls &:= ";\n";
    end if;
  end func;


const func boolean: has_temp_values (in expr_type: c_expr) is
  return c_expr.temp_num >= 2 or
      (c_expr.temp_num = 1 and c_expr.result_expr = "");


const func string: beginCastGeneric (in type: dest_type, inout expr_type: c_expr) is func

  result
    var string: temp_name is "";
  begin
    c_expr.expr &:= "(";
    if dest_type in typeCategory and typeCategory[dest_type] = FLOATOBJECT or
        not ccConf.LITTLE_ENDIAN_INTTYPE then
      incr(c_expr.temp_num);
      temp_name := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "rtlValueUnion ";
      c_expr.temp_decls &:= temp_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= temp_name;
      c_expr.expr &:= ".genericValue=";
    else
      c_expr.expr &:= type_name(dest_type);
      c_expr.expr &:= ")(";
    end if;
  end func;


const proc: endCastGeneric (in type: dest_type, in string: temp_name, inout expr_type: c_expr) is func

  begin
    if dest_type in typeCategory and typeCategory[dest_type] = FLOATOBJECT or
        not ccConf.LITTLE_ENDIAN_INTTYPE then
      c_expr.expr &:= ",";
      c_expr.expr &:= temp_name;
      c_expr.expr &:= ".";
      c_expr.expr &:= raw_type_value(dest_type);
    end if;
    c_expr.expr &:= ")";
  end func;


const func string: beginCastGenericToResultExpr (in type: dest_type, inout expr_type: c_expr) is func

  result
    var string: temp_name is "";
  begin
    c_expr.result_expr &:= "(";
    if dest_type in typeCategory and typeCategory[dest_type] = FLOATOBJECT or
        not ccConf.LITTLE_ENDIAN_INTTYPE then
      incr(c_expr.temp_num);
      temp_name := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "rtlValueUnion ";
      c_expr.temp_decls &:= temp_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.result_expr &:= temp_name;
      c_expr.result_expr &:= ".genericValue=";
    else
      c_expr.result_expr &:= type_name(dest_type);
      c_expr.result_expr &:= ")(";
    end if;
  end func;


const proc: endCastGenericToResultExpr (in type: dest_type, in string: temp_name, inout expr_type: c_expr) is func

  begin
    if dest_type in typeCategory and typeCategory[dest_type] = FLOATOBJECT or
        not ccConf.LITTLE_ENDIAN_INTTYPE then
      c_expr.result_expr &:= ",";
      c_expr.result_expr &:= temp_name;
      c_expr.result_expr &:= ".";
      c_expr.result_expr &:= raw_type_value(dest_type);
    end if;
    c_expr.result_expr &:= ")";
  end func;


const func boolean: useFunctype (in reference: current_object) is func

  result
    var boolean: okay is FALSE;
  local
    var reference: curr_expr is NIL;
    var category: exprCategory is category.value;
  begin
    curr_expr := getValue(current_object, reference);
    if curr_expr <> NIL then
      exprCategory := category(curr_expr);
      okay := exprCategory = ACTOBJECT or
              exprCategory = BLOCKOBJECT;
    end if;
  end func;


const proc: declare_func_pointer_if_necessary (in reference: current_object,
    inout expr_type: c_expr) is func

  local
    var ref_list: params is ref_list.EMPTY;
    var reference: func_pointer is NIL;
  begin
    if category(current_object) = CALLOBJECT then
      params := getValue(current_object, ref_list);
      if length(params) >= 1 then
        func_pointer := params[1];
        if category(func_pointer) = REFOBJECT then
          if func_pointer not in function_pointer_declared then
            if useFunctype(func_pointer) then
              c_expr.expr &:= "extern intfunctype o_";
            else
              c_expr.expr &:= "extern objRefType o_";
            end if;
            create_name(func_pointer, c_expr.expr);
            c_expr.expr &:= ";\n\n";
            function_pointer_declared @:= [func_pointer] TRUE;
          end if;
        end if;
      end if;
    end if;
  end func;


const func boolean: isActionExpression (in reference: current_expression, in string: actionName) is func

  result
    var boolean: isActionExpression is FALSE;
  local
    var ref_list: params is ref_list.EMPTY;
  begin
    if category(current_expression) = CALLOBJECT then
      params := getValue(current_expression, ref_list);
      if category(params[1]) = ACTOBJECT and str(getValue(params[1], ACTION)) = actionName then
        isActionExpression := TRUE;
      end if;
    end if;
  end func;


const func reference: getActionParameter (in reference: current_expression, in integer: number) is func

  result
    var reference: actionParameter is NIL;
  local
    var ref_list: params is ref_list.EMPTY;
  begin
    if category(current_expression) = CALLOBJECT then
      params := getValue(current_expression, ref_list);
      actionParameter := params[succ(number)];
    end if;
  end func;


const proc: doRshift (in string: number_name, in string: rshift_name,
    inout expr_type: c_expr) is func

  begin
    (* Formula used: a<0?~(~a>>b):a>>b *)
    c_expr.expr &:= number_name;
    c_expr.expr &:= "<0?~(~";
    c_expr.expr &:= number_name;
    c_expr.expr &:= " >> ";
    c_expr.expr &:= rshift_name;
    c_expr.expr &:= "):";
    c_expr.expr &:= number_name;
    c_expr.expr &:= " >> ";
    c_expr.expr &:= rshift_name;
  end func;
