(********************************************************************)
(*                                                                  *)
(*  str_act.s7i   Generate code for actions of the type string.     *)
(*  Copyright (C) 1990 - 1994, 2004 - 2017  Thomas Mertes           *)
(*                2019 - 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: STR_APPEND        is action "STR_APPEND";
const ACTION: STR_CAT           is action "STR_CAT";
const ACTION: STR_CHIPOS        is action "STR_CHIPOS";
const ACTION: STR_CHPOS         is action "STR_CHPOS";
const ACTION: STR_CHSPLIT       is action "STR_CHSPLIT";
const ACTION: STR_CLIT          is action "STR_CLIT";
const ACTION: STR_CMP           is action "STR_CMP";
const ACTION: STR_CPY           is action "STR_CPY";
const ACTION: STR_ELEMCPY       is action "STR_ELEMCPY";
const ACTION: STR_EQ            is action "STR_EQ";
const ACTION: STR_FOR           is action "STR_FOR";
const ACTION: STR_FOR_KEY       is action "STR_FOR_KEY";
const ACTION: STR_FOR_VAR_KEY   is action "STR_FOR_VAR_KEY";
const ACTION: STR_FROM_UTF8     is action "STR_FROM_UTF8";
const ACTION: STR_GE            is action "STR_GE";
const ACTION: STR_GT            is action "STR_GT";
const ACTION: STR_HASHCODE      is action "STR_HASHCODE";
const ACTION: STR_HEAD          is action "STR_HEAD";
const ACTION: STR_IDX           is action "STR_IDX";
const ACTION: STR_IPOS          is action "STR_IPOS";
const ACTION: STR_LE            is action "STR_LE";
const ACTION: STR_LIT           is action "STR_LIT";
const ACTION: STR_LNG           is action "STR_LNG";
const ACTION: STR_LOW           is action "STR_LOW";
const ACTION: STR_LPAD          is action "STR_LPAD";
const ACTION: STR_LPAD0         is action "STR_LPAD0";
const ACTION: STR_LT            is action "STR_LT";
const ACTION: STR_LTRIM         is action "STR_LTRIM";
const ACTION: STR_MULT          is action "STR_MULT";
const ACTION: STR_NE            is action "STR_NE";
const ACTION: STR_POS           is action "STR_POS";
const ACTION: STR_POSCPY        is action "STR_POSCPY";
const ACTION: STR_PUSH          is action "STR_PUSH";
const ACTION: STR_RANGE         is action "STR_RANGE";
const ACTION: STR_RCHIPOS       is action "STR_RCHIPOS";
const ACTION: STR_RCHPOS        is action "STR_RCHPOS";
const ACTION: STR_REPL          is action "STR_REPL";
const ACTION: STR_RIPOS         is action "STR_RIPOS";
const ACTION: STR_RPAD          is action "STR_RPAD";
const ACTION: STR_RPOS          is action "STR_RPOS";
const ACTION: STR_RTRIM         is action "STR_RTRIM";
const ACTION: STR_SPLIT         is action "STR_SPLIT";
const ACTION: STR_STR           is action "STR_STR";
const ACTION: STR_SUBSTR        is action "STR_SUBSTR";
const ACTION: STR_SUBSTR_FIXLEN is action "STR_SUBSTR_FIXLEN";
const ACTION: STR_TAIL          is action "STR_TAIL";
const ACTION: STR_TO_UTF8       is action "STR_TO_UTF8";
const ACTION: STR_TRIM          is action "STR_TRIM";
const ACTION: STR_UP            is action "STR_UP";
const ACTION: STR_VALUE         is action "STR_VALUE";


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

  begin
    declareExtern(c_prog, "void        strAppend (striType *const, const_striType);");
    declareExtern(c_prog, "void        strAppendN (striType *const, const const_striType[], memSizeType);");
    declareExtern(c_prog, "void        strAppendTemp (striType *const, const striType);");
    declareExtern(c_prog, "striType    strChChRepl (const const_striType, const charType, const charType);");
    declareExtern(c_prog, "intType     strChIPos (const const_striType, const charType, const intType);");
    declareExtern(c_prog, "striType    strChMult (const charType, const intType);");
    declareExtern(c_prog, "intType     strChPos (const const_striType, const charType);");
    declareExtern(c_prog, "striType    strChRepl (const const_striType, const charType, const const_striType);");
    declareExtern(c_prog, "arrayType   strChSplit (const const_striType, const charType);");
    declareExtern(c_prog, "intType     strCmpGeneric (const genericType, const genericType);");
    declareExtern(c_prog, "intType     strCompare (const const_striType, const const_striType);");
    declareExtern(c_prog, "striType    strConcat (const const_striType, const const_striType);");
    declareExtern(c_prog, "striType    strConcatChar (const const_striType, const charType);");
    declareExtern(c_prog, "striType    strConcatCharTemp (striType, const charType);");
    declareExtern(c_prog, "striType    strConcatN (const const_striType[], memSizeType);");
    declareExtern(c_prog, "striType    strConcatTemp (striType, const const_striType);");
    declareExtern(c_prog, "striType    strCLit (const const_striType);");
    declareExtern(c_prog, "void        strCopy (striType *const, const const_striType);");
    declareExtern(c_prog, "void        strCpyGeneric (genericType *const, const genericType);");
    declareExtern(c_prog, "striType    strCreate (const const_striType);");
    declareExtern(c_prog, "genericType strCreateGeneric (const genericType);");
    declareExtern(c_prog, "void        strDestr (const const_striType);");
    declareExtern(c_prog, "void        strDestrGeneric (const genericType);");
    declareExtern(c_prog, "striType    strEmpty(void);");
    declareExtern(c_prog, "striType    strFromUtf8 (const const_striType);");
    declareExtern(c_prog, "boolType    strGe (const const_striType, const const_striType);");
    declareExtern(c_prog, "boolType    strGt (const const_striType, const const_striType);");
    declareExtern(c_prog, "intType     strHashCode (const const_striType);");
    declareExtern(c_prog, "intType     strHashCodeGeneric (const genericType);");
    declareExtern(c_prog, "striType    strHead (const_striType, intType);");
    declareExtern(c_prog, "void        strHeadSlice (const const_striType, const intType, striType);");
    declareExtern(c_prog, "striType    strHeadAssign (const striType, const intType);");
    declareExtern(c_prog, "striType    strHeadTemp (const striType, const intType);");
    declareExtern(c_prog, "intType     strIPos (const const_striType, const const_striType, const intType);");
    declareExtern(c_prog, "boolType    strLe (const const_striType, const const_striType);");
    declareExtern(c_prog, "striType    strLit (const const_striType);");
    declareExtern(c_prog, "striType    strLow (const const_striType);");
    declareExtern(c_prog, "striType    strLowTemp (const striType);");
    declareExtern(c_prog, "striType    strLpad (const const_striType, const intType);");
    declareExtern(c_prog, "striType    strLpadTemp (const striType, const intType);");
    declareExtern(c_prog, "striType    strLpad0 (const const_striType, const intType);");
    declareExtern(c_prog, "striType    strLpad0Temp (const striType, const intType);");
    declareExtern(c_prog, "boolType    strLt (const const_striType, const const_striType);");
    declareExtern(c_prog, "striType    strLtrim (const const_striType);");
    declareExtern(c_prog, "striType    strMult (const const_striType, const intType);");
    declareExtern(c_prog, "intType     strPos (const const_striType, const const_striType);");
    declareExtern(c_prog, "void        strPush (striType *const, const charType);");
    declareExtern(c_prog, "striType    strRange (const_striType, intType, intType);");
    declareExtern(c_prog, "void        strRangeSlice (const const_striType, intType, intType, striType);");
    declareExtern(c_prog, "intType     strRChIPos (const const_striType, const charType, const intType);");
    declareExtern(c_prog, "intType     strRChPos (const const_striType, const charType);");
    declareExtern(c_prog, "striType    strRepl (const const_striType, const const_striType, const const_striType);");
    declareExtern(c_prog, "intType     strRIPos (const const_striType, const const_striType, const intType);");
    declareExtern(c_prog, "striType    strRpad (const const_striType, const intType);");
    declareExtern(c_prog, "intType     strRPos (const const_striType, const const_striType);");
    declareExtern(c_prog, "striType    strRtrim (const const_striType);");
    declareExtern(c_prog, "arrayType   strSplit (const const_striType, const const_striType);");
    declareExtern(c_prog, "striType    strSubstr (const_striType, intType, intType);");
    declareExtern(c_prog, "void        strSubstrSlice (const const_striType, intType, intType, striType);");
    declareExtern(c_prog, "striType    strSubstrFixLen (const const_striType, intType, intType);");
    declareExtern(c_prog, "void        strSubstrFixLenSlice (const const_striType, intType, intType, striType);");
    declareExtern(c_prog, "striType    strTail (const_striType, intType);");
    declareExtern(c_prog, "void        strTailSlice (const const_striType, intType, striType);");
    declareExtern(c_prog, "striType    strTailAssign (const striType, intType);");
    declareExtern(c_prog, "striType    strToUtf8 (const const_striType);");
    declareExtern(c_prog, "striType    strTrim (const const_striType);");
    declareExtern(c_prog, "striType    strUp (const const_striType);");
    declareExtern(c_prog, "striType    strUpTemp (const striType);");
    declareExtern(c_prog, "striType    strValue (const const_objRefType);");
    declareExtern(c_prog, "const_striType strValueRef (const const_objRefType);");
    declareExtern(c_prog, "striType    strZero (const intType);");
  end func;


const func array reference: getConcatNParamList (in ref_list: params) is func
  result
    var array reference: concatNParamList is 0 times NIL;
  local
    var reference: leftParam is NIL;
    var reference: rightParam is NIL;
    var boolean: concatFound is FALSE;
    var ref_list: subExprParams is ref_list.EMPTY;
    var ref_list: rightParamList is ref_list.EMPTY;
  begin
    leftParam := params[1];
    rightParam := params[3];
    if isActionExpression(rightParam, "STR_CAT") then
      rightParamList := getValue(rightParam, ref_list)[2 ..];
      concatNParamList := getConcatNParamList(rightParamList);
    else
      concatNParamList := [] (rightParam);
    end if;
    repeat
      concatFound := FALSE;
      if category(leftParam) = CALLOBJECT then
        subExprParams := getValue(leftParam, ref_list);
        if category(subExprParams[1]) = ACTOBJECT then
          if str(getValue(subExprParams[1], ACTION)) = "STR_CAT" then
            leftParam := subExprParams[2];
            rightParam := subExprParams[4];
            if isActionExpression(rightParam, "STR_CAT") then
              rightParamList := getValue(rightParam, ref_list)[2 ..];
              concatNParamList := getConcatNParamList(rightParamList) & concatNParamList;
            else
              concatNParamList := [] (rightParam) & concatNParamList;
            end if;
            concatFound := TRUE;
          end if;
        end if;
      end if;
    until not concatFound;
    concatNParamList := [] (leftParam) & concatNParamList;
  end func;


const func array reference: getAppendExtensions (in reference: extension) is func
  result
    var array reference: appendNParamList is 0 times NIL;
  local
    var ref_list: params is ref_list.EMPTY;
  begin
    if category(extension) = CALLOBJECT then
      params := getValue(extension, ref_list);
      if category(params[1]) = ACTOBJECT and
          str(getValue(params[1], ACTION)) = "STR_CAT" then
        appendNParamList := getConcatNParamList(params[2 ..]);
      else
        appendNParamList := [] (extension);
      end if;
    else
      appendNParamList := [] (extension);
    end if;
  end func;


const proc: concatConstants (inout array reference: concatNParamList) is func
  local
    var integer: index is 1;
    var reference: evaluatedParam is NIL;
    var string: paramValue is "";
  begin
    while index <= length(concatNParamList) do
      if getConstant(concatNParamList[index], STRIOBJECT, evaluatedParam) then
        paramValue := getValue(evaluatedParam, string);
        if paramValue = "" then
          # Empty strings are removed.
          incr(countOptimizations);
          ignore(remove(concatNParamList, index));
        elsif succ(index) <= length(concatNParamList) and
            getConstant(concatNParamList[succ(index)], STRIOBJECT, evaluatedParam) then
          # Two consecutive constant strings are concatenated at compile time.
          incr(countOptimizations);
          concatNParamList[index] := alloc(FALSE, getType(concatNParamList[index]),
              paramValue & getValue(evaluatedParam, string));
          ignore(remove(concatNParamList, succ(index)));
        else
          incr(index);
        end if;
      else
        incr(index);
      end if;
    end while;
  end func;


const proc: process_const_inline_str_push (in reference: stri, in char: ch,
    inout expr_type: c_expr) is func

  local
    var expr_type: statement is expr_type.value;
    var string: stri_name is "";
  begin
    if isNormalVariable(stri) then
      stri_name := normalVariable(stri, statement);
    else
      incr(statement.temp_num);
      stri_name := "tmp_" & str(statement.temp_num);
      statement.temp_decls &:= "striType *";
      statement.temp_decls &:= stri_name;
      statement.temp_decls &:= ";\n";
      statement.expr &:= stri_name;
      statement.expr &:= "=&(";
      process_expr(stri, statement);
      statement.expr &:= ");\n";
      stri_name := "*" & stri_name;
    end if;
    statement.expr &:= "if ((";
    statement.expr &:= stri_name;
    statement.expr &:= ")->size == (";
    statement.expr &:= stri_name;
    statement.expr &:= ")->capacity) {\n";
    statement.expr &:= "strPush(&(";
    statement.expr &:= stri_name;
    statement.expr &:= "), ";
    statement.expr &:= charLiteral(ch);
    statement.expr &:= ");\n";
    statement.expr &:= "} else {\n";
    statement.expr &:= "(";
    statement.expr &:= stri_name;
    statement.expr &:= ")->mem[(";
    statement.expr &:= stri_name;
    statement.expr &:= ")->size]=";
    statement.expr &:= charLiteral(ch);
    statement.expr &:= ";\n";
    statement.expr &:= "(";
    statement.expr &:= stri_name;
    statement.expr &:= ")->size++;\n";
    statement.expr &:= "}\n";
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


const proc: process_const_str_push (in reference: stri, in char: ch,
    inout expr_type: c_expr) is func

  begin
    if inlineFunctions and ccConf.WITH_STRI_CAPACITY then
      incr(countInlinedFunctions);
      process_const_inline_str_push(stri, ch, c_expr);
    else
      c_expr.expr &:= "strPush(&(";
      process_expr(stri, c_expr);
      c_expr.expr &:= "), ";
      c_expr.expr &:= charLiteral(ch);
      c_expr.expr &:= ");\n";
    end if;
  end func;


const proc: process_inline_str_push (in reference: stri,
    in reference: extension, inout expr_type: c_expr) is func

  local
    var expr_type: statement is expr_type.value;
    var string: stri_name is "";
    var string: char_name is "";
  begin
    if isNormalVariable(stri) then
      stri_name := normalVariable(stri, statement);
    else
      incr(statement.temp_num);
      stri_name := "tmp_" & str(statement.temp_num);
      statement.temp_decls &:= "striType *";
      statement.temp_decls &:= stri_name;
      statement.temp_decls &:= ";\n";
      statement.expr &:= stri_name;
      statement.expr &:= "=&(";
      process_expr(stri, statement);
      statement.expr &:= ");\n";
      stri_name := "*" & stri_name;
    end if;
    if isNormalVariable(extension) then
      char_name := normalVariable(extension, statement);
    else
      incr(statement.temp_num);
      char_name := "tmp_" & str(statement.temp_num);
      statement.temp_decls &:= "charType ";
      statement.temp_decls &:= char_name;
      statement.temp_decls &:= ";\n";
      statement.expr &:= char_name;
      statement.expr &:= "=";
      process_expr(extension, statement);
      statement.expr &:= ";\n";
    end if;
    statement.expr &:= "if ((";
    statement.expr &:= stri_name;
    statement.expr &:= ")->size == (";
    statement.expr &:= stri_name;
    statement.expr &:= ")->capacity) {\n";
    statement.expr &:= "strPush(&(";
    statement.expr &:= stri_name;
    statement.expr &:= "), ";
    statement.expr &:= char_name;
    statement.expr &:= ");\n";
    statement.expr &:= "} else {\n";
    statement.expr &:= "(";
    statement.expr &:= stri_name;
    statement.expr &:= ")->mem[(";
    statement.expr &:= stri_name;
    statement.expr &:= ")->size]=";
    statement.expr &:= char_name;
    statement.expr &:= ";\n";
    statement.expr &:= "(";
    statement.expr &:= stri_name;
    statement.expr &:= ")->size++;\n";
    statement.expr &:= "}\n";
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


const proc: process_str_push (in reference: stri,
    in reference: extension, inout expr_type: c_expr) is func

  local
    var expr_type: statement is expr_type.value;
  begin
    if inlineFunctions and ccConf.WITH_STRI_CAPACITY then
      incr(countInlinedFunctions);
      process_inline_str_push(stri, extension, c_expr);
    else
      statement.expr := "strPush(&(";
      process_expr(stri, statement);
      statement.expr &:= "), ";
      process_expr(extension, statement);
      statement.expr &:= ");\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process_const_str_append (in reference: param1, in string: stri,
    inout expr_type: c_expr) is func

  begin
    setDiagnosticLine(c_expr);
    if stri = "" then
      incr(countOptimizations);
      c_expr.expr &:= "/* Append empty string */\n";
    elsif length(stri) = 1 then
      incr(countOptimizations);
      process_const_str_push(param1, stri[1], c_expr);
    else
      c_expr.expr &:= "strAppend(&(";
      process_expr(param1, c_expr);
      c_expr.expr &:= "), ";
      c_expr.expr &:= stringLiteral(stri);
      c_expr.expr &:= ");\n";
    end if;
  end func;


(**
 *  Produces code for the string append operator.
 *  If two or more strings are appended the function
 *  strAppendN is used. This avoids copying and allocation operations.
 *)
const proc: optimize_str_append (in reference: dest, in reference: extension,
    inout expr_type: c_expr) is func

  local
    var expr_type: statement is expr_type.value;
    var array reference: appendExtensions is 0 times NIL;
    var string: concatNParamName is "";
    var integer: index is 1;
    var reference: evaluatedParam is NIL;
    var expr_type: c_extension is expr_type.value;
  begin
    appendExtensions := getAppendExtensions(extension);
    concatConstants(appendExtensions);
    if length(appendExtensions) >= 2 then
      incr(countOptimizations);
      incr(statement.temp_num);
      concatNParamName := "tmp_" & str(statement.temp_num);
      statement.temp_decls &:= "const_striType ";
      statement.temp_decls &:= concatNParamName;
      statement.temp_decls &:= "[";
      statement.temp_decls &:= str(length(appendExtensions));
      statement.temp_decls &:= "];\n";
      for key index range appendExtensions do
        statement.expr &:= concatNParamName;
        statement.expr &:= "[";
        statement.expr &:= str(pred(index));
        statement.expr &:= "] = ";
        getAnyParamToExpr(appendExtensions[index], statement);
        statement.expr &:= ";\n";
      end for;
      statement.expr &:= "strAppendN(&(";
      process_expr(dest, statement);
      statement.expr &:= "), ";
      statement.expr &:= concatNParamName;
      statement.expr &:= ", ";
      statement.expr &:= str(length(appendExtensions));
      statement.expr &:= ");\n";
    elsif length(appendExtensions) = 1 then
      if getConstant(appendExtensions[1], STRIOBJECT, evaluatedParam) then
        process_const_str_append(dest, getValue(evaluatedParam, string), c_expr);
      else
        if isActionExpression(appendExtensions[1], "CHR_STR") then
          incr(countOptimizations);
          process_str_push(dest, getActionParameter(appendExtensions[1], 1),
                           statement);
        else
          prepareAnyParamTemporarys(appendExtensions[1], c_extension, statement);
          if c_extension.result_expr <> "" then
            statement.expr := "strAppendTemp(&(";
            process_expr(dest, statement);
            statement.expr &:= "), ";
            statement.expr &:= c_extension.result_expr;
          else
            statement.expr := "strAppend(&(";
            process_expr(dest, statement);
            statement.expr &:= "), ";
            statement.expr &:= c_extension.expr;
          end if;
          statement.expr &:= ");\n";
        end if;
      end if;
    else
      incr(countOptimizations);
      statement.expr &:= "/* Append empty string */\n";
    end if;
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


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

  local
    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
    if optimizeStringFunctions then
      optimize_str_append(param1, param3, c_expr);
    elsif getConstant(param3, STRIOBJECT, evaluatedParam) then
      process_const_str_append(param1, getValue(evaluatedParam, string), c_expr);
    else
      statement.temp_num := c_expr.temp_num;
      prepareAnyParamTemporarys(param1, c_param1, statement);
      if useSpecialCaseFunctions and
          isActionExpression(param3, "CHR_STR") then
        incr(countOptimizations);
        statement.expr &:= "strPush(&(";
        statement.expr &:= c_param1.expr;
        statement.expr &:= "), ";
        process_expr(getActionParameter(param3, 1), statement);
      else
        prepareAnyParamTemporarys(param3, c_param3, statement);
        if c_param3.expr <> "" then
          statement.expr &:= "strAppend(&(";
          statement.expr &:= c_param1.expr;
          statement.expr &:= "), ";
          statement.expr &:= c_param3.expr;
        else
          statement.expr &:= "strAppendTemp(&(";
          statement.expr &:= c_param1.expr;
          statement.expr &:= "), ";
          statement.expr &:= c_param3.result_expr;
        end if;
      end if;
      statement.expr &:= ");\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


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

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


