(********************************************************************)
(*                                                                  *)
(*  arr_act.s7i   Generate code for actions of the type array.      *)
(*  Copyright (C) 1990 - 1994, 2004 - 2015, 2018  Thomas Mertes     *)
(*  Copyright (C) 2020 - 2022  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.                       *)
(*                                                                  *)
(********************************************************************)


const ACTION: ARR_APPEND        is action "ARR_APPEND";
const ACTION: ARR_ARRLIT        is action "ARR_ARRLIT";
const ACTION: ARR_ARRLIT2       is action "ARR_ARRLIT2";
const ACTION: ARR_ARRLIT3       is action "ARR_ARRLIT3";
const ACTION: ARR_BASELIT       is action "ARR_BASELIT";
const ACTION: ARR_BASELIT2      is action "ARR_BASELIT2";
const ACTION: ARR_BASELIT3      is action "ARR_BASELIT3";
const ACTION: ARR_CAT           is action "ARR_CAT";
const ACTION: ARR_CONV          is action "ARR_CONV";
const ACTION: ARR_CPY           is action "ARR_CPY";
const ACTION: ARR_CREATE        is action "ARR_CREATE";
const ACTION: ARR_DESTR         is action "ARR_DESTR";
const ACTION: ARR_EXTEND        is action "ARR_EXTEND";
const ACTION: ARR_GEN           is action "ARR_GEN";
const ACTION: ARR_HEAD          is action "ARR_HEAD";
const ACTION: ARR_IDX           is action "ARR_IDX";
const ACTION: ARR_INSERT        is action "ARR_INSERT";
const ACTION: ARR_INSERT_ARRAY  is action "ARR_INSERT_ARRAY";
const ACTION: ARR_LNG           is action "ARR_LNG";
const ACTION: ARR_MAXIDX        is action "ARR_MAXIDX";
const ACTION: ARR_MINIDX        is action "ARR_MINIDX";
const ACTION: ARR_POSCPY        is action "ARR_POSCPY";
const ACTION: ARR_PUSH          is action "ARR_PUSH";
const ACTION: ARR_RANGE         is action "ARR_RANGE";
const ACTION: ARR_REMOVE        is action "ARR_REMOVE";
const ACTION: ARR_REMOVE_ARRAY  is action "ARR_REMOVE_ARRAY";
const ACTION: ARR_SORT          is action "ARR_SORT";
const ACTION: ARR_SORT_REVERSE  is action "ARR_SORT_REVERSE";
const ACTION: ARR_SUBARR        is action "ARR_SUBARR";
const ACTION: ARR_SUBARR_FIXLEN is action "ARR_SUBARR";
const ACTION: ARR_TAIL          is action "ARR_TAIL";
const ACTION: ARR_TIMES         is action "ARR_TIMES";


const proc: arr_prototypes (inout file: c_prog) is func

  begin
    declareExtern(c_prog, "void        arrAppend (arrayType *const, const arrayType);");
    declareExtern(c_prog, "arrayType   arrArrlit2 (intType, arrayType);");
    declareExtern(c_prog, "arrayType   arrArrlit3 (intType, intType, arrayType);");
    declareExtern(c_prog, "arrayType   arrBaselit (const rtlValueUnion);");
    declareExtern(c_prog, "arrayType   arrBaselit2 (intType, const rtlValueUnion);");
    declareExtern(c_prog, "arrayType   arrBaselit3 (intType, intType, const rtlValueUnion);");
    declareExtern(c_prog, "arrayType   arrCat (arrayType, const arrayType);");
    declareExtern(c_prog, "arrayType   arrExtend (arrayType, const rtlValueUnion);");
    declareExtern(c_prog, "void        arrFree (arrayType);");
    declareExtern(c_prog, "arrayType   arrGen (const rtlValueUnion, const rtlValueUnion);");
    declareExtern(c_prog, "arrayType   arrHead (const const_arrayType, intType);");
    declareExtern(c_prog, "void        arrHeadSlice (const const_arrayType, intType, arrayType);");
    declareExtern(c_prog, "arrayType   arrHeadTemp (arrayType *, intType);");
    declareExtern(c_prog, "rtlValueUnion arrIdxTemp (arrayType *, intType);");
    declareExtern(c_prog, "void        arrInsert (arrayType *, intType, rtlValueUnion);");
    declareExtern(c_prog, "void        arrInsertArray (arrayType *, intType, arrayType);");
    declareExtern(c_prog, "void        arrInsertArrayTemp (arrayType *, intType, arrayType);");
    declareExtern(c_prog, "arrayType   arrMalloc (intType, intType);");
    declareExtern(c_prog, "void        arrPoscpy (const arrayType, intType, const const_arrayType);");
    declareExtern(c_prog, "void        arrPush (arrayType *const, const rtlValueUnion);");
    declareExtern(c_prog, "arrayType   arrRange (const const_arrayType, intType, intType);");
    declareExtern(c_prog, "void        arrRangeSlice (const const_arrayType, intType, intType, arrayType);");
    declareExtern(c_prog, "arrayType   arrRangeTemp (arrayType *, intType, intType);");
    declareExtern(c_prog, "arrayType   arrRealloc (arrayType, memSizeType, memSizeType);");
    declareExtern(c_prog, "rtlValueUnion arrRemove (arrayType *, intType);");
    declareExtern(c_prog, "arrayType   arrRemoveArray (arrayType *, intType, intType);");
    declareExtern(c_prog, "arrayType   arrSort (arrayType, const compareFuncType);");
    declareExtern(c_prog, "arrayType   arrSortReverse (arrayType, const compareFuncType);");
    declareExtern(c_prog, "arrayType   arrSubarr (const const_arrayType, intType, intType);");
    declareExtern(c_prog, "void        arrSubarrSlice (const const_arrayType, intType, intType, arrayType);");
    declareExtern(c_prog, "arrayType   arrSubarrTemp (arrayType *, intType, intType);");
    declareExtern(c_prog, "arrayType   arrSubarrFixLen (const const_arrayType, intType, intType);");
    declareExtern(c_prog, "void        arrSubarrFixLenSlice (const const_arrayType, intType, intType, arrayType);");
    declareExtern(c_prog, "arrayType   arrSubarrFixLenTemp (arrayType *, intType, intType);");
    declareExtern(c_prog, "arrayType   arrTail (const const_arrayType, intType);");
    declareExtern(c_prog, "void        arrTailSlice (const const_arrayType, intType, arrayType);");
    declareExtern(c_prog, "arrayType   arrTailTemp (arrayType *, intType);");
    declareExtern(c_prog, "arrayType   arrTimes (intType, intType, const rtlValueUnion);");
    declareExtern(c_prog, "arrayType   arrTimes0 (intType, intType);");
  end func;


const func boolean: isArraySlice (in var reference: aParam) is func

  result
    var boolean: isArraySlice is FALSE;
  local
    const set of string: sliceActions is
        {"ARR_HEAD", "ARR_TAIL", "ARR_RANGE", "ARR_SUBARR"};
    var ref_list: params is ref_list.EMPTY;
  begin
    if ccConf.ALLOW_RTL_ARRAY_SLICES then
      if isInlineParam(aParam) then
        aParam := inlineParam[aParam][1].actualParam;
      end if;
      if category(aParam) = CALLOBJECT then
        params := getValue(aParam, ref_list);
        if category(params[1]) = ACTOBJECT and
            str(getValue(params[1], ACTION)) in sliceActions then
          isArraySlice := TRUE;
        end if;
      end if;
    end if;
  end func;


const proc: declare_times_prototype (in type: arrayType,
    in type: elementType, inout expr_type: c_expr) is func

  begin
    if arrayType not in typeData.times_prototype_declared then
      process_create_declaration(elementType, c_expr);
      # c_expr.expr &:= type_name(arrayType);
      c_expr.expr &:= "static arrayType times_";
      c_expr.expr &:= str(typeNumber(arrayType));
      c_expr.expr &:= " (intType, const ";
      if useConstPrefix(elementType) then
        c_expr.expr &:= "const_";
      end if;
      c_expr.expr &:= type_name(elementType);
      c_expr.expr &:= ");\n\n";
      typeData.times_prototype_declared @:= [arrayType] TRUE;
    end if;
  end func;


const proc: process_arr_append (in reference: param1, in reference: param3,
    inout expr_type: c_expr) is func

  local
    var expr_type: c_param1 is expr_type.value;
    var expr_type: c_param3 is expr_type.value;
  begin
    process_expr(param1, c_param1);
    c_param3.temp_num := c_param1.temp_num;
    getTemporaryToResultExpr(param3, c_param3);
    incr(c_param3.temp_num);
    if has_temp_values(c_param3) then
      c_expr.expr &:= "{\n";
      appendWithDiagnostic(c_param1.temp_decls, c_expr);
      appendWithDiagnostic(c_param3.temp_decls, c_expr);
      appendWithDiagnostic(c_param1.temp_assigns, c_expr);
      appendWithDiagnostic(c_param3.temp_assigns, c_expr);
    end if;
    setDiagnosticLine(c_expr);
    c_expr.expr &:= "arrAppend(&(";
    c_expr.expr &:= c_param1.expr;
    c_expr.expr &:= "), ";
    c_expr.expr &:= c_param3.result_expr;
    c_expr.expr &:= ");\n";
    if has_temp_values(c_param3) then
      appendWithDiagnostic(c_param1.temp_frees, c_expr);
      appendWithDiagnostic(c_param3.temp_frees, c_expr);
      c_expr.expr &:= "}\n";
    end if;
  end func;


