Skip to content
Snippets Groups Projects
AST.cc 72.8 KiB
Newer Older
Elemer Lelik's avatar
Elemer Lelik committed
/******************************************************************************
 * Copyright (c) 2000-2021 Ericsson Telecom AB
Elemer Lelik's avatar
Elemer Lelik committed
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
Elemer Lelik's avatar
Elemer Lelik committed
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
Elemer Lelik's avatar
Elemer Lelik committed
 *
 * Contributors:
 *   
 *   Baji, Laszlo
 *   Balasko, Jeno
 *   Baranyi, Botond
 *   Beres, Szabolcs
 *   Cserveni, Akos
 *   Czerman, Oliver
 *   Delic, Adam
 *   Feher, Csaba
 *   Forstner, Matyas
 *   Gecse, Roland
 *   Kovacs, Ferenc
 *   Raduly, Csaba
 *   Szabados, Kristof
Elemer Lelik's avatar
Elemer Lelik committed
 *   Szabo, Janos Zoltan – initial implementation
 *   Szalai, Gabor
 *   Zalanyi, Balazs Andor
 *   Pandi, Krisztian
 *
 ******************************************************************************/
#include <set>
#include <string>
#include <sstream>

#include "../common/dbgnew.hh"
#include "../common/version.h"
#include "AST.hh"
#include "asn1/AST_asn1.hh"
#include "Identifier.hh"
#include "Type.hh"
#include "TypeCompat.hh"
#include "Value.hh"
#include "ustring.hh"
#include "main.hh"
#include "asn1/Object0.hh"
#include "PredefFunc.hh"
#include "../common/version.h"
#include "CodeGenHelper.hh"
#include <limits.h>
Elemer Lelik's avatar
Elemer Lelik committed
#include "ttcn3/profiler.h"

reffer::reffer(const char*) {}

namespace Common {
Elemer Lelik's avatar
Elemer Lelik committed
  // =================================
  // ===== Modules
Elemer Lelik's avatar
Elemer Lelik committed
  // =================================
Elemer Lelik's avatar
Elemer Lelik committed
  
  vector<Modules::type_enc_t> Modules::delayed_type_enc_v;

  Modules::Modules()
    : Node(), mods_v(), mods_m()
  {
    set_fullname(string('@'));
  }

  Modules::~Modules()
  {
    for(size_t i = 0; i < mods_v.size(); i++) delete mods_v[i];
    mods_v.clear();
    mods_m.clear();
  }

  Modules *Modules::clone() const
  {
    FATAL_ERROR("Modules::clone()");
    return 0;
  }

  void Modules::add_mod(Module *p_mod)
  {
    if (!p_mod) FATAL_ERROR("NULL parameter: Common::Modules::add_mod()");
    p_mod->set_fullname("@"+p_mod->get_modid().get_dispname());
    p_mod->set_scope_name(p_mod->get_modid().get_dispname());
    mods_v.add(p_mod);
  }

  bool Modules::has_mod_withId(const Identifier& p_modid)
  {
    return mods_m.has_key(p_modid.get_name());
  }

  Module* Modules::get_mod_byId(const Identifier& p_modid)
  {
    const string& name = p_modid.get_name();
    return mods_m.has_key(name)?mods_m[name]:0;
  }

  Assignment* Modules::get_ass_bySRef(Ref_simple *p_ref)
  {
    if(!p_ref)
      FATAL_ERROR("NULL parameter: Common::Modules::get_ass_bySRef()");
    const Identifier *modid=p_ref->get_modid();
    if(modid) {
      if(has_mod_withId(*modid))
	return get_mod_byId(*modid)->get_ass_bySRef(p_ref);
      else {
        p_ref->error("There is no module with identifier `%s'",
                     modid->get_dispname().c_str());
	return 0;
      }
    }
    else {
      p_ref->error("`%s' entity not found in global scope",
                   p_ref->get_dispname().c_str());
      return 0;
    }
  }

  void Modules::chk_uniq()
  {
    for(size_t i = 0; i < mods_v.size(); i++) {
      Module *m = mods_v[i];
      const Identifier& id = m->get_modid();
      const string& name = id.get_name();
      if (mods_m.has_key(name)) {
	Module *m2 = mods_m[name];
	m->error("A module with identifier `%s' already exists",
	  id.get_dispname().c_str());
	m2->error("This is the first module with the same name");
	if (m->get_moduletype() == m2->get_moduletype() &&
	  !strcmp(m->get_filename(), m2->get_filename())) {
	  // the same file was given twice -> drop the entire module
	  delete m;
	  mods_v.replace(i, 1);
	  i--;
	}
      } else mods_m.add(name, m);
    }
  }