(**
 *  Produces code for the string concatenation.
 *  If three or more strings are concatenated the function
 *  strConcatN is used. This saves copying and allocation operations.
 *  If the first parameter is a temporary value the concatenation
 *  is done with strConcatTemp. The strConcatTemp function returns
 *  the first parameter as result of the concatenation. That way the
 *  temporary of the first parameter must not be freed.
 *)
const proc: optimize_str_cat (in ref_list: params, inout expr_type: c_expr) is func

  local
    var array reference: concatNParamList is 0 times NIL;
    var string: concatNParamName is "";
    var integer: index is 1;
    var reference: evaluatedParam is NIL;
    var expr_type: c_param1 is expr_type.value;
  begin
    concatNParamList := getConcatNParamList(params);
    concatConstants(concatNParamList);
    if length(concatNParamList) >= 3 then
      incr(countOptimizations);
      prepare_stri_result(c_expr);
      incr(c_expr.temp_num);
      concatNParamName := "tmp_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "const_striType ";
      c_expr.temp_decls &:= concatNParamName;
      c_expr.temp_decls &:= "[";
      c_expr.temp_decls &:= str(length(concatNParamList));
      c_expr.temp_decls &:= "];\n";
      c_expr.result_expr := "(";
      for key index range concatNParamList do
        if getConstant(concatNParamList[index], STRIOBJECT, evaluatedParam) then
          c_expr.temp_assigns &:= concatNParamName;
          c_expr.temp_assigns &:= "[";
          c_expr.temp_assigns &:= str(pred(index));
          c_expr.temp_assigns &:= "] = ";
          c_expr.temp_assigns &:= stringLiteral(getValue(evaluatedParam, string));
          c_expr.temp_assigns &:= ";\n";
        else
          c_expr.result_expr &:= concatNParamName;
          c_expr.result_expr &:= "[";
          c_expr.result_expr &:= str(pred(index));
          c_expr.result_expr &:= "] = ";
          getAnyParamToResultExpr(concatNParamList[index], c_expr);
          c_expr.result_expr &:= ", ";
        end if;
      end for;
      c_expr.result_expr &:= "strConcatN(";
      c_expr.result_expr &:= concatNParamName;
      c_expr.result_expr &:= ", ";
      c_expr.result_expr &:= str(length(concatNParamList));
      c_expr.result_expr &:= "))";
    elsif length(concatNParamList) = 2 then
      prepare_stri_result(c_expr);
      prepareAnyParamTemporarys(concatNParamList[1], c_param1, c_expr);
      if isActionExpression(concatNParamList[2], "CHR_STR") then
        incr(countOptimizations);
        if c_param1.expr <> "" then
          c_expr.result_expr := "strConcatChar(";
          c_expr.result_expr &:= c_param1.expr;
        else
          c_expr.result_expr := "strConcatCharTemp(";
          c_expr.result_expr &:= c_param1.result_expr;
        end if;
        c_expr.result_expr &:= ", ";
        getAnyParamToResultExpr(getActionParameter(concatNParamList[2], 1), c_expr);
      else
        if c_param1.expr <> "" then
          c_expr.result_expr := "strConcat(";
          c_expr.result_expr &:= c_param1.expr;
        else
          c_expr.result_expr := "strConcatTemp(";
          c_expr.result_expr &:= c_param1.result_expr;
        end if;
        c_expr.result_expr &:= ", ";
        getAnyParamToResultExpr(concatNParamList[2], c_expr);
      end if;
      c_expr.result_expr &:= ")";
    elsif length(concatNParamList) = 1 then
      incr(countOptimizations);
      process_expr(concatNParamList[1], c_expr);
    else
      incr(countOptimizations);
      if c_expr.demand >= ASSIGN_RESULT then
        c_expr.result_expr := "strEmpty()";
      else
        c_expr.expr &:= stringLiteral("");
      end if;
    end if;
  end func;


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

  local
    var expr_type: c_param1 is expr_type.value;
  begin
    if optimizeStringFunctions then
      optimize_str_cat(params, c_expr);
    else
      prepare_stri_result(c_expr);
      prepareAnyParamTemporarys(params[1], c_param1, c_expr);
      if c_param1.result_expr <> "" then
        c_expr.result_expr := "strConcatTemp(";
        c_expr.result_expr &:= c_param1.result_expr;
      else
        c_expr.result_expr := "strConcat(";
        c_expr.result_expr &:= c_param1.expr;
      end if;
      c_expr.result_expr &:= ", ";
      getAnyParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


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

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


const func integer: lengthToSearch (in string: mainStri) is func

  result
    var integer: length is 0;
  begin
    for length range length(mainStri) downto 1
        until pos(mainStri[.. pred(length)], mainStri[length]) = 0 do
      noop;
    end for;
  end func;


const func string: reduceMainStriLengthForCharSearch (in string: mainStri) is
  return mainStri[.. lengthToSearch(mainStri)];


