1 /******************************************************************************
2 * Copyright (c) 2000-2016 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
23 * Szabo, Janos Zoltan – initial implementation
25 * Zalanyi, Balazs Andor
28 ******************************************************************************/
33 #include "../common/dbgnew.hh"
35 #include "asn1/AST_asn1.hh"
36 #include "Identifier.hh"
38 #include "TypeCompat.hh"
42 #include "asn1/Object0.hh"
43 #include "PredefFunc.hh"
44 #include "../common/version.h"
45 #include "CodeGenHelper.hh"
47 #include "ttcn3/profiler.h"
49 reffer::reffer(const char*) {}
53 // =================================
55 // =================================
57 vector
<Modules::type_enc_t
> Modules::delayed_type_enc_v
;
60 : Node(), mods_v(), mods_m()
62 set_fullname(string('@'));
67 for(size_t i
= 0; i
< mods_v
.size(); i
++) delete mods_v
[i
];
72 Modules
*Modules::clone() const
74 FATAL_ERROR("Modules::clone()");
78 void Modules::add_mod(Module
*p_mod
)
80 if (!p_mod
) FATAL_ERROR("NULL parameter: Common::Modules::add_mod()");
81 p_mod
->set_fullname("@"+p_mod
->get_modid().get_dispname());
82 p_mod
->set_scope_name(p_mod
->get_modid().get_dispname());
86 bool Modules::has_mod_withId(const Identifier
& p_modid
)
88 return mods_m
.has_key(p_modid
.get_name());
91 Module
* Modules::get_mod_byId(const Identifier
& p_modid
)
93 const string
& name
= p_modid
.get_name();
94 return mods_m
.has_key(name
)?mods_m
[name
]:0;
97 Assignment
* Modules::get_ass_bySRef(Ref_simple
*p_ref
)
100 FATAL_ERROR("NULL parameter: Common::Modules::get_ass_bySRef()");
101 const Identifier
*modid
=p_ref
->get_modid();
103 if(has_mod_withId(*modid
))
104 return get_mod_byId(*modid
)->get_ass_bySRef(p_ref
);
106 p_ref
->error("There is no module with identifier `%s'",
107 modid
->get_dispname().c_str());
112 p_ref
->error("`%s' entity not found in global scope",
113 p_ref
->get_dispname().c_str());
118 void Modules::chk_uniq()
120 for(size_t i
= 0; i
< mods_v
.size(); i
++) {
121 Module
*m
= mods_v
[i
];
122 const Identifier
& id
= m
->get_modid();
123 const string
& name
= id
.get_name();
124 if (mods_m
.has_key(name
)) {
125 Module
*m2
= mods_m
[name
];
126 m
->error("A module with identifier `%s' already exists",
127 id
.get_dispname().c_str());
128 m2
->error("This is the first module with the same name");
129 if (m
->get_moduletype() == m2
->get_moduletype() &&
130 !strcmp(m
->get_filename(), m2
->get_filename())) {
131 // the same file was given twice -> drop the entire module
133 mods_v
.replace(i
, 1);
136 } else mods_m
.add(name
, m
);
142 // first check the uniqueness of module names
144 // check the import chains
145 size_t nof_mods
= mods_v
.size();
146 for (size_t i
= 0; i
< nof_mods
; i
++) {
147 Module
*m
= mods_v
[i
];
148 ReferenceChain
refch(m
, "While checking import chains");
149 vector
<Common::Module
> modules
;
150 m
->chk_imp(refch
, modules
);
152 //clear the reference chain, get a fresh start
156 Module::module_set_t checked_modules
;
157 if (nof_top_level_pdus
> 0) {
158 chk_top_level_pdus();
159 // do not check ASN.1 modules, but assume they are already checked
160 for (size_t i
= 0; i
< nof_mods
; i
++) {
161 Module
*module
= mods_v
[i
];
162 if (module
->get_moduletype() == Module::MOD_ASN
)
163 checked_modules
.add(module
, 0);
165 for (size_t i
= 0; i
< nof_mods
; i
++) {
166 Module
*module
= mods_v
[i
];
167 if (module
->get_moduletype() != Module::MOD_ASN
)
168 module
->chk_recursive(checked_modules
);
171 // walk through all modules in bottom-up order
172 for (size_t i
= 0; i
< nof_mods
; i
++)
173 mods_v
[i
]->chk_recursive(checked_modules
);
175 checked_modules
.clear();
176 // run delayed Type::chk_coding() calls
177 if (!delayed_type_enc_v
.empty()) {
178 for (size_t i
= 0; i
< delayed_type_enc_v
.size(); ++i
) {
179 delayed_type_enc_v
[i
]->t
->chk_coding(delayed_type_enc_v
[i
]->enc
, true);
180 delete delayed_type_enc_v
[i
];
182 delayed_type_enc_v
.clear();
186 void Modules::chk_top_level_pdus()
188 Location
loc("<command line>");
189 for(size_t i
=0; i
<nof_top_level_pdus
; i
++) {
190 string
pduname(top_level_pdu
[i
]);
191 size_t dotpos
=pduname
.find('.');
192 if(dotpos
>=pduname
.size()) {
193 loc
.error("While searching top-level pdu `%s': "
194 "Please use the `modulename.identifier' format",
199 Identifier
*pdu_id
=0;
200 { // searching the module
201 const string
& pduname_mod
= pduname
.substr(0, dotpos
);
202 const string
& pduname_id
= pduname
.substr(dotpos
+ 1);
204 Identifier
modid(Identifier::ID_ASN
, pduname_mod
, true);
205 module
= get_mod_byId(modid
);
207 if (module
&& module
->get_moduletype() == Module::MOD_ASN
) {
208 pdu_id
= new Identifier(Identifier::ID_ASN
, pduname_id
, true);
212 Identifier
modid(Identifier::ID_TTCN
, pduname_mod
, true);
213 module
= get_mod_byId(modid
);
215 if (module
&& module
->get_moduletype() == Module::MOD_TTCN
) {
216 pdu_id
= new Identifier(Identifier::ID_TTCN
, pduname_id
, true);
220 Identifier
modid(Identifier::ID_NAME
, pduname_mod
, true);
221 module
= get_mod_byId(modid
);
224 pdu_id
= new Identifier(Identifier::ID_NAME
, pduname_id
, true);
227 // error - no such module
228 loc
.error("While searching top-level pdu `%s': "
229 "No module with name `%s'",
230 pduname
.c_str(), pduname_mod
.c_str());
234 Assignments
*asss
=module
->get_asss();
235 if(asss
->has_local_ass_withId(*pdu_id
)) {
236 Assignment
*ass
=asss
->get_local_ass_byId(*pdu_id
);
240 loc
.error("While searching top-level pdu `%s': "
241 "No assignment with identifier `%s'",
242 pduname
.c_str(), pdu_id
->get_dispname().c_str());
245 } // for top-level pdus
248 void Modules::write_checksums()
250 fputs("Module name Language MD5 checksum Version\n"
251 "---------------------------------------------------------------------------\n", stderr
);
252 size_t nof_mods
= mods_v
.size();
253 for (size_t i
= 0; i
< nof_mods
; i
++) {
254 mods_v
[i
]->write_checksum();
258 void Modules::generate_code(CodeGenHelper
& cgh
)
260 Common::Module::rename_default_namespace(); // if needed
262 The White Rabbit put on his spectacles.
263 "Where shall I begin, please your Majesty ?" he asked.
264 "Begin at the beginning,", the King said, very gravely, "and go on
265 till you come to the end: then stop."
268 for (size_t i
= 0; i
< mods_v
.size(); i
++) {
269 mods_v
[i
]->generate_code(cgh
);
270 if (tcov_file_name
&& in_tcov_files(mods_v
[i
]->get_filename())) {
271 Free(effective_module_lines
);
272 Free(effective_module_functions
);
273 effective_module_lines
= effective_module_functions
= NULL
;
281 void Modules::dump(unsigned level
) const
283 DEBUG(level
, "Modules (%lu pcs.)", (unsigned long) mods_v
.size());
284 for(size_t i
= 0; i
< mods_v
.size(); i
++) mods_v
[i
]->dump(level
);
287 std::set
<ModuleVersion
> Modules::getVersionsWithProductNumber() const {
288 std::set
<ModuleVersion
> versions
;
289 for (size_t i
= 0; i
< mods_v
.size(); ++i
) {
290 const ModuleVersion version
= mods_v
[i
]->getVersion();
291 if (version
.hasProductNumber()) {
292 versions
.insert(version
);
298 void Modules::generate_json_schema(JSON_Tokenizer
& json
, map
<Type
*, JSON_Tokenizer
>& json_refs
)
300 for(size_t i
= 0; i
< mods_v
.size(); ++i
) {
301 mods_v
[i
]->generate_json_schema(json
, json_refs
);
305 void Modules::delay_type_encode_check(Type
* p_type
, bool p_encode
)
307 type_enc_t
* elem
= new type_enc_t
;
309 elem
->enc
= p_encode
;
310 delayed_type_enc_v
.add(elem
);
314 // =================================
316 // =================================
318 ModuleVersion
Module::getVersion() const {
319 return ModuleVersion(product_number
, suffix
, release
, patch
, build
, extra
);
322 void Module::generate_literals(output_struct
*target
)
326 generate_bs_literals(src
, hdr
); // implementations follow directly below
327 generate_bp_literals(src
, hdr
);
328 generate_hs_literals(src
, hdr
);
329 generate_hp_literals(src
, hdr
);
330 generate_os_literals(src
, hdr
);
331 generate_op_literals(src
, hdr
);
332 generate_cs_literals(src
, hdr
);
333 generate_us_literals(src
, hdr
);
334 generate_oid_literals(src
, hdr
);
335 generate_pp_literals(src
, hdr
);
336 generate_mp_literals(src
, hdr
);
337 target
->source
.string_literals
=
338 mputstr(target
->source
.string_literals
, src
);
339 if (CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE
) {
340 target
->header
.global_vars
= mputstr(target
->header
.global_vars
, hdr
);
346 void Module::generate_bs_literals(char *&src
, char *&hdr
)
348 if (bs_literals
.size() == 0) return;
349 // indicates whether we have found at least one non-empty bitstring
350 bool is_nonempty
= false;
352 CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE
;
353 for (size_t i
= 0; i
< bs_literals
.size(); i
++) {
354 const string
& str
= bs_literals
.get_nth_key(i
);
355 size_t bits
= str
.size();
356 if (bits
== 0) continue;
357 if (is_nonempty
) src
= mputstr(src
, ",\n");
359 src
= mputstr(src
, "static const unsigned char ");
362 src
= mputprintf(src
, "%s_bits[] = { ",
363 bs_literals
.get_nth_elem(i
)->c_str());
364 // Filling up the octets one-by-one
365 for (size_t j
= 0; j
< (bits
+ 7) / 8; j
++) {
366 size_t offset
= 8 * j
;
367 unsigned char value
= 0;
368 for (size_t k
= 0; k
< 8 && k
< bits
- offset
; k
++) {
369 if (str
[offset
+ k
] == '1') value
|= (1 << k
);
371 if (j
> 0) src
= mputstr(src
, ", ");
372 src
= mputprintf(src
, "%d", value
);
374 src
= mputstr(src
, " }");
376 if (is_nonempty
) src
= mputstr(src
, ";\n");
377 for (size_t i
= 0; i
< bs_literals
.size(); i
++) {
379 src
= mputstr(src
, ",\n");
380 if (splitting
) hdr
= mputstr(hdr
, ",\n");
383 src
= mputprintf(src
, "%s const BITSTRING ",
384 splitting
? "extern" : "static");
385 if (splitting
) hdr
= mputstr(hdr
, "extern const BITSTRING ");
387 size_t bits
= bs_literals
.get_nth_key(i
).size();
388 const char *object_name
= bs_literals
.get_nth_elem(i
)->c_str();
389 if (bits
> 0) src
= mputprintf(src
, "%s(%lu, %s_bits)",
390 object_name
, (unsigned long) bits
, object_name
);
391 else src
= mputprintf(src
, "%s(0, NULL)", object_name
);
392 if (splitting
) hdr
= mputstr(hdr
, object_name
);
394 src
= mputstr(src
, ";\n");
395 if (splitting
) hdr
= mputstr(hdr
, ";\n");
398 void Module::generate_bp_literals(char *&src
, char *& /*hdr*/)
400 if (bp_literals
.size() == 0) return;
401 for (size_t i
= 0; i
< bp_literals
.size(); i
++) {
402 if (i
> 0) src
= mputstr(src
, ",\n");
403 else src
= mputstr(src
, "static const unsigned char ");
404 src
= mputprintf(src
, "%s_elements[] = { ",
405 bp_literals
.get_nth_elem(i
)->c_str());
406 const string
& str
= bp_literals
.get_nth_key(i
);
407 for (size_t j
= 0; j
< str
.size(); j
++) {
408 if (j
> 0) src
= mputstr(src
, ", ");
411 src
= mputc(src
, '0');
414 src
= mputc(src
, '1');
417 src
= mputc(src
, '2');
420 src
= mputc(src
, '3');
423 FATAL_ERROR("Invalid character in bitstring pattern.");
426 src
= mputstr(src
, " }");
428 src
= mputstr(src
, ";\n");
429 for (size_t i
= 0; i
< bp_literals
.size(); i
++) {
430 if (i
> 0) src
= mputstr(src
, ",\n");
431 else src
= mputstr(src
, "static const BITSTRING_template ");
432 const char *name
= bp_literals
.get_nth_elem(i
)->c_str();
433 src
= mputprintf(src
, "%s(%lu, %s_elements)",
434 name
, (unsigned long) bp_literals
.get_nth_key(i
).size(), name
);
436 src
= mputstr(src
, ";\n");
439 void Module::generate_hs_literals(char *&src
, char *&hdr
)
441 if (hs_literals
.size() == 0) return;
442 // indicates whether we have found at least one non-empty hexstring
443 bool is_nonempty
= false;
445 CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE
;
446 for (size_t i
= 0; i
< hs_literals
.size(); i
++) {
447 const string
& str
= hs_literals
.get_nth_key(i
);
448 size_t nibbles
= str
.size();
449 if (nibbles
== 0) continue;
450 size_t octets
= (nibbles
+ 1) / 2;
451 const char *str_ptr
= str
.c_str();
452 if (is_nonempty
) src
= mputstr(src
, ",\n");
454 src
= mputstr(src
, "static const unsigned char ");
457 src
= mputprintf(src
, "%s_nibbles[] = { ",
458 hs_literals
.get_nth_elem(i
)->c_str());
459 for (size_t j
= 0; j
< octets
; j
++) {
460 // Hex digit with even index always goes to the least significant
461 // 4 bits of the octet.
462 unsigned char value
= char_to_hexdigit(str_ptr
[2 * j
]);
463 if (2 * j
+ 1 < nibbles
) {
464 // Hex digit with odd index always goes to the most significant
465 // 4 bits of the octet.
466 // This digit is not present (bits are set to zero) if the length
467 // of hexstring is odd.
468 value
+= 16 * char_to_hexdigit(str_ptr
[2 * j
+ 1]);
470 if (j
> 0) src
= mputstr(src
, ", ");
471 src
= mputprintf(src
, "%u", value
);
473 src
= mputstr(src
, " }");
475 if (is_nonempty
) src
= mputstr(src
, ";\n");
476 for (size_t i
= 0; i
< hs_literals
.size(); i
++) {
478 src
= mputstr(src
, ",\n");
479 if (splitting
) hdr
= mputstr(hdr
, ",\n");
482 src
= mputprintf(src
, "%s const HEXSTRING ",
483 splitting
? "extern" : "static");
484 if (splitting
) hdr
= mputstr(hdr
, "extern const HEXSTRING ");
486 size_t nibbles
= hs_literals
.get_nth_key(i
).size();
487 const char *object_name
= hs_literals
.get_nth_elem(i
)->c_str();
488 if (nibbles
> 0) src
= mputprintf(src
, "%s(%lu, %s_nibbles)",
489 object_name
, (unsigned long) nibbles
, object_name
);
490 else src
= mputprintf(src
, "%s(0, NULL)", object_name
);
491 if (splitting
) hdr
= mputstr(hdr
, object_name
);
493 src
= mputstr(src
, ";\n");
494 if (splitting
) hdr
= mputstr(hdr
, ";\n");
497 void Module::generate_hp_literals(char *&src
, char *& /*hdr*/)
499 if (hp_literals
.size() == 0) return;
500 for (size_t i
= 0; i
< hp_literals
.size(); i
++) {
501 if (i
> 0) src
= mputstr(src
, ",\n");
502 else src
= mputstr(src
, "static const unsigned char ");
503 src
= mputprintf(src
, "%s_elements[] = { ",
504 hp_literals
.get_nth_elem(i
)->c_str());
505 const string
& str
= hp_literals
.get_nth_key(i
);
506 size_t size
= str
.size();
507 const char *str_ptr
= str
.c_str();
508 for (size_t j
= 0; j
< size
; j
++) {
509 if (j
> 0) src
= mputstr(src
, ", ");
511 if (str_ptr
[j
] == '?') num
= 16;
512 else if (str_ptr
[j
] == '*') num
= 17;
513 else num
= char_to_hexdigit(str_ptr
[j
]);
514 src
= mputprintf(src
, "%u", num
);
516 src
= mputstr(src
, " }");
518 src
= mputstr(src
, ";\n");
519 for (size_t i
= 0; i
< hp_literals
.size(); i
++) {
520 if (i
> 0) src
= mputstr(src
, ",\n");
521 else src
= mputstr(src
, "static const HEXSTRING_template ");
522 const char *name
= hp_literals
.get_nth_elem(i
)->c_str();
523 src
= mputprintf(src
, "%s(%lu, %s_elements)",
524 name
, (unsigned long) hp_literals
.get_nth_key(i
).size(), name
);
526 src
= mputstr(src
, ";\n");
529 void Module::generate_os_literals(char *&src
, char *&hdr
)
531 if (os_literals
.size() == 0) return;
532 // indicates whether we have found at least one non-empty octetstring
533 bool is_nonempty
= false;
535 CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE
;
536 for (size_t i
= 0; i
< os_literals
.size(); i
++) {
537 const string
& str
= os_literals
.get_nth_key(i
);
538 size_t size
= str
.size();
539 if (size
% 2) FATAL_ERROR("Invalid length for an octetstring.");
540 size_t octets
= size
/ 2;
541 if (octets
== 0) continue;
542 const char *str_ptr
= str
.c_str();
543 if (is_nonempty
) src
= mputstr(src
, ",\n");
545 src
= mputstr(src
, "static const unsigned char ");
548 src
= mputprintf(src
, "%s_octets[] = { ",
549 os_literals
.get_nth_elem(i
)->c_str());
550 for (size_t j
= 0; j
< octets
; j
++) {
551 if (j
> 0) src
= mputstr(src
, ", ");
552 src
= mputprintf(src
, "%u", 16 * char_to_hexdigit(str_ptr
[2 * j
]) +
553 char_to_hexdigit(str_ptr
[2 * j
+ 1]));
555 src
= mputstr(src
, " }");
557 if (is_nonempty
) src
= mputstr(src
, ";\n");
558 for (size_t i
= 0; i
< os_literals
.size(); i
++) {
560 src
= mputstr(src
, ",\n");
561 if (splitting
) hdr
= mputstr(hdr
, ",\n");
564 src
= mputprintf(src
, "%s const OCTETSTRING ",
565 splitting
? "extern" : "static");
566 if (splitting
) hdr
= mputstr(hdr
, "extern const OCTETSTRING ");
568 size_t octets
= os_literals
.get_nth_key(i
).size() / 2;
569 const char *object_name
= os_literals
.get_nth_elem(i
)->c_str();
570 if (octets
> 0) src
= mputprintf(src
, "%s(%lu, %s_octets)",
571 object_name
, (unsigned long) octets
, object_name
);
572 else src
= mputprintf(src
, "%s(0, NULL)", object_name
);
573 if (splitting
) hdr
= mputstr(hdr
, object_name
);
575 src
= mputstr(src
, ";\n");
576 if (splitting
) hdr
= mputstr(hdr
, ";\n");
579 void Module::generate_op_literals(char *&src
, char *& /*hdr*/)
581 if (op_literals
.size() == 0) return;
582 vector
<size_t> pattern_lens
;
583 for(size_t i
= 0; i
< op_literals
.size(); i
++) {
584 if (i
> 0) src
= mputstr(src
, ",\n");
585 else src
= mputstr(src
, "static const unsigned short ");
586 src
= mputprintf(src
, "%s_elements[] = { ",
587 op_literals
.get_nth_elem(i
)->c_str());
588 const string
& str
= op_literals
.get_nth_key(i
);
589 size_t size
= str
.size();
590 size_t pattern_len
= 0;
591 const char *str_ptr
= str
.c_str();
592 for (size_t j
= 0; j
< size
; j
++) {
593 if (j
> 0) src
= mputstr(src
, ", ");
595 if (str_ptr
[j
] == '?') num
= 256;
596 else if (str_ptr
[j
] == '*') num
= 257;
599 num
= 16 * char_to_hexdigit(str_ptr
[j
]);
601 if (j
>= size
) FATAL_ERROR("Unexpected end of octetstring pattern.");
603 num
+= char_to_hexdigit(str_ptr
[j
]);
605 src
= mputprintf(src
, "%u", num
);
608 src
= mputstr(src
, " }");
609 pattern_lens
.add(new size_t(pattern_len
));
611 src
= mputstr(src
, ";\n");
612 for (size_t i
= 0; i
< op_literals
.size(); i
++) {
613 if (i
> 0) src
= mputstr(src
, ",\n");
614 else src
= mputstr(src
, "static const OCTETSTRING_template ");
615 const char *name
= op_literals
.get_nth_elem(i
)->c_str();
616 src
= mputprintf(src
, "%s(%lu, %s_elements)",
617 name
, (unsigned long) *pattern_lens
[i
], name
);
619 src
= mputstr(src
, ";\n");
620 for (size_t i
= 0; i
< pattern_lens
.size(); i
++) delete pattern_lens
[i
];
621 pattern_lens
.clear();
624 void Module::generate_cs_literals(char *&src
, char *&hdr
)
626 if (cs_literals
.size() == 0) return;
628 CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE
;
629 for (size_t i
= 0; i
< cs_literals
.size(); i
++) {
630 const string
& str
= cs_literals
.get_nth_key(i
);
631 size_t str_len
= str
.size();
632 const char *str_ptr
= str
.c_str();
633 const char *str_name
= cs_literals
.get_nth_elem(i
)->c_str();
636 src
= mputstr(src
, ",\n");
637 if (splitting
) hdr
= mputstr(hdr
, ",\n");
640 src
= mputprintf(src
, "%s const CHARSTRING ",
641 splitting
? "extern" : "static");
642 if (splitting
) hdr
= mputstr(hdr
, "extern const CHARSTRING ");
647 src
= mputprintf(src
, "%s(0, NULL)", str_name
);
650 src
= mputprintf(src
, "%s('", str_name
);
651 src
= Code::translate_character(src
, *str_ptr
, false);
652 src
= mputstr(src
, "')");
655 src
= mputprintf(src
, "%s(%lu, \"", str_name
, (unsigned long) str_len
);
656 // Note: Code::translate_string() is not suitable because the string
657 // may contain NUL characters at which translate_string() stops
659 for (size_t j
= 0; j
< str_len
; j
++)
660 src
= Code::translate_character(src
, str_ptr
[j
], true);
661 src
= mputstr(src
, "\")");
664 if (splitting
) hdr
= mputstr(hdr
, str_name
);
666 src
= mputstr(src
, ";\n");
667 if (splitting
) hdr
= mputstr(hdr
, ";\n");
670 void Module::generate_pp_literals(char *&src
, char *&) // padding patterns
672 if (pp_literals
.size() == 0) return;
673 for (size_t i
= 0; i
< pp_literals
.size(); i
++) {
674 const string
& pattern
= pp_literals
.get_nth_key(i
);
675 size_t pattern_len
= pattern
.size();
676 const char *pattern_ptr
= pattern
.c_str();
677 if (i
> 0) src
= mputstr(src
, ",\n");
678 else src
= mputstr(src
, "static const unsigned char ");
679 src
= mputprintf(src
, "%s[] = { ", pp_literals
.get_nth_elem(i
)->c_str());
680 if (pattern_len
% 8 != 0) FATAL_ERROR("Module::generate_pp_literals()");
681 size_t nof_octets
= pattern_len
/ 8;
682 for (size_t j
= 0; j
< nof_octets
; j
++) {
683 if (j
> 0) src
= mputstr(src
, ", ");
684 unsigned char octet
= 0;
685 for (size_t k
= 0; k
< 8; k
++) {
686 // take the octets in reverse order
687 // MSB is the first character of the string
689 if (pattern_ptr
[8 * (nof_octets
- j
- 1) + k
] == '1') octet
|= 0x01;
691 src
= mputprintf(src
, "0x%02x", octet
);
693 src
= mputstr(src
, " }");
695 src
= mputstr(src
, ";\n");
698 void Module::generate_mp_literals(char *&src
, char *&) // matching patt.
700 if (mp_literals
.size() == 0) return;
701 for (size_t i
= 0; i
< mp_literals
.size(); i
++) {
702 const string
& str
= mp_literals
.get_nth_key(i
);
703 if (str
.size() < 1) FATAL_ERROR("Module::generate_mp_literals()");
704 const char *str_ptr
= str
.c_str();
706 if (i
> 0) src
= mputstr(src
, ",\n");
707 else src
= mputstr(src
, "static const Token_Match ");
709 src
= mputprintf(src
, "%s(\"", mp_literals
.get_nth_elem(i
)->c_str());
710 src
= Code::translate_string(src
, str_ptr
+ 1);
711 // The first character of the string is case-sensitiveness flag:
712 // 'I' for yes, 'N' for no,
713 // 'F' for fixed string matching which is always case sensitive.
714 src
= mputprintf(src
, "\", %s%s)", (str_ptr
[0]!='N') ? "TRUE" : "FALSE",
715 (str_ptr
[0] == 'F') ? ", TRUE" : "");
717 src
= mputstr(src
, ";\n");
720 void Module::generate_us_literals(char *&src
, char *&hdr
) // univ.cs
722 size_t n_literals
= us_literals
.size();
723 if (n_literals
== 0) return;
724 bool array_needed
= false;
726 CodeGenHelper::GetInstance().get_split_mode() != CodeGenHelper::SPLIT_NONE
;
727 for (size_t i
= 0; i
< n_literals
; i
++) {
728 const ustring
& value
= us_literals
.get_nth_key(i
);
729 size_t value_size
= value
.size();
730 if (value_size
< 2) continue;
731 if (array_needed
) src
= mputstr(src
, ",\n");
733 src
= mputstr(src
, "static const universal_char ");
736 src
= mputprintf(src
, "%s_uchars[] = { ",
737 us_literals
.get_nth_elem(i
)->c_str());
738 const ustring::universal_char
*uchars_ptr
= value
.u_str();
739 for (size_t j
= 0; j
< value_size
; j
++) {
740 if (j
> 0) src
= mputstr(src
, ", ");
741 src
= mputprintf(src
, "{ %u, %u, %u, %u }", uchars_ptr
[j
].group
,
742 uchars_ptr
[j
].plane
, uchars_ptr
[j
].row
, uchars_ptr
[j
].cell
);
744 src
= mputstr(src
, " }");
746 if (array_needed
) src
= mputstr(src
, ";\n");
747 for (size_t i
= 0; i
< n_literals
; i
++) {
749 src
= mputstr(src
, ",\n");
750 if (splitting
) hdr
= mputstr(hdr
, ",\n");
753 src
= mputprintf(src
, "%s const UNIVERSAL_CHARSTRING ",
754 splitting
? "extern" : "static");
755 if (splitting
) hdr
= mputstr(hdr
, "extern const UNIVERSAL_CHARSTRING ");
757 const char *value_name
= us_literals
.get_nth_elem(i
)->c_str();
758 const ustring
& value
= us_literals
.get_nth_key(i
);
759 size_t value_size
= value
.size();
760 switch (value_size
) {
762 src
= mputprintf(src
, "%s(0, (const universal_char*)NULL)", value_name
);
765 const ustring::universal_char
& uchar
= value
.u_str()[0];
766 src
= mputprintf(src
, "%s(%u, %u, %u, %u)", value_name
,
767 uchar
.group
, uchar
.plane
, uchar
.row
, uchar
.cell
);
770 src
= mputprintf(src
, "%s(%lu, %s_uchars)", value_name
,
771 (unsigned long) value_size
, value_name
);
774 if (splitting
) hdr
= mputstr(hdr
, value_name
);
776 src
= mputstr(src
, ";\n");
777 if (splitting
) hdr
= mputstr(hdr
, ";\n");
780 void Module::generate_oid_literals(char *&src
, char *& /*hdr*/)
782 if (oid_literals
.size() == 0) return;
783 for (size_t i
= 0; i
< oid_literals
.size(); i
++) {
784 if (i
> 0) src
= mputstr(src
, ",\n");
785 else src
= mputstr(src
, "static const OBJID::objid_element ");
787 src
= mputprintf(src
, "%s_comps[] = { %s }",
788 oid_literals
.get_nth_elem(i
)->oid_id
.c_str(),
789 oid_literals
.get_nth_key(i
).c_str());
791 src
= mputstr(src
, ";\n");
792 for(size_t i
= 0; i
< oid_literals
.size(); i
++) {
793 const OID_literal
*litstruct
= oid_literals
.get_nth_elem(i
);
795 if (i
> 0) src
= mputstr(src
, ",\n");
796 else src
= mputstr(src
, "static const OBJID ");
798 src
= mputprintf(src
, "%s(%lu, %s_comps)",
799 litstruct
->oid_id
.c_str(), (unsigned long) litstruct
->nof_elems
,
800 litstruct
->oid_id
.c_str());
802 src
= mputstr(src
, ";\n");
805 void Module::generate_functions(output_struct
*output
)
807 bool tcov_enabled
= tcov_file_name
&& in_tcov_files(get_filename());
808 bool has_pre_init_before_tcov
= output
->functions
.pre_init
!= NULL
;
810 output
->functions
.pre_init
= mputprintf(output
->functions
.pre_init
,
811 "TTCN_Location_Statistics::init_file_lines(\"%s\", effective_module_lines, sizeof(effective_module_lines) / sizeof(int));\n" \
812 "TTCN_Location_Statistics::init_file_functions(\"%s\", effective_module_functions, sizeof(effective_module_functions) / sizeof(char *));\n",
813 get_tcov_file_name(get_filename()), get_tcov_file_name(get_filename()));
816 bool has_pre_init
= false;
817 bool profiled
= MOD_TTCN
== get_moduletype() && is_file_profiled(get_filename());
818 bool debugged
= debugger_active
&& MOD_TTCN
== get_moduletype();
819 // always generate pre_init_module if the file is profiled
820 if (output
->functions
.pre_init
|| profiled
|| debugged
) {
821 output
->source
.static_function_prototypes
=
822 mputstr(output
->source
.static_function_prototypes
,
823 "static void pre_init_module();\n");
824 output
->source
.static_function_bodies
= mputstr(output
->source
.static_function_bodies
,
825 "static void pre_init_module()\n"
827 if (include_location_info
) {
828 output
->source
.static_function_bodies
=
829 mputstr(output
->source
.static_function_bodies
,
830 (tcov_enabled
&& has_pre_init_before_tcov
) ? "TTCN_Location_Statistics current_location(\""
831 : "TTCN_Location current_location(\"");
832 output
->source
.static_function_bodies
=
833 Code::translate_string(output
->source
.static_function_bodies
, (tcov_enabled
&& has_pre_init_before_tcov
) ? get_tcov_file_name(get_filename()) : get_filename());
834 output
->source
.static_function_bodies
=
835 mputprintf(output
->source
.static_function_bodies
,
836 (tcov_enabled
&& has_pre_init_before_tcov
) ? "\", 0, TTCN_Location_Statistics::LOCATION_UNKNOWN, \"%s\");\n"
837 : "\", 0, TTCN_Location::LOCATION_UNKNOWN, \"%s\");\n", get_modid().get_dispname().c_str());
838 if (tcov_enabled
&& has_pre_init_before_tcov
) {
839 effective_module_lines
=
840 mputprintf(effective_module_lines
, "%s0",
841 (effective_module_lines
? ", " : ""));
842 effective_module_functions
=
843 mputprintf(effective_module_functions
, "%s\"%s\"",
844 (effective_module_functions
? ", " : ""), get_modid().get_dispname().c_str());
847 output
->source
.static_function_bodies
= mputprintf(output
->source
.static_function_bodies
,
848 "%s::init_ttcn3_profiler();\n"
849 "TTCN3_Stack_Depth stack_depth;\n"
850 "ttcn3_prof.execute_line(\"%s\", 0);\n", get_modid().get_name().c_str(), get_filename());
853 output
->source
.static_function_bodies
= mputprintf(output
->source
.static_function_bodies
,
854 "%s::init_ttcn3_debugger();\n", get_modid().get_name().c_str());
857 output
->source
.static_function_bodies
=
858 mputstr(output
->source
.static_function_bodies
, output
->functions
.pre_init
);
859 output
->source
.static_function_bodies
=
860 mputstr(output
->source
.static_function_bodies
, "}\n\n");
861 Free(output
->functions
.pre_init
);
862 output
->functions
.pre_init
= NULL
;
865 bool has_post_init_before_tcov
= output
->functions
.post_init
!= NULL
;
866 // post_init function
867 bool has_post_init
= false;
868 if (output
->functions
.post_init
) {
869 output
->source
.static_function_prototypes
= mputstr(output
->source
.static_function_prototypes
,
870 "static void post_init_module();\n");
871 output
->source
.static_function_bodies
= mputstr(output
->source
.static_function_bodies
,
872 "static void post_init_module()\n"
874 if (include_location_info
) {
875 output
->source
.static_function_bodies
=
876 mputstr(output
->source
.static_function_bodies
,
877 (tcov_enabled
&& has_post_init_before_tcov
) ? "TTCN_Location_Statistics current_location(\""
878 : "TTCN_Location current_location(\"");
879 output
->source
.static_function_bodies
=
880 Code::translate_string(output
->source
.static_function_bodies
, (tcov_enabled
&& has_post_init_before_tcov
) ? get_tcov_file_name(get_filename()) : get_filename());
881 output
->source
.static_function_bodies
=
882 mputprintf(output
->source
.static_function_bodies
,
883 (tcov_enabled
&& has_post_init_before_tcov
) ? "\", 0, TTCN_Location_Statistics::LOCATION_UNKNOWN, \"%s\");\n"
884 : "\", 0, TTCN_Location::LOCATION_UNKNOWN, \"%s\");\n", get_modid().get_dispname().c_str());
885 if (tcov_enabled
&& has_post_init_before_tcov
) {
886 effective_module_lines
=
887 mputprintf(effective_module_lines
, "%s0",
888 (effective_module_lines
? ", " : ""));
889 effective_module_functions
=
890 mputprintf(effective_module_functions
, "%s\"%s\"",
891 (effective_module_functions
? ", " : ""), get_modid().get_dispname().c_str());
893 if (MOD_TTCN
== get_moduletype() && is_file_profiled(get_filename())) {
894 output
->source
.static_function_bodies
= mputprintf(output
->source
.static_function_bodies
,
895 "TTCN3_Stack_Depth stack_depth;\n"
896 "ttcn3_prof.execute_line(\"%s\", 0);\n", get_filename());
899 output
->source
.static_function_bodies
=
900 mputstr(output
->source
.static_function_bodies
, output
->functions
.post_init
);
901 output
->source
.static_function_bodies
=
902 mputstr(output
->source
.static_function_bodies
, "}\n\n");
903 Free(output
->functions
.post_init
);
904 output
->functions
.post_init
= NULL
;
905 has_post_init
= true;
907 // set_param function
909 if (output
->functions
.set_param
) {
910 output
->source
.static_function_prototypes
= mputstr(output
->source
.static_function_prototypes
,
911 "static boolean set_module_param(Module_Param& param);\n");
912 output
->source
.static_function_bodies
= mputstr(output
->source
.static_function_bodies
,
913 "static boolean set_module_param(Module_Param& param)\n"
915 "const char* const par_name = param.get_id()->get_current_name();\n");
916 output
->source
.static_function_bodies
=
917 mputstr(output
->source
.static_function_bodies
, output
->functions
.set_param
);
918 output
->source
.static_function_bodies
=
919 mputstr(output
->source
.static_function_bodies
, "return FALSE;\n"
921 Free(output
->functions
.set_param
);
922 output
->functions
.set_param
= NULL
;
923 has_set_param
= true;
924 } else has_set_param
= false;
925 // get_param function
927 if (output
->functions
.get_param
) {
928 output
->source
.static_function_prototypes
= mputstr(output
->source
.static_function_prototypes
,
929 "static Module_Param* get_module_param(Module_Param_Name& param_name);\n");
930 output
->source
.static_function_bodies
= mputstr(output
->source
.static_function_bodies
,
931 "static Module_Param* get_module_param(Module_Param_Name& param_name)\n"
933 "const char* const par_name = param_name.get_current_name();\n");
934 output
->source
.static_function_bodies
=
935 mputstr(output
->source
.static_function_bodies
, output
->functions
.get_param
);
936 output
->source
.static_function_bodies
=
937 mputstr(output
->source
.static_function_bodies
, "return NULL;\n"
939 Free(output
->functions
.get_param
);
940 output
->functions
.get_param
= NULL
;
941 has_get_param
= true;
942 } else has_get_param
= false;
943 // log_param function
945 if (output
->functions
.log_param
) {
946 output
->source
.static_function_prototypes
= mputstr(output
->source
.static_function_prototypes
,
947 "static void log_module_param();\n");
948 output
->source
.static_function_bodies
= mputstr(output
->source
.static_function_bodies
,
949 "static void log_module_param()\n"
951 output
->source
.static_function_bodies
=
952 mputstr(output
->source
.static_function_bodies
, output
->functions
.log_param
);
953 output
->source
.static_function_bodies
= mputstr(output
->source
.static_function_bodies
,
955 Free(output
->functions
.log_param
);
956 output
->functions
.log_param
= NULL
;
957 has_log_param
= true;
958 } else has_log_param
= false;
959 // init_comp function
961 if (output
->functions
.init_comp
) {
962 output
->source
.static_function_prototypes
=
963 mputstr(output
->source
.static_function_prototypes
,
964 "static boolean init_comp_type("
965 "const char *component_type, boolean init_base_comps);\n");
966 output
->source
.static_function_bodies
=
967 mputstr(output
->source
.static_function_bodies
,
968 "static boolean init_comp_type(const char *component_type, "
969 "boolean init_base_comps)\n"
970 "{\n(void)init_base_comps;\n");
971 output
->source
.static_function_bodies
=
972 mputstr(output
->source
.static_function_bodies
,
973 output
->functions
.init_comp
);
974 output
->source
.static_function_bodies
=
975 mputstr(output
->source
.static_function_bodies
, "return FALSE;\n"
977 Free(output
->functions
.init_comp
);
978 output
->functions
.init_comp
= NULL
;
979 has_init_comp
= true;
980 } else has_init_comp
= false;
983 if (output
->functions
.start
) {
984 output
->source
.static_function_prototypes
= mputstr(output
->source
.static_function_prototypes
,
985 "static boolean start_ptc_function(const char *function_name, "
986 "Text_Buf& function_arguments);\n");
987 output
->source
.static_function_bodies
= mputstr(output
->source
.static_function_bodies
,
988 "static boolean start_ptc_function(const char *function_name, "
989 "Text_Buf& function_arguments)\n"
991 output
->source
.static_function_bodies
=
992 mputstr(output
->source
.static_function_bodies
, output
->functions
.start
);
993 output
->source
.static_function_bodies
=
994 mputstr(output
->source
.static_function_bodies
, "return FALSE;\n"
996 Free(output
->functions
.start
);
997 output
->functions
.start
= NULL
;
999 } else has_start
= false;
1002 if (output
->functions
.control
) {
1003 output
->source
.static_function_prototypes
= mputstr(output
->source
.static_function_prototypes
,
1004 "static void module_control_part();\n");
1005 output
->source
.static_function_bodies
= mputstr(output
->source
.static_function_bodies
,
1006 "static void module_control_part()\n"
1008 output
->source
.static_function_bodies
=
1009 mputstr(output
->source
.static_function_bodies
, output
->functions
.control
);
1010 output
->source
.static_function_bodies
=
1011 mputstr(output
->source
.static_function_bodies
, "}\n\n");
1012 Free(output
->functions
.control
);
1013 output
->functions
.control
= NULL
;
1015 } else has_control
= false;
1018 output
->source
.string_literals
= mputstr(output
->source
.string_literals
,
1019 "static const unsigned char module_checksum[] = {");
1020 for (size_t i
= 0; i
< sizeof(module_checksum
); i
++) {
1021 if (i
> 0) output
->source
.string_literals
=
1022 mputc(output
->source
.string_literals
, ',');
1023 output
->source
.string_literals
=
1024 mputprintf(output
->source
.string_literals
, " 0x%02x",
1025 module_checksum
[i
]);
1027 output
->source
.string_literals
= mputstr(output
->source
.string_literals
,
1030 const char *module_name
= modid
->get_name().c_str();
1032 // XML namespaces. Written in the order they are stored:
1033 // sorted ASCIIbetically by the prefix.
1034 // Not all namespaces are used by every module. Unfortunately, the array
1035 // (which has the same size in all modules) cannot be compacted, because
1036 // the indexes have already been used when the XER descriptors were written.
1037 // All we can do is store NULLs for the unused namespaces.
1038 size_t num_xml_namespaces
= namespaces
.size();
1039 if (moduletype
== MOD_TTCN
) { //TODO remove this when ASN.1 gets EXER
1040 output
->source
.global_vars
= mputprintf(output
->source
.global_vars
,
1042 "// written by %s in " __FILE__
" at %d\n"
1044 "static const size_t num_namespaces = %lu;\n"
1046 , __FUNCTION__
, __LINE__
1048 , (unsigned long)num_xml_namespaces
1050 if (num_xml_namespaces
!= 0 || (control_ns
&& control_ns_prefix
)) {
1051 output
->source
.global_vars
= mputstr(output
->source
.global_vars
,
1052 "static const namespace_t xml_namespaces[num_namespaces+1] = {\n");
1053 for (size_t i
=0; i
< namespaces
.size(); ++i
) {
1054 if (used_namespaces
.has_key(i
)) {
1055 output
->source
.global_vars
= mputprintf(output
->source
.global_vars
,
1056 " { \"%s\", \"%s\" },\n", // ns, then prefix
1057 namespaces
.get_nth_elem(i
), namespaces
.get_nth_key(i
).c_str());
1060 output
->source
.global_vars
= mputstr(output
->source
.global_vars
,
1061 " { NULL, NULL },\n"); // not used in this module
1064 output
->source
.global_vars
= mputprintf(output
->source
.global_vars
,
1065 " { \"%s\", \"%s\" }\n};\n\n",
1066 (control_ns
? control_ns
: ""),
1067 (control_ns_prefix
? control_ns_prefix
: ""));
1068 } // if there are namespaces
1073 output
->header
.global_vars
= mputprintf(output
->header
.global_vars
,
1074 "extern TTCN_Module %s;\n",
1077 output
->source
.global_vars
= mputprintf(output
->source
.global_vars
,
1078 "TTCN_Module %s(\"%s\", __DATE__, __TIME__, %s, %s",
1081 modid
->get_dispname().c_str(),
1082 (has_checksum
? "module_checksum" : "NULL"),
1083 has_pre_init
? "pre_init_module" : "NULL");
1085 if (moduletype
== MOD_TTCN
) {
1086 // TTCN-3 specific function pointers
1087 if (product_number
== NULL
) {
1088 output
->source
.global_vars
= mputstr(output
->source
.global_vars
, ", NULL");
1090 output
->source
.global_vars
= mputprintf(output
->source
.global_vars
, ", \"%s\"", product_number
);
1092 string extra_str
= extra
? ( string('"') + extra
+ string('"') ) : string("NULL");
1093 output
->source
.global_vars
= mputprintf(output
->source
.global_vars
,
1094 ", %uU, %uU, %uU, %uU, %s, %luLU, %s, %s, %s, %s, %s, %s, %s, %s",
1095 suffix
, release
, patch
, build
, extra_str
.c_str(),
1096 (unsigned long)num_xml_namespaces
,
1097 ((num_xml_namespaces
|| (control_ns
&& control_ns_prefix
)) ? "xml_namespaces" : "0"),
1098 has_post_init
? "post_init_module" : "NULL",
1099 has_set_param
? "set_module_param" : "NULL",
1100 has_get_param
? "get_module_param" : "NULL",
1101 has_log_param
? "log_module_param" : "NULL",
1102 has_init_comp
? "init_comp_type" : "NULL",
1103 has_start
? "start_ptc_function" : "NULL",
1104 has_control
? "module_control_part" : "NULL");
1106 // self checks for ASN.1 modules
1108 FATAL_ERROR("Module::generate_functions(): post_init function in ASN.1 module");
1110 FATAL_ERROR("Module::generate_functions(): set_param function in ASN.1 module");
1112 FATAL_ERROR("Module::generate_functions(): get_param function in ASN.1 module");
1114 FATAL_ERROR("Module::generate_functions(): log_param function in ASN.1 module");
1116 FATAL_ERROR("Module::generate_functions(): init_comp function in ASN.1 module");
1118 FATAL_ERROR("Module::generate_functions(): startable function in ASN.1 module");
1120 FATAL_ERROR("Module::generate_functions(): control part in ASN.1 module");
1122 output
->source
.global_vars
= mputstr(output
->source
.global_vars
, ");\n");
1123 // #include into the source file
1124 output
->source
.includes
= mputprintf(output
->source
.includes
,
1125 "#include \"%s.hh\"\n",
1126 duplicate_underscores
? module_name
: modid
->get_ttcnname().c_str());
1128 output
->source
.global_vars
= mputprintf(output
->source
.global_vars
,
1129 "\nstatic const RuntimeVersionChecker ver_checker("
1130 " current_runtime_version.requires_major_version_%d,\n"
1131 " current_runtime_version.requires_minor_version_%d,\n"
1132 " current_runtime_version.requires_patch_level_%d,"
1133 " current_runtime_version.requires_runtime_%d);\n",
1134 TTCN3_MAJOR
, TTCN3_MINOR
, TTCN3_PATCHLEVEL
, use_runtime_2
? 2 : 1
1137 output
->source
.global_vars
= mputprintf(output
->source
.global_vars
,
1138 "\nstatic const int effective_module_lines[] = { %s };\n" \
1139 "static const char *effective_module_functions[] = { %s };\n",
1140 effective_module_lines
? static_cast<const char *>(effective_module_lines
) : "",
1141 effective_module_functions
? static_cast<const char *>(effective_module_functions
) : "");
1145 void Module::generate_conversion_functions(output_struct
*output
)
1147 for (size_t i
= 0; i
< type_conv_v
.size(); i
++)
1149 ->gen_conv_func(&output
->source
.static_conversion_function_prototypes
,
1150 &output
->source
.static_conversion_function_bodies
,
1154 string
Module::add_literal(map
<string
, string
>& literals
, const string
& str
,
1157 if (literals
.has_key(str
)) return *literals
[str
];
1159 string
*literal
= new string(prefix
+Int2string(literals
.size()));
1160 literals
.add(str
, literal
);
1165 void Module::clear_literals(map
<string
, string
>& literals
)
1167 for (size_t i
= 0; i
< literals
.size(); i
++)
1168 delete literals
.get_nth_elem(i
);
1172 map
<string
, const char> Module::namespaces
;
1173 map
<string
, const char> Module::invented_prefixes
;
1174 size_t Module::default_namespace_attempt
= 0;
1175 size_t Module::replacement_for_empty_prefix
= (size_t)-1;
1177 Module::Module(moduletype_t p_mt
, Identifier
*p_modid
)
1178 : Scope(), moduletype(p_mt
), modid(p_modid
),
1179 imp_checked(false), gen_code(false), has_checksum(false),
1180 visible_mods(), module_checksum(),
1181 bs_literals(), bp_literals(), hs_literals(), hp_literals(), os_literals(),
1182 op_literals(), cs_literals(), us_literals(), pp_literals(), mp_literals(),
1183 oid_literals(), tmp_id_count(0),
1184 control_ns(p_mt
== MOD_ASN
? mcopystr("urn:oid:2.1.5.2.0.1") : NULL
),
1185 control_ns_prefix(p_mt
== MOD_ASN
? mcopystr("asn1") : NULL
),
1186 // only ASN.1 modules have default control namespace (X.693 amd1, 16.9)
1187 used_namespaces(), type_conv_v(), product_number(NULL
),
1188 suffix(0), release(UINT_MAX
), patch(UINT_MAX
), build(UINT_MAX
), extra(NULL
)
1191 FATAL_ERROR("NULL parameter: Common::Module::Module()");
1192 memset(module_checksum
, 0, sizeof(module_checksum
));
1193 set_scopeMacro_name(modid
->get_dispname());
1199 visible_mods
.clear();
1200 clear_literals(bs_literals
);
1201 clear_literals(bp_literals
);
1202 clear_literals(hs_literals
);
1203 clear_literals(hp_literals
);
1204 clear_literals(os_literals
);
1205 clear_literals(op_literals
);
1206 clear_literals(cs_literals
);
1207 clear_literals(pp_literals
);
1208 clear_literals(mp_literals
);
1209 for (size_t i
= 0; i
< us_literals
.size(); i
++)
1210 delete us_literals
.get_nth_elem(i
);
1211 us_literals
.clear();
1212 for (size_t i
= 0; i
< oid_literals
.size(); i
++)
1213 delete oid_literals
.get_nth_elem(i
);
1214 oid_literals
.clear();
1215 for (size_t i
= 0; i
< type_conv_v
.size(); i
++)
1216 delete type_conv_v
[i
];
1217 type_conv_v
.clear();
1219 Free(control_ns_prefix
);
1220 used_namespaces
.clear(); // all the values are NULL, no need to free
1221 // static members below; repeated clear()s are redundant but harmless
1223 invented_prefixes
.clear();
1224 Free(product_number
);
1228 Type
*Module::get_address_type()
1230 FATAL_ERROR("Common::Module::get_address_type()");
1234 string
Module::add_ustring_literal(const ustring
& ustr
)
1236 if (us_literals
.has_key(ustr
)) return *us_literals
[ustr
];
1238 string
*literal
= new string("us_" + Int2string(us_literals
.size()));
1239 us_literals
.add(ustr
, literal
);
1244 string
Module::add_objid_literal(const string
& oi_str
, const size_t nof_elems
)
1246 if(oid_literals
.has_key(oi_str
)) return oid_literals
[oi_str
]->oid_id
;
1248 OID_literal
*oi_struct
= new OID_literal
;
1249 oi_struct
->nof_elems
= nof_elems
;
1250 oi_struct
->oid_id
= "oi_" + Int2string(oid_literals
.size());
1251 oid_literals
.add(oi_str
, oi_struct
);
1252 return oi_struct
->oid_id
;
1256 void Module::add_type_conv(TypeConv
*p_conv
)
1258 if (p_conv
== NULL
) FATAL_ERROR("Module::add_type_conv()");
1259 Type
*p_from_type
= p_conv
->get_from_type();
1260 Type
*p_to_type
= p_conv
->get_to_type();
1261 if (!p_from_type
->is_structured_type()
1262 || !p_to_type
->is_structured_type())
1263 FATAL_ERROR("Module::add_type_conv()");
1264 if (p_from_type
== p_to_type
) {
1265 // Never add the same types.
1269 for (size_t i
= 0; i
< type_conv_v
.size(); i
++) {
1270 TypeConv
*conv
= type_conv_v
[i
];
1271 if (conv
->get_from_type() == p_from_type
1272 && conv
->get_to_type() == p_to_type
1273 && conv
->is_temp() == p_conv
->is_temp()) {
1274 // Same pair of types, both for values or templates. We're the
1275 // owners, deallocate.
1280 type_conv_v
.add(p_conv
);
1283 bool Module::needs_type_conv(Type
*p_from_type
, Type
*p_to_type
) const
1285 for (size_t i
= 0; i
< type_conv_v
.size(); i
++) {
1286 TypeConv
*conv
= type_conv_v
[i
];
1287 if (conv
->get_from_type() == p_from_type
1288 && conv
->get_to_type() == p_to_type
)
1294 void Module::chk_recursive(module_set_t
& checked_modules
)
1296 if (checked_modules
.has_key(this)) return;
1297 // this must be added to the set at the beginning
1298 // in order to deal with circular imports
1299 checked_modules
.add(this, 0);
1300 // check the imported modules first
1301 size_t nof_visible_mods
= visible_mods
.size();
1302 for (size_t i
= 0; i
< nof_visible_mods
; i
++) {
1303 Module
*m
= visible_mods
.get_nth_key(i
);
1304 if (m
!= this) m
->chk_recursive(checked_modules
);
1306 // then check the module itself
1307 chk(); // this is the only virtual call
1310 bool Module::is_visible(Module
*m
)
1312 collect_visible_mods();
1313 return visible_mods
.has_key(m
);
1316 void Module::get_visible_mods(module_set_t
& p_visible_mods
)
1318 if (visible_mods
.has_key(this)) {
1319 size_t nof_visible_mods
= visible_mods
.size();
1320 for (size_t i
= 0; i
< nof_visible_mods
; i
++) {
1321 Module
*m
= visible_mods
.get_nth_key(i
);
1322 if (!p_visible_mods
.has_key(m
)) p_visible_mods
.add(m
, 0);
1325 get_imported_mods(p_visible_mods
);
1329 void Module::write_checksum()
1331 fprintf(stderr
, "%-18s ", modid
->get_dispname().c_str());
1332 switch (moduletype
) {
1333 case MOD_TTCN
: fprintf(stderr
, "%-15s ", "TTCN-3"); break;
1334 case MOD_ASN
: fprintf(stderr
, "%-15s ", "ASN.1"); break;
1335 case MOD_UNKNOWN
: fprintf(stderr
, "%-15s ", "OTHER"); break;
1338 if (!has_checksum
) {
1339 fputc('\n', stderr
);
1343 size_t nof_checksum
= sizeof(module_checksum
);
1344 for (size_t i
= 0; i
< nof_checksum
; i
++) {
1345 fprintf(stderr
, "%02x", module_checksum
[i
]);
1348 if (release
<= 999999 && patch
< 30 && build
< 100) {
1349 char *product_identifier
=
1350 get_product_identifier(product_number
, suffix
, release
, patch
, build
, extra
);
1351 fprintf(stderr
, " %s", product_identifier
);
1352 Free(product_identifier
);
1355 fputc('\n', stderr
);
1358 char* Module::get_product_identifier(const char* product_number
,
1359 const unsigned int suffix
, unsigned int release
, unsigned int patch
,
1360 unsigned int build
, const char* extra
)
1362 expstring_t ret_val
= memptystr();
1363 if ( product_number
== NULL
1364 && suffix
== UINT_MAX
1365 && release
== UINT_MAX
1366 && patch
== UINT_MAX
1367 && build
== UINT_MAX
) {
1368 ret_val
= mputstr(ret_val
, "<RnXnn>");
1371 if (product_number
!= NULL
) {
1372 ret_val
= mputstr(ret_val
, product_number
);
1374 ret_val
= mputprintf(ret_val
, "/%d", suffix
);
1376 ret_val
= mputc(ret_val
, ' ');
1379 char* build_str
= buildstr(build
);
1380 ret_val
= mputprintf(ret_val
, "R%u%c%s%s", release
, eri(patch
), build_str
, extra
? extra
: "");
1385 void Module::collect_visible_mods()
1387 if (!visible_mods
.has_key(this)) {
1388 get_imported_mods(visible_mods
);
1389 if (!visible_mods
.has_key(this)) visible_mods
.add(this, 0);
1393 void Module::set_checksum(size_t checksum_len
,
1394 const unsigned char* checksum_ptr
)
1396 if (checksum_len
!= sizeof(module_checksum
))
1397 FATAL_ERROR("Module::set_checksum(): invalid length");
1398 memcpy(module_checksum
, checksum_ptr
, sizeof(module_checksum
));
1399 has_checksum
= true;
1402 void Module::set_controlns(char *ns
, char *prefix
)
1406 Free(control_ns_prefix
);
1407 control_ns_prefix
= prefix
;
1410 void Module::get_controlns(const char *&ns
, const char *&prefix
)
1413 prefix
= control_ns_prefix
;
1416 const size_t max_invented_prefixes
= 10000;
1417 void Module::add_namespace(const char *new_uri
, char *&new_prefix
)
1419 const bool prefix_is_empty
= new_prefix
&& !*new_prefix
;
1420 const string
key(new_prefix
? new_prefix
: "");
1421 if (new_prefix
&& !namespaces
.has_key(key
)) {
1422 namespaces
.add(key
, new_uri
);
1423 if (*new_prefix
== 0) { // first add of default namespace
1424 ++default_namespace_attempt
;
1426 return; // newly added
1428 else { // prefix already present (or we are required to invent one)
1430 const char *uri_value
= namespaces
[key
];
1431 if (!strcmp(uri_value
, new_uri
)) return; // same URI, same prefix: no-op
1434 // prefix already present but different URI,
1435 // or prefix is NULL (which means we must invent a prefix)
1437 if (new_prefix
&& *new_prefix
) {
1438 Free(new_prefix
); // prefix is not empty, discard it and start fresh
1439 new_prefix
= memptystr();
1442 const string
uri_key(new_uri
);
1443 if (invented_prefixes
.has_key(uri_key
)) {
1444 // we already made one up for this URI
1445 new_prefix
= mputstr(new_prefix
, invented_prefixes
[uri_key
]);
1446 return; // already there
1449 // make one up on the spot
1450 size_t iidx
= invented_prefixes
.size(); // "invented index"
1451 new_prefix
= mputprintf(new_prefix
, "tq%04lu", (unsigned long)iidx
++);
1452 string
made_up_prefix(new_prefix
);
1453 for (; iidx
< max_invented_prefixes
; ++iidx
) {
1454 if (namespaces
.has_key(made_up_prefix
)) {
1455 // Some pervert wrote an XSD with a namespace prefix like tq0007!
1456 // Make up another one in the same memory spot.
1457 sprintf(new_prefix
, "tq%04lu", (unsigned long)iidx
);
1458 made_up_prefix
= new_prefix
;
1463 if (iidx
>= max_invented_prefixes
) {
1464 Location loc
; // no particular location
1465 loc
.error("Internal limit: too many assigned prefixes");
1466 return; // not added
1468 invented_prefixes
.add(uri_key
, new_prefix
);
1469 namespaces
.add(made_up_prefix
, new_uri
);
1471 // Search for the newly added prefix and remember it.
1472 replacement_for_empty_prefix
= namespaces
.find_key(made_up_prefix
);
1474 if (prefix_is_empty
) {
1475 ++default_namespace_attempt
;
1477 return; // newly added
1482 static const string empty_prefix
;
1483 void Module::rename_default_namespace()
1485 if (default_namespace_attempt
< 2) return;
1486 // There was more than one default namespace. However, all but the first
1487 // are already renamed to tq%d.
1488 size_t di
= namespaces
.find_key(empty_prefix
); // keys are prefixes
1489 if (di
< namespaces
.size()) { // found it
1490 const char *last_remaining_def_namespace
= namespaces
.get_nth_elem(di
);
1491 // we can't change a key, we can only remove and re-add it
1492 namespaces
.erase(empty_prefix
);
1494 expstring_t empty_prefix_string
= NULL
; // force a made-up prefix
1495 add_namespace(last_remaining_def_namespace
, empty_prefix_string
);
1496 Free(empty_prefix_string
);
1498 else FATAL_ERROR("Module::rename_default_namespace");
1501 size_t Module::get_ns_index(const char *prefix
)
1503 size_t idx
= namespaces
.find_key(string(prefix
));
1504 if (idx
>= namespaces
.size()) { // not found
1505 // If the the caller asked for the empty prefix and it wasn't found
1506 // because it has been replaced, use the replacement.
1507 if (*prefix
== '\0' && replacement_for_empty_prefix
!= (size_t)-1) {
1508 idx
= replacement_for_empty_prefix
;
1510 else FATAL_ERROR("Module::get_ns_index()");
1513 // Remember that the index is used by this module
1514 if (!used_namespaces
.has_key(idx
)) {
1515 used_namespaces
.add(idx
, NULL
);
1520 string
Module::get_temporary_id()
1522 static const string
tmp_prefix("tmp_");
1523 return tmp_prefix
+ Int2string(tmp_id_count
++);
1526 void Module::generate_code(CodeGenHelper
& cgh
)
1529 nof_notupdated_files
+= 2;
1530 DEBUG(1, "Code not generated for module `%s'.",
1531 modid
->get_dispname().c_str());
1534 DEBUG(1, "Generating code for module `%s'.",
1535 modid
->get_dispname().c_str());
1537 // TODO: Always assume to have circular imports until
1538 // full program optimization is available,
1539 // this increases the size of the generated code,
1540 // but otherwise it is possible to create uncompilable code:
1541 // 1) let the project of module A and B refer to each other,
1542 // 2) A refers B, and compile A
1543 // 3) edit B to refer to A and compile it ...
1544 // As the code for A can not be rewritten the code will not compile
1545 cgh
.add_module(modid
->get_name(), modid
->get_ttcnname(),
1546 moduletype
== MOD_TTCN
, true);
1547 cgh
.set_current_module(modid
->get_ttcnname());
1549 // language specific parts (definitions, imports, etc.)
1550 //generate_code_internal(&target); <- needed to pass cgh
1551 generate_code_internal(cgh
);
1553 output_struct
* output
= cgh
.get_current_outputstruct();
1556 generate_literals(output
);
1557 // module level entry points
1558 generate_functions(output
);
1559 // type conversion functions for type compatibility
1560 generate_conversion_functions(output
);
1562 /* generate the initializer function for the TTCN-3 profiler
1563 * (this is done at the end of the code generation, to make sure all code
1564 * lines have been added to the profiler database) */
1565 if (is_file_profiled(get_filename())) {
1566 output
->source
.global_vars
= mputstr(output
->source
.global_vars
,
1567 "\n/* Initializing TTCN-3 profiler */\n"
1568 "void init_ttcn3_profiler()\n"
1570 char* function_name
= 0;
1572 while (get_profiler_code_line(get_filename(), &function_name
, &line_no
)) {
1573 output
->source
.global_vars
= mputprintf(output
->source
.global_vars
,
1574 " ttcn3_prof.create_line(ttcn3_prof.get_element(\"%s\"), %d);\n",
1575 get_filename(), line_no
);
1576 if (0 != function_name
) {
1577 output
->source
.global_vars
= mputprintf(output
->source
.global_vars
,
1578 " ttcn3_prof.create_function(ttcn3_prof.get_element(\"%s\"), %d, \"%s\");\n",
1579 get_filename(), line_no
, function_name
);
1582 output
->source
.global_vars
= mputstr(output
->source
.global_vars
, "}\n");
1585 generate the printing function for the types defined in this module
1586 and initialize the debugger with this module's global variables,
1587 component types and the components' variables */
1588 if (debugger_active
) {
1589 generate_debugger_functions(output
);
1590 generate_debugger_init(output
);
1594 void Module::dump(unsigned level
) const
1596 DEBUG(level
, "Module: %s", get_modid().get_dispname().c_str());
1599 // =================================
1600 // ===== Assignments
1601 // =================================
1603 Assignments
*Assignments::get_scope_asss()
1608 Assignment
*Assignments::get_ass_bySRef(Ref_simple
*p_ref
)
1610 if (!p_ref
|| !parent_scope
)
1611 FATAL_ERROR("NULL parameter: Common::Assignments::get_ass_bySRef()");
1612 if (!p_ref
->get_modid()) {
1613 const Identifier
*id
= p_ref
->get_id();
1614 if (id
&& has_local_ass_withId(*id
)) return get_local_ass_byId(*id
);
1616 return parent_scope
->get_ass_bySRef(p_ref
);
1619 bool Assignments::has_ass_withId(const Identifier
& p_id
)
1621 if (has_local_ass_withId(p_id
)) return true;
1622 else if (parent_scope
) return parent_scope
->has_ass_withId(p_id
);
1626 // =================================
1628 // =================================
1630 Assignment::Assignment(asstype_t p_asstype
, Identifier
*p_id
)
1631 : asstype(p_asstype
), id(p_id
), my_scope(0), checked(false),
1632 visibilitytype(PUBLIC
)
1634 if (!id
) FATAL_ERROR("Assignment::Assignment(): NULL parameter");
1637 Assignment::Assignment(const Assignment
& p
)
1638 : Node(p
), Location(p
), asstype(p
.asstype
), id(p
.id
->clone()), my_scope(0),
1639 checked(false), visibilitytype(p
.visibilitytype
)
1644 Assignment::~Assignment()
1649 Assignment::asstype_t
Assignment::get_asstype() const
1654 const char *Assignment::get_assname() const
1656 switch (get_asstype()) {
1660 if (my_scope
&& my_scope
->get_scope_mod()->get_moduletype() ==
1661 Module::MOD_ASN
) return "value";
1662 else return "constant";
1664 return "erroneous assignment";
1666 return "information object class";
1668 return "information object";
1670 return "information object set";
1674 return "external constant";
1676 return "module parameter";
1677 case A_MODULEPAR_TEMP
:
1678 return "template module parameter";
1683 case A_VAR_TEMPLATE
:
1684 return "template variable";
1690 case A_FUNCTION_RVAL
:
1691 case A_FUNCTION_RTEMP
:
1693 case A_EXT_FUNCTION
:
1694 case A_EXT_FUNCTION_RVAL
:
1695 case A_EXT_FUNCTION_RTEMP
:
1696 return "external function";
1703 return "value parameter";
1705 return "`out' value parameter";
1706 case A_PAR_VAL_INOUT
:
1707 return "`inout' value parameter";
1708 case A_PAR_TEMPL_IN
:
1709 return "template parameter";
1710 case A_PAR_TEMPL_OUT
:
1711 return "`out' template parameter";
1712 case A_PAR_TEMPL_INOUT
:
1713 return "`inout' template parameter";
1715 return "timer parameter";
1717 return "port parameter";
1723 string
Assignment::get_description()
1725 string
ret_val(get_assname());
1731 case A_PAR_VAL_INOUT
:
1732 case A_PAR_TEMPL_IN
:
1733 case A_PAR_TEMPL_OUT
:
1734 case A_PAR_TEMPL_INOUT
:
1737 // parameter is identified using its id
1738 ret_val
+= id
->get_dispname();
1743 case A_VAR_TEMPLATE
:
1745 // these can be both local and global
1746 if (is_local()) ret_val
+= id
->get_dispname();
1747 else ret_val
+= get_fullname();
1750 // the rest is always global
1751 ret_val
+= get_fullname();
1757 void Assignment::set_my_scope(Scope
*p_scope
)
1762 bool Assignment::is_local() const
1767 Setting
*Assignment::get_Setting()
1769 FATAL_ERROR("Common::Assignment::get_Setting()");
1773 Type
*Assignment::get_Type()
1775 FATAL_ERROR("Common::Assignment::get_Type()");
1779 Value
*Assignment::get_Value()
1781 FATAL_ERROR("Common::Assignment::get_Value()");
1785 Ttcn::Template
*Assignment::get_Template()
1787 FATAL_ERROR("Common::Assignment::get_Template()");
1791 bool Assignment::get_lazy_eval() const
1793 FATAL_ERROR("Common::Assignment::get_lazy_eval()");
1797 Ttcn::FormalParList
*Assignment::get_FormalParList()
1802 Ttcn::ArrayDimensions
*Assignment::get_Dimensions()
1807 Type
*Assignment::get_RunsOnType()
1812 void Assignment::chk_ttcn_id()
1814 if(!my_scope
) return;
1815 if(!get_id().get_has_valid(Identifier::ID_TTCN
)
1816 && my_scope
->get_parent_scope()==my_scope
->get_scope_mod()
1817 // <internal> or <error> ...
1818 && my_scope
->get_scope_mod()->get_modid().get_dispname()[0]!='<')
1819 warning("The identifier `%s' is not reachable from TTCN-3",
1820 get_id().get_dispname().c_str());
1823 // *this is the (var/const/modulepar/etc.) definition we want to access.
1824 // p_scope is the location from where we want to reach the definition.
1825 string
Assignment::get_genname_from_scope(Scope
*p_scope
,
1826 const char *p_prefix
)
1828 if (!p_scope
|| !my_scope
)
1829 FATAL_ERROR("Assignment::get_genname_from_scope()");
1832 Module
*my_mod
= my_scope
->get_scope_mod_gen();
1833 if ((my_mod
!= p_scope
->get_scope_mod_gen()) &&
1834 !Asn::Assignments::is_spec_asss(my_mod
)) {
1835 // when the definition is referred from another module
1836 // the reference shall be qualified with the namespace of my module
1837 ret_val
= my_mod
->get_modid().get_name();
1840 if (p_prefix
) ret_val
+= p_prefix
;
1841 ret_val
+= get_genname();
1842 // add the cast to real type if its a lazy formal paramter
1846 case A_PAR_TEMPL_IN
:
1847 if (get_lazy_eval() && p_prefix
==NULL
) {
1848 Type
* type
= get_Type();
1849 string type_genname
= (asstype
==A_PAR_TEMPL_IN
) ? type
->get_genname_template(p_scope
) : type
->get_genname_value(p_scope
);
1850 ret_val
= string("((") + type_genname
+ string("&)") + ret_val
+ string(")");
1860 const char *Assignment::get_module_object_name()
1862 if (!my_scope
) FATAL_ERROR("Assignment::get_module_object_name()");
1863 return "module_object";
1866 void Assignment::use_as_lvalue(const Location
&)
1868 FATAL_ERROR("Common::Assignment::use_as_lvalue()");
1871 void Assignment::generate_code(output_struct
*, bool)
1875 void Assignment::generate_code(CodeGenHelper
&)
1879 void Assignment::dump(unsigned level
) const
1881 DEBUG(level
, "Assignment: %s (%d)",
1882 id
->get_dispname().c_str(), asstype
);
1885 Ttcn::Group
* Assignment::get_parent_group()
1890 } // namespace Common