  void Modules::chk()
  {
    // first check the uniqueness of module names
    chk_uniq();
    // check the import chains
    size_t nof_mods = mods_v.size();
    for (size_t i = 0; i < nof_mods; i++) {
      Module *m = mods_v[i];
      ReferenceChain refch(m, "While checking import chains");
      vector<Common::Module> modules;
      m->chk_imp(refch, modules);
      modules.clear();
      //clear the reference chain, get a fresh start
      refch.reset();
    }
    // check the modules
    Module::module_set_t checked_modules;
    if (nof_top_level_pdus > 0) {
      chk_top_level_pdus();
      // do not check ASN.1 modules, but assume they are already checked
      for (size_t i = 0; i < nof_mods; i++) {
	Module *module = mods_v[i];
	if (module->get_moduletype() == Module::MOD_ASN)
	  checked_modules.add(module, 0);
      }
      for (size_t i = 0; i < nof_mods; i++) {
	Module *module = mods_v[i];
	if (module->get_moduletype() != Module::MOD_ASN)
	  module->chk_recursive(checked_modules);
      }
    } else {
      // walk through all modules in bottom-up order
      for (size_t i = 0; i < nof_mods; i++)
	mods_v[i]->chk_recursive(checked_modules);
    }
    checked_modules.clear();
Elemer Lelik's avatar
Elemer Lelik committed
    // run delayed Type::chk_coding() calls
    if (!delayed_type_enc_v.empty()) {
      for (size_t i = 0; i < delayed_type_enc_v.size(); ++i) {
        delayed_type_enc_v[i]->t->chk_coding(delayed_type_enc_v[i]->enc,
          delayed_type_enc_v[i]->mod, true);
Elemer Lelik's avatar
Elemer Lelik committed
        delete delayed_type_enc_v[i];
      }
      delayed_type_enc_v.clear();
    }
  }

  void Modules::chk_top_level_pdus()
  {
    Location loc("<command line>");
    for(size_t i=0; i<nof_top_level_pdus; i++) {
      string pduname(top_level_pdu[i]);
      size_t dotpos=pduname.find('.');
      if(dotpos>=pduname.size()) {
        loc.error("While searching top-level pdu `%s': "
                  "Please use the `modulename.identifier' format",
                  pduname.c_str());
        continue;
      }
      Module *module=0;
      Identifier *pdu_id=0;
      { // searching the module
        const string& pduname_mod = pduname.substr(0, dotpos);
	const string& pduname_id = pduname.substr(dotpos + 1);
	{ // ASN
          Identifier modid(Identifier::ID_ASN, pduname_mod, true);
          module = get_mod_byId(modid);
	}
        if (module && module->get_moduletype() == Module::MOD_ASN) {
          pdu_id = new Identifier(Identifier::ID_ASN, pduname_id, true);
          goto mod_ok;
        }
	{ // TTCN
          Identifier modid(Identifier::ID_TTCN, pduname_mod, true);
          module = get_mod_byId(modid);
	}
        if (module && module->get_moduletype() == Module::MOD_TTCN) {
          pdu_id = new Identifier(Identifier::ID_TTCN, pduname_id, true);
          goto mod_ok;
        }
	{ // C++
          Identifier modid(Identifier::ID_NAME, pduname_mod, true);
          module = get_mod_byId(modid);
	}
        if(module) {
          pdu_id = new Identifier(Identifier::ID_NAME, pduname_id, true);
          goto mod_ok;
        }
        // error - no such module
        loc.error("While searching top-level pdu `%s': "
                  "No module with name `%s'",
                  pduname.c_str(), pduname_mod.c_str());
        continue;
      }
  mod_ok:
      Assignments *asss=module->get_asss();
      if(asss->has_local_ass_withId(*pdu_id)) {
        Assignment *ass=asss->get_local_ass_byId(*pdu_id);
        ass->chk();
      }
      else {
        loc.error("While searching top-level pdu `%s': "
                  "No assignment with identifier `%s'",
                  pduname.c_str(), pdu_id->get_dispname().c_str());
      }
      delete pdu_id;
    } // for top-level pdus
  }

  void Modules::write_checksums()
  {
    fputs("Module name        Language        MD5 checksum                     Version\n"
	  "---------------------------------------------------------------------------\n", stderr);
    size_t nof_mods = mods_v.size();
    for (size_t i = 0; i < nof_mods; i++) {
      mods_v[i]->write_checksum();
    }
  }

  void Modules::generate_code(CodeGenHelper& cgh)
  {
    Common::Module::rename_default_namespace(); // if needed
    /*
        The  White Rabbit put on his spectacles.
        "Where shall  I  begin, please your Majesty ?" he asked.
        "Begin at the beginning,", the King said, very gravely, "and go on
        till you come to the end: then stop."
                -- Lewis Carroll
    */
    for (size_t i = 0; i < mods_v.size(); i++) {
      mods_v[i]->generate_code(cgh);
      if (tcov_file_name && in_tcov_files(mods_v[i]->get_filename())) {
        Free(effective_module_lines);
        Free(effective_module_functions);
        effective_module_lines = effective_module_functions = NULL;
      }
    }

    cgh.write_output();
  }


  void Modules::dump(unsigned level) const
  {
    DEBUG(level, "Modules (%lu pcs.)", (unsigned long) mods_v.size());
    for(size_t i = 0; i < mods_v.size(); i++) mods_v[i]->dump(level);
  }