const proc: process_const_str_chpos (in string: mainStri, in reference: searched,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: searchedName is "";
    var integer: index is 0;
    var string: memchrResultName is "";
  begin
    if getConstant(searched, CHAROBJECT, evaluatedParam) then
      incr(countOptimizations);
      c_expr.expr &:= "/* pos(";
      c_expr.expr &:= replace(literal(mainStri), "*/", "*\\/");
      c_expr.expr &:= ",";
      c_expr.expr &:= literal(getValue(evaluatedParam, char));
      c_expr.expr &:= ") */ ";
      c_expr.expr &:= integerLiteral(pos(mainStri, getValue(evaluatedParam, char)));
    elsif length(mainStri) = 0 then
      incr(countOptimizations);
      c_expr.expr &:= "/* pos(\"\", *) */ ";
      c_expr.expr &:= integerLiteral(0);
    elsif length(mainStri) = 1 then
      incr(countOptimizations);
      c_expr.expr &:= "/* pos(";
      c_expr.expr &:= replace(literal(mainStri), "*/", "*\\/");
      c_expr.expr &:= ", *) */ ";
      c_expr.expr &:= charLiteral(mainStri[1]);
      c_expr.expr &:= "==(";
      process_expr(searched, c_expr);
      c_expr.expr &:= ")?";
      c_expr.expr &:= integerLiteral(1);
      c_expr.expr &:= ":";
      c_expr.expr &:= integerLiteral(0);
    elsif length(mainStri) <= 2 then
      incr(countOptimizations);
      c_expr.expr &:= "(";
      searchedName := getParameterAsVariable("charType", "searched_", searched, c_expr);
      for key index range mainStri do
        if pos(mainStri[.. pred(index)], mainStri[index]) = 0 then
          c_expr.expr &:= searchedName;
          c_expr.expr &:= "==";
          c_expr.expr &:= charLiteral(mainStri[index]);
          c_expr.expr &:= "?";
          c_expr.expr &:= integerLiteral(index);
          c_expr.expr &:= ":";
        end if;
      end for;
      c_expr.expr &:= integerLiteral(0);
      c_expr.expr &:= ")";
    elsif inlineFunctions and isByteString(mainStri) then
      incr(countOptimizations);
      c_expr.expr &:= "(";
      searchedName := getParameterAsVariable("charType", "searched_", searched, c_expr);
      memchrResultName := getTempVariable("unsigned char *", "ptr_", "", c_expr);
      c_expr.expr &:= searchedName;
      c_expr.expr &:= ">255?0:(";
      c_expr.expr &:= memchrResultName;
      c_expr.expr &:= "=memchr(";
      c_expr.expr &:= bstriLiteral(bstring(mainStri));
      c_expr.expr &:= ".mem[0],(unsigned char)";
      c_expr.expr &:= searchedName;
      c_expr.expr &:= ",";
      c_expr.expr &:= integerLiteral(length(mainStri));
      c_expr.expr &:= "),";
      c_expr.expr &:= memchrResultName;
      c_expr.expr &:= "==NULL?0:(intType)(";
      c_expr.expr &:= memchrResultName;
      c_expr.expr &:= "-bst[";
      c_expr.expr &:= str(bstri_const_table[bstring(mainStri)]);
      c_expr.expr &:= "].mem+1)))";
    else
      c_expr.expr &:= "strChPos(";
      c_expr.expr &:= stringLiteral(mainStri);
      c_expr.expr &:= ", ";
      process_expr(searched, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (STR_CHPOS, 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], STRIOBJECT, evaluatedParam) then
      process_const_str_chpos(
          reduceMainStriLengthForCharSearch(getValue(evaluatedParam, string)),
          params[2], c_expr);
    else
      c_expr.expr &:= "strChPos(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[2], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


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

  begin
    prepare_typed_result(array_type[getExprResultType(params[1])], c_expr);
    c_expr.result_expr := "strChSplit(";
    getAnyParamToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", ";
    getStdParamToResultExpr(params[2], c_expr);
    c_expr.result_expr &:= ")";
  end func;


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

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


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

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


const proc: process (STR_CPY, in reference: function,
    in ref_list: params, 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 expr_type: c_param3 is expr_type.value;
    var boolean: codeGenerated is FALSE;
  begin
    if useSpecialCaseFunctions and
        isActionExpression(params[3], "STR_CAT") and
        getActionParameter(params[3], 1) = params[1] then
      incr(countOptimizations);
      process_str_append(params[1], getActionParameter(params[3], 3), c_expr);
    else
      statement.temp_num := c_expr.temp_num;
      prepareAnyParamTemporarys(params[1], c_param1, statement);
      if useSpecialCaseFunctions then
        if isActionExpression(params[3], "STR_HEAD") and
            getActionParameter(params[3], 1) = params[1] then
          incr(countOptimizations);
          statement.expr &:= c_param1.expr;
          statement.expr &:= "=strHeadAssign(";
          statement.expr &:= c_param1.expr;
          statement.expr &:= ", ";
          process_expr(getActionParameter(params[3], 4), statement);
          statement.expr &:= ");\n";
          codeGenerated := TRUE;
        elsif isActionExpression(params[3], "STR_TAIL") and
            getActionParameter(params[3], 1) = params[1] then
          incr(countOptimizations);
          statement.expr &:= c_param1.expr;
          statement.expr &:= "=strTailAssign(";
          statement.expr &:= c_param1.expr;
          statement.expr &:= ", ";
          process_expr(getActionParameter(params[3], 3), statement);
          statement.expr &:= ");\n";
          codeGenerated := TRUE;
        elsif isActionExpression(params[3], "STR_LOW") and
            getActionParameter(params[3], 1) = params[1] then
          incr(countOptimizations);
          statement.expr &:= c_param1.expr;
          statement.expr &:= "=strLowTemp(";
          statement.expr &:= c_param1.expr;
          statement.expr &:= ");\n";
          codeGenerated := TRUE;
        elsif isActionExpression(params[3], "STR_UP") and
            getActionParameter(params[3], 1) = params[1] then
          incr(countOptimizations);
          statement.expr &:= c_param1.expr;
          statement.expr &:= "=strUpTemp(";
          statement.expr &:= c_param1.expr;
          statement.expr &:= ");\n";
          codeGenerated := TRUE;
        end if;
      end if;
      if not codeGenerated then
        c_param3.demand := ASSIGN_RESULT;
        prepareAnyParamTemporarys(params[3], c_param3, statement);
        if c_param3.result_expr <> "" then
          statement.temp_decls &:= "striType new_stri;\n";
          statement.expr &:= "new_stri=";
          statement.expr &:= c_param3.result_expr;
          statement.expr &:= ";\n";
          if isNormalVariable(params[1]) then
            statement.expr &:= "strDestr(";
            statement.expr &:= c_param1.expr;
            statement.expr &:= ");\n";
            statement.expr &:= c_param1.expr;
            statement.expr &:= "=new_stri;\n";
          else
            statement.temp_decls &:= "striType *stri_ptr=&(";
            statement.temp_decls &:= c_param1.expr;
            statement.temp_decls &:= ");\n";
            statement.expr &:= "strDestr(*stri_ptr);\n";
            statement.expr &:= "*stri_ptr=new_stri;\n";
          end if;
        else
          statement.expr &:= "strCopy(&(";
          statement.expr &:= c_param1.expr;
          statement.expr &:= "), ";
          statement.expr &:= c_param3.expr;
          statement.expr &:= ");\n";
        end if;
      end if;
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process_const_str_elemcpy (in reference: destStri,
    in integer: position, in char: aChar, inout expr_type: c_expr) is func

  local
    var expr_type: statement is expr_type.value;
    var string: destStriName is "";
  begin
    incr(countOptimizations);
    if position < 1 then
      c_expr.expr &:= "/* 'string @:= [n] char' with n < 1 */\n";
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= raiseError("INDEX_ERROR");
    else
      if string_index_check then
        incr(countIndexChecks);
        if isNormalVariable(destStri) then
          destStriName := normalVariable(destStri, statement);
        else
          incr(statement.temp_num);
          destStriName := "tmp_" & str(statement.temp_num);
          statement.temp_decls &:= "striType *";
          statement.temp_decls &:= destStriName;
          statement.temp_decls &:= ";\n";
          statement.expr &:= destStriName;
          statement.expr &:= "=&(";
          process_expr(destStri, statement);
          statement.expr &:= ");\n";
          destStriName := "*" & destStriName;
        end if;
        statement.expr &:= "if (idxChk((";
        statement.expr &:= destStriName;
        statement.expr &:= ")->size<=";
        statement.expr &:= integerLiteral(pred(position));
        statement.expr &:= ")) {\n";
        statement.expr &:= "  ";
        statement.expr &:= raiseError("INDEX_ERROR");
        statement.expr &:= "} else {\n";
        statement.expr &:= "  (";
        statement.expr &:= destStriName;
        statement.expr &:= ")->mem[";
        statement.expr &:= integerLiteral(pred(position));
        statement.expr &:= "] = (strElemType)(";
        statement.expr &:= c_literal(aChar);
        statement.expr &:= ");\n";
        statement.expr &:= "}\n";
      else
        incr(countSuppressedIndexChecks);
        statement.expr &:= "(";
        process_expr(destStri, statement);
        statement.expr &:= ")->mem[";
        statement.expr &:= integerLiteral(pred(position));
        statement.expr &:= "] = (strElemType)(";
        statement.expr &:= c_literal(aChar);
        statement.expr &:= ");\n";
      end if;
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process_const_str_elemcpy (in reference: destStri,
    in integer: position, in reference: aChar, inout expr_type: c_expr) is func

  local
    var expr_type: statement is expr_type.value;
    var string: destStriName is "";
  begin
    incr(countOptimizations);
    if position < 1 then
      c_expr.expr &:= "/* 'string @:= [n] char' with n < 1 */\n";
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= raiseError("INDEX_ERROR");
    else
      if string_index_check then
        incr(countIndexChecks);
        if isNormalVariable(destStri) then
          destStriName := normalVariable(destStri, statement);
        else
          incr(statement.temp_num);
          destStriName := "tmp_" & str(statement.temp_num);
          statement.temp_decls &:= "striType *";
          statement.temp_decls &:= destStriName;
          statement.temp_decls &:= ";\n";
          statement.expr &:= destStriName;
          statement.expr &:= "=&(";
          process_expr(destStri, statement);
          statement.expr &:= ");\n";
          destStriName := "*" & destStriName;
        end if;
        statement.expr &:= "if (idxChk((";
        statement.expr &:= destStriName;
        statement.expr &:= ")->size<=";
        statement.expr &:= integerLiteral(pred(position));
        statement.expr &:= ")) {\n";
        statement.expr &:= "  ";
        statement.expr &:= raiseError("INDEX_ERROR");
        statement.expr &:= "} else {\n";
        statement.expr &:= "  (";
        statement.expr &:= destStriName;
        statement.expr &:= ")->mem[";
        statement.expr &:= integerLiteral(pred(position));
        statement.expr &:= "] = (strElemType)(";
        process_expr(aChar, statement);
        statement.expr &:= ");\n";
        statement.expr &:= "}\n";
      else
        incr(countSuppressedIndexChecks);
        statement.expr &:= "(";
        process_expr(destStri, statement);
        statement.expr &:= ")->mem[";
        statement.expr &:= integerLiteral(pred(position));
        statement.expr &:= "] = (strElemType)(";
        process_expr(aChar, statement);
        statement.expr &:= ");\n";
      end if;
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process_const_str_elemcpy (in reference: destStri,
    in reference: position, in char: aChar, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var expr_type: statement is expr_type.value;
    var string: destStriName is "";
    var string: positionName is "";
  begin
    if getConstant(position, INTOBJECT, evaluatedParam) then
      process_const_str_elemcpy(destStri, getValue(evaluatedParam, integer), aChar, c_expr);
    else
      incr(countOptimizations);
      if string_index_check then
        incr(countIndexChecks);
        if isNormalVariable(destStri) then
          destStriName := normalVariable(destStri, statement);
        else
          incr(statement.temp_num);
          destStriName := "tmp_" & str(statement.temp_num);
          statement.temp_decls &:= "striType *";
          statement.temp_decls &:= destStriName;
          statement.temp_decls &:= ";\n";
          statement.expr &:= destStriName;
          statement.expr &:= "=&(";
          process_expr(destStri, statement);
          statement.expr &:= ");\n";
          destStriName := "*" & destStriName;
        end if;
        incr(statement.temp_num);
        positionName := "pos_" & str(statement.temp_num);
        if ccConf.TWOS_COMPLEMENT_INTTYPE then
          statement.temp_decls &:= "uintType ";
        else
          statement.temp_decls &:= "intType ";
        end if;
        statement.temp_decls &:= positionName;
        statement.temp_decls &:= ";\n";
        statement.expr &:= positionName;
        statement.expr &:= "=";
        if ccConf.TWOS_COMPLEMENT_INTTYPE then
          statement.expr &:= "(uintType)(";
          process_expr(position, statement);
          statement.expr &:= ")-1;\n";
          statement.expr &:= "if (idxChk(";
          statement.expr &:= positionName;
          statement.expr &:= ">=";
        else
          process_expr(position, statement);
          statement.expr &:= ";\n";
          statement.expr &:= "if (idxChk(";
          statement.expr &:= positionName;
          statement.expr &:= "<=0 || ";
          statement.expr &:= positionName;
          statement.expr &:= ">";
        end if;
        statement.expr &:= "(";
        statement.expr &:= destStriName;
        statement.expr &:= ")->size)) {\n";
        statement.expr &:= "  ";
        statement.expr &:= raiseError("INDEX_ERROR");
        statement.expr &:= "} else {\n";
        statement.expr &:= "  (";
        statement.expr &:= destStriName;
        statement.expr &:= ")->mem[";
        statement.expr &:= positionName;
        if ccConf.TWOS_COMPLEMENT_INTTYPE then
          statement.expr &:= "] = (strElemType)(";
        else
          statement.expr &:= "-1] = (strElemType)(";
        end if;
        statement.expr &:= c_literal(aChar);
        statement.expr &:= ");\n";
        statement.expr &:= "}\n";
      else
        incr(countSuppressedIndexChecks);
        statement.expr &:= "(";
        process_expr(destStri, statement);
        statement.expr &:= ")->mem[(";
        process_expr(position, statement);
        statement.expr &:= ")-1] = (strElemType)(";
        statement.expr &:= c_literal(aChar);
        statement.expr &:= ");\n";
      end if;
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process_str_elemcpy_last_char (in reference: destStri,
    in reference: aChar, inout expr_type: c_expr) is func

  local
    var expr_type: statement is expr_type.value;
    var string: destStriName is "";
  begin
    statement.expr &:= "/* stri @:= [length[stri)] ch; */\n";
    if isNormalVariable(destStri) then
      destStriName := normalVariable(destStri, statement);
    else
      incr(statement.temp_num);
      destStriName := "tmp_" & str(statement.temp_num);
      statement.temp_decls &:= "striType *";
      statement.temp_decls &:= destStriName;
      statement.temp_decls &:= ";\n";
      statement.expr &:= destStriName;
      statement.expr &:= "=&(";
      process_expr(destStri, statement);
      statement.expr &:= ");\n";
      destStriName := "*" & destStriName;
    end if;
    if string_index_check then
      statement.expr &:= "if (idxChk(";
      statement.expr &:= destStriName;
      statement.expr &:= "->size==0)) {\n";
      statement.expr &:= raiseError("INDEX_ERROR");
      statement.expr &:= "} else {\n";
    end if;
    statement.expr &:= destStriName;
    statement.expr &:= "->mem[";
    statement.expr &:= destStriName;
    statement.expr &:= "->size-1] = (";
    process_expr(aChar, statement);
    statement.expr &:= ");\n";
    if string_index_check then
      statement.expr &:= "}\n";
    end if;
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


const proc: process (STR_ELEMCPY, 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: destStriName is "";
    var string: positionName is "";
  begin
    if optimizeStringFunctions and
        isActionExpression(params[4], "STR_LNG") and
        getActionParameter(params[4], 1) = params[1] then
      process_str_elemcpy_last_char(params[1], params[6], c_expr);
    elsif getConstant(params[6], CHAROBJECT, evaluatedParam) then
      process_const_str_elemcpy(params[1], params[4], getValue(evaluatedParam, char), c_expr);
    elsif getConstant(params[4], INTOBJECT, evaluatedParam) then
      process_const_str_elemcpy(params[1], getValue(evaluatedParam, integer), params[6], c_expr);
    else
      if string_index_check then
        incr(countIndexChecks);
        if isNormalVariable(params[1]) then
          destStriName := normalVariable(params[1], statement);
        else
          incr(statement.temp_num);
          destStriName := "tmp_" & str(statement.temp_num);
          statement.temp_decls &:= "striType *";
          statement.temp_decls &:= destStriName;
          statement.temp_decls &:= ";\n";
          statement.expr &:= destStriName;
          statement.expr &:= "=&(";
          process_expr(params[1], statement);
          statement.expr &:= ");\n";
          destStriName := "*" & destStriName;
        end if;
        incr(statement.temp_num);
        positionName := "pos_" & str(statement.temp_num);
        if ccConf.TWOS_COMPLEMENT_INTTYPE then
          statement.temp_decls &:= "uintType ";
        else
          statement.temp_decls &:= "intType ";
        end if;
        statement.temp_decls &:= positionName;
        statement.temp_decls &:= ";\n";
        statement.expr &:= positionName;
        statement.expr &:= "=";
        if ccConf.TWOS_COMPLEMENT_INTTYPE then
          statement.expr &:= "(uintType)(";
          process_expr(params[4], statement);
          statement.expr &:= ")-1;\n";
          statement.expr &:= "if (idxChk(";
          statement.expr &:= positionName;
          statement.expr &:= ">=";
        else
          process_expr(params[4], statement);
          statement.expr &:= ";\n";
          statement.expr &:= "if (idxChk(";
          statement.expr &:= positionName;
          statement.expr &:= "<=0 || ";
          statement.expr &:= positionName;
          statement.expr &:= ">";
        end if;
        statement.expr &:= "(";
        statement.expr &:= destStriName;
        statement.expr &:= ")->size)) {\n";
        statement.expr &:= "  ";
        statement.expr &:= raiseError("INDEX_ERROR");
        statement.expr &:= "} else {\n";
        statement.expr &:= "  (";
        statement.expr &:= destStriName;
        statement.expr &:= ")->mem[";
        statement.expr &:= positionName;
        if ccConf.TWOS_COMPLEMENT_INTTYPE then
          statement.expr &:= "] = (strElemType)(";
        else
          statement.expr &:= "-1] = (strElemType)(";
        end if;
        process_expr(params[6], statement);
        statement.expr &:= ");\n";
        statement.expr &:= "}\n";
      else
        incr(countSuppressedIndexChecks);
        statement.expr &:= "(";
        process_expr(params[1], statement);
        statement.expr &:= ")->mem[(";
        process_expr(params[4], statement);
        statement.expr &:= ")-1] = (strElemType)(";
        process_expr(params[6], statement);
        statement.expr &:= ");\n";
      end if;
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const func boolean: optimize_str_eq_of_substr_fixlen (in reference: stri1,
    in reference: start1, in reference: length1, in reference: stri2,
    in reference: start2, in reference: length2, inout expr_type: c_expr) is func
  result
    var boolean: optimizationDone is FALSE;
  local
    var reference: evaluatedParam is NIL;
    var string: stri1_name is "";
    var string: stri1_size is "";
    var string: stri2_name is "";
    var string: stri2_size is "";
    var boolean: start1_is_variable is TRUE;
    var string: start1_name is "";
    var integer: start1_value is 0;
    var intRange: start1_range is intRange.value;
    var boolean: start2_is_variable is TRUE;
    var string: start2_name is "";
    var integer: start2_value is 0;
    var intRange: start2_range is intRange.value;
    var string: length_name is "";
    var integer: length_value is 0;
    var boolean: length_is_variable is TRUE;
    var intRange: length_range is intRange.value;
    var boolean: raisesIndexError is FALSE;
  begin
    if isPureExpression(stri1) and isPureExpression(start1) and
        isPureExpression(length1) and isPureExpression(stri2) and
        isPureExpression(start2) and isPureExpression(length2) and
        equalExpressions(length1, length2) then
      optimizationDone := TRUE;
      c_expr.expr &:= "(";
      stri1_name := getParameterAsVariable("const_striType", "stri1_", stri1, c_expr);
      if getConstant(stri1, STRIOBJECT, evaluatedParam) then
        stri1_size := integerLiteral(length(getValue(evaluatedParam, string)));
      else
        stri1_size := stri1_name & "->size";
      end if;
      stri2_name := getParameterAsVariable("const_striType", "stri2_", stri2, c_expr);
      if getConstant(stri2, STRIOBJECT, evaluatedParam) then
        stri2_size := integerLiteral(length(getValue(evaluatedParam, string)));
      else
        stri2_size := stri2_name & "->size";
      end if;
      if getConstant(start1, INTOBJECT, evaluatedParam) then
        start1_is_variable := FALSE;
        start1_value := getValue(evaluatedParam, integer);
        if start1_value < 1 then
          warning(DOES_RAISE, "INDEX_ERROR", c_expr);
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          raisesIndexError := TRUE;
        else
          start1_name := integerLiteral(start1_value);
        end if;
      else
        start1_name := getTempVariable("intType", "start1_", start1, c_expr);
      end if;
      if not raisesIndexError then
        if getConstant(start2, INTOBJECT, evaluatedParam) then
          start2_is_variable := FALSE;
          start2_value := getValue(evaluatedParam, integer);
          if start2_value < 1 then
            warning(DOES_RAISE, "INDEX_ERROR", c_expr);
            c_expr.expr &:= strRaiseError("INDEX_ERROR");
            raisesIndexError := TRUE;
          else
            start2_name := integerLiteral(start2_value);
          end if;
        else
          start2_name := getTempVariable("intType", "start2_", start2, c_expr);
        end if;
      end if;
      if not raisesIndexError then
        if getConstant(length1, INTOBJECT, evaluatedParam) then
          length_is_variable := FALSE;
          length_value := getValue(evaluatedParam, integer);
          if length_value < 0 then
            warning(DOES_RAISE, "INDEX_ERROR", c_expr);
            c_expr.expr &:= strRaiseError("INDEX_ERROR");
            raisesIndexError := TRUE;
          else
            length_name := integerLiteral(length_value);
          end if;
        else
          length_name := getParameterAsVariable("intType", "length_", length1, c_expr);
        end if;
      end if;
      if not raisesIndexError then
        if string_index_check then
          start1_range := getIntRange(start1);
          start2_range := getIntRange(start2);
          length_range := getIntRange(length1);
          incr(countIndexChecks);
          c_expr.expr &:= "idxChk(";
          if start1_is_variable then
            if start1_range.minValue < 1 then
              c_expr.expr &:= start1_name;
              c_expr.expr &:= "<1||";
            end if;
          end if;
          if start2_is_variable then
            if start2_range.minValue < 1 then
              c_expr.expr &:= start2_name;
              c_expr.expr &:= "<1||";
            end if;
          end if;
          if length_is_variable then
            if length_range.minValue <= 0 then
              c_expr.expr &:= "(unlikely(";
              c_expr.expr &:= length_name;
              c_expr.expr &:= "==0)?";
              c_expr.expr &:= "(uintType)";
              c_expr.expr &:= start1_name;
              c_expr.expr &:= ">";
              c_expr.expr &:= stri1_size;
              c_expr.expr &:= "||";
              c_expr.expr &:= "(uintType)";
              c_expr.expr &:= start2_name;
              c_expr.expr &:= ">";
              c_expr.expr &:= stri2_size;
              c_expr.expr &:= ":(";
            end if;
            if length_range.minValue < 0 then
              c_expr.expr &:= length_name;
              c_expr.expr &:= "<0||";
            end if;
          end if;
          if start1_is_variable then
            c_expr.expr &:= "(uintType)";
            c_expr.expr &:= start1_name;
            if length_is_variable then
              c_expr.expr &:= "+(uintType)";
              c_expr.expr &:= length_name;
              c_expr.expr &:= "-1>";
              c_expr.expr &:= stri1_size;
            else
              if length_value > 1 then
                c_expr.expr &:= "+";
                c_expr.expr &:= memSizeLiteral(pred(length_value));
              end if;
              c_expr.expr &:= ">";
              c_expr.expr &:= stri1_size;
            end if;
          else
            if length_is_variable then
              c_expr.expr &:= "(uintType)";
              c_expr.expr &:= length_name;
              if start1_value > 1 then
                c_expr.expr &:= "+";
                c_expr.expr &:= memSizeLiteral(pred(start1_value));
              end if;
              c_expr.expr &:= ">";
              c_expr.expr &:= stri1_size;
            else
              if length_value > 0 then
                c_expr.expr &:= memSizeLiteral(pred(bigInteger(start1_value) +
                                                    bigInteger(length_value)));
              else
                c_expr.expr &:= "(uintType)";
                c_expr.expr &:= start1_name;
              end if;
              c_expr.expr &:= ">";
              c_expr.expr &:= stri1_size;
            end if;
          end if;
          c_expr.expr &:= "||";
          if start2_is_variable then
            c_expr.expr &:= "(uintType)";
            c_expr.expr &:= start2_name;
            if length_is_variable then
              c_expr.expr &:= "+(uintType)";
              c_expr.expr &:= length_name;
              c_expr.expr &:= "-1>";
              c_expr.expr &:= stri2_size;
            else
              if length_value > 1 then
                c_expr.expr &:= "+";
                c_expr.expr &:= memSizeLiteral(pred(length_value));
              end if;
              c_expr.expr &:= ">";
              c_expr.expr &:= stri2_size;
            end if;
          else
            if length_is_variable then
              c_expr.expr &:= "(uintType)";
              c_expr.expr &:= length_name;
              if start2_value > 1 then
                c_expr.expr &:= "+";
                c_expr.expr &:= memSizeLiteral(pred(start2_value));
              end if;
              c_expr.expr &:= ">";
              c_expr.expr &:= stri2_size;
            else
              if length_value > 0 then
                c_expr.expr &:= memSizeLiteral(pred(bigInteger(start2_value) +
                                                    bigInteger(length_value)));
              else
                c_expr.expr &:= "(uintType)";
                c_expr.expr &:= start2_name;
              end if;
              c_expr.expr &:= ">";
              c_expr.expr &:= stri2_size;
            end if;
          end if;
          if length_is_variable and length_range.minValue <= 0 then
            c_expr.expr &:= "))";
          end if;
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("INDEX_ERROR");
          c_expr.expr &:= ":";
        else
          incr(countSuppressedIndexChecks);
        end if;
        c_expr.expr &:= "memcmp(&";
        c_expr.expr &:= stri1_name;
        c_expr.expr &:= "->mem[";
        if start1_is_variable then
          c_expr.expr &:= start1_name;
          c_expr.expr &:= "-1"
        else
          c_expr.expr &:= memSizeLiteral(pred(start1_value));
        end if;
        c_expr.expr &:= "],&";
        c_expr.expr &:= stri2_name;
        c_expr.expr &:= "->mem[";
        if start2_is_variable then
          c_expr.expr &:= start2_name;
          c_expr.expr &:= "-1";
        else
          c_expr.expr &:= memSizeLiteral(pred(start2_value));
        end if;
        c_expr.expr &:= "],";
        c_expr.expr &:= length_name;
        c_expr.expr &:= "*sizeof(strElemType))==0)";
      end if;
    end if;
  end func;


const proc: process_const_str_eq (in reference: param1, in string: stri_b,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: stri_a_name is "";
  begin
    incr(countOptimizations);
    if getConstant(param1, STRIOBJECT, evaluatedParam) then
      c_expr.expr &:= "/* ";
      c_expr.expr &:= replace(literal(getValue(evaluatedParam, string)), "*/", "*\\/");
      c_expr.expr &:= " == ";
      c_expr.expr &:= replace(literal(stri_b), "*/", "*\\/");
      c_expr.expr &:= " */ ";
      if getValue(evaluatedParam, string) = stri_b then
        c_expr.expr &:= "1";
      else
        c_expr.expr &:= "0";
      end if;
    elsif stri_b = "" then
      c_expr.expr &:= "((";
      getAnyParamToExpr(param1, c_expr);
      c_expr.expr &:= ")->size==0 /* \"\" */)";
    else
      c_expr.expr &:= "(";
      stri_a_name := getParameterAsVariable("const_striType", "tmp_", param1, c_expr);
      if length(stri_b) = 1 then
        (* Formula used: (a->size==1&&a->mem[0]==b->mem[0]) *)
        c_expr.expr &:= stri_a_name;
        c_expr.expr &:= "->size==1&&";
        c_expr.expr &:= stri_a_name;
        c_expr.expr &:= "->mem[0]==(strElemType)(";
        c_expr.expr &:= c_literal(stri_b[1]);
        c_expr.expr &:= ") /* ";
        c_expr.expr &:= literal(stri_b);
        c_expr.expr &:= " */)";
      else
        (* Formula used: (a->size==b->size&&memcmp(a->mem,b->mem,
                         b->size*sizeof(strElemType))==0) *)
        c_expr.expr &:= stri_a_name;
        c_expr.expr &:= "->size==";
        c_expr.expr &:= str(length(stri_b));
        c_expr.expr &:= "&&memcmp(";
        c_expr.expr &:= stri_a_name;
        c_expr.expr &:= "->mem,(";
        c_expr.expr &:= stringLiteral(stri_b);
        c_expr.expr &:= ")->mem,";
        c_expr.expr &:= str(length(stri_b));
        c_expr.expr &:= "*sizeof(strElemType))==0)";
      end if;
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
    var boolean: optimizationDone is FALSE;
    var string: stri_a_name is "";
    var string: stri_b_name is "";
  begin
    if getConstant(params[3], STRIOBJECT, evaluatedParam) then
      process_const_str_eq(params[1], getValue(evaluatedParam, string), c_expr);
      optimizationDone := TRUE;
    elsif getConstant(params[1], STRIOBJECT, evaluatedParam) then
      process_const_str_eq(params[3], getValue(evaluatedParam, string), c_expr);
      optimizationDone := TRUE;
    elsif optimizeStringFunctions and
        isActionExpression(params[1], "STR_SUBSTR_FIXLEN") and
        isActionExpression(params[3], "STR_SUBSTR_FIXLEN") then
      optimizationDone := optimize_str_eq_of_substr_fixlen(
          getActionParameter(params[1], 1), getActionParameter(params[1], 3),
          getActionParameter(params[1], 5), getActionParameter(params[3], 1),
          getActionParameter(params[3], 3), getActionParameter(params[3], 5), c_expr);
    end if;
    if not optimizationDone then
      c_expr.expr &:= "(";
      stri_a_name := getParameterAsVariable("const_striType", "tmp_a_", params[1], c_expr);
      stri_b_name := getParameterAsVariable("const_striType", "tmp_b_", params[3], c_expr);
      (* Formula used: (a->size==b->size&&memcmp(a->mem,b->mem,
                       a->size*sizeof(strElemType))==0) *)
      c_expr.expr &:= stri_a_name;
      c_expr.expr &:= "->size==";
      c_expr.expr &:= stri_b_name;
      c_expr.expr &:= "->size&&memcmp(";
      c_expr.expr &:= stri_a_name;
      c_expr.expr &:= "->mem,";
      c_expr.expr &:= stri_b_name;
      c_expr.expr &:= "->mem,";
      c_expr.expr &:= stri_a_name;
      c_expr.expr &:= "->size*sizeof(strElemType))==0)";
    end if;
  end func;


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

  local
    var string: size_name is "";
    var string: index_name is "";
    var string: stri_name is "";
    var expr_type: statement is expr_type.value;
  begin
    size_name := defineTempVariable("memSizeType", "size_", statement);
    index_name := defineTempVariable("memSizeType", "index_", statement);
    statement.expr &:= "for (";
    stri_name := getParameterAsVariable("const_striType", "stri_", params[4], statement);
    statement.expr &:= size_name;
    statement.expr &:= "=";
    statement.expr &:= stri_name;
    statement.expr &:= "->size,";
    statement.expr &:= index_name;
    statement.expr &:= "=0; ";
    statement.expr &:= index_name;
    statement.expr &:= "<";
    statement.expr &:= size_name;
    statement.expr &:= "; (";
    statement.expr &:= index_name;
    statement.expr &:= ")++) {\n";
    process_expr(params[2], statement);
    statement.expr &:= "=";
    statement.expr &:= stri_name;
    statement.expr &:= "->mem[";
    statement.expr &:= index_name;
    statement.expr &:= "];\n";
    process_call_by_name_expr(params[6], statement);
    statement.expr &:= "}\n";
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


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

  local
    var string: size_name is "";
    var string: index_name is "";
    var string: stri_name is "";
    var expr_type: statement is expr_type.value;
  begin
    size_name := defineTempVariable("memSizeType", "size_", statement);
    index_name := defineTempVariable("memSizeType", "index_", statement);
    statement.expr &:= "for (";
    stri_name := getParameterAsVariable("const_striType", "stri_", params[5], statement);
    statement.expr &:= size_name;
    statement.expr &:= "=";
    statement.expr &:= stri_name;
    statement.expr &:= "->size,";
    statement.expr &:= index_name;
    statement.expr &:= "=0; ";
    statement.expr &:= index_name;
    statement.expr &:= "<";
    statement.expr &:= size_name;
    statement.expr &:= "; (";
    statement.expr &:= index_name;
    statement.expr &:= ")++) {\n";
    process_expr(params[3], statement);
    statement.expr &:= "= (intType)(";
    statement.expr &:= index_name;
    statement.expr &:= " + 1);\n";
    process_call_by_name_expr(params[7], statement);
    statement.expr &:= "}\n";
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


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

  local
    var string: size_name is "";
    var string: index_name is "";
    var string: stri_name is "";
    var expr_type: statement is expr_type.value;
  begin
    size_name := defineTempVariable("memSizeType", "size_", statement);
    index_name := defineTempVariable("memSizeType", "index_", statement);
    statement.expr &:= "for (";
    stri_name := getParameterAsVariable("const_striType", "stri_", params[6], statement);
    statement.expr &:= size_name;
    statement.expr &:= "=";
    statement.expr &:= stri_name;
    statement.expr &:= "->size,";
    statement.expr &:= index_name;
    statement.expr &:= "=0; ";
    statement.expr &:= index_name;
    statement.expr &:= "<";
    statement.expr &:= size_name;
    statement.expr &:= "; (";
    statement.expr &:= index_name;
    statement.expr &:= ")++) {\n";
    process_expr(params[2], statement);
    statement.expr &:= "=";
    statement.expr &:= stri_name;
    statement.expr &:= "->mem[";
    statement.expr &:= index_name;
    statement.expr &:= "];\n";
    process_expr(params[4], statement);
    statement.expr &:= "= (intType)(";
    statement.expr &:= index_name;
    statement.expr &:= " + 1);\n";
    process_call_by_name_expr(params[8], statement);
    statement.expr &:= "}\n";
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


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

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


const proc: process_const_str_le (in string: stri1, in reference: stri2,
    inout expr_type: c_expr) is forward;


const proc: process_const_str_ge (in string: stri1, in reference: stri2,
    inout expr_type: c_expr) is func

  local
    var string: stri2_name is "";
  begin
    if stri1 = "" then
      c_expr.expr &:= "(";
      getAnyParamToExpr(stri2, c_expr);
      c_expr.expr &:= ")->size==0";
    elsif length(stri1) = 1 then
      c_expr.expr &:= "(";
      stri2_name := getParameterAsVariable("const_striType", "stri2_", stri2, c_expr);
      c_expr.expr &:= stri2_name;
      c_expr.expr &:= "->size==0||";
      c_expr.expr &:= stri2_name;
      c_expr.expr &:= "->size==1&&";
      c_expr.expr &:= stri2_name;
      c_expr.expr &:= "->mem[0]<=(strElemType)(";
      c_expr.expr &:= c_literal(stri1[1]);
      c_expr.expr &:= ") /* ";
      c_expr.expr &:= literal(stri1);
      c_expr.expr &:= " */||";
      c_expr.expr &:= stri2_name;
      c_expr.expr &:= "->mem[0]<(strElemType)(";
      c_expr.expr &:= c_literal(stri1[1]);
      c_expr.expr &:= ") /* ";
      c_expr.expr &:= literal(stri1);
      c_expr.expr &:= " */)";
    else
      c_expr.expr &:= "strGe(";
      c_expr.expr &:= stringLiteral(stri1);
      c_expr.expr &:= ", ";
      getAnyParamToExpr(stri2, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (STR_GE, 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], STRIOBJECT, evaluatedParam) then
      process_const_str_ge(getValue(evaluatedParam, string), params[3], c_expr);
    elsif getConstant(params[3], STRIOBJECT, evaluatedParam) then
      process_const_str_le(getValue(evaluatedParam, string), params[1], c_expr);
    else
      c_expr.expr &:= "strGe(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ", ";
      getAnyParamToExpr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_const_str_lt (in string: stri1, in reference: stri2,
    inout expr_type: c_expr) is forward;


const proc: process_const_str_gt (in string: stri1, in reference: stri2,
    inout expr_type: c_expr) is func

  local
    var string: stri2_name is "";
  begin
    if stri1 = "" then
      c_expr.expr &:= "0";
    elsif length(stri1) = 1 then
      c_expr.expr &:= "(";
      stri2_name := getParameterAsVariable("const_striType", "stri2_", stri2, c_expr);
      c_expr.expr &:= stri2_name;
      c_expr.expr &:= "->size==0||";
      c_expr.expr &:= stri2_name;
      c_expr.expr &:= "->mem[0]<(strElemType)(";
      c_expr.expr &:= c_literal(stri1[1]);
      c_expr.expr &:= ") /* ";
      c_expr.expr &:= literal(stri1);
      c_expr.expr &:= " */)";
    else
      c_expr.expr &:= "strGt(";
      c_expr.expr &:= stringLiteral(stri1);
      c_expr.expr &:= ", ";
      getAnyParamToExpr(stri2, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (STR_GT, 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], STRIOBJECT, evaluatedParam) then
      process_const_str_gt(getValue(evaluatedParam, string), params[3], c_expr);
    elsif getConstant(params[3], STRIOBJECT, evaluatedParam) then
      process_const_str_lt(getValue(evaluatedParam, string), params[1], c_expr);
    else
      c_expr.expr &:= "strGt(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ", ";
      getAnyParamToExpr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
    var string: stri_name is "";
  begin
    if getConstant(params[1], STRIOBJECT, evaluatedParam) then
      incr(countOptimizations);
      c_expr.expr &:= integerLiteral(hashCode(getValue(evaluatedParam, string)));
    elsif inlineFunctions then
      incr(countInlinedFunctions);
      c_expr.expr &:= "(";
      stri_name := getParameterAsVariable("const_striType", "tmp_", params[1], c_expr);
      c_expr.expr &:= stri_name;
      c_expr.expr &:= "->size==0 ? 0 : (";
      c_expr.expr &:= stri_name;
      c_expr.expr &:= "->mem[0]<<5 ^ ";
      c_expr.expr &:= stri_name;
      c_expr.expr &:= "->mem[";
      c_expr.expr &:= stri_name;
      c_expr.expr &:= "->size>>1]<<3 ^ ";
      c_expr.expr &:= stri_name;
      c_expr.expr &:= "->mem[";
      c_expr.expr &:= stri_name;
      c_expr.expr &:= "->size-1]<<1 ^ ";
      c_expr.expr &:= stri_name;
      c_expr.expr &:= "->size))";
    else
      c_expr.expr &:= "strHashCode(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_const_str_head (in string: stri, in reference: length,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var integer: length_value is 0;
    var string: length_name is "";
    var intRange: length_range is intRange.value;
    var string: slice_name is "";
  begin
    if getConstant(length, INTOBJECT, evaluatedParam) then
      incr(countOptimizations);
      length_value := getValue(evaluatedParam, integer);
      if length_value < 0 then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
      else
        c_expr.expr &:= stringLiteral(stri[.. length_value]);
      end if;
    elsif stri = "" then
      incr(countOptimizations);
      c_expr.expr &:= "/* \"\"[ .. n] */ (";
      if string_index_check then
        length_range := getIntRange(length);
        if length_range.minValue < 0 then
          incr(countIndexChecks);
          c_expr.expr &:= "idxChk(";
          process_expr(length, c_expr);
          c_expr.expr &:= "<0)?";
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          c_expr.expr &:= ":";
        else
          countIndexOptimizations(c_expr);
        end if;
      else
        incr(countSuppressedIndexChecks);
      end if;
      c_expr.expr &:= stringLiteral("");
      c_expr.expr &:= ")";
    elsif length(stri) = 1 then
      incr(countOptimizations);
      c_expr.expr &:= "(";
      length_name := getParameterAsVariable("intType", "length_", length, c_expr);
      if string_index_check then
        length_range := getIntRange(length);
        if length_range.minValue < 0 then
          incr(countIndexChecks);
          c_expr.expr &:= "idxChk(";
          c_expr.expr &:= length_name;
          c_expr.expr &:= "<0)?";
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          c_expr.expr &:= ":";
        else
          countIndexOptimizations(c_expr);
        end if;
      else
        incr(countSuppressedIndexChecks);
      end if;
      c_expr.expr &:= length_name;
      c_expr.expr &:= ">=1?";
      c_expr.expr &:= stringLiteral(stri);
      c_expr.expr &:= ":";
      c_expr.expr &:= stringLiteral("");
      c_expr.expr &:= ")";
    elsif ccConf.ALLOW_STRITYPE_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 striStruct ";
      c_expr.temp_decls &:= slice_name;
      c_expr.temp_decls &:= ";\n";
      if inlineFunctions then
        incr(countInlinedFunctions);
        length_name := getParameterAsVariable("intType", "length_", length, c_expr);
        if string_index_check then
          length_range := getIntRange(length);
          if length_range.minValue < 0 then
            c_expr.expr &:= "idxChk(";
            c_expr.expr &:= length_name;
            c_expr.expr &:= "<0)?";
            c_expr.expr &:= strRaiseError("INDEX_ERROR");
            c_expr.expr &:= ":";
          else
            countIndexOptimizations(c_expr);
          end if;
        else
          incr(countSuppressedIndexChecks);
        end if;
        c_expr.expr &:= "(";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".mem = (";
        c_expr.expr &:= stringLiteral(stri);
        c_expr.expr &:= ")->mem, ";
        c_expr.expr &:= memSizeLiteral(length(stri));
        c_expr.expr &:= "<=(uintType)";
        c_expr.expr &:= length_name;
        c_expr.expr &:= " ? ";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".size = ";
        c_expr.expr &:= memSizeLiteral(length(stri));
        c_expr.expr &:= " : (";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".size = (memSizeType)";
        c_expr.expr &:= length_name;
        c_expr.expr &:= "), &";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ")";
      else
        c_expr.expr &:= "strHeadSlice(";
        c_expr.expr &:= stringLiteral(stri);
        c_expr.expr &:= ", ";
        process_expr(length, c_expr);
        c_expr.expr &:= ", &";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= "), &";
        c_expr.expr &:= slice_name;
      end if;
      c_expr.expr &:= ")";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "strHead(";
      c_expr.result_expr &:= stringLiteral(stri);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(length, c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


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

  local
    var string: temp_name is "";
    var string: stri1_name is "";
    var expr_type: c_param1 is expr_type.value;
  begin
    if c_expr.demand < REQUIRE_RESULT then
      incr(countOptimizations);
      c_expr.expr &:= "(";
      temp_name := getParameterAsVariable("const_striType", "tmp_", param1, c_expr);
      incr(c_expr.temp_num);
      stri1_name := "stri1_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "struct striStruct ";
      c_expr.temp_decls &:= stri1_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= temp_name;
      c_expr.expr &:= "->size>=1?chrStrMacro(";
      c_expr.expr &:= temp_name;
      c_expr.expr &:= "->mem[0],";
      c_expr.expr &:= stri1_name;
      c_expr.expr &:= "):";
      c_expr.expr &:= stringLiteral("");
      c_expr.expr &:= ")";
    else
      prepareAnyParamTemporarys(param1, c_param1, c_expr);
      prepare_stri_result(c_expr);
      if c_param1.result_expr <> "" then
        c_expr.result_expr := "strHeadTemp(";
        c_expr.result_expr &:= c_param1.result_expr;
      else
        c_expr.result_expr := "strHead(";
        c_expr.result_expr &:= c_param1.expr;
      end if;
      c_expr.result_expr &:= ", 1)";
    end if;
  end func;


const proc: process_inline_str_head (in reference: stri, in reference: length,
    in string: slice_name, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: stri_name is "";
    var string: stri_value is "";
    var string: stri_size is "";
    var string: length_name is "";
    var integer: length_value is 0;
    var boolean: length_is_variable is TRUE;
    var intRange: length_range is intRange.value;
    var boolean: raisesIndexError is FALSE;
  begin
    stri_name := getParameterAsVariable("const_striType", "stri_", stri, c_expr);
    stri_size := stri_name & "->size";
    if getConstant(length, INTOBJECT, evaluatedParam) then
      length_is_variable := FALSE;
      length_value := getValue(evaluatedParam, integer);
      if length_value < 0 then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
        raisesIndexError := TRUE;
      else
        length_name := integerLiteral(length_value);
      end if;
    else
      length_name := getParameterAsVariable("intType", "length_", length, c_expr);
    end if;
    if not raisesIndexError then
      if length_is_variable then
        if string_index_check then
          length_range := getIntRange(length);
          if length_range.minValue < 0 then
            incr(countIndexChecks);
            c_expr.expr &:= "idxChk(";
            c_expr.expr &:= length_name;
            c_expr.expr &:= "<0";
            c_expr.expr &:= ")?";
            c_expr.expr &:= intRaiseError("INDEX_ERROR");
            c_expr.expr &:= ":0, ";
          else
            countIndexOptimizations(c_expr);
          end if;
        else
          incr(countSuppressedIndexChecks);
        end if;
      end if;
      if not length_is_variable and length_value = 0 then
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".mem = NULL, ";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".size = 0";
      else
        (* Formula used: slice.mem = stri->mem,
                         stri->size <= (uintType)length ?
                         slice.size = stri->size :
                         (slice.size = (memSizeType)length) *)
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".mem = ";
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->mem,";
        c_expr.expr &:= stri_size;
        c_expr.expr &:= " <= (uintType)";
        c_expr.expr &:= length_name;
        c_expr.expr &:= " ? ";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".size = ";
        c_expr.expr &:= stri_size;
        c_expr.expr &:= " : (";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".size = (memSizeType)";
        c_expr.expr &:= length_name;
        c_expr.expr &:= ")";
      end if;
    end if;
  end func;


const proc: process_str_head (in reference: stri, in reference: length,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var expr_type: c_stri is expr_type.value;
    var string: slice_name is "";
  begin
    if getConstant(stri, STRIOBJECT, evaluatedParam) then
      process_const_str_head(getValue(evaluatedParam, string), length, c_expr);
    elsif getConstant(length, INTOBJECT, evaluatedParam) and
        getValue(evaluatedParam, integer) = 1 then
      process_const_str_head1(stri, c_expr);
    else
      prepareAnyParamTemporarys(stri, c_stri, c_expr);
      if c_stri.result_expr <> "" then
        prepare_stri_result(c_expr);
        c_expr.result_expr := "strHeadTemp(";
        c_expr.result_expr &:= c_stri.result_expr;
        c_expr.result_expr &:= ", ";
        getStdParamToResultExpr(length, c_expr);
        c_expr.result_expr &:= ")";
      elsif ccConf.ALLOW_STRITYPE_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 striStruct ";
        c_expr.temp_decls &:= slice_name;
        c_expr.temp_decls &:= ";\n";
        if inlineFunctions then
          incr(countInlinedFunctions);
          process_inline_str_head(stri, length, slice_name, c_expr);
        else
          c_expr.expr &:= "strHeadSlice(";
          c_expr.expr &:= c_stri.expr;
          c_expr.expr &:= ", ";
          process_expr(length, c_expr);
          c_expr.expr &:= ", &";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ")";
        end if;
        c_expr.expr &:= ", &";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ")";
      else
        prepare_stri_result(c_expr);
        c_expr.result_expr := "strHead(";
        c_expr.result_expr &:= c_stri.expr;
        c_expr.result_expr &:= ", ";
        getStdParamToResultExpr(length, c_expr);
        c_expr.result_expr &:= ")";
      end if;
    end if;
  end func;


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

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


const proc: process_const_str_idx (in string: stri,
    in reference: index, inout expr_type: c_expr) is func

  local
    var intRange: indexRange is intRange.value;
    var string: index_name is "";
  begin
    incr(countOptimizations);
    if string_index_check then
      indexRange := getIntRange(index);
      if indexRange.maxValue < 1 or
          indexRange.minValue > length(stri) then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("INDEX_ERROR");
      else
        c_expr.expr &:= "(";
        c_expr.expr &:= stringLiteral(stri);
        c_expr.expr &:= ")->mem[";
        if indexRange.minValue < 1 or
            indexRange.maxValue > length(stri) then
          incr(countIndexChecks);
          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;
          c_expr.expr &:= "=";
          if ccConf.TWOS_COMPLEMENT_INTTYPE then
            c_expr.expr &:= "(uintType)(";
            process_expr(index, c_expr);
            c_expr.expr &:= ")-1, idxChk(";
            c_expr.expr &:= index_name;
            c_expr.expr &:= ">=";
          else
            process_expr(index, c_expr);
            c_expr.expr &:= ", idxChk(";
            c_expr.expr &:= index_name;
            c_expr.expr &:= "<=0 || ";
            c_expr.expr &:= index_name;
            c_expr.expr &:= ">";
          end if;
          c_expr.expr &:= str(length(stri));
          c_expr.expr &:= ") ? ";
          c_expr.expr &:= intRaiseError("INDEX_ERROR");
          c_expr.expr &:= " : ";
          c_expr.expr &:= index_name;
          if ccConf.TWOS_COMPLEMENT_INTTYPE then
            c_expr.expr &:= ")";
          else
            c_expr.expr &:= "-1)";
          end if;
        else
          countIndexOptimizations(c_expr);
          c_expr.expr &:= "(";
          process_expr(index, c_expr);
          c_expr.expr &:= ")-1";
        end if;
        c_expr.expr &:= "]";
      end if;
    else
      incr(countSuppressedIndexChecks);
      c_expr.expr &:= "(";
      c_expr.expr &:= stringLiteral(stri);
      c_expr.expr &:= ")->mem[(";
      process_expr(index, c_expr);
      c_expr.expr &:= ")-1]";
    end if;
  end func;


const proc: process_const_str_idx (in reference: stri,
    in integer: index, inout expr_type: c_expr) is func

  local
    var intRange: lengthRange is intRange.value;
    var string: stri_name is "";
  begin
    incr(countOptimizations);
    if index < 1 then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("INDEX_ERROR");
    elsif string_index_check then
      lengthRange := getStrLenRange(stri);
      if index > lengthRange.maxValue then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("INDEX_ERROR");
      elsif index > lengthRange.minValue then
        incr(countIndexChecks);
        c_expr.expr &:= "(";
        stri_name := getParameterAsVariable("const_striType", "tmp_", stri, c_expr);
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->mem[(idxChk(";
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->size<";
        c_expr.expr &:= integerLiteral(index);
        c_expr.expr &:= ") ? ";
        c_expr.expr &:= intRaiseError("INDEX_ERROR");
        c_expr.expr &:= " : ";
        c_expr.expr &:= integerLiteral(pred(index));
        c_expr.expr &:= ")])";
      else
        countIndexOptimizations(c_expr);
        c_expr.expr &:= "(";
        getAnyParamToExpr(stri, c_expr);
        c_expr.expr &:= ")->mem[";
        c_expr.expr &:= integerLiteral(pred(index));
        c_expr.expr &:= "]";
      end if;
    else
      incr(countSuppressedIndexChecks);
      c_expr.expr &:= "(";
      getAnyParamToExpr(stri, c_expr);
      c_expr.expr &:= ")->mem[";
      c_expr.expr &:= integerLiteral(pred(index));
      c_expr.expr &:= "]";
    end if;
  end func;


const proc: process_str_idx_last_char (in reference: stri,
    inout expr_type: c_expr) is func

  local
    var string: stri_name is "";
  begin
    incr(countOptimizations);
    c_expr.expr &:= "/* stri[length[stri)] */ (";
    stri_name := getParameterAsVariable("const_striType", "stri_", stri, c_expr);
    if string_index_check then
      c_expr.expr &:= "idxChk(";
      c_expr.expr &:= stri_name;
      c_expr.expr &:= "->size==0) ? ";
      c_expr.expr &:= intRaiseError("INDEX_ERROR");
      c_expr.expr &:= " : ";
    end if;
    c_expr.expr &:= stri_name;
    c_expr.expr &:= "->mem[";
    c_expr.expr &:= stri_name;
    c_expr.expr &:= "->size-1])";
  end func;


const proc: process_str_idx (in reference: stri,
    in reference: index, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var intRange: lengthRange is intRange.value;
    var intRange: indexRange is intRange.value;
    var string: stri_name is "";
    var string: index_name is "";
  begin
    if getConstant(stri, STRIOBJECT, evaluatedParam) then
      process_const_str_idx(getValue(evaluatedParam, string), index, c_expr);
    elsif getConstant(index, INTOBJECT, evaluatedParam) then
      process_const_str_idx(stri, getValue(evaluatedParam, integer), c_expr);
    elsif optimizeStringFunctions and
        isActionExpression(index, "STR_LNG") and
        getActionParameter(index, 1) = stri then
      process_str_idx_last_char(stri, c_expr);
    elsif string_index_check then
      lengthRange := getStrLenRange(stri);
      indexRange := getIntRange(index);
      if indexRange.maxValue < 1 or
          indexRange.minValue > lengthRange.maxValue then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("INDEX_ERROR");
      elsif indexRange.minValue < 1 or
          indexRange.maxValue > lengthRange.minValue then
        incr(countIndexChecks);
        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 &:= "(";
        stri_name := getParameterAsVariable("const_striType", "stri_", stri, c_expr);
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->mem[(";
        c_expr.expr &:= index_name;
        c_expr.expr &:= "=";
        if ccConf.TWOS_COMPLEMENT_INTTYPE then
          c_expr.expr &:= "(uintType)(";
          process_expr(index, c_expr);
          c_expr.expr &:= ")-1, idxChk(";
          c_expr.expr &:= index_name;
          c_expr.expr &:= ">=";
        else
          process_expr(index, c_expr);
          c_expr.expr &:= ", idxChk(";
          c_expr.expr &:= index_name;
          c_expr.expr &:= "<=0 || ";
          c_expr.expr &:= index_name;
          c_expr.expr &:= ">";
        end if;
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->size) ? ";
        c_expr.expr &:= intRaiseError("INDEX_ERROR");
        c_expr.expr &:= " : ";
        c_expr.expr &:= index_name;
        if ccConf.TWOS_COMPLEMENT_INTTYPE then
          c_expr.expr &:= ")])";
        else
          c_expr.expr &:= "-1)])";
        end if;
      else
        countIndexOptimizations(c_expr);
        c_expr.expr &:= "(";
        getAnyParamToExpr(stri, c_expr);
        c_expr.expr &:= ")->mem[(";
        process_expr(index, c_expr);
        c_expr.expr &:= ")-1]";
      end if;
    else
      incr(countSuppressedIndexChecks);
      c_expr.expr &:= "(";
      getAnyParamToExpr(stri, c_expr);
      c_expr.expr &:= ")->mem[(";
      process_expr(index, c_expr);
      c_expr.expr &:= ")-1]";
    end if;
  end func;


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

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


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

  local
    var reference: evaluatedParam is NIL;
  begin
    if getConstant(params[2], STRIOBJECT, evaluatedParam) and
        length(getValue(evaluatedParam, string)) = 1 then
      incr(countOptimizations);
      c_expr.expr &:= "strChIPos(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ", ";
      c_expr.expr &:= charLiteral(getValue(evaluatedParam, string)[1]);
      c_expr.expr &:= ", ";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= "strIPos(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ", ";
      getAnyParamToExpr(params[2], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_const_str_le (in string: stri1, in reference: stri2,
    inout expr_type: c_expr) is func

  local
    var string: stri2_name is "";
  begin
    if stri1 = "" then
      c_expr.expr &:= "1";
    elsif length(stri1) = 1 then
      c_expr.expr &:= "(";
      stri2_name := getParameterAsVariable("const_striType", "stri2_", stri2, c_expr);
      c_expr.expr &:= stri2_name;
      c_expr.expr &:= "->size>=1&&";
      c_expr.expr &:= stri2_name;
      c_expr.expr &:= "->mem[0]>=(strElemType)(";
      c_expr.expr &:= c_literal(stri1[1]);
      c_expr.expr &:= ") /* ";
      c_expr.expr &:= literal(stri1);
      c_expr.expr &:= " */)";
    else
      c_expr.expr &:= "strLe(";
      c_expr.expr &:= stringLiteral(stri1);
      c_expr.expr &:= ", ";
      getAnyParamToExpr(stri2, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (STR_LE, 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], STRIOBJECT, evaluatedParam) then
      process_const_str_le(getValue(evaluatedParam, string), params[3], c_expr);
    elsif getConstant(params[3], STRIOBJECT, evaluatedParam) then
      process_const_str_ge(getValue(evaluatedParam, string), params[1], c_expr);
    else
      c_expr.expr &:= "strLe(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ", ";
      getAnyParamToExpr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


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

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


const func integer: sumLengthOfConstants (inout array reference: concatNParamList) is func
  result
    var integer: lengthOfConstants is 0;
  local
    var integer: index is 1;
    var reference: evaluatedParam is NIL;
    var string: paramValue is "";
  begin
    while index <= length(concatNParamList) do
      if getConstant(concatNParamList[index], STRIOBJECT, evaluatedParam) then
        lengthOfConstants +:= length(getValue(evaluatedParam, string));
        ignore(remove(concatNParamList, index));
      else
        incr(index);
      end if;
    end while;
  end func;


const proc: optimize_str_lng (in reference: lengthParam,
    inout expr_type: c_expr) is forward;


const proc: optimize_str_lng (STR_CAT, in ref_list: params,
    inout expr_type: c_expr) is func

  local
    var array reference: concatNParamList is 0 times NIL;
    var integer: lengthOfConstants is 0;
    var reference: striObj is NIL;
  begin
    concatNParamList := getConcatNParamList(params);
    lengthOfConstants := sumLengthOfConstants(concatNParamList);
    for striObj range concatNParamList do
      optimize_str_lng(striObj, c_expr);
      c_expr.expr &:= " + ";
    end for;
    c_expr.expr &:= integerLiteral(lengthOfConstants);
  end func;


const proc: optimize_str_lng (in reference: lengthParam,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: stri is "";
    var ref_list: params is ref_list.value;
    var intRange: lengthRange is intRange.value;
  begin
    if getConstant(lengthParam, STRIOBJECT, evaluatedParam) then
      incr(countOptimizations);
      stri := getValue(evaluatedParam, string);
      c_expr.expr &:= integerLiteral(length(stri));
      c_expr.expr &:= " /* length(";
      c_expr.expr &:= replace(literal(stri), "*/", "*\\/");
      c_expr.expr &:= ") */";
    elsif isActionExpression(lengthParam, "STR_CAT") then
      params := getValue(lengthParam, ref_list)[2 ..];
      optimize_str_lng(STR_CAT, params, c_expr);
    elsif isActionExpression(lengthParam, "STR_SUBSTR_FIXLEN") then
      incr(countOptimizations);
      if getConstant(getActionParameter(lengthParam, 5), INTOBJECT, evaluatedParam) then
        c_expr.expr &:= integerLiteral(getValue(evaluatedParam, integer));
      else
        c_expr.expr &:= "(";
        process_expr(getActionParameter(lengthParam, 5), c_expr);
        c_expr.expr &:= ")";
      end if;
      c_expr.expr &:= " /* length of fixlLen substring */";
    else
      lengthRange := getStrLenRange(lengthParam);
      if not lengthRange.mayRaiseException and
          lengthRange.minValue = lengthRange.maxValue then
        c_expr.expr &:= integerLiteral(lengthRange.minValue);
        c_expr.expr &:= " /* length of string does not change */";
      else
        c_expr.expr &:= "(intType)((";
        getAnyParamToExpr(lengthParam, c_expr);
        c_expr.expr &:= ")->size)";
      end if;
    end if;
  end func;


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

  begin
    if optimizeStringFunctions then
      optimize_str_lng(params[1], c_expr);
    else
      c_expr.expr &:= "(intType)((";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ")->size)";
    end if;
  end func;


(**
 *  Produces code to return a string converted to lower case.
 *  If the parameter is a temporary value the conversion is done
 *  with strLowTemp. The strLowTemp function returns the parameter as
 *  result of the conversion. That way the temporary of the parameter
 *  must not be freed.
 *)
const proc: process (STR_LOW, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var expr_type: c_param1 is expr_type.value;
  begin
    prepare_stri_result(c_expr);
    prepareAnyParamTemporarys(params[1], c_param1, c_expr);
    if c_param1.result_expr <> "" then
      c_expr.result_expr := "strLowTemp(";
      c_expr.result_expr &:= c_param1.result_expr;
    else
      c_expr.result_expr := "strLow(";
      c_expr.result_expr &:= c_param1.expr;
    end if;
    c_expr.result_expr &:= ")";
  end func;


(**
 *  Produces code for the lpad operator.
 *  If the first parameter is a temporary value the operation
 *  is done with strLpadTemp. The strLpadTemp function returns
 *  the first parameter as result of the operation. That way the
 *  temporary of the first parameter must not be freed.
 *)
const proc: process (STR_LPAD, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var expr_type: c_param1 is expr_type.value;
  begin
    prepare_stri_result(c_expr);
    prepareAnyParamTemporarys(params[1], c_param1, c_expr);
    if c_param1.result_expr <> "" then
      c_expr.result_expr := "strLpadTemp(";
      c_expr.result_expr &:= c_param1.result_expr;
    else
      c_expr.result_expr := "strLpad(";
      c_expr.result_expr &:= c_param1.expr;
    end if;
    c_expr.result_expr &:= ", ";
    getStdParamToResultExpr(params[3], c_expr);
    c_expr.result_expr &:= ")";
  end func;


(**
 *  Produces code for the lpad0 operator.
 *  If the first parameter is a temporary value the operation
 *  is done with strLpad0Temp. The strLpad0Temp function returns
 *  the first parameter as result of the operation. That way the
 *  temporary of the first parameter must not be freed.
 *)
const proc: process (STR_LPAD0, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var expr_type: c_param1 is expr_type.value;
  begin
    prepare_stri_result(c_expr);
    prepareAnyParamTemporarys(params[1], c_param1, c_expr);
    if c_param1.result_expr <> "" then
      c_expr.result_expr := "strLpad0Temp(";
      c_expr.result_expr &:= c_param1.result_expr;
    else
      c_expr.result_expr := "strLpad0(";
      c_expr.result_expr &:= c_param1.expr;
    end if;
    c_expr.result_expr &:= ", ";
    getStdParamToResultExpr(params[3], c_expr);
    c_expr.result_expr &:= ")";
  end func;


const proc: process_const_str_lt (in string: stri1, in reference: stri2,
    inout expr_type: c_expr) is func

  local
    var string: stri2_name is "";
  begin
    if stri1 = "" then
      c_expr.expr &:= "(";
      getAnyParamToExpr(stri2, c_expr);
      c_expr.expr &:= ")->size!=0";
    elsif length(stri1) = 1 then
      c_expr.expr &:= "(";
      stri2_name := getParameterAsVariable("const_striType", "stri2_", stri2, c_expr);
      c_expr.expr &:= stri2_name;
      c_expr.expr &:= "->size>1&&";
      c_expr.expr &:= stri2_name;
      c_expr.expr &:= "->mem[0]>=(strElemType)(";
      c_expr.expr &:= c_literal(stri1[1]);
      c_expr.expr &:= ") /* ";
      c_expr.expr &:= literal(stri1);
      c_expr.expr &:= " */)||";
      c_expr.expr &:= stri2_name;
      c_expr.expr &:= "->size==1&&";
      c_expr.expr &:= stri2_name;
      c_expr.expr &:= "->mem[0]>(strElemType)(";
      c_expr.expr &:= c_literal(stri1[1]);
      c_expr.expr &:= ") /* ";
      c_expr.expr &:= literal(stri1);
      c_expr.expr &:= " */";
    else
      c_expr.expr &:= "strLt(";
      c_expr.expr &:= stringLiteral(stri1);
      c_expr.expr &:= ", ";
      getAnyParamToExpr(stri2, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (STR_LT, 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], STRIOBJECT, evaluatedParam) then
      process_const_str_lt(getValue(evaluatedParam, string), params[3], c_expr);
    elsif getConstant(params[3], STRIOBJECT, evaluatedParam) then
      process_const_str_gt(getValue(evaluatedParam, string), params[1], c_expr);
    else
      c_expr.expr &:= "strLt(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ", ";
      getAnyParamToExpr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


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

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


const proc: process_const_str_mult (in string: stri, in reference: factor,
    inout expr_type: c_expr) is func

  local
    var char: ch is ' ';
    var intRange: factorRange is intRange.value;
  begin
    if stri = "" then
      incr(countOptimizations);
      if function_range_check then
        factorRange := getIntRange(factor);
        if factorRange.minValue >= 0 then
          # This function cannot trigger a range error.
          countRangeOptimizations(c_expr);
          c_expr.expr &:= stringLiteral("");
        else
          incr(countRangeChecks);
          c_expr.expr &:= "(rngChk((";
          process_expr(factor, c_expr);
          c_expr.expr &:= ")<0)?";
          c_expr.expr &:= strRaiseError("RANGE_ERROR");
          c_expr.expr &:= ":";
          c_expr.expr &:= stringLiteral("");
          c_expr.expr &:= ")";
        end if;
      else
        incr(countNoRangeChecks);
        c_expr.expr &:= stringLiteral("");
      end if;
    else
      prepare_stri_result(c_expr);
      if length(stri) = 1 then
        incr(countOptimizations);
        ch := stri[1];
        if ch = '\0;' then
          c_expr.result_expr := "strZero(";
        else
          c_expr.result_expr := "strChMult(";
          c_expr.result_expr &:= charLiteral(ch);
          c_expr.result_expr &:= ", ";
        end if;
      else
        c_expr.result_expr := "strMult(";
        c_expr.result_expr &:= stringLiteral(stri);
        c_expr.result_expr &:= ", ";
      end if;
      getStdParamToResultExpr(factor, c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process_const_str_mult (in reference: stri, in integer: factor,
    inout expr_type: c_expr) is func

  local
    var expr_type: c_stri is expr_type.value;
  begin
    if factor < 0 then
      incr(countOptimizations);
      warning(DOES_RAISE, "RANGE_ERROR", c_expr);
      c_expr.expr &:= strRaiseError("RANGE_ERROR");
    elsif factor = 0 then
      incr(countOptimizations);
      c_expr.expr &:= stringLiteral("");
    elsif factor = 1 then
      incr(countOptimizations);
      process_expr(stri, c_expr);
    elsif useSpecialCaseFunctions and
        isActionExpression(stri, "CHR_STR") then
      incr(countOptimizations);
      prepare_stri_result(c_expr);
      c_expr.result_expr := "strChMult(";
      getAnyParamToResultExpr(getActionParameter(stri, 1), c_expr);
      c_expr.result_expr &:= ", ";
      c_expr.result_expr &:= integerLiteral(factor);
      c_expr.result_expr &:= ")";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "strMult(";
      getAnyParamToResultExpr(stri, c_expr);
      c_expr.result_expr &:= ", ";
      c_expr.result_expr &:= integerLiteral(factor);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process (STR_MULT, 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], STRIOBJECT, evaluatedParam) then
      process_const_str_mult(getValue(evaluatedParam, string), params[3], c_expr);
    elsif getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_str_mult(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif useSpecialCaseFunctions and
        isActionExpression(params[1], "CHR_STR") then
      incr(countOptimizations);
      prepare_stri_result(c_expr);
      c_expr.result_expr := "strChMult(";
      getAnyParamToResultExpr(getActionParameter(params[1], 1), c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ")";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "strMult(";
      getAnyParamToResultExpr(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_str_ne (in reference: param1, in string: stri_b,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: stri_a_name is "";
  begin
    incr(countOptimizations);
    if getConstant(param1, STRIOBJECT, evaluatedParam) then
      c_expr.expr &:= "/* ";
      c_expr.expr &:= replace(literal(getValue(evaluatedParam, string)), "*/", "*\\/");
      c_expr.expr &:= " != ";
      c_expr.expr &:= replace(literal(stri_b), "*/", "*\\/");
      c_expr.expr &:= " */ ";
      if getValue(evaluatedParam, string) <> stri_b then
        c_expr.expr &:= "1";
      else
        c_expr.expr &:= "0";
      end if;
    elsif stri_b = "" then
      c_expr.expr &:= "((";
      getAnyParamToExpr(param1, c_expr);
      c_expr.expr &:= ")->size!=0 /* \"\" */)";
    else
      c_expr.expr &:= "(";
      stri_a_name := getParameterAsVariable("const_striType", "tmp_", param1, c_expr);
      if length(stri_b) = 1 then
        (* Formula used: (a->size!=1||a->mem[0]!=b->mem[0]) *)
        c_expr.expr &:= stri_a_name;
        c_expr.expr &:= "->size!=1||";
        c_expr.expr &:= stri_a_name;
        c_expr.expr &:= "->mem[0]!=(strElemType)(";
        c_expr.expr &:= c_literal(stri_b[1]);
        c_expr.expr &:= ") /* ";
        c_expr.expr &:= literal(stri_b);
        c_expr.expr &:= " */)";
      else
        (* Formula used: (a->size!=b->size||memcmp(a->mem,b->mem,
                         b->size*sizeof(strElemType))!=0) *)
        c_expr.expr &:= stri_a_name;
        c_expr.expr &:= "->size!=";
        c_expr.expr &:= str(length(stri_b));
        c_expr.expr &:= "||memcmp(";
        c_expr.expr &:= stri_a_name;
        c_expr.expr &:= "->mem,(";
        c_expr.expr &:= stringLiteral(stri_b);
        c_expr.expr &:= ")->mem,";
        c_expr.expr &:= str(length(stri_b));
        c_expr.expr &:= "*sizeof(strElemType))!=0)";
      end if;
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
    var string: stri_a_name is "";
    var string: stri_b_name is "";
  begin
    if getConstant(params[3], STRIOBJECT, evaluatedParam) then
      process_const_str_ne(params[1], getValue(evaluatedParam, string), c_expr);
    elsif getConstant(params[1], STRIOBJECT, evaluatedParam) then
      process_const_str_ne(params[3], getValue(evaluatedParam, string), c_expr);
    else
      c_expr.expr &:= "(";
      stri_a_name := getParameterAsVariable("const_striType", "tmp_a_", params[1], c_expr);
      stri_b_name := getParameterAsVariable("const_striType", "tmp_b_", params[3], c_expr);
      (* Formula used: (a->size!=b->size||memcmp(a->mem,b->mem,
                       a->size*sizeof(strElemType))!=0) *)
      c_expr.expr &:= stri_a_name;
      c_expr.expr &:= "->size!=";
      c_expr.expr &:= stri_b_name;
      c_expr.expr &:= "->size||memcmp(";
      c_expr.expr &:= stri_a_name;
      c_expr.expr &:= "->mem,";
      c_expr.expr &:= stri_b_name;
      c_expr.expr &:= "->mem,";
      c_expr.expr &:= stri_a_name;
      c_expr.expr &:= "->size*sizeof(strElemType))!=0)";
    end if;
  end func;


const proc: process_const_str_pos (in string: mainStri, in reference: searched,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: searchedName is "";
  begin
    if getConstant(searched, STRIOBJECT, evaluatedParam) then
      incr(countOptimizations);
      c_expr.expr &:= "/* pos(";
      c_expr.expr &:= replace(literal(mainStri), "*/", "*\\/");
      c_expr.expr &:= ",";
      c_expr.expr &:= replace(literal(getValue(evaluatedParam, string)), "*/", "*\\/");
      c_expr.expr &:= ") */ ";
      c_expr.expr &:= integerLiteral(pos(mainStri, getValue(evaluatedParam, string)));
    elsif length(mainStri) = 0 then
      incr(countOptimizations);
      c_expr.expr &:= "/* pos(\"\", *) */ ";
      c_expr.expr &:= integerLiteral(0);
    elsif length(mainStri) = 1 then
      incr(countOptimizations);
      c_expr.expr &:= "(";
      searchedName := getParameterAsVariable("const_striType", "searched_", searched, c_expr);
      c_expr.expr &:= searchedName;
      c_expr.expr &:= "->size==1&&";
      c_expr.expr &:= searchedName;
      c_expr.expr &:= "->mem[0]==";
      c_expr.expr &:= charLiteral(mainStri[1]);
      c_expr.expr &:= "?1:0";
      c_expr.expr &:= ")";
    elsif isActionExpression(searched, "CHR_STR") then
      process_const_str_chpos(reduceMainStriLengthForCharSearch(mainStri),
          getActionParameter(searched, 1), c_expr);
    elsif isActionExpression(searched, "STR_SUBSTR_FIXLEN") and
        getConstant(getActionParameter(searched, 5), INTOBJECT, evaluatedParam) and
        getValue(evaluatedParam, integer) = 1 then
      c_expr.expr &:= "strChPos(";
      c_expr.expr &:= stringLiteral(reduceMainStriLengthForCharSearch(mainStri));
      c_expr.expr &:= ", ";
      process_str_idx(getActionParameter(searched, 1),
                      getActionParameter(searched, 3), c_expr);
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= "strPos(";
      c_expr.expr &:= stringLiteral(mainStri);
      c_expr.expr &:= ", ";
      getAnyParamToExpr(searched, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_const_str_pos (in reference: mainStri, in string: searched,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
  begin
    if length(searched) = 0 then
      incr(countOptimizations);
      c_expr.expr &:= "/* pos(*, \"\") */ ";
      c_expr.expr &:= integerLiteral(0);
    elsif length(searched) = 1 then
      incr(countOptimizations);
      c_expr.expr &:= "strChPos(";
      getAnyParamToExpr(mainStri, c_expr);
      c_expr.expr &:= ", ";
      c_expr.expr &:= charLiteral(searched[1]);
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= "strPos(";
      getAnyParamToExpr(mainStri, c_expr);
      c_expr.expr &:= ", ";
      c_expr.expr &:= stringLiteral(searched);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (STR_POS, 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], STRIOBJECT, evaluatedParam) then
      process_const_str_pos(getValue(evaluatedParam, string), params[2], c_expr);
    elsif getConstant(params[2], STRIOBJECT, evaluatedParam) then
      process_const_str_pos(params[1], getValue(evaluatedParam, string), c_expr);
    elsif isActionExpression(params[2], "CHR_STR") then
      c_expr.expr &:= "strChPos(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ", ";
      process_expr(getActionParameter(params[2], 1), c_expr);
      c_expr.expr &:= ")";
    elsif isActionExpression(params[2], "STR_SUBSTR_FIXLEN") and
        getConstant(getActionParameter(params[2], 5), INTOBJECT, evaluatedParam) and
        getValue(evaluatedParam, integer) = 1 then
      c_expr.expr &:= "strChPos(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ", ";
      process_str_idx(getActionParameter(params[2], 1),
                      getActionParameter(params[2], 3), c_expr);
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= "strPos(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ", ";
      getAnyParamToExpr(params[2], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_const_str_poscpy (in reference: destStri,
    in integer: position, in string: aStri, inout expr_type: c_expr) is func
  local
    var expr_type: c_destStri is expr_type.value;
  begin
    incr(countOptimizations);
    if position < 1 then
      c_expr.expr &:= "/* 'string @:= [n] string' with n < 1 */\n";
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= raiseError("INDEX_ERROR");
    else
      incr(countOptimizations);
      process_expr(destStri, c_destStri);
      c_expr.expr &:= "{\n";
      if c_destStri.temp_num <> 0 then
        appendWithDiagnostic(c_destStri.temp_decls, c_expr);
        appendWithDiagnostic(c_destStri.temp_assigns, c_expr);
       end if;
      if string_index_check then
        incr(countIndexChecks);
        c_expr.expr &:= "striType destStri=";
        c_expr.expr &:= c_destStri.expr;
        c_expr.expr &:= ";\n";
        c_expr.expr &:= "if (idxChk(";
        c_expr.expr &:= "destStri->size<";
        c_expr.expr &:= integerLiteral(length(aStri));
        c_expr.expr &:= " || (uintType)";
        c_expr.expr &:= integerLiteral(pred(position));
        c_expr.expr &:= ">destStri->size-";
        c_expr.expr &:= integerLiteral(length(aStri));
        c_expr.expr &:= ")) {\n";
        c_expr.expr &:= "  ";
        c_expr.expr &:= raiseError("INDEX_ERROR");
        c_expr.expr &:= "} else {\n";
        setDiagnosticLine(c_expr);
        c_expr.expr &:= "  memcpy(&destStri->mem[";
        c_expr.expr &:= integerLiteral(pred(position));
        c_expr.expr &:= "], (";
        c_expr.expr &:= stringLiteral(aStri);
        c_expr.expr &:= ")->mem, ";
        c_expr.expr &:= integerLiteral(length(aStri));
        c_expr.expr &:= "*sizeof(strElemType));\n";
        c_expr.expr &:= "}\n";
      else
        incr(countSuppressedIndexChecks);
        setDiagnosticLine(c_expr);
        c_expr.expr &:= "memcpy(&(";
        c_expr.expr &:= c_destStri.expr;
        c_expr.expr &:= ")->mem[";
        c_expr.expr &:= integerLiteral(pred(position));
        c_expr.expr &:= "], (";
        c_expr.expr &:= stringLiteral(aStri);
        c_expr.expr &:= ")->mem, ";
        c_expr.expr &:= integerLiteral(length(aStri));
        c_expr.expr &:= "*sizeof(strElemType));\n";
      end if;
      if c_destStri.temp_num <> 0 then
        appendWithDiagnostic(c_destStri.temp_frees, c_expr);
      end if;
      c_expr.expr &:= "}\n";
    end if;
  end func;


const proc: process_const_str_poscpy (in reference: destStri,
    in integer: position, in reference: aStri, inout expr_type: c_expr) is func

  local
    var expr_type: c_destStri is expr_type.value;
    var expr_type: c_aStri is expr_type.value;
  begin
    incr(countOptimizations);
    if position < 1 then
      c_expr.expr &:= "/* 'string @:= [n] string' with n < 1 */\n";
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= raiseError("INDEX_ERROR");
    else
      process_expr(destStri, c_destStri);
      c_aStri.temp_num := c_destStri.temp_num;
      getAnyParamToExpr(aStri, c_aStri);
      c_expr.expr &:= "{\n";
      if c_aStri.temp_num <> 0 then
        appendWithDiagnostic(c_destStri.temp_decls, c_expr);
        appendWithDiagnostic(c_aStri.temp_decls, c_expr);
        appendWithDiagnostic(c_destStri.temp_assigns, c_expr);
        appendWithDiagnostic(c_aStri.temp_assigns, c_expr);
      end if;
      if string_index_check then
        incr(countIndexChecks);
        c_expr.expr &:= "striType destStri=";
        c_expr.expr &:= c_destStri.expr;
        c_expr.expr &:= ";\n";
        c_expr.expr &:= "const_striType aStri=";
        c_expr.expr &:= c_aStri.expr;
        c_expr.expr &:= ";\n";
        c_expr.expr &:= "if (idxChk(destStri->size<aStri->size || (uintType)";
        c_expr.expr &:= integerLiteral(pred(position));
        c_expr.expr &:= ">destStri->size-aStri->size)) {\n";
        c_expr.expr &:= "  ";
        c_expr.expr &:= raiseError("INDEX_ERROR");
        c_expr.expr &:= "} else {\n";
        setDiagnosticLine(c_expr);
        c_expr.expr &:= "  memmove(&destStri->mem[";
        c_expr.expr &:= integerLiteral(pred(position));
        c_expr.expr &:= "], aStri->mem, aStri->size*sizeof(strElemType));\n";
        c_expr.expr &:= "}\n";
      else
        incr(countSuppressedIndexChecks);
        c_expr.expr &:= "const_striType aStri=";
        c_expr.expr &:= c_aStri.expr;
        c_expr.expr &:= ";\n";
        setDiagnosticLine(c_expr);
        c_expr.expr &:= "memmove(&(";
        c_expr.expr &:= c_destStri.expr;
        c_expr.expr &:= ")->mem[";
        c_expr.expr &:= integerLiteral(pred(position));
        c_expr.expr &:= "], aStri->mem, aStri->size*sizeof(strElemType));\n";
      end if;
      if c_aStri.temp_num <> 0 then
        appendWithDiagnostic(c_destStri.temp_frees, c_expr);
        appendWithDiagnostic(c_aStri.temp_frees, c_expr);
      end if;
      c_expr.expr &:= "}\n";
    end if;
  end func;


const proc: process_const_str_poscpy (in reference: destStri,
    in reference: position, in string: aStri, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var expr_type: c_destStri is expr_type.value;
    var expr_type: c_position is expr_type.value;
  begin
    if getConstant(position, INTOBJECT, evaluatedParam) then
      process_const_str_poscpy(destStri, getValue(evaluatedParam, integer), aStri, c_expr);
    else
      incr(countOptimizations);
      process_expr(destStri, c_destStri);
      c_position.temp_num := c_destStri.temp_num;
      process_expr(position, c_position);
      c_expr.expr &:= "{\n";
      if c_position.temp_num <> 0 then
        appendWithDiagnostic(c_destStri.temp_decls, c_expr);
        appendWithDiagnostic(c_position.temp_decls, c_expr);
        appendWithDiagnostic(c_destStri.temp_assigns, c_expr);
        appendWithDiagnostic(c_position.temp_assigns, c_expr);
      end if;
      if string_index_check then
        incr(countIndexChecks);
        c_expr.expr &:= "striType destStri=";
        c_expr.expr &:= c_destStri.expr;
        c_expr.expr &:= ";\n";
        c_expr.expr &:= "intType position=";
        c_expr.expr &:= c_position.expr;
        c_expr.expr &:= ";\n";
        c_expr.expr &:= "if (idxChk(";
        c_expr.expr &:= "position<=0 || ";
        c_expr.expr &:= "destStri->size<";
        c_expr.expr &:= integerLiteral(length(aStri));
        c_expr.expr &:= " || (uintType)(position-1)>destStri->size-";
        c_expr.expr &:= integerLiteral(length(aStri));
        c_expr.expr &:= ")) {\n";
        c_expr.expr &:= "  ";
        c_expr.expr &:= raiseError("INDEX_ERROR");
        c_expr.expr &:= "} else {\n";
        setDiagnosticLine(c_expr);
        c_expr.expr &:= "  memcpy(&destStri->mem[position-1], (";
        c_expr.expr &:= stringLiteral(aStri);
        c_expr.expr &:= ")->mem, ";
        c_expr.expr &:= integerLiteral(length(aStri));
        c_expr.expr &:= "*sizeof(strElemType));\n";
        c_expr.expr &:= "}\n";
      else
        incr(countSuppressedIndexChecks);
        setDiagnosticLine(c_expr);
        c_expr.expr &:= "memcpy(&(";
        c_expr.expr &:= c_destStri.expr;
        c_expr.expr &:= ")->mem[(";
        c_expr.expr &:= c_position.expr;
        c_expr.expr &:= ")-1], (";
        c_expr.expr &:= stringLiteral(aStri);
        c_expr.expr &:= ")->mem, ";
        c_expr.expr &:= integerLiteral(length(aStri));
        c_expr.expr &:= "*sizeof(strElemType));\n";
      end if;
      if c_position.temp_num <> 0 then
        appendWithDiagnostic(c_destStri.temp_frees, c_expr);
        appendWithDiagnostic(c_position.temp_frees, c_expr);
      end if;
      c_expr.expr &:= "}\n";
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
    var string: destStri is "";
    var expr_type: c_destStri is expr_type.value;
    var expr_type: c_position is expr_type.value;
    var expr_type: c_aStri is expr_type.value;
  begin
    if getConstant(params[6], STRIOBJECT, evaluatedParam) then
      destStri := getValue(evaluatedParam, string);
      if length(destStri) = 1 then
        process_const_str_elemcpy(params[1], params[4], destStri[1], c_expr);
      else
        process_const_str_poscpy(params[1], params[4], destStri, c_expr);
      end if;
    elsif getConstant(params[4], INTOBJECT, evaluatedParam) then
      process_const_str_poscpy(params[1], getValue(evaluatedParam, integer), params[6], c_expr);
    else
      process_expr(params[1], c_destStri);
      c_position.temp_num := c_destStri.temp_num;
      process_expr(params[4], c_position);
      c_aStri.temp_num := c_position.temp_num;
      getAnyParamToExpr(params[6], c_aStri);
      c_expr.expr &:= "{\n";
      if c_aStri.temp_num <> 0 then
        appendWithDiagnostic(c_destStri.temp_decls, c_expr);
        appendWithDiagnostic(c_position.temp_decls, c_expr);
        appendWithDiagnostic(c_aStri.temp_decls, c_expr);
        appendWithDiagnostic(c_destStri.temp_assigns, c_expr);
        appendWithDiagnostic(c_position.temp_assigns, c_expr);
        appendWithDiagnostic(c_aStri.temp_assigns, c_expr);
      end if;
      if string_index_check then
        incr(countIndexChecks);
        c_expr.expr &:= "striType destStri=";
        c_expr.expr &:= c_destStri.expr;
        c_expr.expr &:= ";\n";
        c_expr.expr &:= "const_striType aStri=";
        c_expr.expr &:= c_aStri.expr;
        c_expr.expr &:= ";\n";
        c_expr.expr &:= "intType position=";
        c_expr.expr &:= c_position.expr;
        c_expr.expr &:= ";\n";
        c_expr.expr &:= "if (idxChk(";
        c_expr.expr &:= "position<=0 || ";
        c_expr.expr &:= "destStri->size<aStri->size || (uintType)(position-1)>destStri->size-aStri->size)) {\n";
        c_expr.expr &:= "  ";
        c_expr.expr &:= raiseError("INDEX_ERROR");
        c_expr.expr &:= "} else {\n";
        setDiagnosticLine(c_expr);
        c_expr.expr &:= "  memmove(&destStri->mem[position-1], aStri->mem, aStri->size*sizeof(strElemType));\n";
        c_expr.expr &:= "}\n";
      else
        incr(countSuppressedIndexChecks);
        c_expr.expr &:= "const_striType aStri=";
        c_expr.expr &:= c_aStri.expr;
        c_expr.expr &:= ";\n";
        setDiagnosticLine(c_expr);
        c_expr.expr &:= "memmove(&(";
        c_expr.expr &:= c_destStri.expr;
        c_expr.expr &:= ")->mem[(";
        c_expr.expr &:= c_position.expr;
        c_expr.expr &:= ")-1], aStri->mem, aStri->size*sizeof(strElemType));\n";
      end if;
      if c_aStri.temp_num <> 0 then
        appendWithDiagnostic(c_destStri.temp_frees, c_expr);
        appendWithDiagnostic(c_position.temp_frees, c_expr);
        appendWithDiagnostic(c_aStri.temp_frees, c_expr);
      end if;
      c_expr.expr &:= "}\n";
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
  begin
    if getConstant(params[3], CHAROBJECT, evaluatedParam) then
      process_const_str_push(params[1], getValue(evaluatedParam, char), c_expr);
    else
      process_str_push(params[1], params[3], c_expr);
    end if;
  end func;


const proc: process_inline_str_range (in reference: stri,
    in reference: start, in reference: stop, in string: slice_name,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: stri_name is "";
    var string: stri_value is "";
    var boolean: stri_is_variable is TRUE;
    var string: stri_size is "";
    var string: start_name is "";
    var integer: start_value is 0;
    var boolean: start_is_variable is TRUE;
    var intRange: start_range is intRange.value;
    var string: stop_name is "";
    var integer: stop_value is 0;
    var boolean: stop_is_variable is TRUE;
    var intRange: stop_range is intRange.value;
    var boolean: raisesIndexError is FALSE;
  begin
    if getConstant(stri, STRIOBJECT, evaluatedParam) then
      stri_is_variable := FALSE;
      stri_value := getValue(evaluatedParam, string);
      stri_name := "(" & stringLiteral(stri_value) & ")";
      stri_size := memSizeLiteral(length(stri_value));
    else
      stri_name := getParameterAsVariable("const_striType", "stri_", stri, c_expr);
      stri_size := stri_name & "->size";
    end if;
    start_range := getIntRange(start);
    if getConstant(start, INTOBJECT, evaluatedParam) then
      start_is_variable := FALSE;
      start_value := getValue(evaluatedParam, integer);
      if start_value < 1 then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
        raisesIndexError := TRUE;
      else
        start_name := integerLiteral(start_value);
      end if;
    elsif start_range.maxValue < 1 then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= strRaiseError("INDEX_ERROR");
      raisesIndexError := TRUE;
    else
      start_name := getTempVariable("intType", "start_", start, c_expr);
      if string_index_check then
        if start_range.minValue < 1 then
          incr(countIndexChecks);
          c_expr.expr &:= "idxChk(";
          c_expr.expr &:= start_name;
          c_expr.expr &:= "<1)?";
          c_expr.expr &:= intRaiseError("INDEX_ERROR");
          c_expr.expr &:= ":0, ";
        else
          countIndexOptimizations(c_expr);
        end if;
      else
        incr(countSuppressedIndexChecks);
      end if;
    end if;
    if not raisesIndexError then
      stop_range := getIntRange(stop);
      if getConstant(stop, INTOBJECT, evaluatedParam) then
        stop_is_variable := FALSE;
        stop_value := getValue(evaluatedParam, integer);
        if stop_value < 0 or
            not start_is_variable and stop_value < pred(start_value) then
          warning(DOES_RAISE, "INDEX_ERROR", c_expr);
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          raisesIndexError := TRUE;
        else
          stop_name := integerLiteral(stop_value);
        end if;
      elsif stop_range.maxValue < 0 or
          not start_is_variable and
          stop_range.maxValue < pred(start_value) then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
        raisesIndexError := TRUE;
      else
        stop_name := getParameterAsVariable("intType", "stop_", stop, c_expr);
      end if;
      if not raisesIndexError then
        if not stri_is_variable and not start_is_variable and
            length(stri_value) < start_value then
          if stop_is_variable then
            if string_index_check then
              if stop_range.minValue < pred(start_value) then
                incr(countIndexChecks);
                c_expr.expr &:= "idxChk(";
                c_expr.expr &:= stop_name;
                c_expr.expr &:= "<";
                c_expr.expr &:= integerLiteral(pred(start_value));
                c_expr.expr &:= ")?";
                c_expr.expr &:= intRaiseError("INDEX_ERROR");
                c_expr.expr &:= " : ";
              else
                countIndexOptimizations(c_expr);
              end if;
            else
              incr(countSuppressedIndexChecks);
            end if;
          end if;
          c_expr.expr &:= "(";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".mem = NULL,";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".size = 0)";
        else
          (* Formula used: stop>=start && (uintType)start <= stri->size ?
                           (slice.mem = &stri->mem[start-1],
                           (uintType)stop > stri->size ?
                           slice.size = stri->size-(memSizeType)start+1 :
                           (slice.size = (memSizeType)stop-(memSizeType)start+1))
                           : idxChk(stop<start-1)?INDEX_ERROR
                           : (slice.mem = NULL,slice.size = 0) *)
          c_expr.expr &:= stop_name;
          c_expr.expr &:= ">=";
          c_expr.expr &:= start_name;
          if start_is_variable or stri_is_variable then
            c_expr.expr &:= " && (uintType)";
            c_expr.expr &:= start_name;
            c_expr.expr &:= "<=";
            c_expr.expr &:= stri_size;
          end if;
          c_expr.expr &:= " ? (";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".mem = &";
          c_expr.expr &:= stri_name;
          c_expr.expr &:= "->mem[";
          if start_is_variable then
            c_expr.expr &:= start_name;
            c_expr.expr &:= "-1"
          else
            c_expr.expr &:= integerLiteral(pred(start_value));
          end if;
          c_expr.expr &:= "], (uintType)";
          c_expr.expr &:= stop_name;
          c_expr.expr &:= " > ";
          c_expr.expr &:= stri_size;
          c_expr.expr &:= " ? ";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".size = ";
          c_expr.expr &:= stri_size;
          c_expr.expr &:= "-(memSizeType)";
          if start_is_variable then
            c_expr.expr &:= start_name;
            c_expr.expr &:= "+1";
          else
            c_expr.expr &:= integerLiteral(pred(start_value));
          end if;
          c_expr.expr &:= " : (";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".size = (memSizeType)";
          c_expr.expr &:= stop_name;
          c_expr.expr &:= "-(memSizeType)";
          if start_is_variable then
            c_expr.expr &:= start_name;
            c_expr.expr &:= "+1";
          else
            c_expr.expr &:= integerLiteral(pred(start_value));
          end if;
          c_expr.expr &:= "))";
          if start_is_variable or stop_is_variable then
            if string_index_check then
              if stop_range.minValue < start_range.maxValue then
                incr(countIndexChecks);
                c_expr.expr &:= " : idxChk(";
                c_expr.expr &:= stop_name;
                c_expr.expr &:= "<";
                if start_is_variable then
                  c_expr.expr &:= start_name;
                  c_expr.expr &:= "-1";
                else
                  c_expr.expr &:= integerLiteral(pred(start_value));
                end if;
                c_expr.expr &:= ")?";
                c_expr.expr &:= intRaiseError("INDEX_ERROR");
              else
                countIndexOptimizations(c_expr);
              end if;
            else
              incr(countSuppressedIndexChecks);
            end if;
          end if;
          c_expr.expr &:= " : (";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".mem = NULL,";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".size = 0)";
        end if;
      end if;
    end if;
  end func;


const proc: process_str_range_of_empty_string (in ref_list: params,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: start_name is "";
    var string: stop_name is "";
    var integer: start_value is 0;
    var boolean: start_is_variable is TRUE;
    var integer: stop_value is 0;
    var boolean: stop_is_variable is TRUE;
    var boolean: raisesIndexError is FALSE;
  begin
    incr(countOptimizations);
    c_expr.expr &:= "/* \"\"[m .. n] */ (";
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      start_is_variable := FALSE;
      start_value := getValue(evaluatedParam, integer);
      if start_value < 1 then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
        raisesIndexError := TRUE;
      else
        start_name := integerLiteral(start_value);
      end if;
    else
      start_name := getTempVariable("intType", "start_", params[3], c_expr);
    end if;
    if not raisesIndexError then
      if getConstant(params[5], INTOBJECT, evaluatedParam) then
        stop_is_variable := FALSE;
        stop_value := getValue(evaluatedParam, integer);
        if stop_value < 0 or
            not start_is_variable and stop_value < pred(start_value) then
          warning(DOES_RAISE, "INDEX_ERROR", c_expr);
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          raisesIndexError := TRUE;
        else
          stop_name := integerLiteral(stop_value);
        end if;
      else
        stop_name := getParameterAsVariable("intType", "stop_", params[5], c_expr);
      end if;
      if not raisesIndexError then
        if start_is_variable or stop_is_variable then
          if string_index_check then
            incr(countIndexChecks);
            c_expr.expr &:= "idxChk(";
            if start_is_variable then
              c_expr.expr &:= start_name;
              c_expr.expr &:= "<1||";
            end if;
            c_expr.expr &:= stop_name;
            c_expr.expr &:= "<";
            c_expr.expr &:= start_name;
            c_expr.expr &:= "-1)?";
            c_expr.expr &:= strRaiseError("INDEX_ERROR");
            c_expr.expr &:= ":";
          else
            incr(countSuppressedIndexChecks);
          end if;
        end if;
        c_expr.expr &:= stringLiteral("");
      end if;
    end if;
    c_expr.expr &:= ")";
  end func;


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

  local
    var reference: evaluatedParam is NIL;
    var string: start_name is "";
    var string: slice_name is "";
  begin
    if getConstant(params[1], STRIOBJECT, evaluatedParam) and
        getValue(evaluatedParam, string) = "" then
      process_str_range_of_empty_string(params, c_expr);
    elsif getConstant(params[3], INTOBJECT, evaluatedParam) and
        getValue(evaluatedParam, integer) = 1 then
      incr(countOptimizations);
      process_str_head(params[1], params[5], c_expr);
    elsif ccConf.ALLOW_STRITYPE_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 striStruct ";
      c_expr.temp_decls &:= slice_name;
      c_expr.temp_decls &:= ";\n";
      if inlineFunctions then
        incr(countInlinedFunctions);
        process_inline_str_range(params[1], params[3], params[5],
                                 slice_name, c_expr);
      else
        c_expr.expr &:= "strRangeSlice(";
        getAnyParamToExpr(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 &:= ")";
      end if;
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "strRange(";
      getAnyParamToResultExpr(params[1], c_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 (STR_RCHIPOS, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

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


const proc: process_const_str_rchpos (in string: mainStri, in reference: param2,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
  begin
    if getConstant(param2, CHAROBJECT, evaluatedParam) then
      incr(countOptimizations);
      c_expr.expr &:= "/* rpos(";
      c_expr.expr &:= replace(literal(mainStri), "*/", "*\\/");
      c_expr.expr &:= ",";
      c_expr.expr &:= literal(getValue(evaluatedParam, char));
      c_expr.expr &:= ") */ ";
      c_expr.expr &:= integerLiteral(rpos(mainStri, getValue(evaluatedParam, char)));
    elsif length(mainStri) = 0 then
      incr(countOptimizations);
      c_expr.expr &:= "/* rpos(\"\", *) */ ";
      c_expr.expr &:= integerLiteral(0);
    elsif length(mainStri) = 1 then
      incr(countOptimizations);
      c_expr.expr &:= "/* rpos(";
      c_expr.expr &:= literal(mainStri);
      c_expr.expr &:= ", *) */ ";
      c_expr.expr &:= charLiteral(mainStri[1]);
      c_expr.expr &:= "==(";
      getAnyParamToExpr(param2, c_expr);
      c_expr.expr &:= ")?";
      c_expr.expr &:= integerLiteral(1);
      c_expr.expr &:= ":";
      c_expr.expr &:= integerLiteral(0);
    else
      c_expr.expr &:= "strRChPos(";
      c_expr.expr &:= stringLiteral(mainStri);
      c_expr.expr &:= ", ";
      getAnyParamToExpr(param2, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (STR_RCHPOS, 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], STRIOBJECT, evaluatedParam) then
      process_const_str_rchpos(getValue(evaluatedParam, string), params[2], c_expr);
    else
      c_expr.expr &:= "strRChPos(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[2], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_const_str_repl (in reference: param1,
    in string: searched, in reference: param3, inout expr_type: c_expr) is func

  local
    var expr_type: c_param1 is expr_type.value;
    var reference: evaluatedParam is NIL;
    var string: replacement is "";
  begin
    if searched = "" then
      incr(countOptimizations);
      prepareAnyParamTemporarys(param1, c_param1, c_expr);
      if c_param1.result_expr <> "" then
        prepare_stri_result(c_expr);
        c_expr.result_expr := "/* strRepl(*, \"\", *) */ ";
        c_expr.result_expr &:= c_param1.result_expr;
      else
        c_expr.expr &:= "/* strRepl(*, \"\", *) */ ";
        c_expr.expr &:= c_param1.expr;
      end if;
    elsif getConstant(param3, STRIOBJECT, evaluatedParam) then
      replacement := getValue(evaluatedParam, string);
      if searched = replacement then
        prepareAnyParamTemporarys(param1, c_param1, c_expr);
        if c_param1.result_expr <> "" then
          prepare_stri_result(c_expr);
          c_expr.result_expr := "/* strRepl(*, ";
          c_expr.result_expr &:= replace(literal(searched), "*/", "*\\/");
          c_expr.result_expr &:= ", ";
          c_expr.result_expr &:= replace(literal(replacement), "*/", "*\\/");
          c_expr.result_expr &:= ") */ ";
          c_expr.result_expr &:= c_param1.result_expr;
        else
          c_expr.expr &:= "/* strRepl(*, ";
          c_expr.expr &:= replace(literal(searched), "*/", "*\\/");
          c_expr.expr &:= ", ";
          c_expr.expr &:= replace(literal(replacement), "*/", "*\\/");
          c_expr.expr &:= ") */ ";
          c_expr.expr &:= c_param1.expr;
        end if;
      elsif length(searched) = 1 then
        if length(replacement) = 1 then
          prepare_stri_result(c_expr);
          c_expr.result_expr := "strChChRepl(";
          getAnyParamToResultExpr(param1, c_expr);
          c_expr.result_expr &:= ", ";
          c_expr.result_expr &:= charLiteral(searched[1]);
          c_expr.result_expr &:= ", ";
          c_expr.result_expr &:= charLiteral(replacement[1]);
          c_expr.result_expr &:= ")";
        else
          prepare_stri_result(c_expr);
          c_expr.result_expr := "strChRepl(";
          getAnyParamToResultExpr(param1, c_expr);
          c_expr.result_expr &:= ", ";
          c_expr.result_expr &:= charLiteral(searched[1]);
          c_expr.result_expr &:= ", ";
          c_expr.result_expr &:= stringLiteral(replacement);
          c_expr.result_expr &:= ")";
        end if;
      else
        prepare_stri_result(c_expr);
        c_expr.result_expr := "strRepl(";
        getAnyParamToResultExpr(param1, c_expr);
        c_expr.result_expr &:= ", ";
        c_expr.result_expr &:= stringLiteral(searched);
        c_expr.result_expr &:= ", ";
        c_expr.result_expr &:= stringLiteral(replacement);
        c_expr.result_expr &:= ")";
      end if;
    elsif length(searched) = 1 then
      incr(countOptimizations);
      if isActionExpression(param3, "CHR_STR") then
        prepare_stri_result(c_expr);
        c_expr.result_expr := "strChChRepl(";
        getAnyParamToResultExpr(param1, c_expr);
        c_expr.result_expr &:= ", ";
        c_expr.result_expr &:= charLiteral(searched[1]);
        c_expr.result_expr &:= ", ";
        getAnyParamToResultExpr(getActionParameter(param3, 1), c_expr);
        c_expr.result_expr &:= ")";
      else
        prepare_stri_result(c_expr);
        c_expr.result_expr := "strChRepl(";
        getAnyParamToResultExpr(param1, c_expr);
        c_expr.result_expr &:= ", ";
        c_expr.result_expr &:= charLiteral(searched[1]);
        c_expr.result_expr &:= ", ";
        getAnyParamToResultExpr(param3, c_expr);
        c_expr.result_expr &:= ")";
      end if;
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "strRepl(";
      getAnyParamToResultExpr(param1, c_expr);
      c_expr.result_expr &:= ", ";
      c_expr.result_expr &:= stringLiteral(searched);
      c_expr.result_expr &:= ", ";
      getAnyParamToResultExpr(param3, c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
    var string: replacement is "";
  begin
    if getConstant(params[2], STRIOBJECT, evaluatedParam) then
      process_const_str_repl(params[1], getValue(evaluatedParam, string), params[3], c_expr);
    elsif useSpecialCaseFunctions and
        isActionExpression(params[2], "CHR_STR") then
      incr(countOptimizations);
      prepare_stri_result(c_expr);
      if getConstant(params[3], STRIOBJECT, evaluatedParam) then
        replacement := getValue(evaluatedParam, string);
        if length(replacement) = 1 then
          c_expr.result_expr := "strChChRepl(";
          getAnyParamToResultExpr(params[1], c_expr);
          c_expr.result_expr &:= ", ";
          getAnyParamToResultExpr(getActionParameter(params[2], 1), c_expr);
          c_expr.result_expr &:= ", ";
          c_expr.result_expr &:= charLiteral(replacement[1]);
          c_expr.result_expr &:= ")";
        else
          c_expr.result_expr := "strChRepl(";
          getAnyParamToResultExpr(params[1], c_expr);
          c_expr.result_expr &:= ", ";
          getAnyParamToResultExpr(getActionParameter(params[2], 1), c_expr);
          c_expr.result_expr &:= ", ";
          c_expr.result_expr &:= stringLiteral(replacement);
          c_expr.result_expr &:= ")";
        end if;
      elsif isActionExpression(params[3], "CHR_STR") then
        c_expr.result_expr := "strChChRepl(";
        getAnyParamToResultExpr(params[1], c_expr);
        c_expr.result_expr &:= ", ";
        getAnyParamToResultExpr(getActionParameter(params[2], 1), c_expr);
        c_expr.result_expr &:= ", ";
        getAnyParamToResultExpr(getActionParameter(params[3], 1), c_expr);
        c_expr.result_expr &:= ")";
      else
        c_expr.result_expr := "strChRepl(";
        getAnyParamToResultExpr(params[1], c_expr);
        c_expr.result_expr &:= ", ";
        getAnyParamToResultExpr(getActionParameter(params[2], 1), c_expr);
        c_expr.result_expr &:= ", ";
        getAnyParamToResultExpr(params[3], c_expr);
        c_expr.result_expr &:= ")";
      end if;
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "strRepl(";
      getAnyParamToResultExpr(params[1], c_expr);
      c_expr.result_expr &:= ", ";
      getAnyParamToResultExpr(params[2], c_expr);
      c_expr.result_expr &:= ", ";
      getAnyParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
  begin
    if getConstant(params[2], STRIOBJECT, evaluatedParam) and
        length(getValue(evaluatedParam, string)) = 1 then
      incr(countOptimizations);
      c_expr.expr &:= "strRChIPos(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ", ";
      c_expr.expr &:= charLiteral(getValue(evaluatedParam, string)[1]);
      c_expr.expr &:= ", ";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= "strRIPos(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ", ";
      getAnyParamToExpr(params[2], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


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

  begin
    prepare_stri_result(c_expr);
    c_expr.result_expr := "strRpad(";
    getAnyParamToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", ";
    getStdParamToResultExpr(params[3], c_expr);
    c_expr.result_expr &:= ")";
  end func;


const proc: process_const_str_rpos (in reference: mainStri, in string: searched,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
  begin
    if getConstant(mainStri, STRIOBJECT, evaluatedParam) then
      incr(countOptimizations);
      c_expr.expr &:= "/* rpos(";
      c_expr.expr &:= replace(literal(getValue(evaluatedParam, string)), "*/", "*\\/");
      c_expr.expr &:= ",";
      c_expr.expr &:= replace(literal(searched), "*/", "*\\/");
      c_expr.expr &:= ") */ ";
      c_expr.expr &:= integerLiteral(rpos(getValue(evaluatedParam, string), searched));
    elsif length(searched) = 0 then
      incr(countOptimizations);
      c_expr.expr &:= "/* rpos(*, \"\") */ ";
      c_expr.expr &:= integerLiteral(0);
    elsif length(searched) = 1 then
      incr(countOptimizations);
      c_expr.expr &:= "strRChPos(";
      getAnyParamToExpr(mainStri, c_expr);
      c_expr.expr &:= ", ";
      c_expr.expr &:= charLiteral(searched[1]);
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= "strRPos(";
      getAnyParamToExpr(mainStri, c_expr);
      c_expr.expr &:= ", ";
      c_expr.expr &:= stringLiteral(searched);
      c_expr.expr &:= ")";
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
  begin
    if getConstant(params[2], STRIOBJECT, evaluatedParam) then
      process_const_str_rpos(params[1], getValue(evaluatedParam, string), c_expr);
    elsif getConstant(params[1], STRIOBJECT, evaluatedParam) and
        length(getValue(evaluatedParam, string)) = 0 then
      incr(countOptimizations);
      c_expr.expr &:= "/* rpos(\"\", *) */ ";
      c_expr.expr &:= integerLiteral(0);
    else
      c_expr.expr &:= "strRPos(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ", ";
      getAnyParamToExpr(params[2], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


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

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


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

  local
    var reference: evaluatedParam is NIL;
  begin
    prepare_typed_result(array_type[getExprResultType(params[1])], c_expr);
    if getConstant(params[2], STRIOBJECT, evaluatedParam) and
        length(getValue(evaluatedParam, string)) = 1 then
      incr(countOptimizations);
      c_expr.result_expr := "strChSplit(";
      getAnyParamToResultExpr(params[1], c_expr);
      c_expr.result_expr &:= ", ";
      c_expr.result_expr &:= charLiteral(getValue(evaluatedParam, string)[1]);
      c_expr.result_expr &:= ")";
    else
      c_expr.result_expr := "strSplit(";
      getAnyParamToResultExpr(params[1], c_expr);
      c_expr.result_expr &:= ", ";
      getAnyParamToResultExpr(params[2], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


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

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


const proc: process_str_substr0 (in reference: stri, in reference: start,
    inout expr_type: c_expr) is func

  local
    var intRange: start_range is intRange.value;
  begin
    incr(countOptimizations);
    start_range := getIntRange(start);
    if start_range.maxValue < 1 then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= strRaiseError("INDEX_ERROR");
    else
      c_expr.expr &:= "/* string[m len 0] */ (";
      if string_index_check then
        if start_range.minValue < 1 then
          incr(countIndexChecks);
          c_expr.expr &:= "idxChk((";
          process_expr(start, c_expr);
          c_expr.expr &:= ")<1)?";
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          c_expr.expr &:= ":";
        else
          countIndexOptimizations(c_expr);
        end if;
      else
        incr(countSuppressedIndexChecks);
      end if;
      c_expr.expr &:= stringLiteral("");
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_str_substr1 (in reference: stri, in reference: start,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: stri_name is "";
    var string: stri_value is "";
    var string: stri_size is "";
    var string: start_name is "";
    var intRange: start_range is intRange.value;
    var string: striStruct_name is "";
  begin
    if c_expr.demand < REQUIRE_RESULT then
      incr(countOptimizations);
      c_expr.expr &:= "(";
      if getConstant(stri, STRIOBJECT, evaluatedParam) then
        stri_value := getValue(evaluatedParam, string);
        stri_name := "(" & stringLiteral(stri_value) & ")";
        stri_size := memSizeLiteral(length(stri_value));
      else
        stri_name := getParameterAsVariable("const_striType", "stri_", stri, c_expr);
        stri_size := stri_name & "->size";
      end if;
      incr(c_expr.temp_num);
      start_name := getParameterAsVariable("intType", "start_", start, c_expr);
      incr(c_expr.temp_num);
      striStruct_name := "stri_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "struct striStruct ";
      c_expr.temp_decls &:= striStruct_name;
      c_expr.temp_decls &:= ";\n";
      if string_index_check then
        start_range := getIntRange(start);
        if start_range.minValue < 1 then
          incr(countIndexChecks);
          c_expr.expr &:= "idxChk(";
          c_expr.expr &:= start_name;
          c_expr.expr &:= "<1)?";
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          c_expr.expr &:= ":";
        else
          countIndexOptimizations(c_expr);
        end if;
      else
        incr(countSuppressedIndexChecks);
      end if;
      c_expr.expr &:= "(";
      c_expr.expr &:= start_name;
      c_expr.expr &:= ">";
      c_expr.expr &:= stri_size;
      c_expr.expr &:= " ? ";
      c_expr.expr &:= stringLiteral("");
      c_expr.expr &:= " : chrStrMacro(";
      c_expr.expr &:= stri_name;
      c_expr.expr &:= "->mem[";
      c_expr.expr &:= start_name;
      c_expr.expr &:= "-1],";
      c_expr.expr &:= striStruct_name;
      c_expr.expr &:= ")))";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "strSubstr(";
      getAnyParamToResultExpr(stri, c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(start, c_expr);
      c_expr.result_expr &:= ", 1)";
    end if;
  end func;


const proc: process_inline_str_substr (in reference: stri,
    in reference: start, in reference: length, in string: slice_name,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: stri_name is "";
    var string: stri_value is "";
    var boolean: stri_is_variable is TRUE;
    var string: stri_size is "";
    var string: start_name is "";
    var integer: start_value is 0;
    var boolean: start_is_variable is TRUE;
    var intRange: start_range is intRange.value;
    var string: length_name is "";
    var integer: length_value is 0;
    var boolean: length_is_variable is TRUE;
    var intRange: length_range is intRange.value;
    var boolean: raisesIndexError is FALSE;
  begin
    if getConstant(stri, STRIOBJECT, evaluatedParam) then
      stri_is_variable := FALSE;
      stri_value := getValue(evaluatedParam, string);
      stri_name := "(" & stringLiteral(stri_value) & ")";
      stri_size := memSizeLiteral(length(stri_value));
    else
      stri_name := getParameterAsVariable("const_striType", "stri_", stri, c_expr);
      stri_size := stri_name & "->size";
    end if;
    if getConstant(start, INTOBJECT, evaluatedParam) then
      start_is_variable := FALSE;
      start_value := getValue(evaluatedParam, integer);
      if start_value < 1 then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
        raisesIndexError := TRUE;
      else
        start_name := integerLiteral(start_value);
      end if;
    else
      start_name := getTempVariable("intType", "start_", start, c_expr);
    end if;
    if not raisesIndexError then
      if getConstant(length, INTOBJECT, evaluatedParam) then
        length_is_variable := FALSE;
        length_value := getValue(evaluatedParam, integer);
        if length_value < 0 then
          warning(DOES_RAISE, "INDEX_ERROR", c_expr);
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          raisesIndexError := TRUE;
        else
          length_name := integerLiteral(length_value);
        end if;
      else
        length_name := getParameterAsVariable("intType", "length_", length, c_expr);
      end if;
      if not raisesIndexError then
        if start_is_variable or length_is_variable then
          if string_index_check then
            start_range := getIntRange(start);
            length_range := getIntRange(length);
            if start_range.minValue < 1 or length_range.minValue < 0 then
              incr(countIndexChecks);
              c_expr.expr &:= "idxChk(";
              if start_is_variable and start_range.minValue < 1 then
                c_expr.expr &:= start_name;
                c_expr.expr &:= "<1";
              else
                countIndexOptimizations(c_expr);
              end if;
              if start_is_variable and length_is_variable and
                  start_range.minValue < 1 and length_range.minValue < 0 then
                c_expr.expr &:= "||";
              end if;
              if length_is_variable and length_range.minValue < 0 then
                c_expr.expr &:= length_name;
                c_expr.expr &:= "<0";
              else
                countIndexOptimizations(c_expr);
              end if;
              c_expr.expr &:= ")?";
              c_expr.expr &:= intRaiseError("INDEX_ERROR");
              c_expr.expr &:= ":0, ";
            else
              countIndexOptimizations(c_expr);
            end if;
          else
            incr(countSuppressedIndexChecks);
          end if;
        end if;
        if (not length_is_variable and length_value = 0) or
            (not stri_is_variable and not start_is_variable and
             length(stri_value) < start_value) then
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".mem = NULL, ";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".size = 0";
        elsif not start_is_variable and not length_is_variable and
            start_value <= integer.last - length_value then
          (* Formula used: slice.mem = &stri->mem[start-1],
                           start+length-1 <= stri->size ?
                           slice.size = (memSizeType)length :
                           ((uintType)start <= stri->size ?
                           slice.size = stri->size-(memSizeType)start+1 :
                           (slice.size = 0)) *)
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".mem = &";
          c_expr.expr &:= stri_name;
          c_expr.expr &:= "->mem[";
          c_expr.expr &:= integerLiteral(pred(start_value));
          c_expr.expr &:= "], ";
          c_expr.expr &:= integerLiteral(start_value + length_value - 1);
          c_expr.expr &:= "<=";
          c_expr.expr &:= stri_size;
          c_expr.expr &:= " ? ";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".size = (memSizeType)";
          c_expr.expr &:= length_name;
          c_expr.expr &:= " : (";
          c_expr.expr &:= "(uintType)";
          c_expr.expr &:= start_name;
          c_expr.expr &:= "<=";
          c_expr.expr &:= stri_size;
          c_expr.expr &:= " ? ";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".size = ";
          c_expr.expr &:= stri_size;
          c_expr.expr &:= "-(memSizeType)";
          c_expr.expr &:= integerLiteral(pred(start_value));
          c_expr.expr &:= " : (";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".size = 0))";
        else
          (* Formula used: length!=0 &&
                           (uintType)start<=stri->size ?
                           (slice.mem = &stri->mem[start-1],
                           (uintType)length > stri->size-(memSizeType)start+1 ?
                           slice.size = stri->size-(memSizeType)start+1 :
                           (slice.size = (memSizeType)length)) :
                           (slice.mem = NULL, slice.size = 0) *)
          if length_is_variable then
            c_expr.expr &:= length_name;
            c_expr.expr &:= "!=0 && ";
          end if;
          c_expr.expr &:= "(uintType)";
          c_expr.expr &:= start_name;
          c_expr.expr &:= "<=";
          c_expr.expr &:= stri_size;
          c_expr.expr &:= " ? (";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".mem = &";
          c_expr.expr &:= stri_name;
          c_expr.expr &:= "->mem[";
          if start_is_variable then
            c_expr.expr &:= start_name;
            c_expr.expr &:= "-1";
          else
            c_expr.expr &:= integerLiteral(pred(start_value));
          end if;
          c_expr.expr &:= "], (uintType)";
          c_expr.expr &:= length_name;
          c_expr.expr &:= ">";
          c_expr.expr &:= stri_size;
          c_expr.expr &:= "-(memSizeType)";
          if start_is_variable then
            c_expr.expr &:= start_name;
            c_expr.expr &:= "+1";
          else
            c_expr.expr &:= integerLiteral(pred(start_value));
          end if;
          c_expr.expr &:= " ? ";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".size = ";
          c_expr.expr &:= stri_size;
          c_expr.expr &:= "-(memSizeType)";
          if start_is_variable then
            c_expr.expr &:= start_name;
            c_expr.expr &:= "+1";
          else
            c_expr.expr &:= integerLiteral(pred(start_value));
          end if;
          c_expr.expr &:= " : (";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".size = (memSizeType)";
          c_expr.expr &:= length_name;
          c_expr.expr &:= ")) : (";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".mem = NULL, ";
          c_expr.expr &:= slice_name;
          c_expr.expr &:= ".size = 0)";
        end if;
      end if;
    end if;
  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 func

  begin
    c_expr.temp_decls &:= "struct striStruct ";
    c_expr.temp_decls &:= slice_name;
    c_expr.temp_decls &:= ";\n";
    if inlineFunctions then
      incr(countInlinedFunctions);
      process_inline_str_substr(stri, start, length, slice_name, c_expr);
    else
      c_expr.expr &:= "strSubstrSlice(";
      getAnyParamToExpr(stri, c_expr);
      c_expr.expr &:= ", ";
      process_expr(start, c_expr);
      c_expr.expr &:= ", ";
      process_expr(length, c_expr);
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
    var integer: length is 0;
    var string: slice_name is "";
  begin
    if getConstant(params[1], STRIOBJECT, evaluatedParam) and
        getValue(evaluatedParam, string) = "" then
      incr(countOptimizations);
      c_expr.expr &:= "/* \"\"[m len n] */ (";
      if string_index_check then
        incr(countIndexChecks);
        c_expr.expr &:= "idxChk((";
        process_expr(params[3], c_expr);
        c_expr.expr &:= ")<1||(";
        process_expr(params[5], c_expr);
        c_expr.expr &:= ")<0)?";
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
        c_expr.expr &:= ":";
      else
        incr(countSuppressedIndexChecks);
      end if;
      c_expr.expr &:= stringLiteral("");
      c_expr.expr &:= ")";
    elsif getConstant(params[3], INTOBJECT, evaluatedParam) and
        getValue(evaluatedParam, integer) = 1 then
      incr(countOptimizations);
      process_str_head(params[1], params[5], c_expr);
    elsif getConstant(params[5], INTOBJECT, evaluatedParam) and
        getValue(evaluatedParam, integer) <= 1 then
      length := getValue(evaluatedParam, integer);
      if length = 0 then
        process_str_substr0(params[1], params[3], c_expr);
      elsif length = 1 then
        process_str_substr1(params[1], params[3], c_expr);
      else
        incr(countOptimizations);
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
      end if;
    elsif ccConf.ALLOW_STRITYPE_SLICES and c_expr.demand < REQUIRE_RESULT then
      c_expr.expr &:= "(";
      incr(c_expr.temp_num);
      slice_name := "slice_" & str(c_expr.temp_num);
      process_str_substr_slice(params[1], params[3], params[5],
                               slice_name, c_expr);
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "strSubstr(";
      getAnyParamToResultExpr(params[1], c_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_str_substr_fixlen0 (in reference: stri,
    in reference: start, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var boolean: stri_is_variable is TRUE;
    var integer: stri_length is 0;
    var intRange: start_range is intRange.value;
    var string: start_name is "";
    var boolean: raisesIndexError is FALSE;
  begin
    incr(countOptimizations);
    start_range := getIntRange(start);
    if start_range.maxValue < 1 then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= strRaiseError("INDEX_ERROR");
      raisesIndexError := TRUE;
    elsif getConstant(stri, STRIOBJECT, evaluatedParam) then
      stri_is_variable := FALSE;
      stri_length := length(getValue(evaluatedParam, string));
      if start_range.minValue > stri_length then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
        raisesIndexError := TRUE;
      end if;
    end if;
    if not raisesIndexError then
      c_expr.expr &:= "/* string[m fixLen 0] */ (";
      if string_index_check then
        if stri_is_variable or start_range.minValue < 1 or
                               start_range.maxValue > stri_length then
          incr(countIndexChecks);
          if start_range.minValue >= 1 then
            c_expr.expr &:= "idxChk(";
            c_expr.expr &:= "(";
            process_expr(start, c_expr);
            c_expr.expr &:= ")>";
          else
            start_name := getParameterAsVariable("intType", "start_", start, c_expr);
            c_expr.expr &:= "idxChk(";
            if stri_is_variable or stri_length > 1 then
              c_expr.expr &:= start_name;
              c_expr.expr &:= "<1||(uintType)";
              c_expr.expr &:= start_name;
              c_expr.expr &:= ">";
            else
              c_expr.expr &:= "(uintType)";
              c_expr.expr &:= start_name;
              c_expr.expr &:= "!=";
            end if;
          end if;
          if stri_is_variable then
            c_expr.expr &:= "(";
            getAnyParamToExpr(stri, c_expr);
            c_expr.expr &:= ")->size";
          else
            c_expr.expr &:= memSizeLiteral(stri_length);
          end if;
          c_expr.expr &:= ")?";
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          c_expr.expr &:= ":";
        else
          countIndexOptimizations(c_expr);
        end if;
      else
        incr(countSuppressedIndexChecks);
      end if;
      c_expr.expr &:= stringLiteral("");
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_str_substr_fixlen1 (in reference: stri,
    in reference: start, 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: raisesIndexError is FALSE;
    var string: logicalOr is "";
    var string: striStruct_name is "";
  begin
    if c_expr.demand < REQUIRE_RESULT then
      incr(countOptimizations);
      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;
      if getConstant(start, INTOBJECT, evaluatedParam) then
        start_value := getValue(evaluatedParam, integer);
        if start_value < 1 then
          warning(DOES_RAISE, "INDEX_ERROR", c_expr);
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          raisesIndexError := TRUE;
        elsif not stri_is_variable and start_value > stri_length then
          warning(DOES_RAISE, "INDEX_ERROR", c_expr);
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          raisesIndexError := TRUE;
        else
          start_name := integerLiteral(start_value);
        end if;
      else
        start_name := getParameterAsVariable("intType", "start_", start, c_expr);
      end if;
      if not raisesIndexError then
        incr(c_expr.temp_num);
        striStruct_name := "stri_" & str(c_expr.temp_num);
        c_expr.temp_decls &:= "struct striStruct ";
        c_expr.temp_decls &:= striStruct_name;
        c_expr.temp_decls &:= ";\n";
        if string_index_check then
          start_range := getIntRange(start);
          if stri_is_variable or start_range.minValue < 1 or
                                 start_range.maxValue > stri_length then
            incr(countIndexChecks);
            c_expr.expr &:= "idxChk(";
            if stri_is_variable or stri_length > 1 then
              if start_range.minValue < 1 then
                c_expr.expr &:= start_name;
                c_expr.expr &:= "<1";
                logicalOr := "||";
              end if;
              if stri_is_variable or start_range.maxValue > stri_length then
                c_expr.expr &:= logicalOr;
                c_expr.expr &:= "(uintType)";
                c_expr.expr &:= start_name;
                c_expr.expr &:= ">";
                c_expr.expr &:= stri_size;
              end if;
            else
              c_expr.expr &:= "(uintType)";
              c_expr.expr &:= start_name;
              c_expr.expr &:= "!=";
              c_expr.expr &:= stri_size;
            end if;
            c_expr.expr &:= ")?";
            c_expr.expr &:= strRaiseError("INDEX_ERROR");
            c_expr.expr &:= ":";
          else
            countIndexOptimizations(c_expr);
          end if;
        else
          incr(countSuppressedIndexChecks);
        end if;
        c_expr.expr &:= "chrStrMacro(";
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->mem[";
        c_expr.expr &:= start_name;
        c_expr.expr &:= "-1],";
        c_expr.expr &:= striStruct_name;
        c_expr.expr &:= ")";
      end if;
      c_expr.expr &:= ")";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "strSubstrFixLen(";
      getAnyParamToResultExpr(stri, c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(start, c_expr);
      c_expr.result_expr &:= ", 1)";
    end if;
  end func;


const proc: process_inline_str_substr_fixlen (in string: stri,
    in reference: start, in reference: length, in string: slice_name,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var integer: stri_length is 0;
    var boolean: start_is_variable is TRUE;
    var string: start_name is "";
    var integer: start_value is 0;
    var intRange: start_range is intRange.value;
    var string: length_name is "";
    var integer: length_value is 0;
    var boolean: length_is_variable is TRUE;
    var intRange: length_range is intRange.value;
    var boolean: raisesIndexError is FALSE;
  begin
    # An empty string ("") raises INDEX_ERROR in the calling function.
    stri_length := length(stri);
    if getConstant(start, INTOBJECT, evaluatedParam) then
      start_is_variable := FALSE;
      start_value := getValue(evaluatedParam, integer);
      if start_value < 1 then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
        raisesIndexError := TRUE;
      elsif start_value > stri_length then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
        raisesIndexError := TRUE;
      else
        start_name := integerLiteral(start_value);
      end if;
    else
      start_name := getTempVariable("intType", "start_", start, c_expr);
    end if;
    if not raisesIndexError then
      if getConstant(length, INTOBJECT, evaluatedParam) then
        length_is_variable := FALSE;
        length_value := getValue(evaluatedParam, integer);
        if length_value < 0 then
          warning(DOES_RAISE, "INDEX_ERROR", c_expr);
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          raisesIndexError := TRUE;
        elsif length_value > stri_length then
          warning(DOES_RAISE, "INDEX_ERROR", c_expr);
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          raisesIndexError := TRUE;
        elsif not start_is_variable and
            length_value > stri_length - start_value + 1 then
          warning(DOES_RAISE, "INDEX_ERROR", c_expr);
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          raisesIndexError := TRUE;
        else
          length_name := integerLiteral(length_value);
        end if;
      else
        length_name := getParameterAsVariable("intType", "length_", length, c_expr);
      end if;
      if not raisesIndexError then
        if string_index_check then
          start_range := getIntRange(start);
          length_range := getIntRange(length);
          if start_is_variable or length_is_variable then
            incr(countIndexChecks);
            c_expr.expr &:= "idxChk(";
            if start_is_variable then
              if length_is_variable then
                c_expr.expr &:= start_name;
                if stri_length = 1 then
                  c_expr.expr &:= "!=1||";
                  if not ccConf.TWOS_COMPLEMENT_INTTYPE then
                    c_expr.expr &:= length_name;
                    c_expr.expr &:= "<0||";
                  end if;
                  c_expr.expr &:= "(uintType)";
                  c_expr.expr &:= length_name;
                  c_expr.expr &:= ">1";
                else
                  c_expr.expr &:= "<1||(uintType)";
                  c_expr.expr &:= start_name;
                  c_expr.expr &:= ">";
                  c_expr.expr &:= memSizeLiteral(stri_length);
                  c_expr.expr &:= "||";
                  c_expr.expr &:= length_name;
                  c_expr.expr &:= "<0||(uintType)";
                  c_expr.expr &:= start_name;
                  c_expr.expr &:= "+(uintType)";
                  c_expr.expr &:= length_name;
                  c_expr.expr &:= ">";
                  c_expr.expr &:= memSizeLiteral(succ(stri_length));
                end if;
              else
                c_expr.expr &:= start_name;
                if length_value = stri_length then
                  c_expr.expr &:= "!=1";
                else
                  c_expr.expr &:= "<1||(uintType)";
                  c_expr.expr &:= start_name;
                  if length_value > 0 then
                    c_expr.expr &:= ">";
                    c_expr.expr &:= memSizeLiteral(succ(stri_length - length_value));
                  else
                    c_expr.expr &:= ">";
                    c_expr.expr &:= memSizeLiteral(stri_length);
                  end if;
                end if;
              end if;
            else # length_is_variable then
              if not ccConf.TWOS_COMPLEMENT_INTTYPE then
                c_expr.expr &:= length_name;
                c_expr.expr &:= "<0||";
              end if;
              c_expr.expr &:= "(uintType)";
              c_expr.expr &:= length_name;
              c_expr.expr &:= ">";
              c_expr.expr &:= memSizeLiteral(succ(stri_length - start_value));
            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;
        (* Formula used: slice.mem = &stri->mem[start - 1],
                         slice.size = (memSizeType)length *)
        c_expr.expr &:= "(";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".mem = &(";
        c_expr.expr &:= stringLiteral(stri);
        c_expr.expr &:= ")->mem[";
        if start_is_variable then
          c_expr.expr &:= start_name;
          c_expr.expr &:= "-1";
        else
          c_expr.expr &:= integerLiteral(pred(start_value));
        end if;
        c_expr.expr &:= "], ";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".size = (memSizeType)";
        c_expr.expr &:= length_name;
        c_expr.expr &:= ")";
      end if;
    end if;
  end func;


const proc: process_inline_str_substr_fixlen (in reference: stri,
    in reference: start, in reference: length, in string: slice_name,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: stri_name is "";
    var string: stri_size is "";
    var boolean: start_is_variable is TRUE;
    var string: start_name is "";
    var integer: start_value is 0;
    var intRange: start_range is intRange.value;
    var string: length_name is "";
    var integer: length_value is 0;
    var boolean: length_is_variable is TRUE;
    var intRange: length_range is intRange.value;
    var boolean: raisesIndexError is FALSE;
  begin
    stri_name := getParameterAsVariable("const_striType", "stri_", stri, c_expr);
    stri_size := stri_name & "->size";
    if getConstant(start, INTOBJECT, evaluatedParam) then
      start_is_variable := FALSE;
      start_value := getValue(evaluatedParam, integer);
      if start_value < 1 then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
        raisesIndexError := TRUE;
      else
        start_name := integerLiteral(start_value);
      end if;
    else
      start_name := getTempVariable("intType", "start_", start, c_expr);
    end if;
    if not raisesIndexError then
      if getConstant(length, INTOBJECT, evaluatedParam) then
        length_is_variable := FALSE;
        length_value := getValue(evaluatedParam, integer);
        if length_value < 0 then
          warning(DOES_RAISE, "INDEX_ERROR", c_expr);
          c_expr.expr &:= strRaiseError("INDEX_ERROR");
          raisesIndexError := TRUE;
        else
          length_name := integerLiteral(length_value);
        end if;
      else
        length_name := getParameterAsVariable("intType", "length_", length, c_expr);
      end if;
      if not raisesIndexError then
        if string_index_check then
          start_range := getIntRange(start);
          length_range := getIntRange(length);
          incr(countIndexChecks);
          c_expr.expr &:= "idxChk(";
          if start_is_variable then
            if start_range.minValue < 1 then
              c_expr.expr &:= start_name;
              c_expr.expr &:= "<1||";
            end if;
          end if;
          if length_is_variable then
            if length_range.minValue <= 0 then
              c_expr.expr &:= "(unlikely(";
              c_expr.expr &:= length_name;
              c_expr.expr &:= "==0)?";
              c_expr.expr &:= "(uintType)";
              c_expr.expr &:= start_name;
              c_expr.expr &:= ">";
              c_expr.expr &:= stri_size;
              c_expr.expr &:= ":(";
            end if;
            if length_range.minValue < 0 then
              c_expr.expr &:= length_name;
              c_expr.expr &:= "<0||";
            end if;
          end if;
          if start_is_variable then
            c_expr.expr &:= "(uintType)";
            c_expr.expr &:= start_name;
            if length_is_variable then
              c_expr.expr &:= "+(uintType)";
              c_expr.expr &:= length_name;
              c_expr.expr &:= "-1>";
              c_expr.expr &:= stri_size;
            else
              if length_value > 1 then
                c_expr.expr &:= "+";
                c_expr.expr &:= memSizeLiteral(pred(length_value));
              end if;
              c_expr.expr &:= ">";
              c_expr.expr &:= stri_size;
            end if;
          else
            if length_is_variable then
              c_expr.expr &:= "(uintType)";
              c_expr.expr &:= length_name;
              if start_value > 1 then
                c_expr.expr &:= "+";
                c_expr.expr &:= memSizeLiteral(pred(start_value));
              end if;
              c_expr.expr &:= ">";
              c_expr.expr &:= stri_size;
            else
              if length_value > 0 then
                c_expr.expr &:= memSizeLiteral(pred(bigInteger(start_value) +
                                                    bigInteger(length_value)));
              else
                c_expr.expr &:= "(uintType)";
                c_expr.expr &:= start_name;
              end if;
              c_expr.expr &:= ">";
              c_expr.expr &:= stri_size;
            end if;
          end if;
          if length_is_variable and length_range.minValue <= 0 then
            c_expr.expr &:= "))";
          end if;
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("INDEX_ERROR");
          c_expr.expr &:= ":";
        else
          incr(countSuppressedIndexChecks);
        end if;
        (* Formula used: slice.mem = &stri->mem[start - 1],
                         slice.size = (memSizeType)length *)
        c_expr.expr &:= "(";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".mem = &";
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->mem[";
        if start_is_variable then
          c_expr.expr &:= start_name;
          c_expr.expr &:= "-1";
        else
          c_expr.expr &:= integerLiteral(pred(start_value));
        end if;
        c_expr.expr &:= "], ";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ".size = (memSizeType)";
        c_expr.expr &:= length_name;
        c_expr.expr &:= ")";
      end if;
    end if;
  end func;


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 func

  local
    var reference: evaluatedParam is NIL;
  begin
    c_expr.temp_decls &:= "struct striStruct ";
    c_expr.temp_decls &:= slice_name;
    c_expr.temp_decls &:= ";\n";
    if inlineFunctions then
      incr(countInlinedFunctions);
      if getConstant(stri, STRIOBJECT, evaluatedParam) then
        process_inline_str_substr_fixlen(getValue(evaluatedParam, string),
                                         start, length,
                                         slice_name, c_expr);
      else
        process_inline_str_substr_fixlen(stri, start, length,
                                         slice_name, c_expr);
      end if;
    else
      c_expr.expr &:= "strSubstrFixLenSlice(";
      getAnyParamToExpr(stri, c_expr);
      c_expr.expr &:= ", ";
      process_expr(start, c_expr);
      c_expr.expr &:= ", ";
      process_expr(length, c_expr);
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
    var integer: length is 0;
    var string: slice_name is "";
  begin
    if getConstant(params[1], STRIOBJECT, evaluatedParam) and
        getValue(evaluatedParam, string) = "" then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= strRaiseError("INDEX_ERROR");
    elsif getConstant(params[5], INTOBJECT, evaluatedParam) and
        getValue(evaluatedParam, integer) <= 1 then
      length := getValue(evaluatedParam, integer);
      if length = 0 then
        process_str_substr_fixlen0(params[1], params[3], c_expr);
      elsif length = 1 then
        process_str_substr_fixlen1(params[1], params[3], c_expr);
      else
        incr(countOptimizations);
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
      end if;
    elsif ccConf.ALLOW_STRITYPE_SLICES and c_expr.demand < REQUIRE_RESULT then
      c_expr.expr &:= "(";
      incr(c_expr.temp_num);
      slice_name := "slice_" & str(c_expr.temp_num);
      process_str_substr_fixlen_slice(params[1], params[3], params[5],
                                      slice_name, c_expr);
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "strSubstrFixLen(";
      getAnyParamToResultExpr(params[1], c_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_inline_str_tail (in reference: stri,
    in reference: start, in string: slice_name,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: stri_name is "";
    var string: stri_value is "";
    var string: stri_size is "";
    var string: start_name is "";
    var integer: start_value is 0;
    var boolean: start_is_variable is TRUE;
    var intRange: start_range is intRange.value;
    var boolean: raisesIndexError is FALSE;
  begin
    if getConstant(stri, STRIOBJECT, evaluatedParam) then
      stri_value := getValue(evaluatedParam, string);
      stri_name := "(" & stringLiteral(stri_value) & ")";
      stri_size := memSizeLiteral(length(stri_value));
    else
      stri_name := getParameterAsVariable("const_striType", "stri_", stri, c_expr);
      stri_size := stri_name & "->size";
    end if;
    if getConstant(start, INTOBJECT, evaluatedParam) then
      start_is_variable := FALSE;
      start_value := getValue(evaluatedParam, integer);
      if start_value < 1 then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
        raisesIndexError := TRUE;
      else
        start_name := integerLiteral(start_value);
      end if;
    else
      start_name := getTempVariable("intType", "start_", start, c_expr);
    end if;
    if not raisesIndexError then
      if start_is_variable then
        if string_index_check then
          start_range := getIntRange(start);
          if start_range.minValue < 1 then
            incr(countIndexChecks);
            c_expr.expr &:= "idxChk(";
            c_expr.expr &:= start_name;
            c_expr.expr &:= "<1";
            c_expr.expr &:= ")?";
            c_expr.expr &:= intRaiseError("INDEX_ERROR");
            c_expr.expr &:= ":0, ";
          else
            countIndexOptimizations(c_expr);
          end if;
        else
          incr(countSuppressedIndexChecks);
        end if;
      end if;
      (* Formula used: slice.mem = &stri->mem[start-1],
                       (uintType)start <= stri->size && stri->size >= 1 ?
                       slice.size = stri->size - (memSizeType)start + 1 :
                       (slice.size = 0) *)
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ".mem = &";
      c_expr.expr &:= stri_name;
      c_expr.expr &:= "->mem[";
      if start_is_variable then
        c_expr.expr &:= start_name;
        c_expr.expr &:= "-1";
      else
        c_expr.expr &:= integerLiteral(pred(start_value));
      end if;
      c_expr.expr &:= "], (uintType)";
      c_expr.expr &:= start_name;
      c_expr.expr &:= "<=";
      c_expr.expr &:= stri_size;
      c_expr.expr &:= " && ";
      c_expr.expr &:= stri_size;
      c_expr.expr &:= ">=1 ?";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ".size = ";
      c_expr.expr &:= stri_size;
      c_expr.expr &:= " - (memSizeType)";
      c_expr.expr &:= start_name;
      c_expr.expr &:= " + 1 : (";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ".size = 0)";
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
    var string: slice_name is "";
  begin
    if getConstant(params[1], STRIOBJECT, evaluatedParam) and
        getValue(evaluatedParam, string) = "" then
      incr(countOptimizations);
      c_expr.expr &:= "/* \"\"[n .. ] */ (";
      if string_index_check then
        incr(countIndexChecks);
        c_expr.expr &:= "idxChk((";
        process_expr(params[3], c_expr);
        c_expr.expr &:= ")<1)?";
        c_expr.expr &:= strRaiseError("INDEX_ERROR");
        c_expr.expr &:= ":";
      else
        incr(countSuppressedIndexChecks);
      end if;
      c_expr.expr &:= stringLiteral("");
      c_expr.expr &:= ")";
    elsif ccConf.ALLOW_STRITYPE_SLICES and c_expr.demand < ASSIGN_RESULT then
      c_expr.expr &:= "(";
      incr(c_expr.temp_num);
      slice_name := "slice_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "struct striStruct ";
      c_expr.temp_decls &:= slice_name;
      c_expr.temp_decls &:= ";\n";
      if inlineFunctions then
        incr(countInlinedFunctions);
        process_inline_str_tail(params[1], params[3], slice_name, c_expr);
      else
        c_expr.expr &:= "strTailSlice(";
        getAnyParamToExpr(params[1], c_expr);
        c_expr.expr &:= ", ";
        process_expr(params[3], c_expr);
        c_expr.expr &:= ", &";
        c_expr.expr &:= slice_name;
        c_expr.expr &:= ")";
      end if;
      c_expr.expr &:= ", &";
      c_expr.expr &:= slice_name;
      c_expr.expr &:= ")";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "strTail(";
      getAnyParamToResultExpr(params[1], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


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

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


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

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


(**
 *  Produces code to return a string converted to upper case.
 *  If the parameter is a temporary value the conversion is done
 *  with strUpTemp. The strUpTemp function returns the parameter as
 *  result of the conversion. That way the temporary of the parameter
 *  must not be freed.
 *)
const proc: process (STR_UP, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var expr_type: c_param1 is expr_type.value;
  begin
    prepare_stri_result(c_expr);
    prepareAnyParamTemporarys(params[1], c_param1, c_expr);
    if c_param1.result_expr <> "" then
      c_expr.result_expr := "strUpTemp(";
      c_expr.result_expr &:= c_param1.result_expr;
    else
      c_expr.result_expr := "strUp(";
      c_expr.result_expr &:= c_param1.expr;
    end if;
    c_expr.result_expr &:= ")";
  end func;


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

  begin
    prepare_stri_result(c_expr);
    c_expr.result_expr := "strValue(";
    getStdParamToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ")";
  end func;