(********************************************************************)
(*                                                                  *)
(*  bin_act.s7i   Generate code for bin32 and bin64 actions.        *)
(*  Copyright (C) 1990 - 1994, 2004 - 2017, 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: BIN_AND                 is action "BIN_AND";
const ACTION: BIN_AND_ASSIGN          is action "BIN_AND_ASSIGN";
const ACTION: BIN_BIG                 is action "BIN_BIG";
const ACTION: BIN_BINARY              is action "BIN_BINARY";
const ACTION: BIN_BIT_LENGTH          is action "BIN_BIT_LENGTH";
const ACTION: BIN_BYTES_BE_2_UINT     is action "BIN_BYTES_BE_2_UINT";
const ACTION: BIN_BYTES_LE_2_UINT     is action "BIN_BYTES_LE_2_UINT";
const ACTION: BIN_CARD                is action "BIN_CARD";
const ACTION: BIN_CMP                 is action "BIN_CMP";
const ACTION: BIN_GET_BINARY_FROM_SET is action "BIN_GET_BINARY_FROM_SET";
const ACTION: BIN_LOWEST_SET_BIT      is action "BIN_LOWEST_SET_BIT";
const ACTION: BIN_LSHIFT              is action "BIN_LSHIFT";
const ACTION: BIN_LSHIFT_ASSIGN       is action "BIN_LSHIFT_ASSIGN";
const ACTION: BIN_N_BYTES_BE          is action "BIN_N_BYTES_BE";
const ACTION: BIN_N_BYTES_LE          is action "BIN_N_BYTES_LE";
const ACTION: BIN_OR                  is action "BIN_OR";
const ACTION: BIN_OR_ASSIGN           is action "BIN_OR_ASSIGN";
const ACTION: BIN_radix               is action "BIN_radix";
const ACTION: BIN_RADIX               is action "BIN_RADIX";
const ACTION: BIN_RSHIFT              is action "BIN_RSHIFT";
const ACTION: BIN_RSHIFT_ASSIGN       is action "BIN_RSHIFT_ASSIGN";
const ACTION: BIN_STR                 is action "BIN_STR";
const ACTION: BIN_XOR                 is action "BIN_XOR";
const ACTION: BIN_XOR_ASSIGN          is action "BIN_XOR_ASSIGN";


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

  begin
    declareExtern(c_prog, "uintType    setToUInt (const const_setType, const intType);");
    declareExtern(c_prog, "uintType    uintBytesBe2UInt (const const_striType);");
    declareExtern(c_prog, "uintType    uintBytesLe2UInt (const const_striType);");
    declareExtern(c_prog, "intType     uintCard (uintType);");
    declareExtern(c_prog, "intType     uintCmp (uintType, uintType);");
    declareExtern(c_prog, "intType     uintCmpGeneric (const genericType, const genericType);");
    declareExtern(c_prog, "striType    uintNBytesBe (uintType, intType);");
    declareExtern(c_prog, "striType    uintNBytesLe (uintType, intType);");
    declareExtern(c_prog, "striType    uintRadix (uintType, intType, boolType);");
    declareExtern(c_prog, "striType    uintRadixPow2 (uintType, int, int, boolType);");
    declareExtern(c_prog, "striType    uintStr (uintType);");
    declareExtern(c_prog, "int         uint64LeastSignificantBit (uintType);");
    declareExtern(c_prog, "int         uint64MostSignificantBit (uintType);");
  end func;


const proc: process_str_substr_slice (in reference: stri,
    in reference: start, in reference: length, in string: slice_name,
    inout expr_type: c_expr) is forward;
const proc: process_str_substr_fixlen_slice (in reference: stri,
    in reference: start, in reference: length, in string: slice_name,
    inout expr_type: c_expr) is forward;
const proc: optimize_mod_dividend (in reference: dividend, inout expr_type: c_expr) is forward;


const proc: process_const_bin_and (in reference: bits1, in integer: bits2,
    inout expr_type: c_expr) is func

  begin
    if bits2 = 0 then
      incr(countOptimizations);
      c_expr.expr &:= "/*a & 0*/";
      c_expr.expr &:= integerLiteral(bits2);
    elsif modDividendOptimization then
      incr(countOptimizations);
      c_expr.expr &:= "(";
      if isActionExpression(bits1, "BIN_BINARY") then
        if bits2 > 0 and (bits2 = integer.last or
            2 ** log2(succ(bits2)) = succ(bits2)) then
          optimize_big_mod_dividend(getActionParameter(bits1, 1),
                                    succ(bigInteger(bits2)), c_expr);
        else
          optimize_big_mod_dividend(getActionParameter(bits1, 1),
                                    succ(bigInteger(bin64(-1))), c_expr);
        end if;
      else
        optimize_mod_dividend(bits1, c_expr);
      end if;
      c_expr.expr &:= ")";
      if bits2 <> ord(~bin64(0)) then
        c_expr.expr &:= " & ";
        c_expr.expr &:= integerLiteral(bits2);
      end if;
    else
      c_expr.expr &:= "(";
      process_expr(bits1, c_expr);
      c_expr.expr &:= ") & ";
      c_expr.expr &:= integerLiteral(bits2);
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
  begin
    if getConstant(params[1], INTOBJECT, evaluatedParam) then
      process_const_bin_and(params[3], getValue(evaluatedParam, integer), c_expr);
    elsif getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_bin_and(params[1], getValue(evaluatedParam, integer), c_expr);
    else
      c_expr.expr &:= "(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ") & (";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


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

  local
    var expr_type: statement is expr_type.value;
  begin
    process_expr(params[1], statement);
    statement.expr &:= "&=";
    process_expr(params[3], statement);
    statement.expr &:= ";\n";
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


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

  begin
    prepare_bigint_result(c_expr);
    c_expr.result_expr := "bigFromUInt64(";
    getAnyParamToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ")";
  end func;


const proc: optimize_bin_binary_of_big_mod (in reference: param1,
    in reference: dividend, in bigInteger: divisor,
    inout expr_type: c_expr) is func

  begin
    if divisor > 0_ and log2(divisor) <= 64_ and
        2_ ** ord(log2(divisor)) = divisor then
      optimize_big_mod_dividend(dividend, divisor, c_expr);
      if log2(divisor) < 64_ then
        c_expr.expr &:= "&";
        c_expr.expr &:= integerLiteral(ord(pred(divisor)));
      end if;
    else
      c_expr.expr &:= "bigToUInt64(";
      getAnyParamToExpr(param1, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
  begin
    if evaluate_const_expr >= 1 and
        isActionExpression(params[1], "BIG_MOD") and
        getConstant(getActionParameter(params[1], 3),
                    BIGINTOBJECT, evaluatedParam) then
      optimize_bin_binary_of_big_mod(params[1],
          getActionParameter(params[1], 1),
          getValue(evaluatedParam, bigInteger), c_expr);
    else
      c_expr.expr &:= "bigToUInt64(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


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

  begin
    c_expr.expr &:= "(intType) uint64MostSignificantBit(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ") + 1";
  end func;


const proc: optimize_bin_bytes_2_uint_length_0 (in reference: stri,
    in reference: start, in boolean: fixedLengthSubstring,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var boolean: stri_is_variable is TRUE;
    var string: stri_name is "";
    var integer: stri_length is 0;
    var string: stri_size is "";
    var intRange: start_range is intRange.value;
    var string: start_name is "";
    var boolean: raisesException is FALSE;
    var string: logicalOr is "";
  begin
    incr(countOptimizations);
    incr(countInlinedFunctions);
    start_range := getIntRange(start);
    c_expr.expr &:= "(";
    if start_range.maxValue < 1 then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("INDEX_ERROR");
      raisesException := TRUE;
    elsif getConstant(stri, STRIOBJECT, evaluatedParam) then
      stri_is_variable := FALSE;
      stri_length := length(getValue(evaluatedParam, string));
      stri_size := memSizeLiteral(stri_length);
      if start_range.minValue > stri_length then
        if fixedLengthSubstring then
          warning(DOES_RAISE, "INDEX_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("INDEX_ERROR");
        else
          warning(DOES_RAISE, "RANGE_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("RANGE_ERROR");
        end if;
        raisesException := TRUE;
      end if;
    else
      stri_name := getParameterAsVariable("const_striType", "stri_", stri, c_expr);
      stri_size := stri_name & "->size";
    end if;
    if not raisesException then
      if getConstant(start, INTOBJECT, evaluatedParam) then
        start_name := integerLiteral(getValue(evaluatedParam, integer));
      else
        start_name := getTempVariable("intType", "start_", start, c_expr);
      end if;
      if string_index_check then
        if start_range.minValue < 1 or (fixedLengthSubstring and
            (stri_is_variable or start_range.maxValue > stri_length)) then
          incr(countIndexChecks);
          c_expr.expr &:= "idxChk(";
          if start_range.minValue < 1 then
            c_expr.expr &:= start_name;
            c_expr.expr &:= "<1";
            logicalOr := "||";
          end if;
          if fixedLengthSubstring and
              (stri_is_variable or start_range.maxValue > stri_length) then
            c_expr.expr &:= logicalOr;
            c_expr.expr &:= start_name;
            c_expr.expr &:= ">";
            c_expr.expr &:= stri_size;
          end if;
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("INDEX_ERROR");
          c_expr.expr &:= ":";
        else
          countIndexOptimizations(c_expr);
        end if;
      else
        incr(countSuppressedIndexChecks);
      end if;
      c_expr.expr &:= intRaiseError("RANGE_ERROR");
    end if;
    c_expr.expr &:= ")";
  end func;


const proc: optimize_bin_bytes_2_uint_length_1 (in reference: stri,
    in reference: start, in boolean: fixedLengthSubstring,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var boolean: stri_is_variable is TRUE;
    var string: stri_name is "";
    var string: stri_value is "";
    var integer: stri_length is 0;
    var string: stri_size is "";
    var string: start_name is "";
    var integer: start_value is 0;
    var intRange: start_range is intRange.value;
    var boolean: raisesException is FALSE;
    var string: logicalOr is "";
  begin
    incr(countOptimizations);
    incr(countInlinedFunctions);
    c_expr.expr &:= "(";
    if getConstant(stri, STRIOBJECT, evaluatedParam) then
      stri_is_variable := FALSE;
      stri_value := getValue(evaluatedParam, string);
      stri_name := "(" & stringLiteral(stri_value) & ")";
      stri_length := length(stri_value);
      stri_size := memSizeLiteral(stri_length);
    else
      stri_name := getParameterAsVariable("const_striType", "stri_", stri, c_expr);
      stri_size := stri_name & "->size";
    end if;
    start_range := getIntRange(start);
    if start_range.maxValue < 1 then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("INDEX_ERROR");
      raisesException := TRUE;
    elsif not stri_is_variable and start_range.minValue > stri_length then
      if fixedLengthSubstring then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("INDEX_ERROR");
      else
        warning(DOES_RAISE, "RANGE_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("RANGE_ERROR");
      end if;
      raisesException := TRUE;
    elsif getConstant(start, INTOBJECT, evaluatedParam) then
      start_value := getValue(evaluatedParam, integer);
      start_name := integerLiteral(start_value);
    else
      start_name := getTempVariable("intType", "start_", start, c_expr);
    end if;
    if not raisesException then
      if string_index_check then
        if start_range.minValue < 1 or (fixedLengthSubstring and
            (stri_is_variable or start_range.maxValue > stri_length)) then
          incr(countIndexChecks);
          c_expr.expr &:= "idxChk(";
          if start_range.minValue < 1 then
            c_expr.expr &:= start_name;
            c_expr.expr &:= "<1";
            logicalOr := "||";
          end if;
          if fixedLengthSubstring and
              (stri_is_variable or start_range.maxValue > stri_length) then
            c_expr.expr &:= logicalOr;
            c_expr.expr &:= start_name;
            c_expr.expr &:= ">";
            c_expr.expr &:= stri_size;
          end if;
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("INDEX_ERROR");
          c_expr.expr &:= ":";
        else
          countIndexOptimizations(c_expr);
        end if;
      else
        incr(countSuppressedIndexChecks);
      end if;
      c_expr.expr &:= "(";
      if function_range_check then
        incr(countRangeChecks);
        c_expr.expr &:= "rngChk(";
        if not fixedLengthSubstring then
          c_expr.expr &:= start_name;
          c_expr.expr &:= ">";
          c_expr.expr &:= stri_size;
          c_expr.expr &:= "||";
        end if;
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->mem[";
        c_expr.expr &:= start_name;
        c_expr.expr &:= "-1]>255)?";
        c_expr.expr &:= intRaiseError("RANGE_ERROR");
        c_expr.expr &:= ":";
      else
        incr(countNoRangeChecks);
      end if;
      c_expr.expr &:= "(uintType)";
      c_expr.expr &:= stri_name;
      c_expr.expr &:= "->mem[";
      c_expr.expr &:= start_name;
      c_expr.expr &:= "-1])";
    end if;
    c_expr.expr &:= ")";
  end func;


const proc: optimize_bin_bytes_be_2_uint (in string: slice_name, in integer: length,
    in string: or_name, in string: result_name, inout expr_type: c_expr) is func

  local
    var integer: index is 0;
  begin
    for index range 1 to length do
      if function_range_check then
        incr(countRangeChecks);
        c_expr.expr &:= or_name;
        if index <> 1 then
          c_expr.expr &:= "|";
        end if;
        c_expr.expr &:= "=(uintType)";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".mem[";
        c_expr.expr &:= integerLiteral(pred(index));
        c_expr.expr &:= "],";
      else
        incr(countNoRangeChecks);
      end if;
      c_expr.expr &:= result_name;
      if index <> 1 then
        c_expr.expr &:= "|";
      end if;
      c_expr.expr &:= "=(uintType)";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ".mem[";
      c_expr.expr &:= integerLiteral(pred(index));
      c_expr.expr &:= "]";
      if index < length then
        c_expr.expr &:= "<<";
        c_expr.expr &:= integerLiteral((length - index) * 8);
      end if;
      c_expr.expr &:= ",";
    end for;
    if function_range_check then
      c_expr.expr &:= "rngChk(";
      c_expr.expr &:= or_name;
      c_expr.expr &:= ">255)?";
      c_expr.expr &:= intRaiseError("RANGE_ERROR");
      c_expr.expr &:= ":";
    end if;
    c_expr.expr &:= result_name;
  end func;


const proc: optimize_bin_bytes_be_2_uint (in reference: stri,
    in reference: start, in reference: lengthRef, in integer: length,
    in boolean: fixedLengthSubstring, inout expr_type: c_expr) is func

  local
    var string: or_name is "";
    var string: result_name is "";
    var string: slice_name is "";
  begin
    if length < 0 then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("INDEX_ERROR");
    elsif length = 0 then
      optimize_bin_bytes_2_uint_length_0(getActionParameter(stri, 1),
          start, fixedLengthSubstring, c_expr);
    elsif length = 1 then
      optimize_bin_bytes_2_uint_length_1(getActionParameter(stri, 1),
          start, fixedLengthSubstring, c_expr);
    elsif ccConf.ALLOW_STRITYPE_SLICES and length >= 2 and length <= 8 then
      incr(countOptimizations);
      incr(countInlinedFunctions);
      c_expr.expr &:= "(";
      if function_range_check then
        or_name := defineTempVariable("uintType", "or_", c_expr);
      end if;
      result_name := defineTempVariable("uintType", "result_", c_expr);
      incr(c_expr.temp_num);
      slice_name := "slice_" & str(c_expr.temp_num);
      if fixedLengthSubstring then
        process_str_substr_fixlen_slice(getActionParameter(stri, 1), start,
                                        lengthRef, slice_name, c_expr);
        c_expr.expr &:= ", ";
        optimize_bin_bytes_be_2_uint(slice_name, length, or_name, result_name, c_expr);
      else
        process_str_substr_slice(getActionParameter(stri, 1), start,
                                 lengthRef, slice_name, c_expr);
        c_expr.expr &:= ", ";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".size==";
        c_expr.expr &:= integerLiteral(length);
        c_expr.expr &:= "?(";
        optimize_bin_bytes_be_2_uint(slice_name, length, or_name, result_name, c_expr);
        c_expr.expr &:= "):uintBytesBe2UInt(&";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ")";
      end if;
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= "uintBytesBe2UInt(";
      getAnyParamToExpr(stri, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
  begin
    if inlineFunctions and
        isActionExpression(params[1], "STR_SUBSTR") and
        getConstant(getActionParameter(params[1], 5), INTOBJECT, evaluatedParam) then
      optimize_bin_bytes_be_2_uint(params[1], getActionParameter(params[1], 3),
          getActionParameter(params[1], 5), getValue(evaluatedParam, integer), FALSE, c_expr);
    elsif inlineFunctions and
        isActionExpression(params[1], "STR_SUBSTR_FIXLEN") and
        getConstant(getActionParameter(params[1], 5), INTOBJECT, evaluatedParam) then
      optimize_bin_bytes_be_2_uint(params[1], getActionParameter(params[1], 3),
          getActionParameter(params[1], 5), getValue(evaluatedParam, integer), TRUE, c_expr);
    else
      c_expr.expr &:= "uintBytesBe2UInt(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: optimize_bin_bytes_le_2_uint (in string: slice_name, in integer: length,
    in string: or_name, in string: result_name, inout expr_type: c_expr) is func

  local
    var integer: index is 0;
  begin
    for index range 1 to length do
      if function_range_check then
        incr(countRangeChecks);
        c_expr.expr &:= or_name;
        if index <> 1 then
          c_expr.expr &:= "|";
        end if;
        c_expr.expr &:= "=(uintType)";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".mem[";
        c_expr.expr &:= integerLiteral(pred(index));
        c_expr.expr &:= "],";
      else
        incr(countNoRangeChecks);
      end if;
      c_expr.expr &:= result_name;
      if index <> 1 then
        c_expr.expr &:= "|";
      end if;
      c_expr.expr &:= "=(uintType)";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ".mem[";
      c_expr.expr &:= integerLiteral(pred(index));
      c_expr.expr &:= "]";
      if index <> 1 then
        c_expr.expr &:= "<<";
        c_expr.expr &:= integerLiteral(pred(index) * 8);
      end if;
      c_expr.expr &:= ",";
    end for;
    if function_range_check then
      c_expr.expr &:= "rngChk(";
      c_expr.expr &:= or_name;
      c_expr.expr &:= ">255)?";
      c_expr.expr &:= intRaiseError("RANGE_ERROR");
      c_expr.expr &:= ":";
    end if;
    c_expr.expr &:= result_name;
  end func;


const proc: optimize_bin_bytes_le_2_uint (in reference: stri,
    in reference: start, in reference: lengthRef, in integer: length,
    in boolean: fixedLengthSubstring, inout expr_type: c_expr) is func

  local
    var string: or_name is "";
    var string: result_name is "";
    var string: slice_name is "";
  begin
    if length < 0 then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("INDEX_ERROR");
    elsif length = 0 then
      optimize_bin_bytes_2_uint_length_0(getActionParameter(stri, 1),
          start, fixedLengthSubstring, c_expr);
    elsif length = 1 then
      optimize_bin_bytes_2_uint_length_1(getActionParameter(stri, 1),
          start, fixedLengthSubstring, c_expr);
    elsif ccConf.ALLOW_STRITYPE_SLICES and length >= 2 and length <= 8 then
      incr(countOptimizations);
      incr(countInlinedFunctions);
      c_expr.expr &:= "(";
      if function_range_check then
        or_name := defineTempVariable("uintType", "or_", c_expr);
      end if;
      result_name := defineTempVariable("uintType", "result_", c_expr);
      incr(c_expr.temp_num);
      slice_name := "slice_" & str(c_expr.temp_num);
      if fixedLengthSubstring then
        process_str_substr_fixlen_slice(getActionParameter(stri, 1), start,
                                        lengthRef, slice_name, c_expr);
        c_expr.expr &:= ", ";
        optimize_bin_bytes_le_2_uint(slice_name, length, or_name, result_name, c_expr);
      else
        process_str_substr_slice(getActionParameter(stri, 1), start,
                                 lengthRef, slice_name, c_expr);
        c_expr.expr &:= ", ";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".size==";
        c_expr.expr &:= integerLiteral(length);
        c_expr.expr &:= "?(";
        optimize_bin_bytes_le_2_uint(slice_name, length, or_name, result_name, c_expr);
        c_expr.expr &:= "):uintBytesLe2UInt(&";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ")";
      end if;
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= "uintBytesLe2UInt(";
      getAnyParamToExpr(stri, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
  begin
    if inlineFunctions and
        isActionExpression(params[1], "STR_SUBSTR") and
        getConstant(getActionParameter(params[1], 5), INTOBJECT, evaluatedParam) then
      optimize_bin_bytes_le_2_uint(params[1], getActionParameter(params[1], 3),
          getActionParameter(params[1], 5), getValue(evaluatedParam, integer), FALSE, c_expr);
    elsif inlineFunctions and
        isActionExpression(params[1], "STR_SUBSTR_FIXLEN") and
        getConstant(getActionParameter(params[1], 5), INTOBJECT, evaluatedParam) then
      optimize_bin_bytes_le_2_uint(params[1], getActionParameter(params[1], 3),
          getActionParameter(params[1], 5), getValue(evaluatedParam, integer), TRUE, c_expr);
    else
      c_expr.expr &:= "uintBytesLe2UInt(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


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

  begin
    c_expr.expr &:= "uintCard(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ")";
  end func;


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

  local
    var string: number1_name is "";
    var string: number2_name is "";
  begin
    if inlineFunctions then
      incr(countOptimizations);
      incr(countInlinedFunctions);
      c_expr.expr &:= "(";
      number1_name := getParameterAsVariable("uintType", "num1_", params[1], c_expr);
      number2_name := getParameterAsVariable("uintType", "num2_", params[2], c_expr);
      c_expr.expr &:= number1_name;
      c_expr.expr &:= "<";
      c_expr.expr &:= number2_name;
      c_expr.expr &:= "? -1 : ";
      c_expr.expr &:= number1_name;
      c_expr.expr &:= ">";
      c_expr.expr &:= number2_name;
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= "uintCmp(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[2], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


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

  begin
    c_expr.expr &:= "setToUInt(";
    getAnyParamToExpr(params[1], c_expr);
    c_expr.expr &:= ", ";
    process_expr(params[2], c_expr);
    c_expr.expr &:= ")";
  end func;


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

  local
    var string: numberName is "";
  begin
    c_expr.expr &:= "(intType)(";
    numberName := getParameterAsVariable("uintType", "num1_", params[1], c_expr);
    c_expr.expr &:= numberName;
    c_expr.expr &:= " == 0 ? -1 : uint64LeastSignificantBit(";
    c_expr.expr &:= numberName;
    c_expr.expr &:= "))";
  end func;


const proc: process_const_bin_lshift (in reference: number, in integer: lshift,
    inout expr_type: c_expr) is func

  begin
    if lshift < 0 or lshift >= ccConf.INTTYPE_SIZE then
      incr(countOptimizations);
      warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
    else
      c_expr.expr &:= "(intType)((uintType)(";
      process_expr(number, c_expr);
      c_expr.expr &:= ") << ";
      c_expr.expr &:= integerLiteral(lshift);
      c_expr.expr &:= ")";
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
    var string: lshift_name is "";
    var intRange: lshift_range is intRange.value;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_bin_lshift(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif check_int_shift_overflow then
      lshift_range := getIntRange(params[3]);
      if lshift_range.minValue < 0 or
          lshift_range.maxValue >= ccConf.INTTYPE_SIZE then
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        lshift_name := getParameterAsVariable("intType", "lshift_", params[3], c_expr);
        c_expr.expr &:= "ovfChk(";
        checkRangeFromZero(lshift_name, integerLiteral(ccConf.INTTYPE_SIZE), c_expr);
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":(intType)((uintType)(";
        process_expr(params[1], c_expr);
        c_expr.expr &:= ") << ";
        c_expr.expr &:= lshift_name;
        c_expr.expr &:= "))";
      else
        countOverflowOptimizations(c_expr);
        c_expr.expr &:= "/*no_overflow_check_lshift*/";
        c_expr.expr &:= "(intType)((uintType)(";
        process_expr(params[1], c_expr);
        c_expr.expr &:= ") << (";
        process_expr(params[3], c_expr);
        c_expr.expr &:= "))";
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      c_expr.expr &:= "(intType)((uintType)(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ") << (";
      process_expr(params[3], c_expr);
      c_expr.expr &:= "))";
    end if;
  end func;


const proc: process_const_bin_lshift_assign (in reference: variable, in integer: lshift,
    inout expr_type: c_expr) is func

  local
    var string: variable_name is "";
    var expr_type: statement is expr_type.value;
  begin
    if lshift < 0 or lshift >= ccConf.INTTYPE_SIZE then
      incr(countOptimizations);
      setDiagnosticLine(c_expr);
      warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
      c_expr.expr &:= raiseError("OVERFLOW_ERROR");
    else
      variable_name := getParameterAsReference("intType", "tmp_", variable, statement);
      statement.expr &:= variable_name;
      statement.expr &:= "=(intType)((uintType)(";
      statement.expr &:= variable_name;
      statement.expr &:= ") << ";
      statement.expr &:= integerLiteral(lshift);
      statement.expr &:= ");\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
    var expr_type: statement is expr_type.value;
    var string: variable_name is "";
    var string: lshift_name is "";
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_bin_lshift_assign(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif check_int_shift_overflow then
      incr(countOverflowChecks);
      variable_name := getParameterAsReference("intType", "tmp_", params[1], statement);
      lshift_name := getParameterAsVariable("intType", "tmp_", params[3], statement);
      statement.expr &:= "ovfChk(";
      checkRangeFromZero(lshift_name, integerLiteral(ccConf.INTTYPE_SIZE), statement);
      statement.expr &:= ")?";
      statement.expr &:= intRaiseError("OVERFLOW_ERROR");
      statement.expr &:= ":(";
      statement.expr &:= variable_name;
      statement.expr &:= "=(intType)((uintType)(";
      statement.expr &:= variable_name;
      statement.expr &:= ") << ";
      statement.expr &:= lshift_name;
      statement.expr &:= "));\n";
      doLocalDeclsOfStatement(statement, c_expr);
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      variable_name := getParameterAsReference("intType", "tmp_", params[1], statement);
      statement.expr &:= variable_name;
      statement.expr &:= "=(intType)((uintType)(";
      statement.expr &:= variable_name;
      statement.expr &:= ") << (";
      process_expr(params[3], statement);
      statement.expr &:= "));\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process_const_bin_n_bytes_be (in reference: number,
    in integer: length, inout expr_type: c_expr) is func

  local
    var reference: evaluatedNumber is NIL;
    var integer: numberValue is 0;
    var string: buffer_name is "";
    var string: number_name is "";
    var integer: index is 0;
  begin
    if length <= 0 then
      incr(countOptimizations);
      warning(DOES_RAISE, "RANGE_ERROR", c_expr);
      c_expr.expr &:= strRaiseError("RANGE_ERROR");
    elsif getConstant(number, INTOBJECT, evaluatedNumber) then
      incr(countOptimizations);
      numberValue := getValue(evaluatedNumber, integer);
      if length < 8 and (numberValue >= 2 ** (8 * length) or numberValue < 0) then
        warning(DOES_RAISE, "RANGE_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("RANGE_ERROR");
      else
        c_expr.expr &:= stringLiteral(bytes(bin64(numberValue), BE, length));
      end if;
    elsif ccConf.ALLOW_STRITYPE_SLICES and length <= 8 then
      incr(countOptimizations);
      incr(countInlinedFunctions);
      incr(c_expr.temp_num);
      buffer_name := "buffer_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "union {\n";
      c_expr.temp_decls &:= "  struct striStruct striBuf;\n";
      c_expr.temp_decls &:= "  char charBuf[SIZ_STRI(";
      c_expr.temp_decls &:= str(length);
      c_expr.temp_decls &:= ")];\n";
      c_expr.temp_decls &:= "} ";
      c_expr.temp_decls &:= buffer_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= "(";
      number_name := getParameterAsVariable("intType", "tmp_", number, c_expr);
      if function_range_check and length < 8 then
        incr(countRangeChecks);
        c_expr.expr &:= "rngChk(";
        c_expr.expr &:= "(uintType)";
        c_expr.expr &:= number_name;
        c_expr.expr &:= ">(uintType)";
        c_expr.expr &:= integerLiteral(pred(2 ** (8 * length)));
        c_expr.expr &:= ")?";
        c_expr.expr &:= strRaiseError("RANGE_ERROR");
        c_expr.expr &:= ":(";
      end if;
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf.size=";
      c_expr.expr &:= str(length);
      c_expr.expr &:= ",";
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf.mem=";
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf.mem1,";
      for index range 1 to length do
        c_expr.expr &:= buffer_name;
        c_expr.expr &:= ".striBuf.mem1[";
        c_expr.expr &:= str(pred(index));
        c_expr.expr &:= "]=(strElemType)(";
        if index <> length then
          c_expr.expr &:= "((uintType)(";
          c_expr.expr &:= number_name;
          c_expr.expr &:= ")>>";
          c_expr.expr &:= str(8 * (length - index));
        else
          c_expr.expr &:= "(uintType)(";
          c_expr.expr &:= number_name;
        end if;
        c_expr.expr &:= ")";
        if index <> 1 then
          c_expr.expr &:= "&255";
        end if;
        c_expr.expr &:= "),";
      end for;
      c_expr.expr &:= "&";
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf";
      if function_range_check and length < 8 then
        c_expr.expr &:= ")";
      end if;
      c_expr.expr &:= ")";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "uintNBytesBe(";
      getStdParamToResultExpr(number, c_expr);
      c_expr.result_expr &:= ", ";
      c_expr.result_expr &:= integerLiteral(length);
      c_expr.result_expr &:= ")";
    end if;
  end func;


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

  local
    var reference: evaluatedLength is NIL;
  begin
    if inlineFunctions and
        getConstant(params[3], INTOBJECT, evaluatedLength) then
      process_const_bin_n_bytes_be(params[1],
          getValue(evaluatedLength, integer), c_expr);
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "uintNBytesBe(";
      getStdParamToResultExpr(params[1], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process_const_bin_n_bytes_le (in reference: number,
    in integer: length, inout expr_type: c_expr) is func

  local
    var reference: evaluatedNumber is NIL;
    var integer: numberValue is 0;
    var string: buffer_name is "";
    var string: number_name is "";
    var integer: index is 0;
  begin
    if length <= 0 then
      incr(countOptimizations);
      warning(DOES_RAISE, "RANGE_ERROR", c_expr);
      c_expr.expr &:= strRaiseError("RANGE_ERROR");
    elsif getConstant(number, INTOBJECT, evaluatedNumber) then
      incr(countOptimizations);
      numberValue := getValue(evaluatedNumber, integer);
      if length < 8 and (numberValue >= 2 ** (8 * length) or numberValue < 0) then
        warning(DOES_RAISE, "RANGE_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("RANGE_ERROR");
      else
        c_expr.expr &:= stringLiteral(bytes(bin64(numberValue), LE, length));
      end if;
    elsif ccConf.ALLOW_STRITYPE_SLICES and length <= 8 then
      incr(countOptimizations);
      incr(countInlinedFunctions);
      incr(c_expr.temp_num);
      buffer_name := "buffer_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "union {\n";
      c_expr.temp_decls &:= "  struct striStruct striBuf;\n";
      c_expr.temp_decls &:= "  char charBuf[SIZ_STRI(";
      c_expr.temp_decls &:= str(length);
      c_expr.temp_decls &:= ")];\n";
      c_expr.temp_decls &:= "} ";
      c_expr.temp_decls &:= buffer_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= "(";
      number_name := getParameterAsVariable("intType", "tmp_", number, c_expr);
      if function_range_check and length < 8 then
        incr(countRangeChecks);
        c_expr.expr &:= "rngChk(";
        c_expr.expr &:= "(uintType)";
        c_expr.expr &:= number_name;
        c_expr.expr &:= ">(uintType)";
        c_expr.expr &:= integerLiteral(pred(2 ** (8 * length)));
        c_expr.expr &:= ")?";
        c_expr.expr &:= strRaiseError("RANGE_ERROR");
        c_expr.expr &:= ":(";
      end if;
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf.size=";
      c_expr.expr &:= str(length);
      c_expr.expr &:= ",";
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf.mem=";
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf.mem1,";
      for index range 1 to length do
        c_expr.expr &:= buffer_name;
        c_expr.expr &:= ".striBuf.mem1[";
        c_expr.expr &:= str(pred(index));
        c_expr.expr &:= "]=(strElemType)(";
        if index <> 1 then
          c_expr.expr &:= "((uintType)(";
          c_expr.expr &:= number_name;
          c_expr.expr &:= ")>>";
          c_expr.expr &:= str(8 * pred(index));
        else
          c_expr.expr &:= "(uintType)(";
          c_expr.expr &:= number_name;
        end if;
        c_expr.expr &:= ")";
        if index <> length then
          c_expr.expr &:= "&255";
        end if;
        c_expr.expr &:= "),";
      end for;
      c_expr.expr &:= "&";
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf";
      if function_range_check and length < 8 then
        c_expr.expr &:= ")";
      end if;
      c_expr.expr &:= ")";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "uintNBytesLe(";
      getStdParamToResultExpr(number, c_expr);
      c_expr.result_expr &:= ", ";
      c_expr.result_expr &:= integerLiteral(length);
      c_expr.result_expr &:= ")";
    end if;
  end func;


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

  local
    var reference: evaluatedLength is NIL;
  begin
    if inlineFunctions and
        getConstant(params[3], INTOBJECT, evaluatedLength) then
      process_const_bin_n_bytes_le(params[1],
          getValue(evaluatedLength, integer), c_expr);
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "uintNBytesLe(";
      getStdParamToResultExpr(params[1], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


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

  begin
    c_expr.expr &:= "(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ") | (";
    process_expr(params[3], c_expr);
    c_expr.expr &:= ")";
  end func;


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

  local
    var expr_type: statement is expr_type.value;
  begin
    process_expr(params[1], statement);
    statement.expr &:= "|=";
    process_expr(params[3], statement);
    statement.expr &:= ";\n";
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


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

  begin
    prepare_stri_result(c_expr);
    c_expr.result_expr := "uintStr(";
    getStdParamToResultExpr(param1, c_expr);
    c_expr.result_expr &:= ")";
  end func;


const proc: process_const_bin_radix (in reference: param1, in integer: base,
    in boolean: upperCase, inout expr_type: c_expr) is func

  begin
    if base < 2 or base > 36 then
      incr(countOptimizations);
      warning(DOES_RAISE, "RANGE_ERROR", c_expr);
      c_expr.expr &:= strRaiseError("RANGE_ERROR");
    elsif base = 10 then
      incr(countOptimizations);
      process_bin_str(param1, c_expr);
    elsif 2 ** log2(base) = base then
      incr(countOptimizations);
      prepare_stri_result(c_expr);
      c_expr.result_expr := "uintRadixPow2(";
      getStdParamToResultExpr(param1, c_expr);
      c_expr.result_expr &:= ",";
      c_expr.result_expr &:= integerLiteral(log2(base));
      c_expr.result_expr &:= ",";
      c_expr.result_expr &:= integerLiteral(pred(base));
      c_expr.result_expr &:= ",";
      c_expr.result_expr &:= str(ord(upperCase));
      c_expr.result_expr &:= ")";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "uintRadix(";
      getStdParamToResultExpr(param1, c_expr);
      c_expr.result_expr &:= ", ";
      c_expr.result_expr &:= integerLiteral(base);
      c_expr.result_expr &:= ",";
      c_expr.result_expr &:= str(ord(upperCase));
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process_bin_radix (in ref_list: params, in boolean: upperCase,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_bin_radix(params[1], getValue(evaluatedParam, integer),
          upperCase, c_expr);
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "uintRadix(";
      getStdParamToResultExpr(params[1], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ",";
      c_expr.result_expr &:= str(ord(upperCase));
      c_expr.result_expr &:= ")";
    end if;
  end func;


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

  begin
    process_bin_radix(params, FALSE, c_expr);
  end func;


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

  begin
    process_bin_radix(params, TRUE, c_expr);
  end func;


const proc: process_const_bin_rshift (in reference: number, in integer: rshift,
    inout expr_type: c_expr) is func

  begin
    if rshift < 0 or rshift >= ccConf.INTTYPE_SIZE then
      incr(countOptimizations);
      warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
    else
      c_expr.expr &:= "(intType)((uintType)(";
      process_expr(number, c_expr);
      c_expr.expr &:= ") >> ";
      c_expr.expr &:= integerLiteral(rshift);
      c_expr.expr &:= ")";
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
    var string: rshift_name is "";
    var intRange: rshift_range is intRange.value;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_bin_rshift(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif check_int_shift_overflow then
      rshift_range := getIntRange(params[3]);
      if rshift_range.minValue < 0 or
          rshift_range.maxValue >= ccConf.INTTYPE_SIZE then
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        rshift_name := getParameterAsVariable("intType", "rshift_", params[3], c_expr);
        c_expr.expr &:= "ovfChk(";
        checkRangeFromZero(rshift_name, integerLiteral(ccConf.INTTYPE_SIZE), c_expr);
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":(intType)((uintType)(";
        process_expr(params[1], c_expr);
        c_expr.expr &:= ") >> ";
        c_expr.expr &:= rshift_name;
        c_expr.expr &:= "))";
      else
        countOverflowOptimizations(c_expr);
        c_expr.expr &:= "/*no_overflow_check_rshift*/";
        c_expr.expr &:= "(intType)((uintType)(";
        process_expr(params[1], c_expr);
        c_expr.expr &:= ") >> (";
        process_expr(params[3], c_expr);
        c_expr.expr &:= "))";
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      c_expr.expr &:= "(intType)((uintType)(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ") >> (";
      process_expr(params[3], c_expr);
      c_expr.expr &:= "))";
    end if;
  end func;


const proc: process_const_bin_rshift_assign (in reference: variable, in integer: rshift,
    inout expr_type: c_expr) is func

  local
    var string: variable_name is "";
    var expr_type: statement is expr_type.value;
  begin
    if rshift < 0 or rshift >= ccConf.INTTYPE_SIZE then
      incr(countOptimizations);
      setDiagnosticLine(c_expr);
      warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
      c_expr.expr &:= raiseError("OVERFLOW_ERROR");
    else
      variable_name := getParameterAsReference("intType", "tmp_", variable, statement);
      statement.expr &:= variable_name;
      statement.expr &:= "=(intType)((uintType)(";
      statement.expr &:= variable_name;
      statement.expr &:= ") >> ";
      statement.expr &:= integerLiteral(rshift);
      statement.expr &:= ");\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
    var expr_type: statement is expr_type.value;
    var string: variable_name is "";
    var string: rshift_name is "";
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_bin_rshift_assign(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif check_int_shift_overflow then
      incr(countOverflowChecks);
      variable_name := getParameterAsReference("intType", "tmp_", params[1], statement);
      rshift_name := getParameterAsVariable("intType", "tmp_", params[3], statement);
      statement.expr &:= "ovfChk(";
      checkRangeFromZero(rshift_name, integerLiteral(ccConf.INTTYPE_SIZE), statement);
      statement.expr &:= ")?";
      statement.expr &:= intRaiseError("OVERFLOW_ERROR");
      statement.expr &:= ":(";
      statement.expr &:= variable_name;
      statement.expr &:= "=(intType)((uintType)(";
      statement.expr &:= variable_name;
      statement.expr &:= ") >> ";
      statement.expr &:= rshift_name;
      statement.expr &:= "));\n";
      doLocalDeclsOfStatement(statement, c_expr);
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      variable_name := getParameterAsReference("intType", "tmp_", params[1], statement);
      statement.expr &:= variable_name;
      statement.expr &:= "=(intType)((uintType)(";
      statement.expr &:= variable_name;
      statement.expr &:= ") >> (";
      process_expr(params[3], statement);
      statement.expr &:= "));\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


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

  begin
    process_bin_str(params[1], c_expr);
  end func;


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

  begin
    c_expr.expr &:= "(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ") ^ (";
    process_expr(params[3], c_expr);
    c_expr.expr &:= ")";
  end func;


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

  local
    var expr_type: statement is expr_type.value;
  begin
    process_expr(params[1], statement);
    statement.expr &:= "^=";
    process_expr(params[3], statement);
    statement.expr &:= ";\n";
    doLocalDeclsOfStatement(statement, c_expr);
  end func;