  std::set<ModuleVersion> Modules::getVersionsWithProductNumber() const {
    std::set<ModuleVersion> versions;
    for (size_t i = 0; i < mods_v.size(); ++i) {
      const ModuleVersion version = mods_v[i]->getVersion();
      if (version.hasProductNumber()) {
        versions.insert(version);
      }
    }
    return versions;
  }
  
Elemer Lelik's avatar
Elemer Lelik committed
  void Modules::generate_json_schema(JSON_Tokenizer& json, map<Type*, JSON_Tokenizer>& json_refs)
  {
    for(size_t i = 0; i < mods_v.size(); ++i) {
Elemer Lelik's avatar
Elemer Lelik committed
      mods_v[i]->generate_json_schema(json, json_refs);
Elemer Lelik's avatar
Elemer Lelik committed
  
  void Modules::delay_type_encode_check(Type* p_type, Module* p_module, bool p_encode)
Elemer Lelik's avatar
Elemer Lelik committed
  {
    for (size_t i = 0; i < delayed_type_enc_v.size(); ++i) {
      if (delayed_type_enc_v[i]->t == p_type &&
          delayed_type_enc_v[i]->mod == p_module &&
          delayed_type_enc_v[i]->enc == p_encode) {
        // it's already in the list of delayed checks
        return;
      }
    }
Elemer Lelik's avatar
Elemer Lelik committed
    type_enc_t* elem = new type_enc_t;
    elem->t = p_type;
Elemer Lelik's avatar
Elemer Lelik committed
    elem->enc = p_encode;
    delayed_type_enc_v.add(elem);
  }


  // =================================
  // ===== Module
  // =================================
  
  ModuleVersion Module::getVersion() const {
    return ModuleVersion(product_number, suffix, release, patch, build, extra);
  }

  void Module::generate_literals(output_struct *target)
  {
    char *src = NULL;
    char *hdr = NULL;
    generate_bs_literals(src, hdr); // implementations follow directly below
    generate_bp_literals(src, hdr);
    generate_hs_literals(src, hdr);
    generate_hp_literals(src, hdr);
    generate_os_literals(src, hdr);
    generate_op_literals(src, hdr);
    generate_cs_literals(src, hdr);
    generate_us_literals(src, hdr);
    generate_oid_literals(src, hdr);
    generate_pp_literals(src, hdr);
    generate_mp_literals(src, hdr);
    target->source.string_literals =
      mputstr(target->source.string_literals, src);
    if (CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE) {
      target->header.global_vars = mputstr(target->header.global_vars, hdr);
    }
    Free(src);
    Free(hdr);
  }

  void Module::generate_bs_literals(char *&src, char *&hdr)
  {
    if (bs_literals.size() == 0) return;
    // indicates whether we have found at least one non-empty bitstring
    bool is_nonempty = false;
    bool splitting =
      CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE;
    for (size_t i = 0; i < bs_literals.size(); i++) {
      const string& str = bs_literals.get_nth_key(i);
      size_t bits = str.size();
      if (bits == 0) continue;
      if (is_nonempty) src = mputstr(src, ",\n");
      else {
        src = mputprintf(src, "%sconst unsigned char ", split_to_slices ? "" : "static ");
        is_nonempty = true;
      }
      src = mputprintf(src, "%s_bits[] = { ",
        bs_literals.get_nth_elem(i)->c_str());
      // Filling up the octets one-by-one
      for (size_t j = 0; j < (bits + 7) / 8; j++) {
        size_t offset = 8 * j;
        unsigned char value = 0;
        for (size_t k = 0; k < 8 && k < bits - offset; k++) {
            if (str[offset + k] == '1') value |= (1 << k);
        }
        if (j > 0) src = mputstr(src, ", ");
        src = mputprintf(src, "%d", value);
      }
      src = mputstr(src, " }");
    }
    if (is_nonempty) src = mputstr(src, ";\n");
    for (size_t i = 0; i < bs_literals.size(); i++) {
      if (i > 0) {
        src = mputstr(src, ",\n");
        if (splitting) hdr = mputstr(hdr, ",\n");
      }
      else {
        src = mputprintf(src, "%s const BITSTRING ",
          splitting ? "extern" : "static");
        if (splitting) hdr = mputstr(hdr, "extern const BITSTRING ");
      }
      size_t bits = bs_literals.get_nth_key(i).size();
      const char *object_name = bs_literals.get_nth_elem(i)->c_str();
      if (bits > 0) src = mputprintf(src, "%s(%lu, %s_bits)",
          object_name, (unsigned long) bits, object_name);
      else src = mputprintf(src, "%s(0, NULL)", object_name);
      if (splitting) hdr = mputstr(hdr, object_name);
    }
    src = mputstr(src, ";\n");
    if (splitting) hdr = mputstr(hdr, ";\n");
  }

  void Module::generate_bp_literals(char *&src, char *& hdr)
  {
    if (bp_literals.size() == 0) return;
    for (size_t i = 0; i < bp_literals.size(); i++) {
      if (i > 0) src = mputstr(src, ",\n");
      else {
        src = mputprintf(src, "%sconst unsigned char ", split_to_slices ? "" : "static ");
      }
      src = mputprintf(src, "%s_elements[] = { ",
        bp_literals.get_nth_elem(i)->c_str());
      const string& str = bp_literals.get_nth_key(i);
      for (size_t j = 0; j < str.size(); j++) {
        if (j > 0) src = mputstr(src, ", ");
        switch (str[j]) {
        case '0':
          src = mputc(src, '0');
          break;
        case '1':
          src = mputc(src, '1');
          break;
        case '?':
          src = mputc(src, '2');
          break;
        case '*':
          src = mputc(src, '3');
          break;
        default:
          FATAL_ERROR("Invalid character in bitstring pattern.");
        }
      }
      src = mputstr(src, " }");
    }
    src = mputstr(src, ";\n");
    for (size_t i = 0; i < bp_literals.size(); i++) {
      if (i > 0) {
        src = mputstr(src, ",\n");
        if (split_to_slices) {
          hdr = mputstr(hdr, ",\n");
        }
      }
      else {
        src = mputprintf(src, "%sconst BITSTRING_template ", split_to_slices ? "" : "static ");
        if (split_to_slices) {
            hdr = mputprintf(hdr, "extern const BITSTRING_template ");
        }
      }
      const char *name = bp_literals.get_nth_elem(i)->c_str();
      src = mputprintf(src, "%s(%lu, %s_elements)",
        name, (unsigned long) bp_literals.get_nth_key(i).size(), name);
      if (split_to_slices) {
        hdr = mputstr(hdr, name);
      }
    }
    src = mputstr(src, ";\n");
    if (split_to_slices) {
      hdr = mputstr(hdr, ";\n");
    }
  }

  void Module::generate_hs_literals(char *&src, char *&hdr)
  {
    if (hs_literals.size() == 0) return;
    // indicates whether we have found at least one non-empty hexstring
    bool is_nonempty = false;
    bool splitting =
      CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE;
    for (size_t i = 0; i < hs_literals.size(); i++) {
      const string& str = hs_literals.get_nth_key(i);
      size_t nibbles = str.size();
      if (nibbles == 0) continue;
      size_t octets = (nibbles + 1) / 2;
      const char *str_ptr = str.c_str();
      if (is_nonempty) src = mputstr(src, ",\n");
      else {
        src = mputprintf(src, "%sconst unsigned char ", split_to_slices ? "" : "static ");
        is_nonempty = true;
      }
      src = mputprintf(src, "%s_nibbles[] = { ",
        hs_literals.get_nth_elem(i)->c_str());
      for (size_t j = 0; j < octets; j++) {
        // Hex digit with even index always goes to the least significant
        // 4 bits of the octet.
        unsigned char value = char_to_hexdigit(str_ptr[2 * j]);
        if (2 * j + 1 < nibbles) {
          // Hex digit with odd index always goes to the most significant
          // 4 bits of the octet.
          // This digit is not present (bits are set to zero) if the length
          // of hexstring is odd.
          value += 16 * char_to_hexdigit(str_ptr[2 * j + 1]);
        }
        if (j > 0) src = mputstr(src, ", ");
        src = mputprintf(src, "%u", value);
      }
      src = mputstr(src, " }");
    }
    if (is_nonempty) src = mputstr(src, ";\n");
    for (size_t i = 0; i < hs_literals.size(); i++) {
      if (i > 0) {
        src = mputstr(src, ",\n");
        if (splitting) hdr = mputstr(hdr, ",\n");
      }
      else {
        src = mputprintf(src, "%s const HEXSTRING ",
          splitting ? "extern" : "static");
        if (splitting) hdr = mputstr(hdr, "extern const HEXSTRING ");
      }
      size_t nibbles = hs_literals.get_nth_key(i).size();
      const char *object_name = hs_literals.get_nth_elem(i)->c_str();
      if (nibbles > 0) src = mputprintf(src, "%s(%lu, %s_nibbles)",
          object_name, (unsigned long) nibbles, object_name);
      else src = mputprintf(src, "%s(0, NULL)", object_name);
      if (splitting) hdr = mputstr(hdr, object_name);
    }
    src = mputstr(src, ";\n");
    if (splitting) hdr = mputstr(hdr, ";\n");
  }

  void Module::generate_hp_literals(char *&src, char *& hdr)
  {
    if (hp_literals.size() == 0) return;
    for (size_t i = 0; i < hp_literals.size(); i++) {
      if (i > 0) {
        src = mputstr(src, ",\n");
      } else {
        src = mputprintf(src, "%sconst unsigned char ", split_to_slices ? "" : "static ");
      }
      src = mputprintf(src, "%s_elements[] = { ",
        hp_literals.get_nth_elem(i)->c_str());
      const string& str = hp_literals.get_nth_key(i);
      size_t size = str.size();
      const char *str_ptr = str.c_str();
      for (size_t j = 0; j < size; j++) {
        if (j > 0) src = mputstr(src, ", ");
        unsigned char num;
        if (str_ptr[j] == '?') num = 16;
        else if (str_ptr[j] == '*') num = 17;
        else num = char_to_hexdigit(str_ptr[j]);
        src = mputprintf(src, "%u", num);
      }
      src = mputstr(src, " }");
    }
    src = mputstr(src, ";\n");
    for (size_t i = 0; i < hp_literals.size(); i++) {
      if (i > 0) {
        src = mputstr(src, ",\n");
        if (split_to_slices) {
          hdr = mputstr(hdr, ",\n");
        }
      } else {
        src = mputprintf(src, "%sconst HEXSTRING_template ", split_to_slices ? "" : "static ");
        if (split_to_slices) {
          hdr = mputprintf(hdr, "extern const HEXSTRING_template ");
        }
      }
      const char *name = hp_literals.get_nth_elem(i)->c_str();
      src = mputprintf(src, "%s(%lu, %s_elements)",
        name, (unsigned long) hp_literals.get_nth_key(i).size(), name);
      if (split_to_slices) {
        hdr = mputstr(hdr, name);
      }
    }
    src = mputstr(src, ";\n");
    if (split_to_slices) {
      hdr = mputstr(hdr, ";\n");
    }
  }

  void Module::generate_os_literals(char *&src, char *&hdr)
  {
    if (os_literals.size() == 0) return;
    // indicates whether we have found at least one non-empty octetstring
    bool is_nonempty = false;
    bool splitting =
      CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE;
    for (size_t i = 0; i < os_literals.size(); i++) {
      const string& str = os_literals.get_nth_key(i);
      size_t size = str.size();
      if (size % 2) FATAL_ERROR("Invalid length for an octetstring.");
      size_t octets = size / 2;
      if (octets == 0) continue;
      const char *str_ptr = str.c_str();
      if (is_nonempty) src = mputstr(src, ",\n");
      else {
        src = mputprintf(src, "%sconst unsigned char ", split_to_slices ? "" : "static ");
        is_nonempty = true;
      }
      src = mputprintf(src, "%s_octets[] = { ",
        os_literals.get_nth_elem(i)->c_str());
      for (size_t j = 0; j < octets; j++) {
        if (j > 0) src = mputstr(src, ", ");
        src = mputprintf(src, "%u", 16 * char_to_hexdigit(str_ptr[2 * j]) +
          char_to_hexdigit(str_ptr[2 * j + 1]));
      }
      src = mputstr(src, " }");
    }
    if (is_nonempty) src = mputstr(src, ";\n");
    for (size_t i = 0; i < os_literals.size(); i++) {
      if (i > 0) {
        src = mputstr(src, ",\n");
        if (splitting) hdr = mputstr(hdr, ",\n");
      }
      else {
        src = mputprintf(src, "%s const OCTETSTRING ",
          splitting ? "extern" : "static");
        if (splitting) hdr = mputstr(hdr, "extern const OCTETSTRING ");
      }
      size_t octets = os_literals.get_nth_key(i).size() / 2;
      const char *object_name = os_literals.get_nth_elem(i)->c_str();
      if (octets > 0) src = mputprintf(src, "%s(%lu, %s_octets)",
          object_name, (unsigned long) octets, object_name);
      else src = mputprintf(src, "%s(0, NULL)", object_name);
      if (splitting) hdr = mputstr(hdr, object_name);
    }
    src = mputstr(src, ";\n");
    if (splitting) hdr = mputstr(hdr, ";\n");
  }

  void Module::generate_op_literals(char *&src, char *& hdr)
  {
    if (op_literals.size() == 0) return;
    vector<size_t> pattern_lens;
    for(size_t i = 0; i < op_literals.size(); i++) {
      if (i > 0) {
        src = mputstr(src, ",\n");
      } else {
        src = mputprintf(src, "%sconst unsigned short ", split_to_slices ? "" : "static ");
      }
      src = mputprintf(src, "%s_elements[] = { ",
        op_literals.get_nth_elem(i)->c_str());
      const string& str = op_literals.get_nth_key(i);
      size_t size = str.size();
      size_t pattern_len = 0;
      const char *str_ptr = str.c_str();
      for (size_t j = 0; j < size; j++) {
        if (j > 0) src = mputstr(src, ", ");
        unsigned short num;
        if (str_ptr[j] == '?') num = 256;
        else if (str_ptr[j] == '*') num = 257;
        else {
          // first digit
          num = 16 * char_to_hexdigit(str_ptr[j]);
          j++;
          if (j >= size) FATAL_ERROR("Unexpected end of octetstring pattern.");
          // second digit
          num += char_to_hexdigit(str_ptr[j]);
        }
        src = mputprintf(src, "%u", num);
        pattern_len++;
      }
      src = mputstr(src, " }");
      pattern_lens.add(new size_t(pattern_len));
    }
    src = mputstr(src, ";\n");
    for (size_t i = 0; i < op_literals.size(); i++) {
      if (i > 0) {
        src = mputstr(src, ",\n");
        if (split_to_slices) {
          hdr = mputstr(hdr, ",\n");
        }
      }
      else {
        src = mputprintf(src, "%sconst OCTETSTRING_template ", split_to_slices ? "" : "static ");
        if (split_to_slices) {
            hdr = mputprintf(hdr, "extern const OCTETSTRING_template ");
        }
      }
      const char *name = op_literals.get_nth_elem(i)->c_str();
      src = mputprintf(src, "%s(%lu, %s_elements)",
        name, (unsigned long) *pattern_lens[i], name);
      if (split_to_slices) {
        hdr = mputstr(hdr, name);
      }
    }
    src = mputstr(src, ";\n");
    if (split_to_slices) {
      hdr = mputstr(hdr, ";\n");
    }
    for (size_t i = 0; i < pattern_lens.size(); i++) delete pattern_lens[i];
    pattern_lens.clear();
  }

  void Module::generate_cs_literals(char *&src, char *&hdr)
  {
    if (cs_literals.size() == 0) return;
    bool splitting =
      CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE;
    for (size_t i = 0; i < cs_literals.size(); i++) {
      const string& str = cs_literals.get_nth_key(i);
      size_t str_len = str.size();
      const char *str_ptr = str.c_str();
      const char *str_name = cs_literals.get_nth_elem(i)->c_str();

      if (i > 0) {
        src = mputstr(src, ",\n");
        if (splitting) hdr = mputstr(hdr, ",\n");
      }
      else {
        src = mputprintf(src, "%s const CHARSTRING ",
          splitting ? "extern" : "static");
        if (splitting) hdr = mputstr(hdr, "extern const CHARSTRING ");
      }

      switch (str_len) {
      case 0:
        src = mputprintf(src, "%s(0, NULL)", str_name);
        break;
      case 1:
        src = mputprintf(src, "%s('", str_name);
        src = Code::translate_character(src, *str_ptr, false);
        src = mputstr(src, "')");
        break;
      default:
        src = mputprintf(src, "%s(%lu, \"", str_name, (unsigned long) str_len);
        // Note: Code::translate_string() is not suitable because the string
        // may contain NUL characters at which translate_string() stops
        // immediately
        for (size_t j = 0; j < str_len; j++)
          src = Code::translate_character(src, str_ptr[j], true);
        src = mputstr(src, "\")");
        break;
      } // switch
      if (splitting) hdr = mputstr(hdr, str_name);
    }
    src = mputstr(src, ";\n");
    if (splitting) hdr = mputstr(hdr, ";\n");
  }

  void Module::generate_pp_literals(char *&src, char *&) // padding patterns
  {
    if (pp_literals.size() == 0) return;
    for (size_t i = 0; i < pp_literals.size(); i++) {
      const string& pattern = pp_literals.get_nth_key(i);
      size_t pattern_len = pattern.size();
      const char *pattern_ptr = pattern.c_str();
      if (i > 0) {
        src = mputstr(src, ",\n");
      }
      else {
        src = mputprintf(src, "%sconst unsigned char ", split_to_slices ? "" : "static ");
      }
      src = mputprintf(src, "%s[] = { ", pp_literals.get_nth_elem(i)->c_str());
      if (pattern_len % 8 != 0) FATAL_ERROR("Module::generate_pp_literals()");
      size_t nof_octets = pattern_len / 8;
      for (size_t j = 0; j < nof_octets; j++) {
        if (j > 0) src = mputstr(src, ", ");
        unsigned char octet = 0;
        for (size_t k = 0; k < 8; k++) {
          // take the octets in reverse order
          // MSB is the first character of the string
          octet <<= 1;
          if (pattern_ptr[8 * (nof_octets - j - 1) + k] == '1') octet |= 0x01;
        }
        src = mputprintf(src, "0x%02x", octet);
      }
      src = mputstr(src, " }");
    }
    src = mputstr(src, ";\n");
  }

  void Module::generate_mp_literals(char *&src, char *&) // matching patt.
  {
    if (mp_literals.size() == 0) return;
    for (size_t i = 0; i < mp_literals.size(); i++) {
      const string& str = mp_literals.get_nth_key(i);
      if (str.size() < 1) FATAL_ERROR("Module::generate_mp_literals()");
      const char *str_ptr = str.c_str();

      if (i > 0) src = mputstr(src, ",\n");
      else src = mputprintf(src, "%sconst Token_Match ", split_to_slices ? "" : "static ");

      src = mputprintf(src, "%s(\"", mp_literals.get_nth_elem(i)->c_str());
      src = Code::translate_string(src, str_ptr + 1);
      // The first character of the string is case-sensitiveness flag:
      // 'I' for yes, 'N' for no,
      // 'F' for fixed string matching which is always case sensitive.
      src = mputprintf(src, "\", %s%s)", (str_ptr[0]!='N') ? "TRUE" : "FALSE",
        (str_ptr[0] == 'F') ? ", TRUE" : "");
    }
    src = mputstr(src, ";\n");
  }

  void Module::generate_us_literals(char *&src, char *&hdr) // univ.cs
  {
    size_t n_literals = us_literals.size();
    if (n_literals == 0) return;
    bool array_needed = false;
    bool splitting =
      CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE;
    for (size_t i = 0; i < n_literals; i++) {
      const ustring& value = us_literals.get_nth_key(i);
      size_t value_size = value.size();
      if (value_size < 2) continue;
      if (array_needed) src = mputstr(src, ",\n");
      else {
        src = mputprintf(src, "%sconst universal_char ", split_to_slices ? "" : "static ");
        array_needed = true;
      }
      src = mputprintf(src, "%s_uchars[] = { ",
        us_literals.get_nth_elem(i)->c_str());
      const ustring::universal_char *uchars_ptr = value.u_str();
      for (size_t j = 0; j < value_size; j++) {
        if (j > 0) src = mputstr(src, ", ");
        src = mputprintf(src, "{ %u, %u, %u, %u }", uchars_ptr[j].group,
          uchars_ptr[j].plane, uchars_ptr[j].row, uchars_ptr[j].cell);
      }
      src = mputstr(src, " }");
    }
    if (array_needed) src = mputstr(src, ";\n");
    for (size_t i = 0; i < n_literals; i++) {
      if (i > 0) {
        src = mputstr(src, ",\n");
        if (splitting) hdr = mputstr(hdr, ",\n");
      }
      else {
        src = mputprintf(src, "%s const UNIVERSAL_CHARSTRING ",
          splitting ? "extern" : "static");
        if (splitting) hdr = mputstr(hdr, "extern const UNIVERSAL_CHARSTRING ");
      }
      const char *value_name = us_literals.get_nth_elem(i)->c_str();
      const ustring& value = us_literals.get_nth_key(i);
      size_t value_size = value.size();
      switch (value_size) {
      case 0:
        src = mputprintf(src, "%s(0, (const universal_char*)NULL)", value_name);
        break;
      case 1: {
        const ustring::universal_char& uchar = value.u_str()[0];
        src = mputprintf(src, "%s(%u, %u, %u, %u)", value_name,
          uchar.group, uchar.plane, uchar.row, uchar.cell);
        break; }
      default:
        src = mputprintf(src, "%s(%lu, %s_uchars)", value_name,
          (unsigned long) value_size, value_name);
        break;
      }
      if (splitting) hdr = mputstr(hdr, value_name);
    }
    src = mputstr(src, ";\n");
    if (splitting) hdr = mputstr(hdr, ";\n");
  }

  void Module::generate_oid_literals(char *&src, char *& hdr)
  {
    if (oid_literals.size() == 0) return;
    for (size_t i = 0; i < oid_literals.size(); i++) {
       if (i > 0) src = mputstr(src, ",\n");
       else src = mputprintf(src, "%sconst OBJID::objid_element ", split_to_slices ? "" : "static ");

       src = mputprintf(src, "%s_comps[] = { %s }",
         oid_literals.get_nth_elem(i)->oid_id.c_str(),
         oid_literals.get_nth_key(i).c_str());
    }
    src = mputstr(src, ";\n");
    for(size_t i = 0; i < oid_literals.size(); i++) {
       const OID_literal *litstruct = oid_literals.get_nth_elem(i);

       if (i > 0) { 
         src = mputstr(src, ",\n");
         if (split_to_slices) {
           hdr = mputstr(hdr, ",\n");
         }
       }
       else {
         src = mputprintf(src, "%sconst OBJID ", split_to_slices ? "" : "static ");
         if (split_to_slices) {
           hdr = mputstr(hdr, "extern const OBJID ");
         }
       }

       src = mputprintf(src, "%s(%lu, %s_comps)",
         litstruct->oid_id.c_str(), (unsigned long) litstruct->nof_elems,
         litstruct->oid_id.c_str());
       if (split_to_slices) {
         hdr = mputstr(hdr, litstruct->oid_id.c_str());
       }
    }
    src = mputstr(src, ";\n");
    if (split_to_slices) {
      hdr = mputstr(hdr, ";\n");
    }
  }

  void Module::generate_functions(output_struct *output)
  {
    bool tcov_enabled = tcov_file_name && in_tcov_files(get_filename());
    bool has_pre_init_before_tcov = output->functions.pre_init != NULL;
    if (tcov_enabled) {
      output->functions.pre_init = mputprintf(output->functions.pre_init,
        "TTCN_Location_Statistics::init_file_lines(\"%s\", effective_module_lines, sizeof(effective_module_lines) / sizeof(int));\n" \
        "TTCN_Location_Statistics::init_file_functions(\"%s\", effective_module_functions, sizeof(effective_module_functions) / sizeof(char *));\n",
        get_tcov_file_name(get_filename()), get_tcov_file_name(get_filename()));
    }
    // pre_init function
    bool has_pre_init = false;
Elemer Lelik's avatar
Elemer Lelik committed
    bool profiled = MOD_TTCN == get_moduletype() && is_file_profiled(get_filename());
    bool debugged = debugger_active && MOD_TTCN == get_moduletype();
Elemer Lelik's avatar
Elemer Lelik committed
    // always generate pre_init_module if the file is profiled
    if (output->functions.pre_init || profiled || debugged) {
      output->source.static_function_prototypes =
	  mputprintf(output->source.static_function_prototypes,
	    "%svoid pre_init_module();\n", split_to_slices ? "extern " : "static ");
    output->source.static_function_bodies = mputprintf(output->source.static_function_bodies,
	    "%svoid pre_init_module()\n"
          "{\n", split_to_slices ? "" : "static ");
      if (include_location_info) {
        output->source.static_function_bodies =
          mputstr(output->source.static_function_bodies,
        		  (tcov_enabled && has_pre_init_before_tcov) ? "TTCN_Location_Statistics current_location(\""
        			 	                                     : "TTCN_Location current_location(\"");
        output->source.static_function_bodies =
          Code::translate_string(output->source.static_function_bodies, (tcov_enabled && has_pre_init_before_tcov) ? get_tcov_file_name(get_filename()) : get_filename());
        output->source.static_function_bodies =
          mputprintf(output->source.static_function_bodies,
                     (tcov_enabled && has_pre_init_before_tcov) ? "\", 0, TTCN_Location_Statistics::LOCATION_UNKNOWN, \"%s\");\n"
                       	                                        : "\", 0, TTCN_Location::LOCATION_UNKNOWN, \"%s\");\n", get_modid().get_dispname().c_str());
        if (tcov_enabled && has_pre_init_before_tcov) {
            effective_module_lines =
              mputprintf(effective_module_lines, "%s0",
              		   (effective_module_lines ? ", " : ""));
            effective_module_functions =
              mputprintf(effective_module_functions, "%s\"%s\"",
              		   (effective_module_functions ? ", " : ""), get_modid().get_dispname().c_str());
        }
Elemer Lelik's avatar
Elemer Lelik committed
        if (profiled) {
Elemer Lelik's avatar
Elemer Lelik committed
          output->source.static_function_bodies = mputprintf(output->source.static_function_bodies,
Elemer Lelik's avatar
Elemer Lelik committed
            "%s::init_ttcn3_profiler();\n"
Elemer Lelik's avatar
Elemer Lelik committed
            "TTCN3_Stack_Depth stack_depth;\n"
Elemer Lelik's avatar
Elemer Lelik committed
            "ttcn3_prof.execute_line(\"%s\", 0);\n", get_modid().get_name().c_str(), get_filename());
Elemer Lelik's avatar
Elemer Lelik committed
        }
        if (debugged) {
          output->source.static_function_bodies = mputprintf(output->source.static_function_bodies,
            "%s::init_ttcn3_debugger();\n", get_modid().get_name().c_str());
        }
      }
      output->source.static_function_bodies =
        mputstr(output->source.static_function_bodies, output->functions.pre_init);
      output->source.static_function_bodies =
        mputstr(output->source.static_function_bodies, "}\n\n");
      Free(output->functions.pre_init);
      output->functions.pre_init = NULL;
      has_pre_init = true;
    }
    bool has_post_init_before_tcov = output->functions.post_init != NULL;
    // post_init function
    bool has_post_init = false;
    if (output->functions.post_init) {
      output->source.static_function_prototypes = mputprintf(output->source.static_function_prototypes,
          "%svoid post_init_module();\n", split_to_slices ? "extern " : "static ");
      output->source.static_function_bodies = mputprintf(output->source.static_function_bodies,
	  "%svoid post_init_module()\n"
          "{\n", split_to_slices ? "" : "static ");
      if (include_location_info) {
        output->source.static_function_bodies =
          mputstr(output->source.static_function_bodies,
        		  (tcov_enabled && has_post_init_before_tcov) ? "TTCN_Location_Statistics current_location(\""
        				                                      : "TTCN_Location current_location(\"");
        output->source.static_function_bodies =
          Code::translate_string(output->source.static_function_bodies, (tcov_enabled && has_post_init_before_tcov) ? get_tcov_file_name(get_filename()) : get_filename());
        output->source.static_function_bodies =
          mputprintf(output->source.static_function_bodies,
        		     (tcov_enabled && has_post_init_before_tcov) ? "\", 0, TTCN_Location_Statistics::LOCATION_UNKNOWN, \"%s\");\n"
                      		                                     : "\", 0, TTCN_Location::LOCATION_UNKNOWN, \"%s\");\n", get_modid().get_dispname().c_str());
        if (tcov_enabled && has_post_init_before_tcov) {
          effective_module_lines =
            mputprintf(effective_module_lines, "%s0",
            		   (effective_module_lines ? ", " : ""));
          effective_module_functions =
            mputprintf(effective_module_functions, "%s\"%s\"",
            		   (effective_module_functions ? ", " : ""), get_modid().get_dispname().c_str());
        }
Elemer Lelik's avatar
Elemer Lelik committed
        if (MOD_TTCN == get_moduletype() && is_file_profiled(get_filename())) {
Elemer Lelik's avatar
Elemer Lelik committed
          output->source.static_function_bodies = mputprintf(output->source.static_function_bodies,
            "TTCN3_Stack_Depth stack_depth;\n"
Elemer Lelik's avatar
Elemer Lelik committed
            "ttcn3_prof.execute_line(\"%s\", 0);\n", get_filename());
Elemer Lelik's avatar
Elemer Lelik committed
        }
      }
      output->source.static_function_bodies =
        mputstr(output->source.static_function_bodies, output->functions.post_init);
      output->source.static_function_bodies =
        mputstr(output->source.static_function_bodies, "}\n\n");
      Free(output->functions.post_init);
      output->functions.post_init = NULL;
      has_post_init = true;
    }
    // set_param function
    bool has_set_param;
    if (output->functions.set_param) {
      output->source.static_function_prototypes = mputprintf(output->source.static_function_prototypes,
        "%sboolean set_module_param(Module_Param& param);\n", split_to_slices ? "extern " : "static ");
      output->source.static_function_bodies = mputprintf(output->source.static_function_bodies,
        "%sboolean set_module_param(Module_Param& param)\n"