| 1 | /////////////////////////////////////////////////////////////////////////////// |
| 2 | // Copyright (c) 2000-2015 Ericsson Telecom AB |
| 3 | // All rights reserved. This program and the accompanying materials |
| 4 | // are made available under the terms of the Eclipse Public License v1.0 |
| 5 | // which accompanies this distribution, and is available at |
| 6 | // http://www.eclipse.org/legal/epl-v10.html |
| 7 | /////////////////////////////////////////////////////////////////////////////// |
| 8 | #include <set> |
| 9 | #include <string> |
| 10 | #include <sstream> |
| 11 | |
| 12 | #include "../common/dbgnew.hh" |
| 13 | #include "AST.hh" |
| 14 | #include "asn1/AST_asn1.hh" |
| 15 | #include "Identifier.hh" |
| 16 | #include "Type.hh" |
| 17 | #include "TypeCompat.hh" |
| 18 | #include "Value.hh" |
| 19 | #include "ustring.hh" |
| 20 | #include "main.hh" |
| 21 | #include "asn1/Object0.hh" |
| 22 | #include "PredefFunc.hh" |
| 23 | #include "../common/version.h" |
| 24 | #include "CodeGenHelper.hh" |
| 25 | #include <limits.h> |
| 26 | #include "ttcn3/profiler.h" |
| 27 | |
| 28 | reffer::reffer(const char*) {} |
| 29 | |
| 30 | namespace Common { |
| 31 | |
| 32 | // ================================= |
| 33 | // ===== Modules |
| 34 | // ================================= |
| 35 | |
| 36 | vector<Modules::type_enc_t> Modules::delayed_type_enc_v; |
| 37 | |
| 38 | Modules::Modules() |
| 39 | : Node(), mods_v(), mods_m() |
| 40 | { |
| 41 | set_fullname(string('@')); |
| 42 | } |
| 43 | |
| 44 | Modules::~Modules() |
| 45 | { |
| 46 | for(size_t i = 0; i < mods_v.size(); i++) delete mods_v[i]; |
| 47 | mods_v.clear(); |
| 48 | mods_m.clear(); |
| 49 | } |
| 50 | |
| 51 | Modules *Modules::clone() const |
| 52 | { |
| 53 | FATAL_ERROR("Modules::clone()"); |
| 54 | return 0; |
| 55 | } |
| 56 | |
| 57 | void Modules::add_mod(Module *p_mod) |
| 58 | { |
| 59 | if (!p_mod) FATAL_ERROR("NULL parameter: Common::Modules::add_mod()"); |
| 60 | p_mod->set_fullname("@"+p_mod->get_modid().get_dispname()); |
| 61 | p_mod->set_scope_name(p_mod->get_modid().get_dispname()); |
| 62 | mods_v.add(p_mod); |
| 63 | } |
| 64 | |
| 65 | bool Modules::has_mod_withId(const Identifier& p_modid) |
| 66 | { |
| 67 | return mods_m.has_key(p_modid.get_name()); |
| 68 | } |
| 69 | |
| 70 | Module* Modules::get_mod_byId(const Identifier& p_modid) |
| 71 | { |
| 72 | const string& name = p_modid.get_name(); |
| 73 | return mods_m.has_key(name)?mods_m[name]:0; |
| 74 | } |
| 75 | |
| 76 | Assignment* Modules::get_ass_bySRef(Ref_simple *p_ref) |
| 77 | { |
| 78 | if(!p_ref) |
| 79 | FATAL_ERROR("NULL parameter: Common::Modules::get_ass_bySRef()"); |
| 80 | const Identifier *modid=p_ref->get_modid(); |
| 81 | if(modid) { |
| 82 | if(has_mod_withId(*modid)) |
| 83 | return get_mod_byId(*modid)->get_ass_bySRef(p_ref); |
| 84 | else { |
| 85 | p_ref->error("There is no module with identifier `%s'", |
| 86 | modid->get_dispname().c_str()); |
| 87 | return 0; |
| 88 | } |
| 89 | } |
| 90 | else { |
| 91 | p_ref->error("`%s' entity not found in global scope", |
| 92 | p_ref->get_dispname().c_str()); |
| 93 | return 0; |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | void Modules::chk_uniq() |
| 98 | { |
| 99 | for(size_t i = 0; i < mods_v.size(); i++) { |
| 100 | Module *m = mods_v[i]; |
| 101 | const Identifier& id = m->get_modid(); |
| 102 | const string& name = id.get_name(); |
| 103 | if (mods_m.has_key(name)) { |
| 104 | Module *m2 = mods_m[name]; |
| 105 | m->error("A module with identifier `%s' already exists", |
| 106 | id.get_dispname().c_str()); |
| 107 | m2->error("This is the first module with the same name"); |
| 108 | if (m->get_moduletype() == m2->get_moduletype() && |
| 109 | !strcmp(m->get_filename(), m2->get_filename())) { |
| 110 | // the same file was given twice -> drop the entire module |
| 111 | delete m; |
| 112 | mods_v.replace(i, 1); |
| 113 | i--; |
| 114 | } |
| 115 | } else mods_m.add(name, m); |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | void Modules::chk() |
| 120 | { |
| 121 | // first check the uniqueness of module names |
| 122 | chk_uniq(); |
| 123 | // check the import chains |
| 124 | size_t nof_mods = mods_v.size(); |
| 125 | for (size_t i = 0; i < nof_mods; i++) { |
| 126 | Module *m = mods_v[i]; |
| 127 | ReferenceChain refch(m, "While checking import chains"); |
| 128 | vector<Common::Module> modules; |
| 129 | m->chk_imp(refch, modules); |
| 130 | modules.clear(); |
| 131 | //clear the reference chain, get a fresh start |
| 132 | refch.reset(); |
| 133 | } |
| 134 | // check the modules |
| 135 | Module::module_set_t checked_modules; |
| 136 | if (nof_top_level_pdus > 0) { |
| 137 | chk_top_level_pdus(); |
| 138 | // do not check ASN.1 modules, but assume they are already checked |
| 139 | for (size_t i = 0; i < nof_mods; i++) { |
| 140 | Module *module = mods_v[i]; |
| 141 | if (module->get_moduletype() == Module::MOD_ASN) |
| 142 | checked_modules.add(module, 0); |
| 143 | } |
| 144 | for (size_t i = 0; i < nof_mods; i++) { |
| 145 | Module *module = mods_v[i]; |
| 146 | if (module->get_moduletype() != Module::MOD_ASN) |
| 147 | module->chk_recursive(checked_modules); |
| 148 | } |
| 149 | } else { |
| 150 | // walk through all modules in bottom-up order |
| 151 | for (size_t i = 0; i < nof_mods; i++) |
| 152 | mods_v[i]->chk_recursive(checked_modules); |
| 153 | } |
| 154 | checked_modules.clear(); |
| 155 | // run delayed Type::chk_coding() calls |
| 156 | if (!delayed_type_enc_v.empty()) { |
| 157 | for (size_t i = 0; i < delayed_type_enc_v.size(); ++i) { |
| 158 | delayed_type_enc_v[i]->t->chk_coding(delayed_type_enc_v[i]->enc, true); |
| 159 | delete delayed_type_enc_v[i]; |
| 160 | } |
| 161 | delayed_type_enc_v.clear(); |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | void Modules::chk_top_level_pdus() |
| 166 | { |
| 167 | Location loc("<command line>"); |
| 168 | for(size_t i=0; i<nof_top_level_pdus; i++) { |
| 169 | string pduname(top_level_pdu[i]); |
| 170 | size_t dotpos=pduname.find('.'); |
| 171 | if(dotpos>=pduname.size()) { |
| 172 | loc.error("While searching top-level pdu `%s': " |
| 173 | "Please use the `modulename.identifier' format", |
| 174 | pduname.c_str()); |
| 175 | continue; |
| 176 | } |
| 177 | Module *module=0; |
| 178 | Identifier *pdu_id=0; |
| 179 | { // searching the module |
| 180 | const string& pduname_mod = pduname.substr(0, dotpos); |
| 181 | const string& pduname_id = pduname.substr(dotpos + 1); |
| 182 | { // ASN |
| 183 | Identifier modid(Identifier::ID_ASN, pduname_mod, true); |
| 184 | module = get_mod_byId(modid); |
| 185 | } |
| 186 | if (module && module->get_moduletype() == Module::MOD_ASN) { |
| 187 | pdu_id = new Identifier(Identifier::ID_ASN, pduname_id, true); |
| 188 | goto mod_ok; |
| 189 | } |
| 190 | { // TTCN |
| 191 | Identifier modid(Identifier::ID_TTCN, pduname_mod, true); |
| 192 | module = get_mod_byId(modid); |
| 193 | } |
| 194 | if (module && module->get_moduletype() == Module::MOD_TTCN) { |
| 195 | pdu_id = new Identifier(Identifier::ID_TTCN, pduname_id, true); |
| 196 | goto mod_ok; |
| 197 | } |
| 198 | { // C++ |
| 199 | Identifier modid(Identifier::ID_NAME, pduname_mod, true); |
| 200 | module = get_mod_byId(modid); |
| 201 | } |
| 202 | if(module) { |
| 203 | pdu_id = new Identifier(Identifier::ID_NAME, pduname_id, true); |
| 204 | goto mod_ok; |
| 205 | } |
| 206 | // error - no such module |
| 207 | loc.error("While searching top-level pdu `%s': " |
| 208 | "No module with name `%s'", |
| 209 | pduname.c_str(), pduname_mod.c_str()); |
| 210 | continue; |
| 211 | } |
| 212 | mod_ok: |
| 213 | Assignments *asss=module->get_asss(); |
| 214 | if(asss->has_local_ass_withId(*pdu_id)) { |
| 215 | Assignment *ass=asss->get_local_ass_byId(*pdu_id); |
| 216 | ass->chk(); |
| 217 | } |
| 218 | else { |
| 219 | loc.error("While searching top-level pdu `%s': " |
| 220 | "No assignment with identifier `%s'", |
| 221 | pduname.c_str(), pdu_id->get_dispname().c_str()); |
| 222 | } |
| 223 | delete pdu_id; |
| 224 | } // for top-level pdus |
| 225 | } |
| 226 | |
| 227 | void Modules::write_checksums() |
| 228 | { |
| 229 | fputs("Module name Language MD5 checksum Version\n" |
| 230 | "---------------------------------------------------------------------------\n", stderr); |
| 231 | size_t nof_mods = mods_v.size(); |
| 232 | for (size_t i = 0; i < nof_mods; i++) { |
| 233 | mods_v[i]->write_checksum(); |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | void Modules::generate_code(CodeGenHelper& cgh) |
| 238 | { |
| 239 | Common::Module::rename_default_namespace(); // if needed |
| 240 | /* |
| 241 | The White Rabbit put on his spectacles. |
| 242 | "Where shall I begin, please your Majesty ?" he asked. |
| 243 | "Begin at the beginning,", the King said, very gravely, "and go on |
| 244 | till you come to the end: then stop." |
| 245 | -- Lewis Carroll |
| 246 | */ |
| 247 | for (size_t i = 0; i < mods_v.size(); i++) { |
| 248 | mods_v[i]->generate_code(cgh); |
| 249 | if (tcov_file_name && in_tcov_files(mods_v[i]->get_filename())) { |
| 250 | Free(effective_module_lines); |
| 251 | Free(effective_module_functions); |
| 252 | effective_module_lines = effective_module_functions = NULL; |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | cgh.write_output(); |
| 257 | } |
| 258 | |
| 259 | |
| 260 | void Modules::dump(unsigned level) const |
| 261 | { |
| 262 | DEBUG(level, "Modules (%lu pcs.)", (unsigned long) mods_v.size()); |
| 263 | for(size_t i = 0; i < mods_v.size(); i++) mods_v[i]->dump(level); |
| 264 | } |
| 265 | |
| 266 | std::set<ModuleVersion> Modules::getVersionsWithProductNumber() const { |
| 267 | std::set<ModuleVersion> versions; |
| 268 | for (size_t i = 0; i < mods_v.size(); ++i) { |
| 269 | const ModuleVersion version = mods_v[i]->getVersion(); |
| 270 | if (version.hasProductNumber()) { |
| 271 | versions.insert(version); |
| 272 | } |
| 273 | } |
| 274 | return versions; |
| 275 | } |
| 276 | |
| 277 | void Modules::generate_json_schema(JSON_Tokenizer& json, map<Type*, JSON_Tokenizer>& json_refs) |
| 278 | { |
| 279 | for(size_t i = 0; i < mods_v.size(); ++i) { |
| 280 | mods_v[i]->generate_json_schema(json, json_refs); |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | void Modules::delay_type_encode_check(Type* p_type, bool p_encode) |
| 285 | { |
| 286 | type_enc_t* elem = new type_enc_t; |
| 287 | elem->t = p_type; |
| 288 | elem->enc = p_encode; |
| 289 | delayed_type_enc_v.add(elem); |
| 290 | } |
| 291 | |
| 292 | |
| 293 | // ================================= |
| 294 | // ===== Module |
| 295 | // ================================= |
| 296 | |
| 297 | ModuleVersion Module::getVersion() const { |
| 298 | return ModuleVersion(product_number, suffix, release, patch, build, extra); |
| 299 | } |
| 300 | |
| 301 | void Module::generate_literals(output_struct *target) |
| 302 | { |
| 303 | char *src = NULL; |
| 304 | char *hdr = NULL; |
| 305 | generate_bs_literals(src, hdr); // implementations follow directly below |
| 306 | generate_bp_literals(src, hdr); |
| 307 | generate_hs_literals(src, hdr); |
| 308 | generate_hp_literals(src, hdr); |
| 309 | generate_os_literals(src, hdr); |
| 310 | generate_op_literals(src, hdr); |
| 311 | generate_cs_literals(src, hdr); |
| 312 | generate_us_literals(src, hdr); |
| 313 | generate_oid_literals(src, hdr); |
| 314 | generate_pp_literals(src, hdr); |
| 315 | generate_mp_literals(src, hdr); |
| 316 | target->source.string_literals = |
| 317 | mputstr(target->source.string_literals, src); |
| 318 | if (CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE) { |
| 319 | target->header.global_vars = mputstr(target->header.global_vars, hdr); |
| 320 | } |
| 321 | Free(src); |
| 322 | Free(hdr); |
| 323 | } |
| 324 | |
| 325 | void Module::generate_bs_literals(char *&src, char *&hdr) |
| 326 | { |
| 327 | if (bs_literals.size() == 0) return; |
| 328 | // indicates whether we have found at least one non-empty bitstring |
| 329 | bool is_nonempty = false; |
| 330 | bool splitting = |
| 331 | CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE; |
| 332 | for (size_t i = 0; i < bs_literals.size(); i++) { |
| 333 | const string& str = bs_literals.get_nth_key(i); |
| 334 | size_t bits = str.size(); |
| 335 | if (bits == 0) continue; |
| 336 | if (is_nonempty) src = mputstr(src, ",\n"); |
| 337 | else { |
| 338 | src = mputstr(src, "static const unsigned char "); |
| 339 | is_nonempty = true; |
| 340 | } |
| 341 | src = mputprintf(src, "%s_bits[] = { ", |
| 342 | bs_literals.get_nth_elem(i)->c_str()); |
| 343 | // Filling up the octets one-by-one |
| 344 | for (size_t j = 0; j < (bits + 7) / 8; j++) { |
| 345 | size_t offset = 8 * j; |
| 346 | unsigned char value = 0; |
| 347 | for (size_t k = 0; k < 8 && k < bits - offset; k++) { |
| 348 | if (str[offset + k] == '1') value |= (1 << k); |
| 349 | } |
| 350 | if (j > 0) src = mputstr(src, ", "); |
| 351 | src = mputprintf(src, "%d", value); |
| 352 | } |
| 353 | src = mputstr(src, " }"); |
| 354 | } |
| 355 | if (is_nonempty) src = mputstr(src, ";\n"); |
| 356 | for (size_t i = 0; i < bs_literals.size(); i++) { |
| 357 | if (i > 0) { |
| 358 | src = mputstr(src, ",\n"); |
| 359 | if (splitting) hdr = mputstr(hdr, ",\n"); |
| 360 | } |
| 361 | else { |
| 362 | src = mputprintf(src, "%s const BITSTRING ", |
| 363 | splitting ? "extern" : "static"); |
| 364 | if (splitting) hdr = mputstr(hdr, "extern const BITSTRING "); |
| 365 | } |
| 366 | size_t bits = bs_literals.get_nth_key(i).size(); |
| 367 | const char *object_name = bs_literals.get_nth_elem(i)->c_str(); |
| 368 | if (bits > 0) src = mputprintf(src, "%s(%lu, %s_bits)", |
| 369 | object_name, (unsigned long) bits, object_name); |
| 370 | else src = mputprintf(src, "%s(0, NULL)", object_name); |
| 371 | if (splitting) hdr = mputstr(hdr, object_name); |
| 372 | } |
| 373 | src = mputstr(src, ";\n"); |
| 374 | if (splitting) hdr = mputstr(hdr, ";\n"); |
| 375 | } |
| 376 | |
| 377 | void Module::generate_bp_literals(char *&src, char *& /*hdr*/) |
| 378 | { |
| 379 | if (bp_literals.size() == 0) return; |
| 380 | for (size_t i = 0; i < bp_literals.size(); i++) { |
| 381 | if (i > 0) src = mputstr(src, ",\n"); |
| 382 | else src = mputstr(src, "static const unsigned char "); |
| 383 | src = mputprintf(src, "%s_elements[] = { ", |
| 384 | bp_literals.get_nth_elem(i)->c_str()); |
| 385 | const string& str = bp_literals.get_nth_key(i); |
| 386 | for (size_t j = 0; j < str.size(); j++) { |
| 387 | if (j > 0) src = mputstr(src, ", "); |
| 388 | switch (str[j]) { |
| 389 | case '0': |
| 390 | src = mputc(src, '0'); |
| 391 | break; |
| 392 | case '1': |
| 393 | src = mputc(src, '1'); |
| 394 | break; |
| 395 | case '?': |
| 396 | src = mputc(src, '2'); |
| 397 | break; |
| 398 | case '*': |
| 399 | src = mputc(src, '3'); |
| 400 | break; |
| 401 | default: |
| 402 | FATAL_ERROR("Invalid character in bitstring pattern."); |
| 403 | } |
| 404 | } |
| 405 | src = mputstr(src, " }"); |
| 406 | } |
| 407 | src = mputstr(src, ";\n"); |
| 408 | for (size_t i = 0; i < bp_literals.size(); i++) { |
| 409 | if (i > 0) src = mputstr(src, ",\n"); |
| 410 | else src = mputstr(src, "static const BITSTRING_template "); |
| 411 | const char *name = bp_literals.get_nth_elem(i)->c_str(); |
| 412 | src = mputprintf(src, "%s(%lu, %s_elements)", |
| 413 | name, (unsigned long) bp_literals.get_nth_key(i).size(), name); |
| 414 | } |
| 415 | src = mputstr(src, ";\n"); |
| 416 | } |
| 417 | |
| 418 | void Module::generate_hs_literals(char *&src, char *&hdr) |
| 419 | { |
| 420 | if (hs_literals.size() == 0) return; |
| 421 | // indicates whether we have found at least one non-empty hexstring |
| 422 | bool is_nonempty = false; |
| 423 | bool splitting = |
| 424 | CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE; |
| 425 | for (size_t i = 0; i < hs_literals.size(); i++) { |
| 426 | const string& str = hs_literals.get_nth_key(i); |
| 427 | size_t nibbles = str.size(); |
| 428 | if (nibbles == 0) continue; |
| 429 | size_t octets = (nibbles + 1) / 2; |
| 430 | const char *str_ptr = str.c_str(); |
| 431 | if (is_nonempty) src = mputstr(src, ",\n"); |
| 432 | else { |
| 433 | src = mputstr(src, "static const unsigned char "); |
| 434 | is_nonempty = true; |
| 435 | } |
| 436 | src = mputprintf(src, "%s_nibbles[] = { ", |
| 437 | hs_literals.get_nth_elem(i)->c_str()); |
| 438 | for (size_t j = 0; j < octets; j++) { |
| 439 | // Hex digit with even index always goes to the least significant |
| 440 | // 4 bits of the octet. |
| 441 | unsigned char value = char_to_hexdigit(str_ptr[2 * j]); |
| 442 | if (2 * j + 1 < nibbles) { |
| 443 | // Hex digit with odd index always goes to the most significant |
| 444 | // 4 bits of the octet. |
| 445 | // This digit is not present (bits are set to zero) if the length |
| 446 | // of hexstring is odd. |
| 447 | value += 16 * char_to_hexdigit(str_ptr[2 * j + 1]); |
| 448 | } |
| 449 | if (j > 0) src = mputstr(src, ", "); |
| 450 | src = mputprintf(src, "%u", value); |
| 451 | } |
| 452 | src = mputstr(src, " }"); |
| 453 | } |
| 454 | if (is_nonempty) src = mputstr(src, ";\n"); |
| 455 | for (size_t i = 0; i < hs_literals.size(); i++) { |
| 456 | if (i > 0) { |
| 457 | src = mputstr(src, ",\n"); |
| 458 | if (splitting) hdr = mputstr(hdr, ",\n"); |
| 459 | } |
| 460 | else { |
| 461 | src = mputprintf(src, "%s const HEXSTRING ", |
| 462 | splitting ? "extern" : "static"); |
| 463 | if (splitting) hdr = mputstr(hdr, "extern const HEXSTRING "); |
| 464 | } |
| 465 | size_t nibbles = hs_literals.get_nth_key(i).size(); |
| 466 | const char *object_name = hs_literals.get_nth_elem(i)->c_str(); |
| 467 | if (nibbles > 0) src = mputprintf(src, "%s(%lu, %s_nibbles)", |
| 468 | object_name, (unsigned long) nibbles, object_name); |
| 469 | else src = mputprintf(src, "%s(0, NULL)", object_name); |
| 470 | if (splitting) hdr = mputstr(hdr, object_name); |
| 471 | } |
| 472 | src = mputstr(src, ";\n"); |
| 473 | if (splitting) hdr = mputstr(hdr, ";\n"); |
| 474 | } |
| 475 | |
| 476 | void Module::generate_hp_literals(char *&src, char *& /*hdr*/) |
| 477 | { |
| 478 | if (hp_literals.size() == 0) return; |
| 479 | for (size_t i = 0; i < hp_literals.size(); i++) { |
| 480 | if (i > 0) src = mputstr(src, ",\n"); |
| 481 | else src = mputstr(src, "static const unsigned char "); |
| 482 | src = mputprintf(src, "%s_elements[] = { ", |
| 483 | hp_literals.get_nth_elem(i)->c_str()); |
| 484 | const string& str = hp_literals.get_nth_key(i); |
| 485 | size_t size = str.size(); |
| 486 | const char *str_ptr = str.c_str(); |
| 487 | for (size_t j = 0; j < size; j++) { |
| 488 | if (j > 0) src = mputstr(src, ", "); |
| 489 | unsigned char num; |
| 490 | if (str_ptr[j] == '?') num = 16; |
| 491 | else if (str_ptr[j] == '*') num = 17; |
| 492 | else num = char_to_hexdigit(str_ptr[j]); |
| 493 | src = mputprintf(src, "%u", num); |
| 494 | } |
| 495 | src = mputstr(src, " }"); |
| 496 | } |
| 497 | src = mputstr(src, ";\n"); |
| 498 | for (size_t i = 0; i < hp_literals.size(); i++) { |
| 499 | if (i > 0) src = mputstr(src, ",\n"); |
| 500 | else src = mputstr(src, "static const HEXSTRING_template "); |
| 501 | const char *name = hp_literals.get_nth_elem(i)->c_str(); |
| 502 | src = mputprintf(src, "%s(%lu, %s_elements)", |
| 503 | name, (unsigned long) hp_literals.get_nth_key(i).size(), name); |
| 504 | } |
| 505 | src = mputstr(src, ";\n"); |
| 506 | } |
| 507 | |
| 508 | void Module::generate_os_literals(char *&src, char *&hdr) |
| 509 | { |
| 510 | if (os_literals.size() == 0) return; |
| 511 | // indicates whether we have found at least one non-empty octetstring |
| 512 | bool is_nonempty = false; |
| 513 | bool splitting = |
| 514 | CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE; |
| 515 | for (size_t i = 0; i < os_literals.size(); i++) { |
| 516 | const string& str = os_literals.get_nth_key(i); |
| 517 | size_t size = str.size(); |
| 518 | if (size % 2) FATAL_ERROR("Invalid length for an octetstring."); |
| 519 | size_t octets = size / 2; |
| 520 | if (octets == 0) continue; |
| 521 | const char *str_ptr = str.c_str(); |
| 522 | if (is_nonempty) src = mputstr(src, ",\n"); |
| 523 | else { |
| 524 | src = mputstr(src, "static const unsigned char "); |
| 525 | is_nonempty = true; |
| 526 | } |
| 527 | src = mputprintf(src, "%s_octets[] = { ", |
| 528 | os_literals.get_nth_elem(i)->c_str()); |
| 529 | for (size_t j = 0; j < octets; j++) { |
| 530 | if (j > 0) src = mputstr(src, ", "); |
| 531 | src = mputprintf(src, "%u", 16 * char_to_hexdigit(str_ptr[2 * j]) + |
| 532 | char_to_hexdigit(str_ptr[2 * j + 1])); |
| 533 | } |
| 534 | src = mputstr(src, " }"); |
| 535 | } |
| 536 | if (is_nonempty) src = mputstr(src, ";\n"); |
| 537 | for (size_t i = 0; i < os_literals.size(); i++) { |
| 538 | if (i > 0) { |
| 539 | src = mputstr(src, ",\n"); |
| 540 | if (splitting) hdr = mputstr(hdr, ",\n"); |
| 541 | } |
| 542 | else { |
| 543 | src = mputprintf(src, "%s const OCTETSTRING ", |
| 544 | splitting ? "extern" : "static"); |
| 545 | if (splitting) hdr = mputstr(hdr, "extern const OCTETSTRING "); |
| 546 | } |
| 547 | size_t octets = os_literals.get_nth_key(i).size() / 2; |
| 548 | const char *object_name = os_literals.get_nth_elem(i)->c_str(); |
| 549 | if (octets > 0) src = mputprintf(src, "%s(%lu, %s_octets)", |
| 550 | object_name, (unsigned long) octets, object_name); |
| 551 | else src = mputprintf(src, "%s(0, NULL)", object_name); |
| 552 | if (splitting) hdr = mputstr(hdr, object_name); |
| 553 | } |
| 554 | src = mputstr(src, ";\n"); |
| 555 | if (splitting) hdr = mputstr(hdr, ";\n"); |
| 556 | } |
| 557 | |
| 558 | void Module::generate_op_literals(char *&src, char *& /*hdr*/) |
| 559 | { |
| 560 | if (op_literals.size() == 0) return; |
| 561 | vector<size_t> pattern_lens; |
| 562 | for(size_t i = 0; i < op_literals.size(); i++) { |
| 563 | if (i > 0) src = mputstr(src, ",\n"); |
| 564 | else src = mputstr(src, "static const unsigned short "); |
| 565 | src = mputprintf(src, "%s_elements[] = { ", |
| 566 | op_literals.get_nth_elem(i)->c_str()); |
| 567 | const string& str = op_literals.get_nth_key(i); |
| 568 | size_t size = str.size(); |
| 569 | size_t pattern_len = 0; |
| 570 | const char *str_ptr = str.c_str(); |
| 571 | for (size_t j = 0; j < size; j++) { |
| 572 | if (j > 0) src = mputstr(src, ", "); |
| 573 | unsigned short num; |
| 574 | if (str_ptr[j] == '?') num = 256; |
| 575 | else if (str_ptr[j] == '*') num = 257; |
| 576 | else { |
| 577 | // first digit |
| 578 | num = 16 * char_to_hexdigit(str_ptr[j]); |
| 579 | j++; |
| 580 | if (j >= size) FATAL_ERROR("Unexpected end of octetstring pattern."); |
| 581 | // second digit |
| 582 | num += char_to_hexdigit(str_ptr[j]); |
| 583 | } |
| 584 | src = mputprintf(src, "%u", num); |
| 585 | pattern_len++; |
| 586 | } |
| 587 | src = mputstr(src, " }"); |
| 588 | pattern_lens.add(new size_t(pattern_len)); |
| 589 | } |
| 590 | src = mputstr(src, ";\n"); |
| 591 | for (size_t i = 0; i < op_literals.size(); i++) { |
| 592 | if (i > 0) src = mputstr(src, ",\n"); |
| 593 | else src = mputstr(src, "static const OCTETSTRING_template "); |
| 594 | const char *name = op_literals.get_nth_elem(i)->c_str(); |
| 595 | src = mputprintf(src, "%s(%lu, %s_elements)", |
| 596 | name, (unsigned long) *pattern_lens[i], name); |
| 597 | } |
| 598 | src = mputstr(src, ";\n"); |
| 599 | for (size_t i = 0; i < pattern_lens.size(); i++) delete pattern_lens[i]; |
| 600 | pattern_lens.clear(); |
| 601 | } |
| 602 | |
| 603 | void Module::generate_cs_literals(char *&src, char *&hdr) |
| 604 | { |
| 605 | if (cs_literals.size() == 0) return; |
| 606 | bool splitting = |
| 607 | CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE; |
| 608 | for (size_t i = 0; i < cs_literals.size(); i++) { |
| 609 | const string& str = cs_literals.get_nth_key(i); |
| 610 | size_t str_len = str.size(); |
| 611 | const char *str_ptr = str.c_str(); |
| 612 | const char *str_name = cs_literals.get_nth_elem(i)->c_str(); |
| 613 | |
| 614 | if (i > 0) { |
| 615 | src = mputstr(src, ",\n"); |
| 616 | if (splitting) hdr = mputstr(hdr, ",\n"); |
| 617 | } |
| 618 | else { |
| 619 | src = mputprintf(src, "%s const CHARSTRING ", |
| 620 | splitting ? "extern" : "static"); |
| 621 | if (splitting) hdr = mputstr(hdr, "extern const CHARSTRING "); |
| 622 | } |
| 623 | |
| 624 | switch (str_len) { |
| 625 | case 0: |
| 626 | src = mputprintf(src, "%s(0, NULL)", str_name); |
| 627 | break; |
| 628 | case 1: |
| 629 | src = mputprintf(src, "%s('", str_name); |
| 630 | src = Code::translate_character(src, *str_ptr, false); |
| 631 | src = mputstr(src, "')"); |
| 632 | break; |
| 633 | default: |
| 634 | src = mputprintf(src, "%s(%lu, \"", str_name, (unsigned long) str_len); |
| 635 | // Note: Code::translate_string() is not suitable because the string |
| 636 | // may contain NUL characters at which translate_string() stops |
| 637 | // immediately |
| 638 | for (size_t j = 0; j < str_len; j++) |
| 639 | src = Code::translate_character(src, str_ptr[j], true); |
| 640 | src = mputstr(src, "\")"); |
| 641 | break; |
| 642 | } // switch |
| 643 | if (splitting) hdr = mputstr(hdr, str_name); |
| 644 | } |
| 645 | src = mputstr(src, ";\n"); |
| 646 | if (splitting) hdr = mputstr(hdr, ";\n"); |
| 647 | } |
| 648 | |
| 649 | void Module::generate_pp_literals(char *&src, char *&) // padding patterns |
| 650 | { |
| 651 | if (pp_literals.size() == 0) return; |
| 652 | for (size_t i = 0; i < pp_literals.size(); i++) { |
| 653 | const string& pattern = pp_literals.get_nth_key(i); |
| 654 | size_t pattern_len = pattern.size(); |
| 655 | const char *pattern_ptr = pattern.c_str(); |
| 656 | if (i > 0) src = mputstr(src, ",\n"); |
| 657 | else src = mputstr(src, "static const unsigned char "); |
| 658 | src = mputprintf(src, "%s[] = { ", pp_literals.get_nth_elem(i)->c_str()); |
| 659 | if (pattern_len % 8 != 0) FATAL_ERROR("Module::generate_pp_literals()"); |
| 660 | size_t nof_octets = pattern_len / 8; |
| 661 | for (size_t j = 0; j < nof_octets; j++) { |
| 662 | if (j > 0) src = mputstr(src, ", "); |
| 663 | unsigned char octet = 0; |
| 664 | for (size_t k = 0; k < 8; k++) { |
| 665 | // take the octets in reverse order |
| 666 | // MSB is the first character of the string |
| 667 | octet <<= 1; |
| 668 | if (pattern_ptr[8 * (nof_octets - j - 1) + k] == '1') octet |= 0x01; |
| 669 | } |
| 670 | src = mputprintf(src, "0x%02x", octet); |
| 671 | } |
| 672 | src = mputstr(src, " }"); |
| 673 | } |
| 674 | src = mputstr(src, ";\n"); |
| 675 | } |
| 676 | |
| 677 | void Module::generate_mp_literals(char *&src, char *&) // matching patt. |
| 678 | { |
| 679 | if (mp_literals.size() == 0) return; |
| 680 | for (size_t i = 0; i < mp_literals.size(); i++) { |
| 681 | const string& str = mp_literals.get_nth_key(i); |
| 682 | if (str.size() < 1) FATAL_ERROR("Module::generate_mp_literals()"); |
| 683 | const char *str_ptr = str.c_str(); |
| 684 | |
| 685 | if (i > 0) src = mputstr(src, ",\n"); |
| 686 | else src = mputstr(src, "static const Token_Match "); |
| 687 | |
| 688 | src = mputprintf(src, "%s(\"", mp_literals.get_nth_elem(i)->c_str()); |
| 689 | src = Code::translate_string(src, str_ptr + 1); |
| 690 | // The first character of the string is case-sensitiveness flag: |
| 691 | // 'I' for yes, 'N' for no, |
| 692 | // 'F' for fixed string matching which is always case sensitive. |
| 693 | src = mputprintf(src, "\", %s%s)", (str_ptr[0]!='N') ? "TRUE" : "FALSE", |
| 694 | (str_ptr[0] == 'F') ? ", TRUE" : ""); |
| 695 | } |
| 696 | src = mputstr(src, ";\n"); |
| 697 | } |
| 698 | |
| 699 | void Module::generate_us_literals(char *&src, char *&hdr) // univ.cs |
| 700 | { |
| 701 | size_t n_literals = us_literals.size(); |
| 702 | if (n_literals == 0) return; |
| 703 | bool array_needed = false; |
| 704 | bool splitting = |
| 705 | CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE; |
| 706 | for (size_t i = 0; i < n_literals; i++) { |
| 707 | const ustring& value = us_literals.get_nth_key(i); |
| 708 | size_t value_size = value.size(); |
| 709 | if (value_size < 2) continue; |
| 710 | if (array_needed) src = mputstr(src, ",\n"); |
| 711 | else { |
| 712 | src = mputstr(src, "static const universal_char "); |
| 713 | array_needed = true; |
| 714 | } |
| 715 | src = mputprintf(src, "%s_uchars[] = { ", |
| 716 | us_literals.get_nth_elem(i)->c_str()); |
| 717 | const ustring::universal_char *uchars_ptr = value.u_str(); |
| 718 | for (size_t j = 0; j < value_size; j++) { |
| 719 | if (j > 0) src = mputstr(src, ", "); |
| 720 | src = mputprintf(src, "{ %u, %u, %u, %u }", uchars_ptr[j].group, |
| 721 | uchars_ptr[j].plane, uchars_ptr[j].row, uchars_ptr[j].cell); |
| 722 | } |
| 723 | src = mputstr(src, " }"); |
| 724 | } |
| 725 | if (array_needed) src = mputstr(src, ";\n"); |
| 726 | for (size_t i = 0; i < n_literals; i++) { |
| 727 | if (i > 0) { |
| 728 | src = mputstr(src, ",\n"); |
| 729 | if (splitting) hdr = mputstr(hdr, ",\n"); |
| 730 | } |
| 731 | else { |
| 732 | src = mputprintf(src, "%s const UNIVERSAL_CHARSTRING ", |
| 733 | splitting ? "extern" : "static"); |
| 734 | if (splitting) hdr = mputstr(hdr, "extern const UNIVERSAL_CHARSTRING "); |
| 735 | } |
| 736 | const char *value_name = us_literals.get_nth_elem(i)->c_str(); |
| 737 | const ustring& value = us_literals.get_nth_key(i); |
| 738 | size_t value_size = value.size(); |
| 739 | switch (value_size) { |
| 740 | case 0: |
| 741 | src = mputprintf(src, "%s(0, (const universal_char*)NULL)", value_name); |
| 742 | break; |
| 743 | case 1: { |
| 744 | const ustring::universal_char& uchar = value.u_str()[0]; |
| 745 | src = mputprintf(src, "%s(%u, %u, %u, %u)", value_name, |
| 746 | uchar.group, uchar.plane, uchar.row, uchar.cell); |
| 747 | break; } |
| 748 | default: |
| 749 | src = mputprintf(src, "%s(%lu, %s_uchars)", value_name, |
| 750 | (unsigned long) value_size, value_name); |
| 751 | break; |
| 752 | } |
| 753 | if (splitting) hdr = mputstr(hdr, value_name); |
| 754 | } |
| 755 | src = mputstr(src, ";\n"); |
| 756 | if (splitting) hdr = mputstr(hdr, ";\n"); |
| 757 | } |
| 758 | |
| 759 | void Module::generate_oid_literals(char *&src, char *& /*hdr*/) |
| 760 | { |
| 761 | if (oid_literals.size() == 0) return; |
| 762 | for (size_t i = 0; i < oid_literals.size(); i++) { |
| 763 | if (i > 0) src = mputstr(src, ",\n"); |
| 764 | else src = mputstr(src, "static const OBJID::objid_element "); |
| 765 | |
| 766 | src = mputprintf(src, "%s_comps[] = { %s }", |
| 767 | oid_literals.get_nth_elem(i)->oid_id.c_str(), |
| 768 | oid_literals.get_nth_key(i).c_str()); |
| 769 | } |
| 770 | src = mputstr(src, ";\n"); |
| 771 | for(size_t i = 0; i < oid_literals.size(); i++) { |
| 772 | const OID_literal *litstruct = oid_literals.get_nth_elem(i); |
| 773 | |
| 774 | if (i > 0) src = mputstr(src, ",\n"); |
| 775 | else src = mputstr(src, "static const OBJID "); |
| 776 | |
| 777 | src = mputprintf(src, "%s(%lu, %s_comps)", |
| 778 | litstruct->oid_id.c_str(), (unsigned long) litstruct->nof_elems, |
| 779 | litstruct->oid_id.c_str()); |
| 780 | } |
| 781 | src = mputstr(src, ";\n"); |
| 782 | } |
| 783 | |
| 784 | void Module::generate_functions(output_struct *output) |
| 785 | { |
| 786 | bool tcov_enabled = tcov_file_name && in_tcov_files(get_filename()); |
| 787 | bool has_pre_init_before_tcov = output->functions.pre_init != NULL; |
| 788 | if (tcov_enabled) { |
| 789 | output->functions.pre_init = mputprintf(output->functions.pre_init, |
| 790 | "TTCN_Location_Statistics::init_file_lines(\"%s\", effective_module_lines, sizeof(effective_module_lines) / sizeof(int));\n" \ |
| 791 | "TTCN_Location_Statistics::init_file_functions(\"%s\", effective_module_functions, sizeof(effective_module_functions) / sizeof(char *));\n", |
| 792 | get_tcov_file_name(get_filename()), get_tcov_file_name(get_filename())); |
| 793 | } |
| 794 | // pre_init function |
| 795 | bool has_pre_init = false; |
| 796 | bool profiled = MOD_TTCN == get_moduletype() && is_file_profiled(get_filename()); |
| 797 | // always generate pre_init_module if the file is profiled |
| 798 | if (output->functions.pre_init || profiled) { |
| 799 | output->source.static_function_prototypes = |
| 800 | mputstr(output->source.static_function_prototypes, |
| 801 | "static void pre_init_module();\n"); |
| 802 | output->source.static_function_bodies = mputstr(output->source.static_function_bodies, |
| 803 | "static void pre_init_module()\n" |
| 804 | "{\n"); |
| 805 | if (include_location_info) { |
| 806 | output->source.static_function_bodies = |
| 807 | mputstr(output->source.static_function_bodies, |
| 808 | (tcov_enabled && has_pre_init_before_tcov) ? "TTCN_Location_Statistics current_location(\"" |
| 809 | : "TTCN_Location current_location(\""); |
| 810 | output->source.static_function_bodies = |
| 811 | Code::translate_string(output->source.static_function_bodies, (tcov_enabled && has_pre_init_before_tcov) ? get_tcov_file_name(get_filename()) : get_filename()); |
| 812 | output->source.static_function_bodies = |
| 813 | mputprintf(output->source.static_function_bodies, |
| 814 | (tcov_enabled && has_pre_init_before_tcov) ? "\", 0, TTCN_Location_Statistics::LOCATION_UNKNOWN, \"%s\");\n" |
| 815 | : "\", 0, TTCN_Location::LOCATION_UNKNOWN, \"%s\");\n", get_modid().get_dispname().c_str()); |
| 816 | if (tcov_enabled && has_pre_init_before_tcov) { |
| 817 | effective_module_lines = |
| 818 | mputprintf(effective_module_lines, "%s0", |
| 819 | (effective_module_lines ? ", " : "")); |
| 820 | effective_module_functions = |
| 821 | mputprintf(effective_module_functions, "%s\"%s\"", |
| 822 | (effective_module_functions ? ", " : ""), get_modid().get_dispname().c_str()); |
| 823 | } |
| 824 | if (profiled) { |
| 825 | output->source.static_function_bodies = mputprintf(output->source.static_function_bodies, |
| 826 | "%s::init_ttcn3_profiler();\n" |
| 827 | "TTCN3_Stack_Depth stack_depth;\n" |
| 828 | "ttcn3_prof.execute_line(\"%s\", 0);\n", get_modid().get_name().c_str(), get_filename()); |
| 829 | } |
| 830 | } |
| 831 | output->source.static_function_bodies = |
| 832 | mputstr(output->source.static_function_bodies, output->functions.pre_init); |
| 833 | output->source.static_function_bodies = |
| 834 | mputstr(output->source.static_function_bodies, "}\n\n"); |
| 835 | Free(output->functions.pre_init); |
| 836 | output->functions.pre_init = NULL; |
| 837 | has_pre_init = true; |
| 838 | } |
| 839 | bool has_post_init_before_tcov = output->functions.post_init != NULL; |
| 840 | // post_init function |
| 841 | bool has_post_init = false; |
| 842 | if (output->functions.post_init) { |
| 843 | output->source.static_function_prototypes = mputstr(output->source.static_function_prototypes, |
| 844 | "static void post_init_module();\n"); |
| 845 | output->source.static_function_bodies = mputstr(output->source.static_function_bodies, |
| 846 | "static void post_init_module()\n" |
| 847 | "{\n"); |
| 848 | if (include_location_info) { |
| 849 | output->source.static_function_bodies = |
| 850 | mputstr(output->source.static_function_bodies, |
| 851 | (tcov_enabled && has_post_init_before_tcov) ? "TTCN_Location_Statistics current_location(\"" |
| 852 | : "TTCN_Location current_location(\""); |
| 853 | output->source.static_function_bodies = |
| 854 | Code::translate_string(output->source.static_function_bodies, (tcov_enabled && has_post_init_before_tcov) ? get_tcov_file_name(get_filename()) : get_filename()); |
| 855 | output->source.static_function_bodies = |
| 856 | mputprintf(output->source.static_function_bodies, |
| 857 | (tcov_enabled && has_post_init_before_tcov) ? "\", 0, TTCN_Location_Statistics::LOCATION_UNKNOWN, \"%s\");\n" |
| 858 | : "\", 0, TTCN_Location::LOCATION_UNKNOWN, \"%s\");\n", get_modid().get_dispname().c_str()); |
| 859 | if (tcov_enabled && has_post_init_before_tcov) { |
| 860 | effective_module_lines = |
| 861 | mputprintf(effective_module_lines, "%s0", |
| 862 | (effective_module_lines ? ", " : "")); |
| 863 | effective_module_functions = |
| 864 | mputprintf(effective_module_functions, "%s\"%s\"", |
| 865 | (effective_module_functions ? ", " : ""), get_modid().get_dispname().c_str()); |
| 866 | } |
| 867 | if (MOD_TTCN == get_moduletype() && is_file_profiled(get_filename())) { |
| 868 | output->source.static_function_bodies = mputprintf(output->source.static_function_bodies, |
| 869 | "TTCN3_Stack_Depth stack_depth;\n" |
| 870 | "ttcn3_prof.execute_line(\"%s\", 0);\n", get_filename()); |
| 871 | } |
| 872 | } |
| 873 | output->source.static_function_bodies = |
| 874 | mputstr(output->source.static_function_bodies, output->functions.post_init); |
| 875 | output->source.static_function_bodies = |
| 876 | mputstr(output->source.static_function_bodies, "}\n\n"); |
| 877 | Free(output->functions.post_init); |
| 878 | output->functions.post_init = NULL; |
| 879 | has_post_init = true; |
| 880 | } |
| 881 | // set_param function |
| 882 | bool has_set_param; |
| 883 | if (output->functions.set_param) { |
| 884 | output->source.static_function_prototypes = mputstr(output->source.static_function_prototypes, |
| 885 | "static boolean set_module_param(Module_Param& param);\n"); |
| 886 | output->source.static_function_bodies = mputstr(output->source.static_function_bodies, |
| 887 | "static boolean set_module_param(Module_Param& param)\n" |
| 888 | "{\n" |
| 889 | "const char* const par_name = param.get_id()->get_current_name();\n"); |
| 890 | output->source.static_function_bodies = |
| 891 | mputstr(output->source.static_function_bodies, output->functions.set_param); |
| 892 | output->source.static_function_bodies = |
| 893 | mputstr(output->source.static_function_bodies, "return FALSE;\n" |
| 894 | "}\n\n"); |
| 895 | Free(output->functions.set_param); |
| 896 | output->functions.set_param = NULL; |
| 897 | has_set_param = true; |
| 898 | } else has_set_param = false; |
| 899 | // get_param function |
| 900 | bool has_get_param; |
| 901 | if (output->functions.get_param) { |
| 902 | output->source.static_function_prototypes = mputstr(output->source.static_function_prototypes, |
| 903 | "static Module_Param* get_module_param(Module_Param_Name& param_name);\n"); |
| 904 | output->source.static_function_bodies = mputstr(output->source.static_function_bodies, |
| 905 | "static Module_Param* get_module_param(Module_Param_Name& param_name)\n" |
| 906 | "{\n" |
| 907 | "const char* const par_name = param_name.get_current_name();\n"); |
| 908 | output->source.static_function_bodies = |
| 909 | mputstr(output->source.static_function_bodies, output->functions.get_param); |
| 910 | output->source.static_function_bodies = |
| 911 | mputstr(output->source.static_function_bodies, "return NULL;\n" |
| 912 | "}\n\n"); |
| 913 | Free(output->functions.get_param); |
| 914 | output->functions.get_param = NULL; |
| 915 | has_get_param = true; |
| 916 | } else has_get_param = false; |
| 917 | // log_param function |
| 918 | bool has_log_param; |
| 919 | if (output->functions.log_param) { |
| 920 | output->source.static_function_prototypes = mputstr(output->source.static_function_prototypes, |
| 921 | "static void log_module_param();\n"); |
| 922 | output->source.static_function_bodies = mputstr(output->source.static_function_bodies, |
| 923 | "static void log_module_param()\n" |
| 924 | "{\n"); |
| 925 | output->source.static_function_bodies = |
| 926 | mputstr(output->source.static_function_bodies, output->functions.log_param); |
| 927 | output->source.static_function_bodies = mputstr(output->source.static_function_bodies, |
| 928 | "}\n\n"); |
| 929 | Free(output->functions.log_param); |
| 930 | output->functions.log_param = NULL; |
| 931 | has_log_param = true; |
| 932 | } else has_log_param = false; |
| 933 | // init_comp function |
| 934 | bool has_init_comp; |
| 935 | if (output->functions.init_comp) { |
| 936 | output->source.static_function_prototypes = |
| 937 | mputstr(output->source.static_function_prototypes, |
| 938 | "static boolean init_comp_type(" |
| 939 | "const char *component_type, boolean init_base_comps);\n"); |
| 940 | output->source.static_function_bodies = |
| 941 | mputstr(output->source.static_function_bodies, |
| 942 | "static boolean init_comp_type(const char *component_type, " |
| 943 | "boolean init_base_comps)\n" |
| 944 | "{\n(void)init_base_comps;\n"); |
| 945 | output->source.static_function_bodies = |
| 946 | mputstr(output->source.static_function_bodies, |
| 947 | output->functions.init_comp); |
| 948 | output->source.static_function_bodies = |
| 949 | mputstr(output->source.static_function_bodies, "return FALSE;\n" |
| 950 | "}\n\n"); |
| 951 | Free(output->functions.init_comp); |
| 952 | output->functions.init_comp = NULL; |
| 953 | has_init_comp = true; |
| 954 | } else has_init_comp = false; |
| 955 | // start function |
| 956 | bool has_start; |
| 957 | if (output->functions.start) { |
| 958 | output->source.static_function_prototypes = mputstr(output->source.static_function_prototypes, |
| 959 | "static boolean start_ptc_function(const char *function_name, " |
| 960 | "Text_Buf& function_arguments);\n"); |
| 961 | output->source.static_function_bodies = mputstr(output->source.static_function_bodies, |
| 962 | "static boolean start_ptc_function(const char *function_name, " |
| 963 | "Text_Buf& function_arguments)\n" |
| 964 | "{\n"); |
| 965 | output->source.static_function_bodies = |
| 966 | mputstr(output->source.static_function_bodies, output->functions.start); |
| 967 | output->source.static_function_bodies = |
| 968 | mputstr(output->source.static_function_bodies, "return FALSE;\n" |
| 969 | "}\n\n"); |
| 970 | Free(output->functions.start); |
| 971 | output->functions.start = NULL; |
| 972 | has_start = true; |
| 973 | } else has_start = false; |
| 974 | // control part |
| 975 | bool has_control; |
| 976 | if (output->functions.control) { |
| 977 | output->source.static_function_prototypes = mputstr(output->source.static_function_prototypes, |
| 978 | "static void module_control_part();\n"); |
| 979 | output->source.static_function_bodies = mputstr(output->source.static_function_bodies, |
| 980 | "static void module_control_part()\n" |
| 981 | "{\n"); |
| 982 | output->source.static_function_bodies = |
| 983 | mputstr(output->source.static_function_bodies, output->functions.control); |
| 984 | output->source.static_function_bodies = |
| 985 | mputstr(output->source.static_function_bodies, "}\n\n"); |
| 986 | Free(output->functions.control); |
| 987 | output->functions.control = NULL; |
| 988 | has_control = true; |
| 989 | } else has_control = false; |
| 990 | // module checksum |
| 991 | if (has_checksum) { |
| 992 | output->source.string_literals = mputstr(output->source.string_literals, |
| 993 | "static const unsigned char module_checksum[] = {"); |
| 994 | for (size_t i = 0; i < sizeof(module_checksum); i++) { |
| 995 | if (i > 0) output->source.string_literals = |
| 996 | mputc(output->source.string_literals, ','); |
| 997 | output->source.string_literals = |
| 998 | mputprintf(output->source.string_literals, " 0x%02x", |
| 999 | module_checksum[i]); |
| 1000 | } |
| 1001 | output->source.string_literals = mputstr(output->source.string_literals, |
| 1002 | " };\n"); |
| 1003 | } |
| 1004 | const char *module_name = modid->get_name().c_str(); |
| 1005 | |
| 1006 | // XML namespaces. Written in the order they are stored: |
| 1007 | // sorted ASCIIbetically by the prefix. |
| 1008 | // Not all namespaces are used by every module. Unfortunately, the array |
| 1009 | // (which has the same size in all modules) cannot be compacted, because |
| 1010 | // the indexes have already been used when the XER descriptors were written. |
| 1011 | // All we can do is store NULLs for the unused namespaces. |
| 1012 | size_t num_xml_namespaces = namespaces.size(); |
| 1013 | if (moduletype == MOD_TTCN) { //TODO remove this when ASN.1 gets EXER |
| 1014 | output->source.global_vars = mputprintf(output->source.global_vars, |
| 1015 | #ifndef NDEBUG |
| 1016 | "// written by %s in " __FILE__ " at %d\n" |
| 1017 | #endif |
| 1018 | "static const size_t num_namespaces = %lu;\n" |
| 1019 | #ifndef NDEBUG |
| 1020 | , __FUNCTION__, __LINE__ |
| 1021 | #endif |
| 1022 | , (unsigned long)num_xml_namespaces |
| 1023 | ); |
| 1024 | if (num_xml_namespaces != 0 || (control_ns && control_ns_prefix)) { |
| 1025 | output->source.global_vars = mputstr(output->source.global_vars, |
| 1026 | "static const namespace_t xml_namespaces[num_namespaces+1] = {\n"); |
| 1027 | for (size_t i=0; i < namespaces.size(); ++i) { |
| 1028 | if (used_namespaces.has_key(i)) { |
| 1029 | output->source.global_vars = mputprintf(output->source.global_vars, |
| 1030 | " { \"%s\", \"%s\" },\n", // ns, then prefix |
| 1031 | namespaces.get_nth_elem(i), namespaces.get_nth_key(i).c_str()); |
| 1032 | } |
| 1033 | else { |
| 1034 | output->source.global_vars = mputstr(output->source.global_vars, |
| 1035 | " { NULL, NULL },\n"); // not used in this module |
| 1036 | } |
| 1037 | } // next namespace |
| 1038 | output->source.global_vars = mputprintf(output->source.global_vars, |
| 1039 | " { \"%s\", \"%s\" }\n};\n\n", |
| 1040 | (control_ns ? control_ns : ""), |
| 1041 | (control_ns_prefix ? control_ns_prefix : "")); |
| 1042 | } // if there are namespaces |
| 1043 | } // if TTCN |
| 1044 | |
| 1045 | |
| 1046 | // module object |
| 1047 | output->header.global_vars = mputprintf(output->header.global_vars, |
| 1048 | "extern TTCN_Module %s;\n", |
| 1049 | "module_object"); |
| 1050 | |
| 1051 | output->source.global_vars = mputprintf(output->source.global_vars, |
| 1052 | "TTCN_Module %s(\"%s\", __DATE__, __TIME__, %s, %s", |
| 1053 | "module_object", |
| 1054 | |
| 1055 | modid->get_dispname().c_str(), |
| 1056 | (has_checksum ? "module_checksum" : "NULL"), |
| 1057 | has_pre_init ? "pre_init_module" : "NULL"); |
| 1058 | |
| 1059 | if (moduletype == MOD_TTCN) { |
| 1060 | // TTCN-3 specific function pointers |
| 1061 | if (product_number == NULL) { |
| 1062 | output->source.global_vars = mputstr(output->source.global_vars, ", NULL"); |
| 1063 | } else { |
| 1064 | output->source.global_vars = mputprintf(output->source.global_vars, ", \"%s\"", product_number); |
| 1065 | } |
| 1066 | string extra_str = extra ? ( string('"') + extra + string('"') ) : string("NULL"); |
| 1067 | output->source.global_vars = mputprintf(output->source.global_vars, |
| 1068 | ", %uU, %uU, %uU, %uU, %s, %luLU, %s, %s, %s, %s, %s, %s, %s, %s", |
| 1069 | suffix, release, patch, build, extra_str.c_str(), |
| 1070 | (unsigned long)num_xml_namespaces, |
| 1071 | ((num_xml_namespaces || (control_ns && control_ns_prefix)) ? "xml_namespaces" : "0"), |
| 1072 | has_post_init ? "post_init_module" : "NULL", |
| 1073 | has_set_param ? "set_module_param" : "NULL", |
| 1074 | has_get_param ? "get_module_param" : "NULL", |
| 1075 | has_log_param ? "log_module_param" : "NULL", |
| 1076 | has_init_comp ? "init_comp_type" : "NULL", |
| 1077 | has_start ? "start_ptc_function" : "NULL", |
| 1078 | has_control ? "module_control_part" : "NULL"); |
| 1079 | } else { |
| 1080 | // self checks for ASN.1 modules |
| 1081 | if (has_post_init) |
| 1082 | FATAL_ERROR("Module::generate_functions(): post_init function in ASN.1 module"); |
| 1083 | if (has_set_param) |
| 1084 | FATAL_ERROR("Module::generate_functions(): set_param function in ASN.1 module"); |
| 1085 | if (has_get_param) |
| 1086 | FATAL_ERROR("Module::generate_functions(): get_param function in ASN.1 module"); |
| 1087 | if (has_log_param) |
| 1088 | FATAL_ERROR("Module::generate_functions(): log_param function in ASN.1 module"); |
| 1089 | if (has_init_comp) |
| 1090 | FATAL_ERROR("Module::generate_functions(): init_comp function in ASN.1 module"); |
| 1091 | if (has_start) |
| 1092 | FATAL_ERROR("Module::generate_functions(): startable function in ASN.1 module"); |
| 1093 | if (has_control) |
| 1094 | FATAL_ERROR("Module::generate_functions(): control part in ASN.1 module"); |
| 1095 | } |
| 1096 | output->source.global_vars = mputstr(output->source.global_vars, ");\n"); |
| 1097 | // #include into the source file |
| 1098 | output->source.includes = mputprintf(output->source.includes, |
| 1099 | "#include \"%s.hh\"\n", |
| 1100 | duplicate_underscores ? module_name : modid->get_ttcnname().c_str()); |
| 1101 | |
| 1102 | output->source.global_vars = mputprintf(output->source.global_vars, |
| 1103 | "\nstatic const RuntimeVersionChecker ver_checker(" |
| 1104 | " current_runtime_version.requires_major_version_%d,\n" |
| 1105 | " current_runtime_version.requires_minor_version_%d,\n" |
| 1106 | " current_runtime_version.requires_patch_level_%d," |
| 1107 | " current_runtime_version.requires_runtime_%d);\n", |
| 1108 | TTCN3_MAJOR, TTCN3_MINOR, TTCN3_PATCHLEVEL, use_runtime_2 ? 2 : 1 |
| 1109 | ); |
| 1110 | if (tcov_enabled) { |
| 1111 | output->source.global_vars = mputprintf(output->source.global_vars, |
| 1112 | "\nstatic const int effective_module_lines[] = { %s };\n" \ |
| 1113 | "static const char *effective_module_functions[] = { %s };\n", |
| 1114 | effective_module_lines ? static_cast<const char *>(effective_module_lines) : "", |
| 1115 | effective_module_functions ? static_cast<const char *>(effective_module_functions) : ""); |
| 1116 | } |
| 1117 | } |
| 1118 | |
| 1119 | void Module::generate_conversion_functions(output_struct *output) |
| 1120 | { |
| 1121 | for (size_t i = 0; i < type_conv_v.size(); i++) |
| 1122 | type_conv_v[i] |
| 1123 | ->gen_conv_func(&output->source.static_conversion_function_prototypes, |
| 1124 | &output->source.static_conversion_function_bodies, |
| 1125 | this); |
| 1126 | } |
| 1127 | |
| 1128 | string Module::add_literal(map<string, string>& literals, const string& str, |
| 1129 | const char *prefix) |
| 1130 | { |
| 1131 | if (literals.has_key(str)) return *literals[str]; |
| 1132 | else { |
| 1133 | string *literal = new string(prefix+Int2string(literals.size())); |
| 1134 | literals.add(str, literal); |
| 1135 | return *literal; |
| 1136 | } |
| 1137 | } |
| 1138 | |
| 1139 | void Module::clear_literals(map<string, string>& literals) |
| 1140 | { |
| 1141 | for (size_t i = 0; i < literals.size(); i++) |
| 1142 | delete literals.get_nth_elem(i); |
| 1143 | literals.clear(); |
| 1144 | } |
| 1145 | |
| 1146 | map<string, const char> Module::namespaces; |
| 1147 | map<string, const char> Module::invented_prefixes; |
| 1148 | size_t Module::default_namespace_attempt = 0; |
| 1149 | size_t Module::replacement_for_empty_prefix = (size_t)-1; |
| 1150 | |
| 1151 | Module::Module(moduletype_t p_mt, Identifier *p_modid) |
| 1152 | : Scope(), moduletype(p_mt), modid(p_modid), |
| 1153 | imp_checked(false), gen_code(false), has_checksum(false), |
| 1154 | visible_mods(), module_checksum(), |
| 1155 | bs_literals(), bp_literals(), hs_literals(), hp_literals(), os_literals(), |
| 1156 | op_literals(), cs_literals(), us_literals(), pp_literals(), mp_literals(), |
| 1157 | oid_literals(), tmp_id_count(0), |
| 1158 | control_ns(p_mt == MOD_ASN ? mcopystr("urn:oid:2.1.5.2.0.1") : NULL), |
| 1159 | control_ns_prefix(p_mt == MOD_ASN ? mcopystr("asn1") : NULL), |
| 1160 | // only ASN.1 modules have default control namespace (X.693 amd1, 16.9) |
| 1161 | used_namespaces(), type_conv_v(), product_number(NULL), |
| 1162 | suffix(0), release(UINT_MAX), patch(UINT_MAX), build(UINT_MAX), extra(NULL) |
| 1163 | { |
| 1164 | if(!p_modid) |
| 1165 | FATAL_ERROR("NULL parameter: Common::Module::Module()"); |
| 1166 | memset(module_checksum, 0, sizeof(module_checksum)); |
| 1167 | set_scopeMacro_name(modid->get_dispname()); |
| 1168 | } |
| 1169 | |
| 1170 | Module::~Module() |
| 1171 | { |
| 1172 | delete modid; |
| 1173 | visible_mods.clear(); |
| 1174 | clear_literals(bs_literals); |
| 1175 | clear_literals(bp_literals); |
| 1176 | clear_literals(hs_literals); |
| 1177 | clear_literals(hp_literals); |
| 1178 | clear_literals(os_literals); |
| 1179 | clear_literals(op_literals); |
| 1180 | clear_literals(cs_literals); |
| 1181 | clear_literals(pp_literals); |
| 1182 | clear_literals(mp_literals); |
| 1183 | for (size_t i = 0; i < us_literals.size(); i++) |
| 1184 | delete us_literals.get_nth_elem(i); |
| 1185 | us_literals.clear(); |
| 1186 | for (size_t i = 0; i < oid_literals.size(); i++) |
| 1187 | delete oid_literals.get_nth_elem(i); |
| 1188 | oid_literals.clear(); |
| 1189 | for (size_t i = 0; i < type_conv_v.size(); i++) |
| 1190 | delete type_conv_v[i]; |
| 1191 | type_conv_v.clear(); |
| 1192 | Free(control_ns); |
| 1193 | Free(control_ns_prefix); |
| 1194 | used_namespaces.clear(); // all the values are NULL, no need to free |
| 1195 | // static members below; repeated clear()s are redundant but harmless |
| 1196 | namespaces.clear(); |
| 1197 | invented_prefixes.clear(); |
| 1198 | Free(product_number); |
| 1199 | Free(extra); |
| 1200 | } |
| 1201 | |
| 1202 | Type *Module::get_address_type() |
| 1203 | { |
| 1204 | FATAL_ERROR("Common::Module::get_address_type()"); |
| 1205 | return 0; |
| 1206 | } |
| 1207 | |
| 1208 | string Module::add_ustring_literal(const ustring& ustr) |
| 1209 | { |
| 1210 | if (us_literals.has_key(ustr)) return *us_literals[ustr]; |
| 1211 | else { |
| 1212 | string *literal = new string("us_" + Int2string(us_literals.size())); |
| 1213 | us_literals.add(ustr, literal); |
| 1214 | return *literal; |
| 1215 | } |
| 1216 | } |
| 1217 | |
| 1218 | string Module::add_objid_literal(const string& oi_str, const size_t nof_elems) |
| 1219 | { |
| 1220 | if(oid_literals.has_key(oi_str)) return oid_literals[oi_str]->oid_id; |
| 1221 | else { |
| 1222 | OID_literal *oi_struct = new OID_literal; |
| 1223 | oi_struct->nof_elems = nof_elems; |
| 1224 | oi_struct->oid_id = "oi_" + Int2string(oid_literals.size()); |
| 1225 | oid_literals.add(oi_str, oi_struct); |
| 1226 | return oi_struct->oid_id; |
| 1227 | } |
| 1228 | } |
| 1229 | |
| 1230 | void Module::add_type_conv(TypeConv *p_conv) |
| 1231 | { |
| 1232 | if (p_conv == NULL) FATAL_ERROR("Module::add_type_conv()"); |
| 1233 | Type *p_from_type = p_conv->get_from_type(); |
| 1234 | Type *p_to_type = p_conv->get_to_type(); |
| 1235 | if (!p_from_type->is_structured_type() |
| 1236 | || !p_to_type->is_structured_type()) |
| 1237 | FATAL_ERROR("Module::add_type_conv()"); |
| 1238 | if (p_from_type == p_to_type) { |
| 1239 | // Never add the same types. |
| 1240 | delete p_conv; |
| 1241 | return; |
| 1242 | } |
| 1243 | for (size_t i = 0; i < type_conv_v.size(); i++) { |
| 1244 | TypeConv *conv = type_conv_v[i]; |
| 1245 | if (conv->get_from_type() == p_from_type |
| 1246 | && conv->get_to_type() == p_to_type |
| 1247 | && conv->is_temp() == p_conv->is_temp()) { |
| 1248 | // Same pair of types, both for values or templates. We're the |
| 1249 | // owners, deallocate. |
| 1250 | delete p_conv; |
| 1251 | return; |
| 1252 | } |
| 1253 | } |
| 1254 | type_conv_v.add(p_conv); |
| 1255 | } |
| 1256 | |
| 1257 | bool Module::needs_type_conv(Type *p_from_type, Type *p_to_type) const |
| 1258 | { |
| 1259 | for (size_t i = 0; i < type_conv_v.size(); i++) { |
| 1260 | TypeConv *conv = type_conv_v[i]; |
| 1261 | if (conv->get_from_type() == p_from_type |
| 1262 | && conv->get_to_type() == p_to_type) |
| 1263 | return true; |
| 1264 | } |
| 1265 | return false; |
| 1266 | } |
| 1267 | |
| 1268 | void Module::chk_recursive(module_set_t& checked_modules) |
| 1269 | { |
| 1270 | if (checked_modules.has_key(this)) return; |
| 1271 | // this must be added to the set at the beginning |
| 1272 | // in order to deal with circular imports |
| 1273 | checked_modules.add(this, 0); |
| 1274 | // check the imported modules first |
| 1275 | size_t nof_visible_mods = visible_mods.size(); |
| 1276 | for (size_t i = 0; i < nof_visible_mods; i++) { |
| 1277 | Module *m = visible_mods.get_nth_key(i); |
| 1278 | if (m != this) m->chk_recursive(checked_modules); |
| 1279 | } |
| 1280 | // then check the module itself |
| 1281 | chk(); // this is the only virtual call |
| 1282 | } |
| 1283 | |
| 1284 | bool Module::is_visible(Module *m) |
| 1285 | { |
| 1286 | collect_visible_mods(); |
| 1287 | return visible_mods.has_key(m); |
| 1288 | } |
| 1289 | |
| 1290 | void Module::get_visible_mods(module_set_t& p_visible_mods) |
| 1291 | { |
| 1292 | if (visible_mods.has_key(this)) { |
| 1293 | size_t nof_visible_mods = visible_mods.size(); |
| 1294 | for (size_t i = 0; i < nof_visible_mods; i++) { |
| 1295 | Module *m = visible_mods.get_nth_key(i); |
| 1296 | if (!p_visible_mods.has_key(m)) p_visible_mods.add(m, 0); |
| 1297 | } |
| 1298 | } else { |
| 1299 | get_imported_mods(p_visible_mods); |
| 1300 | } |
| 1301 | } |
| 1302 | |
| 1303 | void Module::write_checksum() |
| 1304 | { |
| 1305 | fprintf(stderr, "%-18s ", modid->get_dispname().c_str()); |
| 1306 | switch (moduletype) { |
| 1307 | case MOD_TTCN: fprintf(stderr, "%-15s ", "TTCN-3"); break; |
| 1308 | case MOD_ASN: fprintf(stderr, "%-15s ", "ASN.1"); break; |
| 1309 | case MOD_UNKNOWN: fprintf(stderr, "%-15s ", "OTHER"); break; |
| 1310 | } |
| 1311 | |
| 1312 | if (!has_checksum) { |
| 1313 | fputc('\n', stderr); |
| 1314 | return; |
| 1315 | } |
| 1316 | |
| 1317 | size_t nof_checksum = sizeof(module_checksum); |
| 1318 | for (size_t i = 0; i < nof_checksum; i++) { |
| 1319 | fprintf(stderr, "%02x", module_checksum[i]); |
| 1320 | } |
| 1321 | |
| 1322 | if (release <= 999999 && patch < 30 && build < 100) { |
| 1323 | char *product_identifier = |
| 1324 | get_product_identifier(product_number, suffix, release, patch, build, extra); |
| 1325 | fprintf(stderr, " %s", product_identifier); |
| 1326 | Free(product_identifier); |
| 1327 | } |
| 1328 | |
| 1329 | fputc('\n', stderr); |
| 1330 | } |
| 1331 | |
| 1332 | char* Module::get_product_identifier(const char* product_number, |
| 1333 | const unsigned int suffix, unsigned int release, unsigned int patch, |
| 1334 | unsigned int build, const char* extra) |
| 1335 | { |
| 1336 | expstring_t ret_val = memptystr(); |
| 1337 | if ( product_number == NULL |
| 1338 | && suffix == UINT_MAX |
| 1339 | && release == UINT_MAX |
| 1340 | && patch == UINT_MAX |
| 1341 | && build == UINT_MAX) { |
| 1342 | ret_val = mputstr(ret_val, "<RnXnn>"); |
| 1343 | return ret_val; |
| 1344 | } |
| 1345 | if (product_number != NULL) { |
| 1346 | ret_val = mputstr(ret_val, product_number); |
| 1347 | if (suffix != 0) { |
| 1348 | ret_val = mputprintf(ret_val, "/%d", suffix); |
| 1349 | } |
| 1350 | ret_val = mputc(ret_val, ' '); |
| 1351 | } |
| 1352 | |
| 1353 | char* build_str = buildstr(build); |
| 1354 | ret_val = mputprintf(ret_val, "R%u%c%s%s", release, eri(patch), build_str, extra ? extra : ""); |
| 1355 | Free(build_str); |
| 1356 | return ret_val; |
| 1357 | } |
| 1358 | |
| 1359 | void Module::collect_visible_mods() |
| 1360 | { |
| 1361 | if (!visible_mods.has_key(this)) { |
| 1362 | get_imported_mods(visible_mods); |
| 1363 | if (!visible_mods.has_key(this)) visible_mods.add(this, 0); |
| 1364 | } |
| 1365 | } |
| 1366 | |
| 1367 | void Module::set_checksum(size_t checksum_len, |
| 1368 | const unsigned char* checksum_ptr) |
| 1369 | { |
| 1370 | if (checksum_len != sizeof(module_checksum)) |
| 1371 | FATAL_ERROR("Module::set_checksum(): invalid length"); |
| 1372 | memcpy(module_checksum, checksum_ptr, sizeof(module_checksum)); |
| 1373 | has_checksum = true; |
| 1374 | } |
| 1375 | |
| 1376 | void Module::set_controlns(char *ns, char *prefix) |
| 1377 | { |
| 1378 | Free(control_ns); |
| 1379 | control_ns = ns; |
| 1380 | Free(control_ns_prefix); |
| 1381 | control_ns_prefix = prefix; |
| 1382 | } |
| 1383 | |
| 1384 | void Module::get_controlns(const char *&ns, const char *&prefix) |
| 1385 | { |
| 1386 | ns = control_ns; |
| 1387 | prefix = control_ns_prefix; |
| 1388 | } |
| 1389 | |
| 1390 | const size_t max_invented_prefixes = 10000; |
| 1391 | void Module::add_namespace(const char *new_uri, char *&new_prefix) |
| 1392 | { |
| 1393 | const bool prefix_is_empty = new_prefix && !*new_prefix; |
| 1394 | const string key(new_prefix ? new_prefix : ""); |
| 1395 | if (new_prefix && !namespaces.has_key(key)) { |
| 1396 | namespaces.add(key, new_uri); |
| 1397 | if (*new_prefix == 0) { // first add of default namespace |
| 1398 | ++default_namespace_attempt; |
| 1399 | } |
| 1400 | return; // newly added |
| 1401 | } |
| 1402 | else { // prefix already present (or we are required to invent one) |
| 1403 | if (new_prefix) { |
| 1404 | const char *uri_value = namespaces[key]; |
| 1405 | if (!strcmp(uri_value, new_uri)) return; // same URI, same prefix: no-op |
| 1406 | } |
| 1407 | |
| 1408 | // prefix already present but different URI, |
| 1409 | // or prefix is NULL (which means we must invent a prefix) |
| 1410 | |
| 1411 | if (new_prefix && *new_prefix) { |
| 1412 | Free(new_prefix); // prefix is not empty, discard it and start fresh |
| 1413 | new_prefix = memptystr(); |
| 1414 | } |
| 1415 | |
| 1416 | const string uri_key(new_uri); |
| 1417 | if (invented_prefixes.has_key(uri_key)) { |
| 1418 | // we already made one up for this URI |
| 1419 | new_prefix = mputstr(new_prefix, invented_prefixes[uri_key]); |
| 1420 | return; // already there |
| 1421 | } |
| 1422 | else { |
| 1423 | // make one up on the spot |
| 1424 | size_t iidx = invented_prefixes.size(); // "invented index" |
| 1425 | new_prefix = mputprintf(new_prefix, "tq%04lu", (unsigned long)iidx++); |
| 1426 | string made_up_prefix(new_prefix); |
| 1427 | for (; iidx < max_invented_prefixes; ++iidx) { |
| 1428 | if (namespaces.has_key(made_up_prefix)) { |
| 1429 | // Some pervert wrote an XSD with a namespace prefix like tq0007! |
| 1430 | // Make up another one in the same memory spot. |
| 1431 | sprintf(new_prefix, "tq%04lu", (unsigned long)iidx); |
| 1432 | made_up_prefix = new_prefix; |
| 1433 | } |
| 1434 | else break; |
| 1435 | } |
| 1436 | |
| 1437 | if (iidx >= max_invented_prefixes) { |
| 1438 | Location loc; // no particular location |
| 1439 | loc.error("Internal limit: too many assigned prefixes"); |
| 1440 | return; // not added |
| 1441 | } |
| 1442 | invented_prefixes.add(uri_key, new_prefix); |
| 1443 | namespaces.add(made_up_prefix, new_uri); |
| 1444 | |
| 1445 | // Search for the newly added prefix and remember it. |
| 1446 | replacement_for_empty_prefix = namespaces.find_key(made_up_prefix); |
| 1447 | |
| 1448 | if (prefix_is_empty) { |
| 1449 | ++default_namespace_attempt; |
| 1450 | } |
| 1451 | return; // newly added |
| 1452 | } |
| 1453 | } // if (present) |
| 1454 | } |
| 1455 | |
| 1456 | static const string empty_prefix; |
| 1457 | void Module::rename_default_namespace() |
| 1458 | { |
| 1459 | if (default_namespace_attempt < 2) return; |
| 1460 | // There was more than one default namespace. However, all but the first |
| 1461 | // are already renamed to tq%d. |
| 1462 | size_t di = namespaces.find_key(empty_prefix); // keys are prefixes |
| 1463 | if (di < namespaces.size()) { // found it |
| 1464 | const char *last_remaining_def_namespace = namespaces.get_nth_elem(di); |
| 1465 | // we can't change a key, we can only remove and re-add it |
| 1466 | namespaces.erase(empty_prefix); |
| 1467 | |
| 1468 | expstring_t empty_prefix_string = NULL; // force a made-up prefix |
| 1469 | add_namespace(last_remaining_def_namespace, empty_prefix_string); |
| 1470 | Free(empty_prefix_string); |
| 1471 | } |
| 1472 | else FATAL_ERROR("Module::rename_default_namespace"); |
| 1473 | } |
| 1474 | |
| 1475 | size_t Module::get_ns_index(const char *prefix) |
| 1476 | { |
| 1477 | size_t idx = namespaces.find_key(string(prefix)); |
| 1478 | if (idx >= namespaces.size()) { // not found |
| 1479 | // If the the caller asked for the empty prefix and it wasn't found |
| 1480 | // because it has been replaced, use the replacement. |
| 1481 | if (*prefix == '\0' && replacement_for_empty_prefix != (size_t)-1) { |
| 1482 | idx = replacement_for_empty_prefix; |
| 1483 | } |
| 1484 | else FATAL_ERROR("Module::get_ns_index()"); |
| 1485 | } |
| 1486 | |
| 1487 | // Remember that the index is used by this module |
| 1488 | if (!used_namespaces.has_key(idx)) { |
| 1489 | used_namespaces.add(idx, NULL); |
| 1490 | } |
| 1491 | return idx; |
| 1492 | } |
| 1493 | |
| 1494 | string Module::get_temporary_id() |
| 1495 | { |
| 1496 | static const string tmp_prefix("tmp_"); |
| 1497 | return tmp_prefix + Int2string(tmp_id_count++); |
| 1498 | } |
| 1499 | |
| 1500 | void Module::generate_code(CodeGenHelper& cgh) |
| 1501 | { |
| 1502 | if (!gen_code) { |
| 1503 | nof_notupdated_files += 2; |
| 1504 | DEBUG(1, "Code not generated for module `%s'.", |
| 1505 | modid->get_dispname().c_str()); |
| 1506 | return; |
| 1507 | } |
| 1508 | DEBUG(1, "Generating code for module `%s'.", |
| 1509 | modid->get_dispname().c_str()); |
| 1510 | |
| 1511 | // TODO: Always assume to have circular imports until |
| 1512 | // full program optimization is available, |
| 1513 | // this increases the size of the generated code, |
| 1514 | // but otherwise it is possible to create uncompilable code: |
| 1515 | // 1) let the project of module A and B refer to each other, |
| 1516 | // 2) A refers B, and compile A |
| 1517 | // 3) edit B to refer to A and compile it ... |
| 1518 | // As the code for A can not be rewritten the code will not compile |
| 1519 | cgh.add_module(modid->get_name(), modid->get_ttcnname(), |
| 1520 | moduletype == MOD_TTCN, true); |
| 1521 | cgh.set_current_module(modid->get_ttcnname()); |
| 1522 | |
| 1523 | // language specific parts (definitions, imports, etc.) |
| 1524 | //generate_code_internal(&target); <- needed to pass cgh |
| 1525 | generate_code_internal(cgh); |
| 1526 | |
| 1527 | output_struct* output = cgh.get_current_outputstruct(); |
| 1528 | |
| 1529 | // string literals |
| 1530 | generate_literals(output); |
| 1531 | // module level entry points |
| 1532 | generate_functions(output); |
| 1533 | // type conversion functions for type compatibility |
| 1534 | generate_conversion_functions(output); |
| 1535 | |
| 1536 | /* generate the initializer function for the TTCN-3 profiler |
| 1537 | * (this is done at the end of the code generation, to make sure all code |
| 1538 | * lines have been added to the profiler database) */ |
| 1539 | if (is_file_profiled(get_filename())) { |
| 1540 | output->source.global_vars = mputstr(output->source.global_vars, |
| 1541 | "\n/* Initializing TTCN-3 profiler */\n" |
| 1542 | "void init_ttcn3_profiler()\n" |
| 1543 | "{\n"); |
| 1544 | char* function_name = 0; |
| 1545 | int line_no = -1; |
| 1546 | while(get_profiler_code_line(get_filename(), &function_name, &line_no)) { |
| 1547 | output->source.global_vars = mputprintf(output->source.global_vars, |
| 1548 | " ttcn3_prof.create_line(ttcn3_prof.get_element(\"%s\"), %d);\n", |
| 1549 | get_filename(), line_no); |
| 1550 | if (0 != function_name) { |
| 1551 | output->source.global_vars = mputprintf(output->source.global_vars, |
| 1552 | " ttcn3_prof.create_function(ttcn3_prof.get_element(\"%s\"), %d, \"%s\");\n", |
| 1553 | get_filename(), line_no, function_name); |
| 1554 | } |
| 1555 | } |
| 1556 | output->source.global_vars = mputstr(output->source.global_vars, "}\n\n"); |
| 1557 | } |
| 1558 | } |
| 1559 | |
| 1560 | void Module::dump(unsigned level) const |
| 1561 | { |
| 1562 | DEBUG(level, "Module: %s", get_modid().get_dispname().c_str()); |
| 1563 | } |
| 1564 | |
| 1565 | // ================================= |
| 1566 | // ===== Assignments |
| 1567 | // ================================= |
| 1568 | |
| 1569 | Assignments *Assignments::get_scope_asss() |
| 1570 | { |
| 1571 | return this; |
| 1572 | } |
| 1573 | |
| 1574 | Assignment *Assignments::get_ass_bySRef(Ref_simple *p_ref) |
| 1575 | { |
| 1576 | if (!p_ref || !parent_scope) |
| 1577 | FATAL_ERROR("NULL parameter: Common::Assignments::get_ass_bySRef()"); |
| 1578 | if (!p_ref->get_modid()) { |
| 1579 | const Identifier *id = p_ref->get_id(); |
| 1580 | if (id && has_local_ass_withId(*id)) return get_local_ass_byId(*id); |
| 1581 | } |
| 1582 | return parent_scope->get_ass_bySRef(p_ref); |
| 1583 | } |
| 1584 | |
| 1585 | bool Assignments::has_ass_withId(const Identifier& p_id) |
| 1586 | { |
| 1587 | if (has_local_ass_withId(p_id)) return true; |
| 1588 | else if (parent_scope) return parent_scope->has_ass_withId(p_id); |
| 1589 | else return false; |
| 1590 | } |
| 1591 | |
| 1592 | // ================================= |
| 1593 | // ===== Assignment |
| 1594 | // ================================= |
| 1595 | |
| 1596 | Assignment::Assignment(asstype_t p_asstype, Identifier *p_id) |
| 1597 | : asstype(p_asstype), id(p_id), my_scope(0), checked(false), |
| 1598 | visibilitytype(PUBLIC) |
| 1599 | { |
| 1600 | if (!id) FATAL_ERROR("Assignment::Assignment(): NULL parameter"); |
| 1601 | } |
| 1602 | |
| 1603 | Assignment::Assignment(const Assignment& p) |
| 1604 | : Node(p), Location(p), asstype(p.asstype), id(p.id->clone()), my_scope(0), |
| 1605 | checked(false), visibilitytype(p.visibilitytype) |
| 1606 | { |
| 1607 | |
| 1608 | } |
| 1609 | |
| 1610 | Assignment::~Assignment() |
| 1611 | { |
| 1612 | delete id; |
| 1613 | } |
| 1614 | |
| 1615 | Assignment::asstype_t Assignment::get_asstype() const |
| 1616 | { |
| 1617 | return asstype; |
| 1618 | } |
| 1619 | |
| 1620 | const char *Assignment::get_assname() const |
| 1621 | { |
| 1622 | switch (get_asstype()) { |
| 1623 | case A_TYPE: |
| 1624 | return "type"; |
| 1625 | case A_CONST: |
| 1626 | if (my_scope && my_scope->get_scope_mod()->get_moduletype() == |
| 1627 | Module::MOD_ASN) return "value"; |
| 1628 | else return "constant"; |
| 1629 | case A_ERROR: |
| 1630 | return "erroneous assignment"; |
| 1631 | case A_OC: |
| 1632 | return "information object class"; |
| 1633 | case A_OBJECT: |
| 1634 | return "information object"; |
| 1635 | case A_OS: |
| 1636 | return "information object set"; |
| 1637 | case A_VS: |
| 1638 | return "value set"; |
| 1639 | case A_EXT_CONST: |
| 1640 | return "external constant"; |
| 1641 | case A_MODULEPAR: |
| 1642 | return "module parameter"; |
| 1643 | case A_MODULEPAR_TEMP: |
| 1644 | return "template module parameter"; |
| 1645 | case A_TEMPLATE: |
| 1646 | return "template"; |
| 1647 | case A_VAR: |
| 1648 | return "variable"; |
| 1649 | case A_VAR_TEMPLATE: |
| 1650 | return "template variable"; |
| 1651 | case A_TIMER: |
| 1652 | return "timer"; |
| 1653 | case A_PORT: |
| 1654 | return "port"; |
| 1655 | case A_FUNCTION: |
| 1656 | case A_FUNCTION_RVAL: |
| 1657 | case A_FUNCTION_RTEMP: |
| 1658 | return "function"; |
| 1659 | case A_EXT_FUNCTION: |
| 1660 | case A_EXT_FUNCTION_RVAL: |
| 1661 | case A_EXT_FUNCTION_RTEMP: |
| 1662 | return "external function"; |
| 1663 | case A_ALTSTEP: |
| 1664 | return "altstep"; |
| 1665 | case A_TESTCASE: |
| 1666 | return "testcase"; |
| 1667 | case A_PAR_VAL: |
| 1668 | case A_PAR_VAL_IN: |
| 1669 | return "value parameter"; |
| 1670 | case A_PAR_VAL_OUT: |
| 1671 | return "`out' value parameter"; |
| 1672 | case A_PAR_VAL_INOUT: |
| 1673 | return "`inout' value parameter"; |
| 1674 | case A_PAR_TEMPL_IN: |
| 1675 | return "template parameter"; |
| 1676 | case A_PAR_TEMPL_OUT: |
| 1677 | return "`out' template parameter"; |
| 1678 | case A_PAR_TEMPL_INOUT: |
| 1679 | return "`inout' template parameter"; |
| 1680 | case A_PAR_TIMER: |
| 1681 | return "timer parameter"; |
| 1682 | case A_PAR_PORT: |
| 1683 | return "port parameter"; |
| 1684 | default: |
| 1685 | return "<unknown>"; |
| 1686 | } |
| 1687 | } |
| 1688 | |
| 1689 | string Assignment::get_description() |
| 1690 | { |
| 1691 | string ret_val(get_assname()); |
| 1692 | ret_val += " `"; |
| 1693 | switch (asstype) { |
| 1694 | case A_PAR_VAL: |
| 1695 | case A_PAR_VAL_IN: |
| 1696 | case A_PAR_VAL_OUT: |
| 1697 | case A_PAR_VAL_INOUT: |
| 1698 | case A_PAR_TEMPL_IN: |
| 1699 | case A_PAR_TEMPL_OUT: |
| 1700 | case A_PAR_TEMPL_INOUT: |
| 1701 | case A_PAR_TIMER: |
| 1702 | case A_PAR_PORT: |
| 1703 | // parameter is identified using its id |
| 1704 | ret_val += id->get_dispname(); |
| 1705 | break; |
| 1706 | case A_CONST: |
| 1707 | case A_TEMPLATE: |
| 1708 | case A_VAR: |
| 1709 | case A_VAR_TEMPLATE: |
| 1710 | case A_TIMER: |
| 1711 | // these can be both local and global |
| 1712 | if (is_local()) ret_val += id->get_dispname(); |
| 1713 | else ret_val += get_fullname(); |
| 1714 | break; |
| 1715 | default: |
| 1716 | // the rest is always global |
| 1717 | ret_val += get_fullname(); |
| 1718 | } |
| 1719 | ret_val += "'"; |
| 1720 | return ret_val; |
| 1721 | } |
| 1722 | |
| 1723 | void Assignment::set_my_scope(Scope *p_scope) |
| 1724 | { |
| 1725 | my_scope=p_scope; |
| 1726 | } |
| 1727 | |
| 1728 | bool Assignment::is_local() const |
| 1729 | { |
| 1730 | return false; |
| 1731 | } |
| 1732 | |
| 1733 | Setting *Assignment::get_Setting() |
| 1734 | { |
| 1735 | FATAL_ERROR("Common::Assignment::get_Setting()"); |
| 1736 | return 0; |
| 1737 | } |
| 1738 | |
| 1739 | Type *Assignment::get_Type() |
| 1740 | { |
| 1741 | FATAL_ERROR("Common::Assignment::get_Type()"); |
| 1742 | return 0; |
| 1743 | } |
| 1744 | |
| 1745 | Value *Assignment::get_Value() |
| 1746 | { |
| 1747 | FATAL_ERROR("Common::Assignment::get_Value()"); |
| 1748 | return 0; |
| 1749 | } |
| 1750 | |
| 1751 | Ttcn::Template *Assignment::get_Template() |
| 1752 | { |
| 1753 | FATAL_ERROR("Common::Assignment::get_Template()"); |
| 1754 | return 0; |
| 1755 | } |
| 1756 | |
| 1757 | bool Assignment::get_lazy_eval() const |
| 1758 | { |
| 1759 | FATAL_ERROR("Common::Assignment::get_lazy_eval()"); |
| 1760 | return false; |
| 1761 | } |
| 1762 | |
| 1763 | Ttcn::FormalParList *Assignment::get_FormalParList() |
| 1764 | { |
| 1765 | return 0; |
| 1766 | } |
| 1767 | |
| 1768 | Ttcn::ArrayDimensions *Assignment::get_Dimensions() |
| 1769 | { |
| 1770 | return 0; |
| 1771 | } |
| 1772 | |
| 1773 | Type *Assignment::get_RunsOnType() |
| 1774 | { |
| 1775 | return 0; |
| 1776 | } |
| 1777 | |
| 1778 | void Assignment::chk_ttcn_id() |
| 1779 | { |
| 1780 | if(!my_scope) return; |
| 1781 | if(!get_id().get_has_valid(Identifier::ID_TTCN) |
| 1782 | && my_scope->get_parent_scope()==my_scope->get_scope_mod() |
| 1783 | // <internal> or <error> ... |
| 1784 | && my_scope->get_scope_mod()->get_modid().get_dispname()[0]!='<') |
| 1785 | warning("The identifier `%s' is not reachable from TTCN-3", |
| 1786 | get_id().get_dispname().c_str()); |
| 1787 | } |
| 1788 | |
| 1789 | // *this is the (var/const/modulepar/etc.) definition we want to access. |
| 1790 | // p_scope is the location from where we want to reach the definition. |
| 1791 | string Assignment::get_genname_from_scope(Scope *p_scope, |
| 1792 | const char *p_prefix) |
| 1793 | { |
| 1794 | if (!p_scope || !my_scope) |
| 1795 | FATAL_ERROR("Assignment::get_genname_from_scope()"); |
| 1796 | string ret_val; |
| 1797 | |
| 1798 | Module *my_mod = my_scope->get_scope_mod_gen(); |
| 1799 | if ((my_mod != p_scope->get_scope_mod_gen()) && |
| 1800 | !Asn::Assignments::is_spec_asss(my_mod)) { |
| 1801 | // when the definition is referred from another module |
| 1802 | // the reference shall be qualified with the namespace of my module |
| 1803 | ret_val = my_mod->get_modid().get_name(); |
| 1804 | ret_val += "::"; |
| 1805 | } |
| 1806 | if (p_prefix) ret_val += p_prefix; |
| 1807 | ret_val += get_genname(); |
| 1808 | // add the cast to real type if its a lazy formal paramter |
| 1809 | switch (asstype) { |
| 1810 | case A_PAR_VAL: |
| 1811 | case A_PAR_VAL_IN: |
| 1812 | case A_PAR_TEMPL_IN: |
| 1813 | if (get_lazy_eval() && p_prefix==NULL) { |
| 1814 | Type* type = get_Type(); |
| 1815 | string type_genname = (asstype==A_PAR_TEMPL_IN) ? type->get_genname_template(p_scope) : type->get_genname_value(p_scope); |
| 1816 | ret_val = string("((") + type_genname + string("&)") + ret_val + string(")"); |
| 1817 | } |
| 1818 | break; |
| 1819 | default: |
| 1820 | // nothing to do |
| 1821 | break; |
| 1822 | } |
| 1823 | return ret_val; |
| 1824 | } |
| 1825 | |
| 1826 | const char *Assignment::get_module_object_name() |
| 1827 | { |
| 1828 | if (!my_scope) FATAL_ERROR("Assignment::get_module_object_name()"); |
| 1829 | return "module_object"; |
| 1830 | } |
| 1831 | |
| 1832 | void Assignment::use_as_lvalue(const Location&) |
| 1833 | { |
| 1834 | FATAL_ERROR("Common::Assignment::use_as_lvalue()"); |
| 1835 | } |
| 1836 | |
| 1837 | void Assignment::generate_code(output_struct *, bool) |
| 1838 | { |
| 1839 | } |
| 1840 | |
| 1841 | void Assignment::generate_code(CodeGenHelper&) |
| 1842 | { |
| 1843 | } |
| 1844 | |
| 1845 | void Assignment::dump(unsigned level) const |
| 1846 | { |
| 1847 | DEBUG(level, "Assignment: %s (%d)", |
| 1848 | id->get_dispname().c_str(), asstype); |
| 1849 | } |
| 1850 | |
| 1851 | Ttcn::Group* Assignment::get_parent_group() |
| 1852 | { |
| 1853 | return NULL; |
| 1854 | } |
| 1855 | |
| 1856 | } // namespace Common |