const proc: process (ARR_APPEND, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    checkGlobalVariableChange(params[1], c_expr);
    process_arr_append(params[1], params[3], c_expr);
  end func;


const proc: process (ARR_ARRLIT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: anArray is NIL;
    var expr_type: c_param is expr_type.value;
  begin
    if isConstant(params[3]) then
      anArray := evaluate(prog, params[3]);
      if category(anArray) = ARRAYOBJECT then
        if anArray not in constTable.other_const then
          constTable.other_const @:= [anArray] length(constTable.other_const);
        end if;
        c_expr.expr &:= "arr[";
        c_expr.expr &:= str(constTable.other_const[anArray]);
        c_expr.expr &:= "]";
      end if;
    else
      prepareAnyParamTemporarys(params[3], c_param, c_expr);
      if c_param.result_expr <> "" then
        prepare_typed_result(getExprResultType(params[3]), c_expr);
        c_expr.result_expr := "/*arrArrlit()*/";
        c_expr.result_expr &:= c_param.result_expr;
      else
        c_expr.expr &:= "/*arrArrlit()*/";
        c_expr.expr &:= c_param.expr;
      end if;
    end if;
  end func;


const proc: process (ARR_ARRLIT2, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var expr_type: c_param is expr_type.value;
  begin
    if isArraySlice(params[4]) then
      prepareAnyParamTemporarys(params[4], c_param, c_expr);
      if c_param.result_expr <> "" then
        prepare_typed_result(getExprResultType(params[4]), c_expr);
        c_expr.result_expr := "arrArrlit2(";
        getStdParamToResultExpr(params[2], c_expr);
        c_expr.result_expr &:= ", ";
        c_expr.result_expr &:= c_param.result_expr;
        c_expr.result_expr &:= ")";
      else
        c_expr.expr &:= "arrArrlit2(";
        process_expr(params[2], c_expr);
        c_expr.expr &:= ", ";
        c_expr.expr &:= c_param.expr;
        c_expr.expr &:= ")";
      end if;
    else
      prepare_typed_result(getExprResultType(params[4]), c_expr);
      c_expr.result_expr := "arrArrlit2(";
      getStdParamToResultExpr(params[2], c_expr);
      c_expr.result_expr &:= ", ";
      getTemporaryToResultExpr(params[4], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process (ARR_ARRLIT3, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    prepare_typed_result(getExprResultType(params[3]), c_expr);
    c_expr.result_expr := "arrArrlit3(";
    getStdParamToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", ";
    getStdParamToResultExpr(params[2], c_expr);
    c_expr.result_expr &:= ", ";
    getTemporaryToResultExpr(params[3], c_expr);
    c_expr.result_expr &:= ")";
  end func;


const proc: process (ARR_BASELIT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    if resultType(getType(function)) not in typeData.array_element then
      typeData.array_element @:= [resultType(getType(function))] getType(params[3]);
    end if;
    prepare_typed_result(resultType(getType(function)), c_expr);
    c_expr.result_expr := "arrBaselit(";
    getRtlValueTemporaryToResultExpr(params[3], c_expr);
    c_expr.result_expr &:= ")";
  end func;


const proc: process (ARR_BASELIT2, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    if resultType(getType(function)) not in typeData.array_element then
      typeData.array_element @:= [resultType(getType(function))] getType(params[4]);
    end if;
    prepare_typed_result(resultType(getType(function)), c_expr);
    c_expr.result_expr := "arrBaselit2(";
    getStdParamToResultExpr(params[2], c_expr);
    c_expr.result_expr &:= ", ";
    getRtlValueTemporaryToResultExpr(params[4], c_expr);
    c_expr.result_expr &:= ")";
  end func;


const proc: process (ARR_BASELIT3, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    if resultType(getType(function)) not in typeData.array_element then
      typeData.array_element @:= [resultType(getType(function))] getType(params[3]);
    end if;
    prepare_typed_result(resultType(getType(function)), c_expr);
    c_expr.result_expr := "arrBaselit3(";
    getStdParamToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", ";
    getStdParamToResultExpr(params[2], c_expr);
    c_expr.result_expr &:= ", ";
    getRtlValueTemporaryToResultExpr(params[3], c_expr);
    c_expr.result_expr &:= ")";
  end func;


const proc: process (ARR_CAT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    prepare_typed_result(getExprResultType(params[1]), c_expr);
    c_expr.result_expr := "arrCat(";
    getTemporaryToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", ";
    getTemporaryToResultExpr(params[3], c_expr);
    c_expr.result_expr &:= ")";
  end func;


const proc: process (ARR_CONV, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var expr_type: c_param is expr_type.value;
  begin
    prepareAnyParamTemporarys(params[3], c_param, c_expr);
    if c_param.result_expr <> "" then
      prepare_typed_result(getExprResultType(params[3]), c_expr);
      c_expr.result_expr := "/*arrConv()*/";
      c_expr.result_expr &:= c_param.result_expr;
    else
      c_expr.expr &:= "/*arrConv()*/";
      c_expr.expr &:= c_param.expr;
    end if;
  end func;


const func boolean: isIntArrayOfZeros (in reference: arr) is func
  result
    var boolean: isIntArrayOfZeros is FALSE;
  local
    var type: arrayType is void;
    var type: elementType is void;
    var ref_list: arrayList is ref_list.EMPTY;
    var reference: element is NIL;
    var integer: elementValue is 0;
  begin
    arrayType := getExprResultType(arr);
    elementType := typeData.array_element[arrayType];
    if elementType in typeData.typeCategory and
        typeData.typeCategory[elementType] = INTOBJECT then
      arrayList := arrayToList(arr);
      isIntArrayOfZeros := TRUE;
      for element range arrayList until not isIntArrayOfZeros do
        elementValue := getValue(element, integer);
        if elementValue <> 0 then
          isIntArrayOfZeros := FALSE;
        end if;
      end for;
    end if;
  end func;


const proc: process_arr_cpy_times_optimization (in reference: dest,
    in reference: factor, inout expr_type: c_expr) is func

  local
    var expr_type: statement is expr_type.value;
    var expr_type: c_param1 is expr_type.value;
    var intRange: factorRange is intRange.value;
    var string: factorName is "";
  begin
    statement.temp_num := c_expr.temp_num;
    prepareAnyParamTemporarys(dest, c_param1, statement);
    statement.expr &:= "(";
    factorName := getParameterAsVariable("intType", "factor_", factor, statement);
    if config.function_range_check then
      factorRange := getIntRange(factor);
      if factorRange.minValue < 0 then
        statement.expr &:= "(rngChk((";
        statement.expr &:= factorName;
        statement.expr &:= ") < 0)?";
        statement.expr &:= intRaiseError("RANGE_ERROR");
        statement.expr &:= ":0),\n";
      else
        countRangeOptimizations(statement);
      end if;
    else
      incr(count.noRangeChecks);
    end if;
    if isNormalVariable(dest) then
      statement.temp_decls &:= "memSizeType size_a = (uintType)((";
      statement.temp_decls &:= c_param1.expr;
      statement.temp_decls &:= ")->max_position - (";
      statement.temp_decls &:= c_param1.expr;
      statement.temp_decls &:= ")->min_position + 1);\n";
      statement.expr &:= "(size_a != (uintType)(";
      statement.expr &:= factorName;
      statement.expr &:= ")?";
      statement.expr &:= c_param1.expr;
      statement.expr &:= "=(arrayType)(arrRealloc(";
      statement.expr &:= c_param1.expr;
      statement.expr &:= ", size_a, ";
      statement.expr &:= factorName;
      statement.expr &:= ")):0),\n";
      statement.expr &:= "memset((";
      statement.expr &:= c_param1.expr;
      statement.expr &:= ")->arr, 0, ";
      statement.expr &:= factorName;
      statement.expr &:= " * sizeof(rtlObjectType)),\n";
      statement.expr &:= "(";
      statement.expr &:= c_param1.expr;
      statement.expr &:= ")->min_position = 1,\n";
      statement.expr &:= "(";
      statement.expr &:= c_param1.expr;
      statement.expr &:= ")->max_position = ";
    else
      statement.temp_decls &:= "arrayType *array_ptr=&(";
      statement.temp_decls &:= c_param1.expr;
      statement.temp_decls &:= ");\n";
      statement.temp_decls &:= "memSizeType size_a = (uintType)((*array_ptr)->max_position - (*array_ptr)->min_position + 1);\n";
      statement.expr &:= "(size_a != (uintType)(";
      statement.expr &:= factorName;
      statement.expr &:= ")?\n";
      statement.expr &:= "*array_ptr=(arrayType)(arrRealloc(*array_ptr, size_a, ";
      statement.expr &:= factorName;
      statement.expr &:= ")):0),\n";
      statement.expr &:= "memset((*array_ptr)->arr, 0, ";
      statement.expr &:= factorName;
      statement.expr &:= " * sizeof(rtlObjectType)),\n";
      statement.expr &:= "(*array_ptr)->min_position = 1,\n";
      statement.expr &:= "(*array_ptr)->max_position = ";
    end if;
    statement.expr &:= factorName;
    statement.expr &:= ");\n";
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


const proc: process_arr_cpy_array_of_zeros (in reference: dest,
    in integer: minPosition, in integer: maxPosition, inout expr_type: c_expr) is func

  local
    var integer: arraySize is 0;
    var type: arrayType is void;
    var expr_type: statement is expr_type.value;
    var expr_type: c_param1 is expr_type.value;
  begin
    arraySize := succ(maxPosition - minPosition);
    statement.temp_num := c_expr.temp_num;
    prepareAnyParamTemporarys(dest, c_param1, statement);
    statement.expr &:= "(";
    arrayType := getExprResultType(dest);
    if isNormalVariable(dest) then
      if arrayType not in typeData.array_minIdx or
          arrayType not in typeData.array_maxIdx or
          (minPosition <> typeData.array_minIdx[arrayType] and
           maxPosition <> typeData.array_maxIdx[arrayType]) then
        statement.temp_decls &:= "memSizeType size_a = (uintType)((";
        statement.temp_decls &:= c_param1.expr;
        statement.temp_decls &:= ")->max_position - (";
        statement.temp_decls &:= c_param1.expr;
        statement.temp_decls &:= ")->min_position + 1);\n";
        statement.expr &:= "(size_a != (uintType)(";
        statement.expr &:= integerLiteral(arraySize);
        statement.expr &:= ")?";
        statement.expr &:= c_param1.expr;
        statement.expr &:= "=(arrayType)(arrRealloc(";
        statement.expr &:= c_param1.expr;
        statement.expr &:= ", size_a, ";
        statement.expr &:= integerLiteral(arraySize);
        statement.expr &:= ")):0),\n";
        statement.expr &:= "memset((";
        statement.expr &:= c_param1.expr;
        statement.expr &:= ")->arr, 0, ";
        statement.expr &:= integerLiteral(arraySize);
        statement.expr &:= " * sizeof(rtlObjectType)),\n";
        statement.expr &:= "(";
        statement.expr &:= c_param1.expr;
        statement.expr &:= ")->min_position = ";
        statement.expr &:= integerLiteral(minPosition);
        statement.expr &:= ",\n";
        statement.expr &:= "(";
        statement.expr &:= c_param1.expr;
        statement.expr &:= ")->max_position = ";
        statement.expr &:= integerLiteral(maxPosition);
      else
        statement.expr &:= "memset((";
        statement.expr &:= c_param1.expr;
        statement.expr &:= ")->arr, 0, ";
        statement.expr &:= integerLiteral(arraySize);
        statement.expr &:= " * sizeof(rtlObjectType))";
      end if;
    else
      statement.temp_decls &:= "arrayType *array_ptr=&(";
      statement.temp_decls &:= c_param1.expr;
      statement.temp_decls &:= ");\n";
      if arrayType not in typeData.array_minIdx or
          arrayType not in typeData.array_maxIdx or
          (minPosition <> typeData.array_minIdx[arrayType] and
           maxPosition <> typeData.array_maxIdx[arrayType]) then
        statement.temp_decls &:= "memSizeType size_a = (uintType)((*array_ptr)->max_position - (*array_ptr)->min_position + 1);\n";
        statement.expr &:= "(size_a != (uintType)(";
        statement.expr &:= integerLiteral(arraySize);
        statement.expr &:= ")?\n";
        statement.expr &:= "*array_ptr=(arrayType)(arrRealloc(*array_ptr, size_a, ";
        statement.expr &:= integerLiteral(arraySize);
        statement.expr &:= ")):0),\n";
        statement.expr &:= "memset((*array_ptr)->arr, 0, ";
        statement.expr &:= integerLiteral(arraySize);
        statement.expr &:= " * sizeof(rtlObjectType)),\n";
        statement.expr &:= "(*array_ptr)->min_position = ";
        statement.expr &:= integerLiteral(minPosition);
        statement.expr &:= ",\n";
        statement.expr &:= "(*array_ptr)->max_position = ";
        statement.expr &:= integerLiteral(maxPosition);
      else
        statement.expr &:= "memset((*array_ptr)->arr, 0, ";
        statement.expr &:= integerLiteral(arraySize);
        statement.expr &:= " * sizeof(rtlObjectType))";
      end if;
    end if;
    statement.expr &:= ");\n";
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


const func boolean: isFixedMinIdxTimes (in reference: aParam) is func
  result
    var boolean: isFixedMinIdxTimes is FALSE;
  local
    var type: arrayType is void;
    var reference: timesBody is NIL;
    var reference: timesExpression is NIL;
  begin
    arrayType := getExprResultType(aParam);
    if arrayType in typeData.array_minIdx and
        category(aParam) = CALLOBJECT and
        length(getValue(aParam, ref_list)) >= 4 and
        str(getActionParameter(aParam, 2)) = "times" and
        category(getValue(aParam, ref_list)[1]) = BLOCKOBJECT then
      timesBody := body(getValue(aParam, ref_list)[1]);
      if isActionExpression(timesBody, "ARR_ARRLIT2") then
        timesExpression := getActionParameter(timesBody, 4);
        if isActionExpression(timesExpression, "ARR_TIMES") then
          isFixedMinIdxTimes := TRUE;
        end if;
      end if;
    end if;
  end func;


const proc: two_dimensional_times_optimization (in reference: dest,
    in integer: minIdx1, in reference: maxIdx1, in integer: minIdx2, in reference: maxIdx2,
    inout expr_type: c_expr) is func

  local
    var type: arrayType is void;
    var string: maxIdx1Name is "";
    var string: maxIdx2Name is "";
    var string: resultName is "";
    var expr_type: statement is expr_type.value;
    var expr_type: c_param1 is expr_type.value;
  begin
    incr(count.optimizations);
    arrayType := getExprResultType(dest);
    statement.temp_num := c_expr.temp_num;
    prepareAnyParamTemporarys(dest, c_param1, statement);
    maxIdx1Name := defineTempVariable("intType", "maxIdx1_", statement);
    if isNormalVariable(maxIdx2) then
      maxIdx2Name := normalVariable(maxIdx2, statement);
    else
      maxIdx2Name := defineTempVariable("intType", "maxIdx2_", statement);
    end if;
    statement.expr &:= maxIdx1Name;
    statement.expr &:= "=(";
    process_expr(maxIdx1, statement);
    statement.expr &:= ");\n";
    if not isNormalVariable(maxIdx2) then
      statement.expr &:= maxIdx2Name;
      statement.expr &:= "=(";
      process_expr(maxIdx2, statement);
      statement.expr &:= ");\n";
    end if;
    if isNormalVariable(dest) then
      resultName := "(" & c_param1.expr & ")";
    else
      statement.temp_decls &:= "arrayType *array_ptr=&(";
      statement.temp_decls &:= c_param1.expr;
      statement.temp_decls &:= ");\n";
      resultName := "(*array_ptr)";
    end if;
    process_destr_declaration(arrayType, global_c_expr);
    process_destr_call(arrayType, resultName, statement.expr);
    statement.expr &:= resultName;
    statement.expr &:= "=arrMalloc(";
    statement.expr &:= integerLiteral(minIdx1);
    statement.expr &:= ", ";
    statement.expr &:= maxIdx1Name;
    statement.expr &:= ");\n";
    if minIdx1 > 1 then
      statement.expr &:= maxIdx1Name;
      statement.expr &:= "-= ";
      statement.expr &:= integerLiteral(pred(minIdx1));
      statement.expr &:= ";\n";
    elsif minIdx1 <= succ(integer.first) then
      statement.expr &:= maxIdx1Name;
      statement.expr &:= "-= ";
      statement.expr &:= integerLiteral(minIdx1);
      statement.expr &:= ";\n";
      statement.expr &:= maxIdx1Name;
      statement.expr &:= "++;\n";
    elsif minIdx1 < 1 then
      statement.expr &:= maxIdx1Name;
      statement.expr &:= "+= ";
      statement.expr &:= integerLiteral(succ(-minIdx1));
      statement.expr &:= ";\n";
    end if;
    statement.expr &:= "while (";
    statement.expr &:= maxIdx1Name;
    statement.expr &:= "!=0) {\n";
    statement.expr &:= maxIdx1Name;
    statement.expr &:= "--;\n";
    statement.expr &:= resultName;
    statement.expr &:= "->arr[";
    statement.expr &:= maxIdx1Name;
    statement.expr &:= "].value.arrayValue=arrTimes0(";
    statement.expr &:= integerLiteral(minIdx2);
    statement.expr &:= ", ";
    statement.expr &:= maxIdx2Name;
    statement.expr &:= ");\n";
    statement.expr &:= "}\n";
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


const proc: process (ARR_CPY, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var type: arrayType is void;
    var reference: evaluatedParam is NIL;
    var expr_type: statement is expr_type.value;
    var expr_type: c_param1 is expr_type.value;
    var expr_type: c_param3 is expr_type.value;
  begin
    checkGlobalVariableChange(params[1], c_expr);
    arrayType := getExprResultType(params[1]);
    if isActionExpression(params[3], "ARR_CAT") and
        getActionParameter(params[3], 1) = params[1] then
      process_arr_append(params[1], getActionParameter(params[3], 3), c_expr);
    elsif config.inlineFunctions and
        isActionExpression(params[3], "ARR_TIMES") and
        getConstant(getActionParameter(params[3], 3), INTOBJECT, evaluatedParam) and
        getValue(evaluatedParam, integer) = 0 then
      process_arr_cpy_times_optimization(params[1],
          getActionParameter(params[3], 1), c_expr);
    elsif config.inlineFunctions and
        getConstant(params[3], ARRAYOBJECT, evaluatedParam) and
        isIntArrayOfZeros(evaluatedParam) then
      process_arr_cpy_array_of_zeros(params[1],
          arrayMinIdx(evaluatedParam), arrayMaxIdx(evaluatedParam), c_expr);
    elsif isFixedMinIdxTimes(params[3]) and
        isFixedMinIdxTimes(getActionParameter(params[3], 3)) and
        getConstant(getActionParameter(getActionParameter(params[3], 3), 3), INTOBJECT, evaluatedParam) and
        getValue(evaluatedParam, integer) = 0 then
      two_dimensional_times_optimization(params[1],
          typeData.array_minIdx[arrayType], getActionParameter(params[3], 1),
          typeData.array_minIdx[getExprResultType(getActionParameter(params[3], 3))],
          getActionParameter(getActionParameter(params[3], 3), 1), c_expr);
    else
      statement.temp_num := c_expr.temp_num;
      prepareAnyParamTemporarys(params[1], c_param1, statement);
      c_param3.demand := ASSIGN_RESULT;
      prepareAnyParamTemporarys(params[3], c_param3, statement);
      if c_param3.result_expr <> "" then
        statement.temp_decls &:= "arrayType new_array;\n";
        statement.expr &:= "new_array=";
        statement.expr &:= c_param3.result_expr;
        statement.expr &:= ";\n";
        process_destr_declaration(arrayType, global_c_expr);
        if isNormalVariable(params[1]) then
          process_destr_call(arrayType, c_param1.expr, statement.expr);
          statement.expr &:= c_param1.expr;
          statement.expr &:= "=new_array;\n";
        else
          statement.temp_decls &:= "arrayType *array_ptr=&(";
          statement.temp_decls &:= c_param1.expr;
          statement.temp_decls &:= ");\n";
          process_destr_call(arrayType, "*array_ptr", statement.expr);
          statement.expr &:= "*array_ptr=new_array;\n";
        end if;
      else
        process_cpy_declaration(arrayType, global_c_expr);
        process_cpy_call(arrayType, c_param1.expr, c_param3.expr,
            statement.expr);
        statement.expr &:= ";\n";
      end if;
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process (ARR_CREATE, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var type: param_type is void;
  begin
    param_type := getExprResultType(params[3]);
    typeData.typeCategory @:= [param_type] ARRAYOBJECT;
    process_create_declaration(param_type, global_c_expr);
    process_expr(params[1], c_expr);
    c_expr.expr &:= "=create_";
    c_expr.expr &:= str(typeNumber(param_type));
    c_expr.expr &:= "(";
    process_expr(params[3], c_expr);
    c_expr.expr &:= ");\n";
  end func;


const proc: process (ARR_DESTR, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var type: param_type is void;
  begin
    param_type := getExprResultType(params[1]);
    process_destr_declaration(param_type, global_c_expr);
    c_expr.expr &:= "destr_";
    c_expr.expr &:= str(typeNumber(param_type));
    c_expr.expr &:= "(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ");\n";
  end func;


const proc: process (ARR_EXTEND, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    prepare_typed_result(getExprResultType(params[1]), c_expr);
    c_expr.result_expr := "arrExtend(";
    getTemporaryToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", ";
    getRtlValueTemporaryToResultExpr(params[3], c_expr);
    c_expr.result_expr &:= ")";
  end func;


const proc: process (ARR_GEN, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    prepare_typed_result(resultType(getType(function)), c_expr);
    c_expr.result_expr := "arrGen(";
    getRtlValueTemporaryToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", ";
    getRtlValueTemporaryToResultExpr(params[3], c_expr);
    c_expr.result_expr &:= ")";
  end func;


const proc: process (ARR_HEAD, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var type: param_type is void;
    var expr_type: c_param is expr_type.value;
    var string: slice_name is "";
    var string: array_name is "";
  begin
    param_type := getExprResultType(params[1]);
    prepare_typed_result(param_type, c_expr);
    prepareAnyParamTemporarys(params[1], c_param, c_expr);
    if c_param.result_expr <> "" then
      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_expr.result_expr &:= c_param.result_intro;
      c_expr.result_expr &:= c_param.result_expr;
      c_expr.result_expr &:= c_param.result_finish;
      c_expr.result_expr &:= ", arrHeadTemp(&(";
      c_expr.result_expr &:= c_param.result_name;
      c_expr.result_expr &:= "), ";
      getStdParamToResultExpr(params[4], c_expr);
      c_expr.result_expr &:= "))";
    elsif ccConf.ALLOW_RTL_ARRAY_SLICES and c_expr.demand < REQUIRE_RESULT then
      c_expr.expr &:= "(";
      incr(c_expr.temp_num);
      slice_name := "slice_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "struct rtlArrayStruct ";
      c_expr.temp_decls &:= slice_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= "arrHeadSlice(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[4], c_expr);
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
    elsif valueIsAtHeap(typeData.array_element[param_type]) then
      incr(c_expr.temp_num);
      array_name := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "arrayType ";
      c_expr.temp_decls &:= array_name;
      c_expr.temp_decls &:= "=NULL;\n";
      c_expr.temp_frees &:= "if (";
      c_expr.temp_frees &:= array_name;
      c_expr.temp_frees &:= " != NULL) {arrFree(";
      c_expr.temp_frees &:= array_name;
      c_expr.temp_frees &:= ");}\n";
      c_expr.temp_to_null &:= array_name;
      c_expr.temp_to_null &:= "=NULL;\n";
      c_expr.result_expr := "(";
      c_expr.result_expr &:= array_name;
      c_expr.result_expr &:= "=arrHead(";
      c_expr.result_expr &:= c_param.expr;
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[4], c_expr);
      c_expr.result_expr &:= "), ";
      typeData.typeCategory @:= [param_type] ARRAYOBJECT;
      process_create_declaration(param_type, global_c_expr);
      process_create_call(param_type, array_name, c_expr.result_expr);
      c_expr.result_expr &:= ")";
    else
      c_expr.result_expr := "arrHead(";
      c_expr.result_expr &:= c_param.expr;
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[4], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process_const_arr_idx (in reference: function, in reference: anArray,
    in reference: index, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var integer: index_value is 0;
    var intRange: indexRange is intRange.value;
    var string: index_name is "";
  begin
    incr(count.optimizations);
    if anArray not in constTable.other_const then
      constTable.other_const @:= [anArray] length(constTable.other_const);
    end if;
    if getConstant(index, INTOBJECT, evaluatedParam) then
      index_value := getValue(evaluatedParam, integer);
      if index_value < arrayMinIdx(anArray) or index_value > arrayMaxIdx(anArray) then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= "(";
        c_expr.expr &:= type_name(resultType(getType(function)));
        c_expr.expr &:= ")(raiseError(INDEX_ERROR), 0)";
      else
        c_expr.expr &:= "arr[";
        c_expr.expr &:= str(constTable.other_const[anArray]);
        c_expr.expr &:= "]->arr[";
        c_expr.expr &:= str(index_value - arrayMinIdx(anArray));
        c_expr.expr &:= "]";
        c_expr.expr &:= select_value_from_rtlObjectStruct(resultType(getType(function)));
      end if;
    else
      indexRange := getIntRange(index);
      if indexRange.maxValue < arrayMinIdx(anArray) or
          indexRange.minValue > arrayMaxIdx(anArray) then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= "(";
        c_expr.expr &:= type_name(resultType(getType(function)));
        c_expr.expr &:= ")(raiseError(INDEX_ERROR), 0)";
      else
        c_expr.expr &:= "arr[";
        c_expr.expr &:= str(constTable.other_const[anArray]);
        c_expr.expr &:= "]->arr[";
        if config.array_index_check then
          if indexRange.minValue < arrayMinIdx(anArray) or
              indexRange.maxValue > arrayMaxIdx(anArray) then
            incr(count.indexChecks);
            incr(c_expr.temp_num);
            index_name := "idx_" & str(c_expr.temp_num);
            if ccConf.TWOS_COMPLEMENT_INTTYPE then
              c_expr.temp_decls &:= "uintType ";
            else
              c_expr.temp_decls &:= "intType ";
            end if;
            c_expr.temp_decls &:= index_name;
            c_expr.temp_decls &:= ";\n";
            c_expr.expr &:= "(";
            c_expr.expr &:= index_name;
            if ccConf.TWOS_COMPLEMENT_INTTYPE then
              c_expr.expr &:= "=(uintType)(";
            else
              c_expr.expr &:= "=(";
            end if;
            process_expr(index, c_expr);
            c_expr.expr &:= ")";
            if arrayMinIdx(anArray) <> 0 then
              if ccConf.TWOS_COMPLEMENT_INTTYPE then
                c_expr.expr &:= "- (uintType) ";
              else
                c_expr.expr &:= "- ";
              end if;
              c_expr.expr &:= integerLiteral(arrayMinIdx(anArray));
            end if;
            c_expr.expr &:= ", idxChk(";
            if not ccConf.TWOS_COMPLEMENT_INTTYPE then
              c_expr.expr &:= index_name;
              c_expr.expr &:= "<0 || ";
            end if;
            c_expr.expr &:= index_name;
            c_expr.expr &:= ">=";
            c_expr.expr &:= integerLiteral(arrayLength(anArray));
            c_expr.expr &:= ") ? ";
            c_expr.expr &:= intRaiseError("INDEX_ERROR");
            c_expr.expr &:= " : ";
            c_expr.expr &:= index_name;
            c_expr.expr &:= ")";
          else
            countIndexOptimizations(c_expr);
            c_expr.expr &:= "(";
            process_expr(index, c_expr);
            c_expr.expr &:= ")";
            if arrayMinIdx(anArray) <> 0 then
              c_expr.expr &:= "- ";
              c_expr.expr &:= integerLiteral(arrayMinIdx(anArray));
            end if;
          end if;
        else
          incr(count.suppressedIndexChecks);
          c_expr.expr &:= "(";
          process_expr(index, c_expr);
          c_expr.expr &:= ")";
          if arrayMinIdx(anArray) <> 0 then
            c_expr.expr &:= "- ";
            c_expr.expr &:= integerLiteral(arrayMinIdx(anArray));
          end if;
        end if;
        c_expr.expr &:= "]";
        c_expr.expr &:= select_value_from_rtlObjectStruct(resultType(getType(function)));
      end if;
    end if;
  end func;


const proc: process_const_arr_idx (in reference: function, in reference: param1,
    in integer: index, inout expr_type: c_expr) is func

  local
    var expr_type: c_param is expr_type.value;
    var string: array_name is "";
    var type: arrayType is void;
    var string: result_name is "";
    var integer: c_index is 0;
    var boolean: index_overflows is FALSE;
  begin
    prepareAnyParamTemporarys(param1, c_param, c_expr);
    if c_param.result_expr <> "" then
      incr(c_expr.temp_num);
      result_name := "help_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "rtlObjectType ";
      c_expr.temp_decls &:= result_name;
      c_expr.temp_decls &:= ";\n";
      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;
      if resultType(getType(function)) in typeData.typeCategory and
          typeData.typeCategory[resultType(getType(function))] in destrNecessary then
        prepare_typed_result(resultType(getType(function)), c_expr);
        c_expr.result_expr &:= "(";
        c_expr.result_expr &:= c_param.result_intro;
        c_expr.result_expr &:= c_param.result_expr;
        c_expr.result_expr &:= c_param.result_finish;
        c_expr.result_expr &:= ", ";
        c_expr.result_expr &:= result_name;
        c_expr.result_expr &:= ".value=arrIdxTemp(&(";
        c_expr.result_expr &:= c_param.result_name;
        c_expr.result_expr &:= "), ";
        c_expr.result_expr &:= integerLiteral(index);
        c_expr.result_expr &:= "), ";
        c_expr.result_expr &:= result_name;
        c_expr.result_expr &:= select_value_from_rtlObjectStruct(resultType(getType(function)));
        c_expr.result_expr &:= ")";
      else
        c_expr.expr &:= "(";
        c_expr.expr &:= c_param.result_intro;
        c_expr.expr &:= c_param.result_expr;
        c_expr.expr &:= c_param.result_finish;
        c_expr.expr &:= ", ";
        c_expr.expr &:= result_name;
        c_expr.expr &:= ".value=arrIdxTemp(&(";
        c_expr.expr &:= c_param.result_name;
        c_expr.expr &:= "), ";
        c_expr.expr &:= integerLiteral(index);
        c_expr.expr &:= "), ";
        c_expr.expr &:= result_name;
        c_expr.expr &:= select_value_from_rtlObjectStruct(resultType(getType(function)));
        c_expr.expr &:= ")";
      end if;
    else
      incr(count.optimizations);
      if isNormalVariable(param1) then
        array_name := "(" & c_param.expr & ")";
      else
        incr(c_expr.temp_num);
        array_name := "tmp_" & str(c_expr.temp_num);
        if not isVarfunc(getType(function)) then
          c_expr.temp_decls &:= "const_";
        end if;
        c_expr.temp_decls &:= "arrayType ";
        c_expr.temp_decls &:= array_name;
        c_expr.temp_decls &:= ";\n";
        c_expr.expr &:= "(*(";
        c_expr.expr &:= array_name;
        c_expr.expr &:= "=";
        c_expr.expr &:= c_param.expr;
        c_expr.expr &:= ", &";
      end if;
      c_expr.expr &:= array_name;
      c_expr.expr &:= "->arr[";
      arrayType := getExprResultType(param1);
      if arrayType in typeData.array_minIdx then
        block
          c_index := index - typeData.array_minIdx[arrayType];
        exception
          catch OVERFLOW_ERROR: index_overflows := TRUE;
        end block;
      end if;
      if config.array_index_check then
        if arrayType in typeData.array_minIdx and
            arrayType in typeData.array_maxIdx then
          if index_overflows or
              index < typeData.array_minIdx[arrayType] or
              index > typeData.array_maxIdx[arrayType] then
            warning(DOES_RAISE, "INDEX_ERROR", c_expr);
            c_expr.expr &:= intRaiseError("INDEX_ERROR");
          else
            countIndexOptimizations(c_expr);
            c_expr.expr &:= integerLiteral(c_index);
          end if;
        elsif arrayType in typeData.array_minIdx and
            (index_overflows or
             index < typeData.array_minIdx[arrayType]) then
          warning(DOES_RAISE, "INDEX_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("INDEX_ERROR");
        else
          incr(count.indexChecks);
          c_expr.expr &:= "(idxChk(";
          if arrayType not in typeData.array_minIdx then
            c_expr.expr &:= integerLiteral(index);
            c_expr.expr &:= "<";
            c_expr.expr &:= array_name;
            c_expr.expr &:= "->min_position || ";
          end if;
          c_expr.expr &:= integerLiteral(index);
          c_expr.expr &:= ">";
          c_expr.expr &:= array_name;
          c_expr.expr &:= "->max_position) ? ";
          c_expr.expr &:= intRaiseError("INDEX_ERROR");
          c_expr.expr &:= " : ";
          if arrayType in typeData.array_minIdx then
            c_expr.expr &:= integerLiteral(c_index);
          else
            c_expr.expr &:= integerLiteral(index);
            c_expr.expr &:= "-";
            c_expr.expr &:= array_name;
            c_expr.expr &:= "->min_position";
          end if;
          c_expr.expr &:= ")";
        end if;
      else
        incr(count.suppressedIndexChecks);
        if arrayType in typeData.array_minIdx then
          if index_overflows then
            warning(DOES_RAISE, "INDEX_ERROR", c_expr);
            c_expr.expr &:= intRaiseError("INDEX_ERROR");
          else
            c_expr.expr &:= integerLiteral(c_index);
          end if;
        else
          c_expr.expr &:= integerLiteral(index);
          c_expr.expr &:= "-";
          c_expr.expr &:= array_name;
          c_expr.expr &:= "->min_position";
        end if;
      end if;
      c_expr.expr &:= "]";
      c_expr.expr &:= select_value_from_rtlObjectStruct(resultType(getType(function)));
      if not isNormalVariable(param1) then
        c_expr.expr &:= "))";
      end if;
    end if;
  end func;


const proc: process_fixlen_array_index (in reference: index,
    in intRange: indexRange, in integer: minIndex, in integer: maxIndex,
    inout expr_type: c_expr) is func

  local
    var string: index_name is "";
  begin
    if indexRange.maxValue < minIndex or
        indexRange.minValue > maxIndex then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("INDEX_ERROR");
    elsif indexRange.minValue >= minIndex and
        indexRange.maxValue <= maxIndex then
      countIndexOptimizations(c_expr);
      c_expr.expr &:= "(";
      process_expr(index, c_expr);
      c_expr.expr &:= ")";
      if minIndex <> 0 then
        c_expr.expr &:= "- ";
        c_expr.expr &:= integerLiteral(minIndex);
      end if;
    else
      incr(count.indexChecks);
      if ccConf.TWOS_COMPLEMENT_INTTYPE then
        index_name := getTempVariable("uintType", "idx_", "", c_expr);
        c_expr.expr &:= "(";
        c_expr.expr &:= index_name;
        c_expr.expr &:= " = (uintType)(";
        process_expr(index, c_expr);
        c_expr.expr &:= ")";
        if minIndex <> 0 then
          c_expr.expr &:= "-(uintType)";
          c_expr.expr &:= integerLiteral(minIndex);
        end if;
        c_expr.expr &:= ",idxChk(";
        c_expr.expr &:= index_name;
        c_expr.expr &:= " >= (uintType)";
        c_expr.expr &:= integerLiteral(succ(maxIndex - minIndex));
        c_expr.expr &:= ") ? ";
        c_expr.expr &:= intRaiseError("INDEX_ERROR");
        c_expr.expr &:= " : ";
        c_expr.expr &:= index_name;
        c_expr.expr &:= ")";
      else
        index_name := getParameterAsVariable("intType", "idx_", index, c_expr);
        c_expr.expr &:= "(idxChk(";
        c_expr.expr &:= index_name;
        c_expr.expr &:= " < ";
        c_expr.expr &:= integerLiteral(minIndex);
        c_expr.expr &:= " || ";
        c_expr.expr &:= index_name;
        c_expr.expr &:= " > ";
        c_expr.expr &:= integerLiteral(maxIndex);
        c_expr.expr &:= ") ? ";
        c_expr.expr &:= intRaiseError("INDEX_ERROR");
        c_expr.expr &:= " : ";
        c_expr.expr &:= index_name;
        if minIndex <> 0 then
          c_expr.expr &:= "- ";
          c_expr.expr &:= integerLiteral(minIndex);
        end if;
        c_expr.expr &:= ")";
      end if;
    end if;
  end func;


const proc: process_base_array_index (in string: array_name,
    in reference: index, in intRange: indexRange, in integer: minIndex,
    inout expr_type: c_expr) is func

  local
    var string: index_name is "";
  begin
    if indexRange.maxValue < minIndex then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("INDEX_ERROR");
    else
      incr(count.indexChecks);
      index_name := getParameterAsVariable("intType", "idx_", index, c_expr);
      c_expr.expr &:= "(idxChk(";
      if ccConf.TWOS_COMPLEMENT_INTTYPE and
          indexRange.minValue < minIndex and
          minIndex = 0 then
        c_expr.expr &:= "(uintType)";
        c_expr.expr &:= index_name;
        c_expr.expr &:= " >= (uintType)(";
        c_expr.expr &:= array_name;
        c_expr.expr &:= "->max_position) + 1";
      else
        if indexRange.minValue < minIndex then
          c_expr.expr &:= index_name;
          c_expr.expr &:= " < ";
          c_expr.expr &:= integerLiteral(minIndex);
          c_expr.expr &:= " || ";
        end if;
        c_expr.expr &:= index_name;
        c_expr.expr &:= " > ";
        c_expr.expr &:= array_name;
        c_expr.expr &:= "->max_position";
      end if;
      c_expr.expr &:= ") ? ";
      c_expr.expr &:= intRaiseError("INDEX_ERROR");
      c_expr.expr &:= " : ";
      c_expr.expr &:= index_name;
      if minIndex <> 0 then
        c_expr.expr &:= "- ";
        c_expr.expr &:= integerLiteral(minIndex);
      end if;
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (ARR_IDX, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var expr_type: c_param is expr_type.value;
    var string: array_name is "";
    var type: arrayType is void;
    var intRange: indexRange is intRange.value;
    var string: index_name is "";
    var string: result_name is "";
  begin
    if getType(params[1]) not in typeData.array_element then
      typeData.array_element @:= [getType(params[1])] resultType(getType(function));
    end if;
    if getConstant(params[1], ARRAYOBJECT, evaluatedParam) then
      process_const_arr_idx(function, evaluatedParam, params[3], c_expr);
    elsif getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_arr_idx(function, params[1], getValue(evaluatedParam, integer), c_expr);
    else
      prepareAnyParamTemporarys(params[1], c_param, c_expr);
      if c_param.result_expr <> "" then
        incr(c_expr.temp_num);
        result_name := "help_" & str(c_expr.temp_num);
        c_expr.temp_decls &:= "rtlObjectType ";
        c_expr.temp_decls &:= result_name;
        c_expr.temp_decls &:= ";\n";
        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;
        if resultType(getType(function)) in typeData.typeCategory and
            typeData.typeCategory[resultType(getType(function))] in destrNecessary then
          prepare_typed_result(resultType(getType(function)), c_expr);
          c_expr.result_expr &:= "(";
          c_expr.result_expr &:= c_param.result_intro;
          c_expr.result_expr &:= c_param.result_expr;
          c_expr.result_expr &:= c_param.result_finish;
          c_expr.result_expr &:= ", ";
          c_expr.result_expr &:= result_name;
          c_expr.result_expr &:= ".value=arrIdxTemp(&(";
          c_expr.result_expr &:= c_param.result_name;
          c_expr.result_expr &:= "), ";
          getAnyParamToResultExpr(params[3], c_expr);
          c_expr.result_expr &:= "), ";
          c_expr.result_expr &:= result_name;
          c_expr.result_expr &:= select_value_from_rtlObjectStruct(resultType(getType(function)));
          c_expr.result_expr &:= ")";
        else
          c_expr.expr &:= "(";
          c_expr.expr &:= c_param.result_intro;
          c_expr.expr &:= c_param.result_expr;
          c_expr.expr &:= c_param.result_finish;
          c_expr.expr &:= ", ";
          c_expr.expr &:= result_name;
          c_expr.expr &:= ".value=arrIdxTemp(&(";
          c_expr.expr &:= c_param.result_name;
          c_expr.expr &:= "), ";
          process_expr(params[3], c_expr);
          c_expr.expr &:= "), ";
          c_expr.expr &:= result_name;
          c_expr.expr &:= select_value_from_rtlObjectStruct(resultType(getType(function)));
          c_expr.expr &:= ")";
        end if;
      else
        if isNormalVariable(params[1]) then
          array_name := "(" & c_param.expr & ")";
        else
          incr(c_expr.temp_num);
          array_name := "tmp_" & str(c_expr.temp_num);
          if not isVarfunc(getType(function)) then
            c_expr.temp_decls &:= "const_";
          end if;
          c_expr.temp_decls &:= "arrayType ";
          c_expr.temp_decls &:= array_name;
          c_expr.temp_decls &:= ";\n";
          c_expr.expr &:= "(*(";
          c_expr.expr &:= array_name;
          c_expr.expr &:= "=";
          c_expr.expr &:= c_param.expr;
          c_expr.expr &:= ", &";
        end if;
        c_expr.expr &:= array_name;
        c_expr.expr &:= "->arr[";
        arrayType := getExprResultType(params[1]);
        if config.array_index_check then
          indexRange := getIntRange(params[3]);
          if arrayType in typeData.array_minIdx and
              arrayType in typeData.array_maxIdx then
            process_fixlen_array_index(params[3], indexRange,
                typeData.array_minIdx[arrayType],
                typeData.array_maxIdx[arrayType], c_expr);
          elsif arrayType in typeData.array_minIdx then
            process_base_array_index(array_name, params[3], indexRange,
                typeData.array_minIdx[arrayType], c_expr);
          else
            incr(count.indexChecks);
            if ccConf.TWOS_COMPLEMENT_INTTYPE then
              index_name := getTempVariable("uintType", "idx_", "", c_expr);
              c_expr.expr &:= "(";
              c_expr.expr &:= index_name;
              c_expr.expr &:= " = (uintType)(";
              process_expr(params[3], c_expr);
              c_expr.expr &:= ")-(uintType)(";
              c_expr.expr &:= array_name;
              c_expr.expr &:= "->min_position),idxChk(";
              c_expr.expr &:= index_name;
              c_expr.expr &:= " >= (uintType)(";
              c_expr.expr &:= array_name;
              c_expr.expr &:= "->max_position) - (uintType)(";
              c_expr.expr &:= array_name;
              c_expr.expr &:= "->min_position) + (uintType)1) ? ";
              c_expr.expr &:= intRaiseError("INDEX_ERROR");
              c_expr.expr &:= " : ";
              c_expr.expr &:= index_name;
              c_expr.expr &:= ")";
            else
              index_name := getParameterAsVariable("intType", "idx_", params[3], c_expr);
              c_expr.expr &:= "(idxChk(";
              c_expr.expr &:= index_name;
              c_expr.expr &:= " < ";
              c_expr.expr &:= array_name;
              c_expr.expr &:= "->min_position || ";
              c_expr.expr &:= index_name;
              c_expr.expr &:= " > ";
              c_expr.expr &:= array_name;
              c_expr.expr &:= "->max_position) ? ";
              c_expr.expr &:= intRaiseError("INDEX_ERROR");
              c_expr.expr &:= " : ";
              c_expr.expr &:= index_name;
              c_expr.expr &:= "-";
              c_expr.expr &:= array_name;
              c_expr.expr &:= "->min_position)";
            end if;
          end if;
        else
          incr(count.suppressedIndexChecks);
          c_expr.expr &:= "(";
          process_expr(params[3], c_expr);
          c_expr.expr &:= ")";
          if arrayType in typeData.array_minIdx then
            if typeData.array_minIdx[arrayType] <> 0 then
              c_expr.expr &:= "- ";
              c_expr.expr &:= integerLiteral(typeData.array_minIdx[arrayType]);
            end if;
          else
            c_expr.expr &:= "- ";
            c_expr.expr &:= array_name;
            c_expr.expr &:= "->min_position";
          end if;
        end if;
        c_expr.expr &:= "]";
        c_expr.expr &:= select_value_from_rtlObjectStruct(resultType(getType(function)));
        if not isNormalVariable(params[1]) then
          c_expr.expr &:= "))";
        end if;
      end if;
    end if;
  end func;


const proc: process (ARR_INSERT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var type: array_type is void;
    var type: element_type is void;
    var expr_type: statement is expr_type.value;
    var reference: evaluatedParam is NIL;
    var string: array_name is "";
    var string: position_name is "";
  begin
    checkGlobalVariableChange(params[1], c_expr);
    array_type := getExprResultType(params[1]);
    element_type := getExprResultType(params[3]);
    if array_type not in typeData.array_element then
      typeData.array_element @:= [array_type] element_type;
    end if;
    if valueIsAtHeap(element_type) then
      if config.array_index_check then
        incr(count.indexChecks);
        incr(statement.temp_num);
        if getConstant(params[2], INTOBJECT, evaluatedParam) then
          position_name := integerLiteral(getValue(evaluatedParam, integer));
        else
          position_name := "pos_" & str(statement.temp_num);
          statement.temp_decls &:= "intType ";
          statement.temp_decls &:= position_name;
          statement.temp_decls &:= ";";
          statement.expr &:= position_name;
          statement.expr &:= " = ";
          process_expr(params[2], statement);
          statement.expr &:= ";\n";
        end if;
        array_name := getParameterAsReference(type_name(array_type),
                                              "arr_", params[1], statement);
        statement.expr &:= "if (idxChk(";
        statement.expr &:= position_name;
        statement.expr &:= " < ";
        statement.expr &:= array_name;
        statement.expr &:= "->min_position || ";
        statement.expr &:= position_name;
        statement.expr &:= " > ";
        statement.expr &:= array_name;
        statement.expr &:= "->max_position + 1)) {\n";
        statement.expr &:= raiseError("INDEX_ERROR");
        statement.expr &:= "} else {\n";
        statement.expr &:= "arrInsert(&(";
        statement.expr &:= array_name;
        statement.expr &:= "), ";
        statement.expr &:= position_name;
        statement.expr &:= ", ";
        getCreatedRtlValue(params[3], statement);
        statement.expr &:= ");\n";
        statement.expr &:= "}\n";
        doLocalDeclsOfStatement(statement, c_expr);
      else
        setDiagnosticLine(c_expr);
        c_expr.expr &:= "arrInsert(&(";
        process_expr(params[1], c_expr);
        c_expr.expr &:= "), ";
        process_expr(params[2], c_expr);
        c_expr.expr &:= ", ";
        getCreatedRtlValue(params[3], c_expr);
        c_expr.expr &:= ");\n";
      end if;
    else
      setDiagnosticLine(c_expr);
      c_expr.expr &:= "arrInsert(&(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= "), ";
      process_expr(params[2], c_expr);
      c_expr.expr &:= ", ";
      getCreatedRtlValue(params[3], c_expr);
      c_expr.expr &:= ");\n";
    end if;
  end func;


const proc: process (ARR_INSERT_ARRAY, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var type: param3_type is void;
    var expr_type: statement is expr_type.value;
  begin
    checkGlobalVariableChange(params[1], c_expr);
    param3_type := getExprResultType(params[3]);
    if valueIsAtHeap(typeData.array_element[param3_type]) then
      statement.expr &:= "arrInsertArrayTemp(&(";
      process_expr(params[1], statement);
      statement.expr &:= "), ";
      process_expr(params[2], statement);
      statement.expr &:= ", ";
      getTemporaryToExpr(params[3], statement);
      statement.expr &:= ");\n";
    else
      statement.expr &:= "arrInsertArray(&(";
      process_expr(params[1], statement);
      statement.expr &:= "), ";
      process_expr(params[2], statement);
      statement.expr &:= ", ";
      getAnyParamToExpr(params[3], statement);
      statement.expr &:= ");\n";
    end if;
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


const proc: process (ARR_LNG, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: array_name is "";
    var type: arrayType is void;
    var integer: minIdx is 0;
  begin
    if getConstant(params[1], ARRAYOBJECT, evaluatedParam) then
      incr(count.optimizations);
      c_expr.expr &:= str(arrayMaxIdx(evaluatedParam) - arrayMinIdx(evaluatedParam) + 1);
      if evaluatedParam in constTable.other_const then
        c_expr.expr &:= " /* length(arr[";
        c_expr.expr &:= str(constTable.other_const[evaluatedParam]);
        c_expr.expr &:= "]) */";
      else
        c_expr.expr &:= " /* length(array) */";
      end if;
    else
      arrayType := getExprResultType(params[1]);
      if arrayType in typeData.array_minIdx then
        minIdx := typeData.array_minIdx[arrayType];
        if arrayType in typeData.array_maxIdx then
          c_expr.expr &:= integerLiteral(typeData.array_maxIdx[arrayType] - minIdx + 1);
        else
          c_expr.expr &:= "(";
          getAnyParamToExpr(params[1], c_expr);
          c_expr.expr &:= ")->max_position";
          if minIdx > 1 then
            c_expr.expr &:= "- ";
            c_expr.expr &:= integerLiteral(pred(minIdx));
          elsif minIdx < 1 then
            if minIdx > integer.first then
              c_expr.expr &:= "+ ";
              c_expr.expr &:= integerLiteral(succ(-minIdx));
            else
              c_expr.expr &:= "- ";
              c_expr.expr &:= integerLiteral(integer.first);
              c_expr.expr &:= " + 1";
            end if;
          end if;
        end if;
      else
        c_expr.expr &:= "(";
        array_name := getParameterAsVariable("const_arrayType", "tmp_", params[1], c_expr);
        c_expr.expr &:= array_name;
        c_expr.expr &:= "->max_position - ";
        c_expr.expr &:= array_name;
        c_expr.expr &:= "->min_position + 1)";
      end if;
    end if;
  end func;


const proc: process (ARR_MAXIDX, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var type: arrayType is void;
  begin
    if getConstant(params[1], ARRAYOBJECT, evaluatedParam) then
      incr(count.optimizations);
      c_expr.expr &:= str(arrayMaxIdx(evaluatedParam));
      if evaluatedParam in constTable.other_const then
        c_expr.expr &:= " /* maxIdx(arr[";
        c_expr.expr &:= str(constTable.other_const[evaluatedParam]);
        c_expr.expr &:= "]) */";
      else
        c_expr.expr &:= " /* maxIdx(array) */";
      end if;
    else
      arrayType := getExprResultType(params[1]);
      if arrayType in typeData.array_maxIdx then
        c_expr.expr &:= integerLiteral(typeData.array_maxIdx[arrayType]);
      else
        c_expr.expr &:= "(";
        getAnyParamToExpr(params[1], c_expr);
        c_expr.expr &:= ")->max_position";
      end if;
    end if;
  end func;


const proc: process (ARR_MINIDX, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var type: arrayType is void;
  begin
    if getConstant(params[1], ARRAYOBJECT, evaluatedParam) then
      incr(count.optimizations);
      c_expr.expr &:= str(arrayMinIdx(evaluatedParam));
      if evaluatedParam in constTable.other_const then
        c_expr.expr &:= " /* minIdx(arr[";
        c_expr.expr &:= str(constTable.other_const[evaluatedParam]);
        c_expr.expr &:= "]) */";
      else
        c_expr.expr &:= " /* minIdx(array) */";
      end if;
    else
      arrayType := getExprResultType(params[1]);
      if arrayType in typeData.array_minIdx then
        c_expr.expr &:= integerLiteral(typeData.array_minIdx[arrayType]);
      else
        c_expr.expr &:= "(";
        getAnyParamToExpr(params[1], c_expr);
        c_expr.expr &:= ")->min_position";
      end if;
    end if;
  end func;


const func string: checkDestPos0 (in string: destName, in string: destPosName,
    in intRange: destPosRange, in type: destArrayType) is func

  result
    var string: checkExpr is "";
  local
    var integer: MAX_MEM_INDEX is integer.last;
  begin
    if ccConf.POINTER_SIZE = 32 then
      MAX_MEM_INDEX := 2 ** 31 - 1;
    end if;
    if destArrayType not in typeData.array_minIdx or
        destPosRange.minValue < typeData.array_minIdx[destArrayType] then
      checkExpr &:= destPosName;
      checkExpr &:= "<";
      if destArrayType in typeData.array_minIdx then
        checkExpr &:= integerLiteral(typeData.array_minIdx[destArrayType]);
      else
        checkExpr &:= destName;
        checkExpr &:= "->min_position";
      end if;
    end if;
    if destArrayType not in typeData.array_maxIdx or
        (typeData.array_maxIdx[destArrayType] <> integer.last and
         destPosRange.maxValue > succ(typeData.array_maxIdx[destArrayType]))  then
      if checkExpr <> "" then
        checkExpr &:= " || ";
      end if;
      if destArrayType in typeData.array_maxIdx then
        checkExpr &:= destPosName;
        checkExpr &:= ">";
        checkExpr &:= integerLiteral(succ(typeData.array_maxIdx[destArrayType]));
      else
        checkExpr &:= "(";
        checkExpr &:= destName;
        checkExpr &:= "->max_position";
        checkExpr &:= " != ";
        checkExpr &:= integerLiteral(integer.last);
        checkExpr &:= " && ";
        checkExpr &:= destPosName;
        checkExpr &:= ">";
        checkExpr &:= destName;
        checkExpr &:= "->max_position";
        checkExpr &:= " + 1)";
      end if;
    end if;
  end func;


const func string: checkDestPos (in string: destName, in string: destPosName,
    in intRange: destPosRange, in type: destArrayType) is func

  result
    var string: checkExpr is "";
  begin
    if destArrayType not in typeData.array_minIdx or
        destPosRange.minValue < typeData.array_minIdx[destArrayType] then
      checkExpr &:= destPosName;
      checkExpr &:= "<";
      if destArrayType in typeData.array_minIdx then
        checkExpr &:= integerLiteral(typeData.array_minIdx[destArrayType]);
      else
        checkExpr &:= destName;
        checkExpr &:= "->min_position";
      end if;
    end if;
    if destArrayType not in typeData.array_maxIdx or
        destPosRange.maxValue > typeData.array_maxIdx[destArrayType] then
      if checkExpr <> "" then
        checkExpr &:= " || ";
      end if;
      checkExpr &:= destPosName;
      checkExpr &:= ">";
      if destArrayType in typeData.array_maxIdx then
        checkExpr &:= integerLiteral(typeData.array_maxIdx[destArrayType]);
      else
        checkExpr &:= destName;
        checkExpr &:= "->max_position";
      end if;
    end if;
  end func;


const func string: checkDestPos (in string: destName,
    in boolean: sourceLenIsVariable, in integer: sourceLenValue,
    in string: sourceLenName, in boolean: destPosIsVariable,
    in integer: destPosValue, in string: destPosName,
    in type: destArrayType) is func

  result
    var string: checkExpr is "";
  begin
    if not sourceLenIsVariable and not destPosIsVariable and
        destPosValue <= integer.last - sourceLenValue and
        destPosValue <> integer.first then
      checkExpr &:= integerLiteral(pred(sourceLenValue + destPosValue));
      checkExpr &:= ">";
      if destArrayType in typeData.array_maxIdx then
        checkExpr &:= integerLiteral(typeData.array_maxIdx[destArrayType]);
      else
        checkExpr &:= destName;
        checkExpr &:= "->max_position";
      end if;
    else
      if not sourceLenIsVariable then
        checkExpr &:= integerLiteral(pred(sourceLenValue));
      else
        checkExpr &:= sourceLenName;
        checkExpr &:= "-1";
      end if;
      checkExpr &:= ">";
      if destArrayType in typeData.array_maxIdx then
        checkExpr &:= integerLiteral(typeData.array_maxIdx[destArrayType]);
      else
        checkExpr &:= destName;
        checkExpr &:= "->max_position";
      end if;
      checkExpr &:= " - ";
      checkExpr &:= destPosName;
    end if;
  end func;


const func string: checkDestPos (in string: destName, in string: destPosName,
    in intRange: destPosRange, in type: destArrayType, in integer: sourceLen) is func

  result
    var string: checkExpr is "";
  begin
    checkExpr :=  checkDestPos(destName, destPosName, destPosRange, destArrayType);
    if checkExpr <> "" then
      checkExpr &:= " || ";
    end if;
    checkExpr &:= integerLiteral(pred(sourceLen));
    checkExpr &:= ">";
    if destArrayType in typeData.array_maxIdx then
      checkExpr &:= integerLiteral(typeData.array_maxIdx[destArrayType]);
    else
      checkExpr &:= destName;
      checkExpr &:= "->max_position";
    end if;
    checkExpr &:= " - ";
    checkExpr &:= destPosName;
  end func;


const func string: checkDestPos (in string: destName, in string: destPosName,
    in intRange: destPosRange, in type: destArrayType, in string: sourceLenName) is func

  result
    var string: checkExpr is "";
  begin
    checkExpr :=  checkDestPos(destName, destPosName, destPosRange, destArrayType);
    if checkExpr <> "" then
      checkExpr &:= " || ";
    end if;
    checkExpr &:= sourceLenName;
    checkExpr &:= "-1>";
    if destArrayType in typeData.array_maxIdx then
      checkExpr &:= integerLiteral(typeData.array_maxIdx[destArrayType]);
    else
      checkExpr &:= destName;
      checkExpr &:= "->max_position";
    end if;
    checkExpr &:= " - ";
    checkExpr &:= destPosName;
  end func;


const func string: defineSourceLenName (in string: sourceName,
    in type: sourceArrayType, inout expr_type: c_expr) is func

  result
    var string: sourceLenName is "";
  begin
    incr(c_expr.temp_num);
    sourceLenName := "sourceLen_" <& c_expr.temp_num;
    c_expr.temp_decls &:= "memSizeType ";
    c_expr.temp_decls &:= sourceLenName;
    c_expr.temp_decls &:= ";\n";
    c_expr.expr &:= sourceLenName;
    c_expr.expr &:= "= (memSizeType) ((uintType) ";
    if sourceArrayType in typeData.array_maxIdx then
      c_expr.expr &:= integerLiteral(typeData.array_maxIdx[sourceArrayType]);
    else
      c_expr.expr &:= sourceName;
      c_expr.expr &:= "->max_position";
    end if;
    c_expr.expr &:= " - (uintType) ";
    if sourceArrayType in typeData.array_minIdx then
      c_expr.expr &:= integerLiteral(typeData.array_minIdx[sourceArrayType]);
    else
      c_expr.expr &:= sourceName;
      c_expr.expr &:= "->min_position";
    end if;
    c_expr.expr &:= " + 1);\n";
  end func;


const proc: process_inline_arr_poscpy_subarr_fixlen (in reference: dest,
    in reference: destPos, in reference: source, in reference: sourcePos,
    in reference: sourceLen, in type: destArrayType, inout expr_type: c_expr) is func

  local
    var type: sourceArrayType is void;
    var intRange: destPosRange is intRange.value;
    var intRange: sourcePosRange is intRange.value;
    var intRange: sourceLenRange is intRange.value;
    var string: destName is "";
    var string: sourceName is "";
    var reference: evaluatedParam is NIL;
    var boolean: destPosIsVariable is TRUE;
    var integer: destPosValue is 0;
    var string: destPosName is "";
    var boolean: sourcePosIsVariable is TRUE;
    var integer: sourcePosValue is 0;
    var string: sourcePosName is "";
    var boolean: sourceLenIsVariable is TRUE;
    var integer: sourceLenValue is 0;
    var string: sourceLenName is "";
    var boolean: sourceLenMightBe0 is FALSE;
    var expr_type: statement is expr_type.value;
    var string: checkExpr is "";
    var string: checkExpr1 is "";
  begin
    sourceArrayType := getExprResultType(source);
    destPosRange := getIntRange(destPos);
    sourcePosRange := getIntRange(sourcePos);
    sourceLenRange := getIntRange(sourceLen);
    if destArrayType in typeData.array_minIdx and
        destPosRange.maxValue < typeData.array_minIdx[destArrayType] then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= raiseError("INDEX_ERROR");
    elsif sourceArrayType in typeData.array_minIdx and
        sourcePosRange.maxValue < typeData.array_minIdx[sourceArrayType] then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= raiseError("INDEX_ERROR");
    elsif sourceArrayType in typeData.array_maxIdx and
        sourcePosRange.minValue > typeData.array_maxIdx[sourceArrayType] then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= raiseError("INDEX_ERROR");
    elsif sourceLenRange.maxValue < 0 then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= raiseError("INDEX_ERROR");
    else
      statement.temp_num := c_expr.temp_num;
      destName := getParameterAsReference(type_name(destArrayType),
                                          "dest_", dest, statement);
      sourceName := defineParameterAsVariable(type_name(sourceArrayType),
                                              "src_", source, statement);

      if getConstant(destPos, INTOBJECT, evaluatedParam) then
        destPosIsVariable := FALSE;
        destPosValue := getValue(evaluatedParam, integer);
        destPosName := integerLiteral(destPosValue);
      else
        destPosName := defineParameterAsVariable("intType", "destPos_",
                                                   destPos, statement);
      end if;
      if getConstant(sourcePos, INTOBJECT, evaluatedParam) then
        sourcePosIsVariable := FALSE;
        sourcePosValue := getValue(evaluatedParam, integer);
        sourcePosName := integerLiteral(sourcePosValue);
      else
        sourcePosName := defineParameterAsVariable("intType", "sourcePos_",
                                                   sourcePos, statement);
      end if;
      if getConstant(sourceLen, INTOBJECT, evaluatedParam) then
        sourceLenIsVariable := FALSE;
        sourceLenValue := getValue(evaluatedParam, integer);
        sourceLenName := integerLiteral(sourceLenValue);
      else
        sourceLenName := defineParameterAsVariable("intType", "sourceLen_",
                                                   sourceLen, statement);
      end if;

      if config.array_index_check then
        if sourceLenIsVariable and sourceLenRange.minValue < 0 then
          checkExpr &:= sourceLenName;
          checkExpr &:= " < 0";
        end if;
        if not sourceLenIsVariable then
          if sourceLenValue = 0 then
            checkExpr1 := checkDestPos0(destName, destPosName,
                                        destPosRange, destArrayType);
            if checkExpr1 <> "" then
              if checkExpr <> "" then
                checkExpr &:= " || ";
              end if;
              checkExpr &:= checkExpr1;
            end if;
          else
            checkExpr1 :=  checkDestPos(destName, destPosName, destPosRange, destArrayType);
            if checkExpr1 <> "" then
              if checkExpr <> "" then
                checkExpr &:= " || ";
              end if;
              checkExpr &:= checkExpr1;
            end if;
            if checkExpr <> "" then
              checkExpr &:= " || ";
            end if;
            checkExpr &:= checkDestPos(destName, sourceLenIsVariable, sourceLenValue,
                                       sourceLenName, destPosIsVariable, destPosValue, destPosName, destArrayType);
          end if;
        else
          if sourceLenRange.minValue <= 0 and
              sourceLenRange.maxValue >= 0 then
            if checkExpr <> "" then
              checkExpr &:= " || ";
            end if;
            checkExpr &:= "(";
            checkExpr &:= sourceLenName;
            checkExpr &:= " == 0 ? ";
            checkExpr1 := checkDestPos0(destName, destPosName,
                                        destPosRange, destArrayType);
            if checkExpr1 <> "" then
              checkExpr &:= "(";
              checkExpr &:= checkExpr1;
              checkExpr &:= ") : (";
            else
              checkExpr &:= "0 : (";
            end if;
            sourceLenMightBe0 := TRUE;
          end if;
          checkExpr1 :=  checkDestPos(destName, destPosName, destPosRange, destArrayType);
          if checkExpr1 <> "" then
            if checkExpr <> "" and not sourceLenMightBe0 then
              checkExpr &:= " || ";
            end if;
            checkExpr &:= checkExpr1;
            if checkExpr <> "" then
              checkExpr &:= " || ";
            end if;
          end if;
          checkExpr &:= checkDestPos(destName, sourceLenIsVariable, sourceLenValue,
                                     sourceLenName, destPosIsVariable, destPosValue, destPosName, destArrayType);
          if sourceLenMightBe0 then
            checkExpr &:= "))";
          end if;
        end if;
        if sourceArrayType not in typeData.array_minIdx or
           sourcePosRange.minValue < typeData.array_minIdx[sourceArrayType] then
          if checkExpr <> "" then
            checkExpr &:= " || ";
          end if;
          checkExpr &:= sourcePosName;
          checkExpr &:= "<";
          if sourceArrayType in typeData.array_minIdx then
            checkExpr &:= integerLiteral(typeData.array_minIdx[sourceArrayType]);
          else
            checkExpr &:= sourceName;
            checkExpr &:= "->min_position";
          end if;
        end if;
        if sourceArrayType not in typeData.array_maxIdx or
            sourcePosRange.maxValue > typeData.array_maxIdx[sourceArrayType] then
          if checkExpr <> "" then
            checkExpr &:= " || ";
          end if;
          checkExpr &:= sourcePosName;
          checkExpr &:= ">";
          if sourceArrayType in typeData.array_maxIdx then
            checkExpr &:= integerLiteral(typeData.array_maxIdx[sourceArrayType]);
          else
            checkExpr &:= sourceName;
            checkExpr &:= "->max_position";
          end if;
        end if;
        if checkExpr <> "" then
          checkExpr &:= " || ";
        end if;
        if not sourceLenIsVariable and not sourcePosIsVariable and
            sourcePosValue <= integer.last - sourceLenValue and
            sourcePosValue <> integer.first then
          checkExpr &:= integerLiteral(pred(sourceLenValue + sourcePosValue));
          checkExpr &:= ">";
          if sourceArrayType in typeData.array_maxIdx then
            checkExpr &:= integerLiteral(typeData.array_maxIdx[sourceArrayType]);
          else
            checkExpr &:= sourceName;
            checkExpr &:= "->max_position";
          end if;
        else
          checkExpr &:= "(uintType) ";
          checkExpr &:= sourceLenName;
          checkExpr &:= " > (memSizeType) ((uintType) (";
          if sourceArrayType in typeData.array_maxIdx then
            checkExpr &:= integerLiteral(typeData.array_maxIdx[sourceArrayType]);
          else
            checkExpr &:= sourceName;
            checkExpr &:= "->max_position";
          end if;
          checkExpr &:= ") - (uintType) ";
          if not sourcePosIsVariable then
            checkExpr &:= integerLiteral(pred(sourcePosValue));
          else
            checkExpr &:= sourcePosName;
            checkExpr &:= " + 1";
          end if;
          checkExpr &:= ")";
        end if;

        statement.expr &:= "if (idxChk(";
        statement.expr &:= checkExpr;
        statement.expr &:= ")) {\n";
        statement.expr &:= raiseError("INDEX_ERROR");
        statement.expr &:= "} else {\n";
      end if;

      statement.expr &:= "memmove(&";
      statement.expr &:= destName;
      statement.expr &:= "->arr[";
      statement.expr &:= destPosName;
      if destArrayType in typeData.array_minIdx then
        if typeData.array_minIdx[destArrayType] <> 0 then
          statement.expr &:= "- ";
          statement.expr &:= integerLiteral(typeData.array_minIdx[destArrayType]);
        end if;
      else
        statement.expr &:= "- ";
        statement.expr &:= destName;
        statement.expr &:= "->min_position";
      end if;
      statement.expr &:= "], &";
      statement.expr &:= sourceName;
      statement.expr &:= "->arr[";
      statement.expr &:= sourcePosName;
      if sourceArrayType in typeData.array_minIdx then
        if typeData.array_minIdx[sourceArrayType] <> 0 then
          statement.expr &:= "- ";
          statement.expr &:= integerLiteral(typeData.array_minIdx[sourceArrayType]);
        end if;
      else
        statement.expr &:= "- ";
        statement.expr &:= sourceName;
        statement.expr &:= "->min_position";
      end if;
      statement.expr &:= "], ";
      statement.expr &:= sourceLenName;
      statement.expr &:= "  * sizeof(rtlObjectType));\n";

      if config.array_index_check then
        statement.expr &:= "}\n";
      end if;
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process_inline_arr_poscpy_const_source_len (in string: destName,
    in string: destPosName, in string: sourceName, in type: destArrayType,
    in type: sourceArrayType, in intRange: positionRange,
    inout expr_type: c_expr) is func

  local
    var integer: sourceLen is 0;
  begin
    sourceLen := succ(typeData.array_maxIdx[sourceArrayType] -
                       typeData.array_minIdx[sourceArrayType]);
    if sourceLen = 0 then
      if  (destArrayType not in typeData.array_minIdx or
           positionRange.minValue < typeData.array_minIdx[destArrayType]) and
          (destArrayType not in typeData.array_maxIdx or
           positionRange.maxValue > typeData.array_maxIdx[destArrayType]) then
        c_expr.expr &:= "if (idxChk(";
        c_expr.expr &:= checkDestPos0(destName, destPosName,
                                      positionRange, destArrayType);
        c_expr.expr &:= ")) {\n";
        c_expr.expr &:= raiseError("INDEX_ERROR");
        c_expr.expr &:= "}\n";
      end if;
    else
      c_expr.expr &:= "if (idxChk(";
      c_expr.expr &:= checkDestPos(destName, destPosName,
                                   positionRange, destArrayType, sourceLen);
      c_expr.expr &:= ")) {\n";
      c_expr.expr &:= raiseError("INDEX_ERROR");
      c_expr.expr &:= "} else {\n";
      c_expr.expr &:= "memmove(&";
      c_expr.expr &:= destName;
      c_expr.expr &:= "->arr[";
      c_expr.expr &:= destPosName;
      if destArrayType in typeData.array_minIdx then
        if typeData.array_minIdx[destArrayType] <> 0 then
          c_expr.expr &:= "- ";
          c_expr.expr &:= integerLiteral(typeData.array_minIdx[destArrayType]);
        end if;
      else
        c_expr.expr &:= "- ";
        c_expr.expr &:= destName;
        c_expr.expr &:= "->min_position";
      end if;
      c_expr.expr &:= "], ";
      c_expr.expr &:= sourceName;
      c_expr.expr &:= "->arr, ";
      c_expr.expr &:= integerLiteral(sourceLen);
      c_expr.expr &:= "  * sizeof(rtlObjectType));\n";
      c_expr.expr &:= "}\n";
    end if;
  end func;


const proc: process_inline_arr_poscpy (in string: destName,
    in string: destPosName, in string: sourceName, in type: destArrayType,
    in type: sourceArrayType, in intRange: positionRange,
    inout expr_type: c_expr) is func

  local
    var string: sourceLenName is "";
  begin
    sourceLenName := defineSourceLenName(sourceName, sourceArrayType, c_expr);
    c_expr.expr &:= "if (";
    c_expr.expr &:= sourceLenName;
    c_expr.expr &:= " == 0) {\n";
    if  (destArrayType not in typeData.array_minIdx or
         positionRange.minValue < typeData.array_minIdx[destArrayType]) and
        (destArrayType not in typeData.array_maxIdx or
         positionRange.maxValue > typeData.array_maxIdx[destArrayType]) then
      c_expr.expr &:= "if (idxChk(";
      c_expr.expr &:= checkDestPos0(destName, destPosName,
                                    positionRange, destArrayType);
      c_expr.expr &:= ")) {\n";
      c_expr.expr &:= raiseError("INDEX_ERROR");
      c_expr.expr &:= "}\n";
    end if;
    c_expr.expr &:= "} else if (idxChk(";
    c_expr.expr &:= checkDestPos(destName, destPosName,
                                 positionRange, destArrayType,
                                 sourceLenName);
    c_expr.expr &:= ")) {\n";
    c_expr.expr &:= raiseError("INDEX_ERROR");
    c_expr.expr &:= "} else {\n";
    c_expr.expr &:= "memmove(&";
    c_expr.expr &:= destName;
    c_expr.expr &:= "->arr[";
    c_expr.expr &:= destPosName;
    if destArrayType in typeData.array_minIdx then
      if typeData.array_minIdx[destArrayType] <> 0 then
        c_expr.expr &:= "- ";
        c_expr.expr &:= integerLiteral(typeData.array_minIdx[destArrayType]);
      end if;
    else
      c_expr.expr &:= "- ";
      c_expr.expr &:= destName;
      c_expr.expr &:= "->min_position";
    end if;
    c_expr.expr &:= "], ";
    c_expr.expr &:= sourceName;
    c_expr.expr &:= "->arr, ";
    c_expr.expr &:= sourceLenName;
    c_expr.expr &:= "  * sizeof(rtlObjectType));\n";
    c_expr.expr &:= "}\n";
  end func;


const proc: process_inline_arr_poscpy_no_check (in reference: dest,
    in reference: destPos, in reference: source, in type: destArrayType,
    in type: sourceArrayType, inout expr_type: c_expr) is func
  local
    var string: destName is "";
    var string: sourceName is "";
  begin
    incr(count.suppressedIndexChecks);
    destName := getParameterAsReference(type_name(destArrayType),
                                        "dest_", dest, c_expr);
    sourceName := defineParameterAsVariable(type_name(sourceArrayType),
                                            "src_", source, c_expr);
    c_expr.expr &:= "memmove(&";
    c_expr.expr &:= destName;
    c_expr.expr &:= "->arr[(";
    process_expr(destPos, c_expr);
    c_expr.expr &:= ")";
    if destArrayType in typeData.array_minIdx then
      if typeData.array_minIdx[destArrayType] <> 0 then
        c_expr.expr &:= "- ";
        c_expr.expr &:= integerLiteral(typeData.array_minIdx[destArrayType]);
      end if;
    else
      c_expr.expr &:= "- ";
      c_expr.expr &:= destName;
      c_expr.expr &:= "->min_position";
    end if;
    c_expr.expr &:= "], ";
    c_expr.expr &:= sourceName;
    c_expr.expr &:= "->arr, (memSizeType) ((uintType) ";
    if sourceArrayType in typeData.array_maxIdx then
      c_expr.expr &:= integerLiteral(typeData.array_maxIdx[sourceArrayType]);
    else
      c_expr.expr &:= sourceName;
      c_expr.expr &:= "->max_position";
    end if;
    c_expr.expr &:= " - (uintType) ";
    if sourceArrayType in typeData.array_minIdx then
      c_expr.expr &:= integerLiteral(typeData.array_minIdx[sourceArrayType]);
    else
      c_expr.expr &:= sourceName;
      c_expr.expr &:= "->min_position";
    end if;
    c_expr.expr &:= " + 1) * sizeof(rtlObjectType));\n";
  end func;


const proc: process_inline_arr_poscpy (in reference: dest,
    in reference: destPos, in reference: source, in type: destArrayType,
    in type: elementType,  inout expr_type: c_expr) is func

  local
    var expr_type: statement is expr_type.value;
    var intRange: destPosRange is intRange.value;
    var string: destName is "";
    var string: destPosName is "";
    var string: sourceName is "";
    var type: sourceArrayType is void;
  begin
    if isActionExpression(source, "ARR_SUBARR_FIXLEN") then
      process_inline_arr_poscpy_subarr_fixlen(dest, destPos,
          getActionParameter(source, 1), getActionParameter(source, 3),
          getActionParameter(source, 5), destArrayType, c_expr);
    else
      sourceArrayType := getExprResultType(source);
      statement.temp_num := c_expr.temp_num;
      if config.array_index_check then
        destPosRange := getIntRange(destPos);
        if destArrayType in typeData.array_minIdx and
            destPosRange.maxValue < typeData.array_minIdx[destArrayType] then
          warning(DOES_RAISE, "INDEX_ERROR", statement);
          statement.expr &:= raiseError("INDEX_ERROR");
        else
          destName := getParameterAsReference(type_name(destArrayType),
                                              "dest_", dest, statement);
          destPosName := defineParameterAsVariable("intType", "pos_",
                                                   destPos, statement);
          sourceName := defineParameterAsVariable(type_name(sourceArrayType),
                                                  "src_", source, statement);
          if sourceArrayType in typeData.array_minIdx and
              sourceArrayType in typeData.array_maxIdx then
            process_inline_arr_poscpy_const_source_len(destName,
                destPosName, sourceName, destArrayType,
                sourceArrayType, destPosRange, statement);
          else
            process_inline_arr_poscpy(destName, destPosName,
                sourceName, destArrayType, sourceArrayType,
                destPosRange, statement);
          end if;
        end if;
      else
        process_inline_arr_poscpy_no_check(dest, destPos, source,
            destArrayType, sourceArrayType, statement);
      end if;
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process (ARR_POSCPY, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var type: arrayType is void;
    var type: elementType is void;
    var expr_type: c_param6 is expr_type.value;
    var expr_type: statement is expr_type.value;
    var string: destName is "";
    var string: sourceName is "";
  begin
    checkGlobalVariableChange(params[1], c_expr);
    arrayType := getExprResultType(params[1]);
    elementType := typeData.array_element[arrayType];
    if config.inlineFunctions and
        elementType in typeData.typeCategory and
        typeData.typeCategory[elementType] in simpleValueType then
      process_inline_arr_poscpy(params[1], params[4], params[6],
                                arrayType, elementType, c_expr);
    else
      statement.temp_num := c_expr.temp_num;
      destName := getParameterAsReference(type_name(arrayType),
                                          "arr_", params[1], statement);
      prepareAnyParamTemporarys(params[6], c_param6, statement);
      if c_param6.result_expr <> "" then
        if elementType in typeData.typeCategory and
            typeData.typeCategory[elementType] in simpleValueType then
          incr(statement.temp_num);
          sourceName := "source_" <& statement.temp_num;
          statement.temp_decls &:= type_name(arrayType);
          statement.temp_decls &:= " ";
          statement.temp_decls &:= sourceName;
          statement.temp_decls &:= ";\n";
          statement.expr &:= sourceName;
          statement.expr &:= "=";
          statement.expr &:= c_param6.result_expr;
          statement.expr &:= ";\n";
          statement.expr &:= "arrPoscpy(";
          statement.expr &:= destName;
          statement.expr &:= ", ";
          process_expr(params[4], statement);
          statement.expr &:= ", ";
          statement.expr &:= sourceName;
          statement.expr &:= ");\n";
          statement.expr &:= "arrFree((arrayType)(";
          statement.expr &:= sourceName;
          statement.expr &:= "));\n";
        else
          process_arr_poscpy_temp_declaration(elementType, global_c_expr);
          statement.expr &:= "poscpy_temp_";
          statement.expr &:= str(typeNumber(elementType));
          statement.expr &:= "((arrayType)(";
          statement.expr &:= destName;
          statement.expr &:= "), ";
          process_expr(params[4], statement);
          statement.expr &:= ", (arrayType)(";
          statement.expr &:= c_param6.result_expr;
          statement.expr &:= "));\n";
        end if;
      else
        if elementType in typeData.typeCategory and
            typeData.typeCategory[elementType] in simpleValueType then
          statement.expr &:= "arrPoscpy(";
          statement.expr &:= destName;
          statement.expr &:= ", ";
          process_expr(params[4], statement);
          statement.expr &:= ", ";
          statement.expr &:= c_param6.expr;
          statement.expr &:= ");\n";
        else
          process_arr_poscpy_declaration(elementType, global_c_expr);
          statement.expr &:= "poscpy_";
          statement.expr &:= str(typeNumber(elementType));
          statement.expr &:= "((arrayType)(";
          statement.expr &:= destName;
          statement.expr &:= "), ";
          process_expr(params[4], statement);
          statement.expr &:= ", (arrayType)(";
          statement.expr &:= c_param6.expr;
          statement.expr &:= "));\n";
        end if;
      end if;
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process (ARR_PUSH, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var expr_type: c_param1 is expr_type.value;
    var expr_type: c_param3 is expr_type.value;
  begin
    checkGlobalVariableChange(params[1], c_expr);
    if getType(params[1]) not in typeData.array_element then
      typeData.array_element @:= [getType(params[1])] getType(params[3]);
    end if;
    process_expr(params[1], c_param1);
    c_param3.temp_num := c_param1.temp_num;
    getRtlValueTemporaryToResultExpr(params[3], c_param3);
    incr(c_param3.temp_num);
    if has_temp_values(c_param3) then
      c_expr.expr &:= "{\n";
      appendWithDiagnostic(c_param1.temp_decls, c_expr);
      appendWithDiagnostic(c_param3.temp_decls, c_expr);
      appendWithDiagnostic(c_param1.temp_assigns, c_expr);
      appendWithDiagnostic(c_param3.temp_assigns, c_expr);
    end if;
    setDiagnosticLine(c_expr);
    c_expr.expr &:= "arrPush(&(";
    c_expr.expr &:= c_param1.expr;
    c_expr.expr &:= "), (";
    c_expr.expr &:= c_param3.result_expr;
    c_expr.expr &:= "));\n";
    if has_temp_values(c_param3) then
      appendWithDiagnostic(c_param1.temp_frees, c_expr);
      appendWithDiagnostic(c_param3.temp_frees, c_expr);
      c_expr.expr &:= "}\n";
    end if;
  end func;


const proc: process (ARR_RANGE, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var type: param_type is void;
    var expr_type: c_param is expr_type.value;
    var string: slice_name is "";
    var string: array_name is "";
  begin
    param_type := getExprResultType(params[1]);
    prepare_typed_result(param_type, c_expr);
    prepareAnyParamTemporarys(params[1], c_param, c_expr);
    if c_param.result_expr <> "" then
      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_expr.result_expr &:= c_param.result_intro;
      c_expr.result_expr &:= c_param.result_expr;
      c_expr.result_expr &:= c_param.result_finish;
      c_expr.result_expr &:= ", arrRangeTemp(&(";
      c_expr.result_expr &:= c_param.result_name;
      c_expr.result_expr &:= "), ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[5], c_expr);
      c_expr.result_expr &:= "))";
    elsif ccConf.ALLOW_RTL_ARRAY_SLICES and c_expr.demand < REQUIRE_RESULT then
      c_expr.expr &:= "(";
      incr(c_expr.temp_num);
      slice_name := "slice_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "struct rtlArrayStruct ";
      c_expr.temp_decls &:= slice_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= "arrRangeSlice(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[5], c_expr);
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
    elsif valueIsAtHeap(typeData.array_element[param_type]) then
      incr(c_expr.temp_num);
      array_name := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "arrayType ";
      c_expr.temp_decls &:= array_name;
      c_expr.temp_decls &:= "=NULL;\n";
      c_expr.temp_frees &:= "if (";
      c_expr.temp_frees &:= array_name;
      c_expr.temp_frees &:= " != NULL) {arrFree(";
      c_expr.temp_frees &:= array_name;
      c_expr.temp_frees &:= ");}\n";
      c_expr.temp_to_null &:= array_name;
      c_expr.temp_to_null &:= "=NULL;\n";
      c_expr.result_expr := "(";
      c_expr.result_expr &:= array_name;
      c_expr.result_expr &:= "=arrRange(";
      c_expr.result_expr &:= c_param.expr;
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[5], c_expr);
      c_expr.result_expr &:= "), ";
      typeData.typeCategory @:= [param_type] ARRAYOBJECT;
      process_create_declaration(param_type, global_c_expr);
      process_create_call(param_type, array_name, c_expr.result_expr);
      c_expr.result_expr &:= ")";
    else
      c_expr.result_expr := "arrRange(";
      c_expr.result_expr &:= c_param.expr;
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[5], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process (ARR_REMOVE, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var type: proc_type is void;
    var type: result_type is void;
  begin
    checkGlobalVariableChange(params[1], c_expr);
    proc_type := getType(function);
    result_type := resultType(proc_type);
    if valueIsAtHeap(result_type) then
      prepare_typed_result(result_type, c_expr);
      c_expr.result_expr &:= "arrRemove(&(";
      getStdParamToResultExpr(params[1], c_expr);
      c_expr.result_expr &:= "), ";
      getStdParamToResultExpr(params[2], c_expr);
      c_expr.result_expr &:= ").";
      c_expr.result_expr &:= raw_type_value(result_type);
    else
      c_expr.expr &:= "arrRemove(&(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= "), ";
      process_expr(params[2], c_expr);
      c_expr.expr &:= ").";
      c_expr.expr &:= raw_type_value(result_type);
    end if;
  end func;


const proc: process (ARR_REMOVE_ARRAY, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var type: param_type is void;
  begin
    checkGlobalVariableChange(params[1], c_expr);
    param_type := getExprResultType(params[1]);
    prepare_typed_result(param_type, c_expr);
    c_expr.result_expr := "arrRemoveArray(&(";
    getStdParamToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= "), ";
    getStdParamToResultExpr(params[2], c_expr);
    c_expr.result_expr &:= ", ";
    getStdParamToResultExpr(params[3], c_expr);
    c_expr.result_expr &:= ")";
  end func;


const proc: process (ARR_SORT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    declare_func_pointer_if_necessary(params[2], global_c_expr);
    prepare_typed_result(getExprResultType(params[1]), c_expr);
    c_expr.result_expr := "arrSort(";
    getTemporaryToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", (compareFuncType)(";
    getStdParamToResultExpr(params[2], c_expr);
    c_expr.result_expr &:= "))";
  end func;


const proc: process (ARR_SORT_REVERSE, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    declare_func_pointer_if_necessary(params[2], global_c_expr);
    prepare_typed_result(getExprResultType(params[1]), c_expr);
    c_expr.result_expr := "arrSortReverse(";
    getTemporaryToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", (compareFuncType)(";
    getStdParamToResultExpr(params[2], c_expr);
    c_expr.result_expr &:= "))";
  end func;


const proc: process (ARR_SUBARR, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var type: param_type is void;
    var expr_type: c_param is expr_type.value;
    var string: slice_name is "";
    var string: array_name is "";
  begin
    param_type := getExprResultType(params[1]);
    prepare_typed_result(param_type, c_expr);
    prepareAnyParamTemporarys(params[1], c_param, c_expr);
    if c_param.result_expr <> "" then
      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_expr.result_expr &:= c_param.result_intro;
      c_expr.result_expr &:= c_param.result_expr;
      c_expr.result_expr &:= c_param.result_finish;
      c_expr.result_expr &:= ", arrSubarrTemp(&(";
      c_expr.result_expr &:= c_param.result_name;
      c_expr.result_expr &:= "), ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[5], c_expr);
      c_expr.result_expr &:= "))";
    elsif ccConf.ALLOW_RTL_ARRAY_SLICES and c_expr.demand < REQUIRE_RESULT then
      c_expr.expr &:= "(";
      incr(c_expr.temp_num);
      slice_name := "slice_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "struct rtlArrayStruct ";
      c_expr.temp_decls &:= slice_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= "arrSubarrSlice(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[5], c_expr);
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
    elsif valueIsAtHeap(typeData.array_element[param_type]) then
      incr(c_expr.temp_num);
      array_name := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "arrayType ";
      c_expr.temp_decls &:= array_name;
      c_expr.temp_decls &:= "=NULL;\n";
      c_expr.temp_frees &:= "if (";
      c_expr.temp_frees &:= array_name;
      c_expr.temp_frees &:= " != NULL) {arrFree(";
      c_expr.temp_frees &:= array_name;
      c_expr.temp_frees &:= ");}\n";
      c_expr.temp_to_null &:= array_name;
      c_expr.temp_to_null &:= "=NULL;\n";
      c_expr.result_expr := "(";
      c_expr.result_expr &:= array_name;
      c_expr.result_expr &:= "=arrSubarr(";
      c_expr.result_expr &:= c_param.expr;
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[5], c_expr);
      c_expr.result_expr &:= "), ";
      typeData.typeCategory @:= [param_type] ARRAYOBJECT;
      process_create_declaration(param_type, global_c_expr);
      process_create_call(param_type, array_name, c_expr.result_expr);
      c_expr.result_expr &:= ")";
    else
      c_expr.result_expr := "arrSubarr(";
      c_expr.result_expr &:= c_param.expr;
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[5], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process (ARR_SUBARR_FIXLEN, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var type: param_type is void;
    var expr_type: c_param is expr_type.value;
    var string: slice_name is "";
    var string: array_name is "";
  begin
    param_type := getExprResultType(params[1]);
    prepare_typed_result(param_type, c_expr);
    prepareAnyParamTemporarys(params[1], c_param, c_expr);
    if c_param.result_expr <> "" then
      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_expr.result_expr &:= c_param.result_intro;
      c_expr.result_expr &:= c_param.result_expr;
      c_expr.result_expr &:= c_param.result_finish;
      c_expr.result_expr &:= ", arrSubarrFixLenTemp(&(";
      c_expr.result_expr &:= c_param.result_name;
      c_expr.result_expr &:= "), ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[5], c_expr);
      c_expr.result_expr &:= "))";
    elsif ccConf.ALLOW_RTL_ARRAY_SLICES and c_expr.demand < REQUIRE_RESULT then
      c_expr.expr &:= "(";
      incr(c_expr.temp_num);
      slice_name := "slice_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "struct rtlArrayStruct ";
      c_expr.temp_decls &:= slice_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= "arrSubarrFixLenSlice(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[5], c_expr);
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
    elsif valueIsAtHeap(typeData.array_element[param_type]) then
      incr(c_expr.temp_num);
      array_name := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "arrayType ";
      c_expr.temp_decls &:= array_name;
      c_expr.temp_decls &:= "=NULL;\n";
      c_expr.temp_frees &:= "if (";
      c_expr.temp_frees &:= array_name;
      c_expr.temp_frees &:= " != NULL) {arrFree(";
      c_expr.temp_frees &:= array_name;
      c_expr.temp_frees &:= ");}\n";
      c_expr.temp_to_null &:= array_name;
      c_expr.temp_to_null &:= "=NULL;\n";
      c_expr.result_expr := "(";
      c_expr.result_expr &:= array_name;
      c_expr.result_expr &:= "=arrSubarrFixLen(";
      c_expr.result_expr &:= c_param.expr;
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[5], c_expr);
      c_expr.result_expr &:= "), ";
      typeData.typeCategory @:= [param_type] ARRAYOBJECT;
      process_create_declaration(param_type, global_c_expr);
      process_create_call(param_type, array_name, c_expr.result_expr);
      c_expr.result_expr &:= ")";
    else
      c_expr.result_expr := "arrSubarrFixLen(";
      c_expr.result_expr &:= c_param.expr;
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[5], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process (ARR_TAIL, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var type: param_type is void;
    var expr_type: c_param is expr_type.value;
    var string: slice_name is "";
    var string: array_name is "";
  begin
    param_type := getExprResultType(params[1]);
    prepare_typed_result(param_type, c_expr);
    prepareAnyParamTemporarys(params[1], c_param, c_expr);
    if c_param.result_expr <> "" then
      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_expr.result_expr &:= c_param.result_intro;
      c_expr.result_expr &:= c_param.result_expr;
      c_expr.result_expr &:= c_param.result_finish;
      c_expr.result_expr &:= ", arrTailTemp(&(";
      c_expr.result_expr &:= c_param.result_name;
      c_expr.result_expr &:= "), ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= "))";
    elsif ccConf.ALLOW_RTL_ARRAY_SLICES and c_expr.demand < REQUIRE_RESULT then
      c_expr.expr &:= "(";
      incr(c_expr.temp_num);
      slice_name := "slice_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "struct rtlArrayStruct ";
      c_expr.temp_decls &:= slice_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= "arrTailSlice(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
    elsif valueIsAtHeap(typeData.array_element[param_type]) then
      incr(c_expr.temp_num);
      array_name := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "arrayType ";
      c_expr.temp_decls &:= array_name;
      c_expr.temp_decls &:= "=NULL;\n";
      c_expr.temp_frees &:= "if (";
      c_expr.temp_frees &:= array_name;
      c_expr.temp_frees &:= " != NULL) {arrFree(";
      c_expr.temp_frees &:= array_name;
      c_expr.temp_frees &:= ");}\n";
      c_expr.temp_to_null &:= array_name;
      c_expr.temp_to_null &:= "=NULL;\n";
      c_expr.result_expr := "(";
      c_expr.result_expr &:= array_name;
      c_expr.result_expr &:= "=arrTail(";
      c_expr.result_expr &:= c_param.expr;
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= "), ";
      typeData.typeCategory @:= [param_type] ARRAYOBJECT;
      process_create_declaration(param_type, global_c_expr);
      process_create_call(param_type, array_name, c_expr.result_expr);
      c_expr.result_expr &:= ")";
    else
      c_expr.result_expr := "arrTail(";
      c_expr.result_expr &:= c_param.expr;
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: two_dimensional_times_optimization (in type: result_type,
    in reference: factor1, in reference: factor2, inout expr_type: c_expr) is func

  local
    var string: factor1Name is "";
    var string: factor2Name is "";
    var string: resultName is "";
  begin
    incr(count.optimizations);
    prepare_typed_result(result_type, c_expr);
    c_expr.result_expr := "({";
    factor1Name := defineTempVariable("intType", "factor1_", c_expr);
    factor2Name := getParameterInResultStatement("intType",
        "factor2_", factor2, c_expr);
    resultName := defineTempVariable("arrayType", "times_res_", c_expr);
    c_expr.result_expr &:= factor1Name;
    c_expr.result_expr &:= "=(";
    getStdParamToResultExpr(factor1, c_expr);
    c_expr.result_expr &:= ");\n";
    c_expr.result_expr &:= resultName;
    c_expr.result_expr &:= "=arrMalloc(1, ";
    c_expr.result_expr &:= factor1Name;
    c_expr.result_expr &:= ");\n";
    c_expr.result_expr &:= "while (";
    c_expr.result_expr &:= factor1Name;
    c_expr.result_expr &:= "!=0) {\n";
    c_expr.result_expr &:= factor1Name;
    c_expr.result_expr &:= "--;\n";
    c_expr.result_expr &:= resultName;
    c_expr.result_expr &:= "->arr[";
    c_expr.result_expr &:= factor1Name;
    c_expr.result_expr &:= "].value.arrayValue=arrTimes0(1, ";
    c_expr.result_expr &:= factor2Name;
    c_expr.result_expr &:= ");\n";
    c_expr.result_expr &:= "}\n";
    c_expr.result_expr &:= resultName;
    c_expr.result_expr &:= ";})";
  end func;


const proc: process (ARR_TIMES, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var type: result_type is void;
    var type: element_type is void;
  begin
    result_type := resultType(getType(function));
    typeData.typeCategory @:= [result_type] ARRAYOBJECT;
    if getConstant(params[1], INTOBJECT, evaluatedParam) and
        getValue(evaluatedParam, integer) = 0 then
      incr(count.optimizations);
      prepare_typed_result(result_type, c_expr);
      c_expr.result_expr := "arrMalloc(1, 0)";
    elsif config.inlineFunctions and ccConf.STMT_BLOCK_IN_PARENTHESES_OK and
        isActionExpression(params[3], "ARR_TIMES") and
        getConstant(getActionParameter(params[3], 3), INTOBJECT, evaluatedParam) and
        getValue(evaluatedParam, integer) = 0 then
      two_dimensional_times_optimization(result_type, params[1],
          getActionParameter(params[3], 1), c_expr);
    else
      element_type := getType(formalParams(function)[3]);
      if element_type in typeData.typeCategory and
          typeData.typeCategory[element_type] in simpleValueType then
        incr(count.optimizations);
        prepare_typed_result(result_type, c_expr);
        c_expr.result_expr := "arrTimes(1, ";
        getStdParamToResultExpr(params[1], c_expr);
        c_expr.result_expr &:= ", ";
        getRtlValueToResultExpr(params[3], c_expr);
        c_expr.result_expr &:= ")";
      else
        declare_times_prototype(result_type, element_type, global_c_expr);
        prepare_typed_result(result_type, c_expr);
        c_expr.result_expr := "times_";
        c_expr.result_expr &:= str(typeNumber(result_type));
        c_expr.result_expr &:= "(";
        getStdParamToResultExpr(params[1], c_expr);
        c_expr.result_expr &:= ", ";
        getAnyParamToResultExpr(params[3], c_expr);
        c_expr.result_expr &:= ")";
      end if;
    end if;
  end func;