added include for atoi
[deliverable/titan.core.git] / compiler2 / CodeGenHelper.cc
CommitLineData
d44e3c4f 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
7 *
8 * Contributors:
9 * Balasko, Jeno
10 * Baranyi, Botond
11 * Raduly, Csaba
14e21cff 12 * Szabo, Bence Janos
d44e3c4f 13 * Zalanyi, Balazs Andor
14 *
15 ******************************************************************************/
970ed795
EL
16#include "CodeGenHelper.hh"
17#include "Code.hh"
18#include "error.h"
19#include "main.hh"
20#include <cstdio>
21#include <cstring>
faf9c345 22#include <stdlib.h>
970ed795
EL
23
24namespace Common {
14e21cff 25
970ed795
EL
26CodeGenHelper* CodeGenHelper::instance = 0;
27
28CodeGenHelper::generated_output_t::generated_output_t() :
29 is_module(false),
30 is_ttcn(true),
31 has_circular_import(false)
32{
33 Code::init_output(&os);
34}
35
36CodeGenHelper::generated_output_t::~generated_output_t() {
37 Code::free_output(&os);
38}
39
40// from Type.cc
41const char* const CodeGenHelper::typetypemap[] = {
42 "", /**< undefined */
43 "", /**< erroneous (e.g. nonexistent reference) */
44 "", /**< null (ASN.1) */
45 "", /**< boolean */
46 "", /**< integer */
47 "", /**< integer / ASN */
48 "", /**< real/float */
49 "", /**< enumerated / ASN */
50 "", /**< enumerated / TTCN */
51 "", /**< bitstring */
52 "", /**< bitstring */
53 "", /**< hexstring (TTCN-3) */
54 "", /**< octetstring */
55 "", /**< charstring (TTCN-3) */
56 "", /**< universal charstring (TTCN-3) */
57 "", /**< UTF8String (ASN.1) */
58 "", /**< NumericString (ASN.1) */
59 "", /**< PrintableString (ASN.1) */
60 "", /**< TeletexString (ASN.1) */
61 "", /**< VideotexString (ASN.1) */
62 "", /**< IA5String (ASN.1) */
63 "", /**< GraphicString (ASN.1) */
64 "", /**< VisibleString (ASN.1) */
65 "", /**< GeneralString (ASN.1) */
66 "", /**< UniversalString (ASN.1) */
67 "", /**< BMPString (ASN.1) */
68 "", /**< UnrestrictedCharacterString (ASN.1) */
69 "", /**< UTCTime (ASN.1) */
70 "", /**< GeneralizedTime (ASN.1) */
71 "", /** Object descriptor, a kind of string (ASN.1) */
72 "", /**< object identifier */
73 "", /**< relative OID (ASN.1) */
74 "_union", /**< choice /ASN, uses u.secho */
75 "_union", /**< union /TTCN, uses u.secho */
76 "_seqof", /**< sequence (record) of */
77 "_setof", /**< set of */
78 "_seq", /**< sequence /ASN, uses u.secho */
79 "_seq", /**< record /TTCN, uses u.secho */
80 "_set", /**< set /ASN, uses u.secho */
81 "_set", /**< set /TTCN, uses u.secho */
82 "", /**< ObjectClassFieldType (ASN.1) */
83 "", /**< open type (ASN.1) */
84 "", /**< ANY (deprecated ASN.1) */
85 "", /**< %EXTERNAL (ASN.1) */
86 "", /**< EMBEDDED PDV (ASN.1) */
87 "", /**< referenced */
88 "", /**< special referenced (by pointer, not by name) */
89 "", /**< selection type (ASN.1) */
90 "", /**< verdict type (TTCN-3) */
91 "", /**< port type (TTCN-3) */
92 "", /**< component type (TTCN-3) */
93 "", /**< address type (TTCN-3) */
94 "", /**< default type (TTCN-3) */
95 "", /**< array (TTCN-3), uses u.array */
96 "", /**< signature (TTCN-3) */
97 "", /**< function reference (TTCN-3) */
98 "", /**< altstep reference (TTCN-3) */
99 "", /**< testcase reference (TTCN-3) */
100 "", /**< anytype (TTCN-3) */
101 0
102};
103
104CodeGenHelper::CodeGenHelper() :
14e21cff 105 split_mode(SPLIT_NONE),
106 slice_num(1)
970ed795
EL
107{
108 if (instance != 0)
109 FATAL_ERROR("Attempted to create a second code generator.");
110 instance = this;
111}
112
113CodeGenHelper& CodeGenHelper::GetInstance() {
114 if (instance == 0)
115 FATAL_ERROR("Trying to access to the already destroyed code generator.");
116 return *instance;
117}
118
119void CodeGenHelper::set_split_mode(split_type st) {
120 split_mode = st;
14e21cff 121
122 if (split_mode == SPLIT_TO_SLICES) {
123 split_to_slices = true;
124 } else {
125 split_to_slices = false;
126 }
970ed795
EL
127}
128
129bool CodeGenHelper::set_split_mode(const char* type) {
14e21cff 130 int n;
131 if (strcmp(type, "none") == 0) {
970ed795 132 split_mode = SPLIT_NONE;
14e21cff 133 split_to_slices = false;
134 } else if (strcmp(type, "type") == 0) {
970ed795 135 split_mode = SPLIT_BY_KIND;
14e21cff 136 split_to_slices = false;
137 } else if ((n = atoi(type))) {
138 size_t length = strlen(type);
139 for (int i=0;i<length; i++) {
140 if (!isdigit(type[i])) {
141 ERROR("The number argument of -U must be a valid number.");
142 break;
143 }
144 }
145 split_mode = SPLIT_TO_SLICES;
146 if (n < 1 || n > 999999) {
147 ERROR("The number argument of -U must be between 1 and 999999.");
148 return false;
149 }
150 slice_num = n;
151 split_to_slices = slice_num > 1; // slice_num == 1 has no effect
152 } else
970ed795
EL
153 return false;
154 return true;
155}
156
157CodeGenHelper::split_type CodeGenHelper::get_split_mode() const {
158 return split_mode;
159}
160
161void CodeGenHelper::add_module(const string& name, const string& dispname,
162 bool is_ttcn, bool has_circular_import) {
163 generated_output_t* go = new generated_output_t;
164 go->filename.clear();
165 go->modulename = name;
166 go->module_dispname = dispname;
167 go->is_module = true;
168 go->is_ttcn = is_ttcn;
169 go->has_circular_import = has_circular_import;
170 generated_code.add(dispname, go);
171 module_names_t* mod_names = new module_names_t;
172 mod_names->name = name;
173 mod_names->dispname = dispname;
174 modules.add(mod_names);
175}
176
177output_struct* CodeGenHelper::get_outputstruct(const string& name) {
178 return &generated_code[name]->os;
179}
180
181void CodeGenHelper::set_current_module(const string& name) {
182 current_module = name;
183}
184
14e21cff 185void CodeGenHelper::update_intervals(output_struct* const output) {
186 if(instance->split_mode != SPLIT_TO_SLICES) return;
187
188 size_t tmp;
189
190 // 1. check if some characters are added to the charstring
191 // 2. increment size variable
192 // 3. if size is bigger than the array's size, then double the array size
193 // 4. store new end position
194
195 // class_defs are not counted as they will be in the header
196 tmp = mstrlen(output->source.function_bodies);
197 if (output->intervals.function_bodies[output->intervals.function_bodies_size] < tmp) {
198 output->intervals.function_bodies_size++;
199 if (output->intervals.function_bodies_size > output->intervals.function_bodies_max_size) {
200 output->intervals.function_bodies_max_size *= 2;
201 output->intervals.function_bodies = (size_t*)Realloc(output->intervals.function_bodies, output->intervals.function_bodies_max_size * sizeof(size_t));
202 }
203 output->intervals.function_bodies[output->intervals.function_bodies_size] = tmp;
204 }
205 tmp = mstrlen(output->source.methods);
206 if (output->intervals.methods[output->intervals.methods_size] < tmp) {
207 output->intervals.methods_size++;
208 if (output->intervals.methods_size > output->intervals.methods_max_size) {
209 output->intervals.methods_max_size *= 2;
210 output->intervals.methods = (size_t*)Realloc(output->intervals.methods, output->intervals.methods_max_size * sizeof(size_t));
211 }
212 output->intervals.methods[output->intervals.methods_size] = tmp;
213 }
214 tmp = mstrlen(output->source.static_conversion_function_bodies);
215 if (output->intervals.static_conversion_function_bodies[output->intervals.static_conversion_function_bodies_size] < tmp) {
216 output->intervals.static_conversion_function_bodies_size++;
217 if (output->intervals.static_conversion_function_bodies_size > output->intervals.static_conversion_function_bodies_max_size) {
218 output->intervals.static_conversion_function_bodies_max_size *= 2;
219 output->intervals.static_conversion_function_bodies = (size_t*)Realloc(output->intervals.static_conversion_function_bodies, output->intervals.static_conversion_function_bodies_max_size * sizeof(size_t));
220 }
221 output->intervals.static_conversion_function_bodies[output->intervals.static_conversion_function_bodies_size] = tmp;
222 }
223 tmp = mstrlen(output->source.static_function_bodies);
224 if (output->intervals.static_function_bodies[output->intervals.static_function_bodies_size] < tmp) {
225 output->intervals.static_function_bodies_size++;
226 if (output->intervals.static_function_bodies_size > output->intervals.static_function_bodies_max_size) {
227 output->intervals.static_function_bodies_max_size *= 2;
228 output->intervals.static_function_bodies = (size_t*)Realloc(output->intervals.static_function_bodies, output->intervals.static_function_bodies_max_size * sizeof(size_t));
229 }
230 output->intervals.static_function_bodies[output->intervals.static_function_bodies_size] = tmp;
231 }
232}
233//Advised to call update_intervals before this
234size_t CodeGenHelper::size_of_sources(output_struct * const output) {
235 size_t size = 0;
236 // Calculate global var and string literals size
237 output->intervals.pre_things_size = mstrlen(output->source.global_vars) + mstrlen(output->source.string_literals);
238
239 // Class_defs, static_conversion_function_prototypes, static_function_prototypes are in the header,
240 // and includes are not counted
241 size = output->intervals.pre_things_size +
242 output->intervals.function_bodies[output->intervals.function_bodies_size] +
243 output->intervals.methods[output->intervals.methods_size] +
244 output->intervals.static_conversion_function_bodies[output->intervals.static_conversion_function_bodies_size] +
245 output->intervals.static_function_bodies[output->intervals.static_function_bodies_size];
246 return size;
247}
248
249size_t CodeGenHelper::get_next_chunk_pos(const output_struct * const from, output_struct * const to, const size_t base_pos, const size_t chunk_size) {
250 size_t pos = 0; // Holds the position from the beginning
251
252 pos += from->intervals.pre_things_size;
253
254 if (pos > base_pos) {
255 to->source.global_vars = mputstr(to->source.global_vars, from->source.global_vars);
256 to->source.string_literals = mputstr(to->source.string_literals, from->source.string_literals);
257 }
258
259 get_chunk_from_poslist(from->source.methods, to->source.methods, from->intervals.methods, from->intervals.methods_size, base_pos, chunk_size, pos);
260 get_chunk_from_poslist(from->source.function_bodies, to->source.function_bodies, from->intervals.function_bodies, from->intervals.function_bodies_size, base_pos, chunk_size, pos);
261 get_chunk_from_poslist(from->source.static_function_bodies, to->source.static_function_bodies, from->intervals.static_function_bodies, from->intervals.static_function_bodies_size, base_pos, chunk_size, pos);
262 get_chunk_from_poslist(from->source.static_conversion_function_bodies, to->source.static_conversion_function_bodies, from->intervals.static_conversion_function_bodies, from->intervals.static_conversion_function_bodies_size, base_pos, chunk_size, pos);
263
264 return pos;
265}
266//if from null return.
267void CodeGenHelper::get_chunk_from_poslist(const char* from, char *& to, const size_t interval_array[], const size_t interval_array_size, const size_t base_pos, const size_t chunk_size, size_t& pos) {
268 if (from == NULL) return;
269 // If we have enough to form a chunk
270
271 // pos is unsigned so it can't be negative
272 if (pos > base_pos && pos - base_pos >= chunk_size) return;
273
274 size_t tmp = pos;
275
276 pos += interval_array[interval_array_size];
277
278 if (pos > base_pos) { // If we haven't finished with this interval_array
279 if (pos - base_pos >= chunk_size) { // It is a good chunk, but make it more precise because it may be too big
280 int ind = 0;
281 for (int i = 0; i <= interval_array_size; i++) {
282 if (tmp + interval_array[i] <= base_pos) { // Find the pos where we left off
283 ind = i;
284 } else if (tmp + interval_array[i] - base_pos >= chunk_size) {
285 // Found the first optimal position that is a good chunk
286 to = mputstrn(to, from + interval_array[ind], interval_array[i] - interval_array[ind]);
287 pos = tmp + interval_array[i];
288 return;
289 }
290 }
291 } else { // We can't form a new chunk from the remaining characters
292 int ind = 0;
293 for (int i = 0; i <= interval_array_size; i++) {
294 if (tmp + interval_array[i] <= base_pos) {
295 ind = i;
296 } else {
297 break;
298 }
299 }
300 // Put the remaining characters
301 to = mputstrn(to, from + interval_array[ind], interval_array[interval_array_size] - interval_array[ind]);
302 pos = tmp + interval_array[interval_array_size];
303 }
304 }
305}
306
970ed795
EL
307output_struct* CodeGenHelper::get_outputstruct(Ttcn::Definition* def) {
308 string key = get_key(*def);
309 const string& new_name = current_module + key;
310 if (!generated_code.has_key(new_name)) {
311 generated_output_t* go = new generated_output_t;
312 go->filename = key;
313 go->modulename = generated_code[current_module]->modulename;
314 go->module_dispname = generated_code[current_module]->module_dispname;
315 generated_code.add(new_name, go);
316 go->os.source.includes = mprintf("\n#include \"%s.hh\"\n"
317 , current_module.c_str());
318 }
319 return &generated_code[new_name]->os;
320}
321
322output_struct* CodeGenHelper::get_outputstruct(Type* type) {
323 string key = get_key(*type);
324 const string& new_name = current_module + key;
325 if (!generated_code.has_key(new_name)) {
326 generated_output_t* go = new generated_output_t;
327 go->filename = key;
328 go->modulename = generated_code[current_module]->modulename;
329 go->module_dispname = generated_code[current_module]->module_dispname;
330 generated_code.add(new_name, go);
331 go->os.source.includes = mprintf("\n#include \"%s.hh\"\n"
332 , current_module.c_str());
333 }
334 return &generated_code[new_name]->os;
335}
336
337output_struct* CodeGenHelper::get_current_outputstruct() {
338 return &generated_code[current_module]->os;
339}
340
341void CodeGenHelper::transfer_value(char* &dst, char* &src) {
342 dst = mputstr(dst, src);
343 Free(src);
344 src = 0;
345}
346
347void CodeGenHelper::finalize_generation(Type* type) {
348 string key = get_key(*type);
349 if (key.empty()) return;
350
351 output_struct& dst = *get_current_outputstruct();
352 output_struct& src = *get_outputstruct(current_module + key);
353 // key is not empty so these can never be the same
354
355 transfer_value(dst.header.includes, src.header.includes);
356 transfer_value(dst.header.class_decls, src.header.class_decls);
357 transfer_value(dst.header.typedefs, src.header.typedefs);
358 transfer_value(dst.header.class_defs, src.header.class_defs);
359 transfer_value(dst.header.function_prototypes, src.header.function_prototypes);
360 transfer_value(dst.header.global_vars, src.header.global_vars);
361 transfer_value(dst.header.testport_includes, src.header.testport_includes);
362
363 transfer_value(dst.source.global_vars, src.source.global_vars);
364
365 transfer_value(dst.functions.pre_init, src.functions.pre_init);
366 transfer_value(dst.functions.post_init, src.functions.post_init);
367
368 transfer_value(dst.functions.set_param, src.functions.set_param);
3abe9331 369 transfer_value(dst.functions.get_param, src.functions.get_param);
970ed795
EL
370 transfer_value(dst.functions.log_param, src.functions.log_param);
371 transfer_value(dst.functions.init_comp, src.functions.init_comp);
372 transfer_value(dst.functions.start, src.functions.start);
373 transfer_value(dst.functions.control, src.functions.control);
374}
375
376string CodeGenHelper::get_key(Ttcn::Definition& def) const {
377 string retval;
378 switch (split_mode) {
379 case SPLIT_NONE:
380 // returns the current module
381 break;
382 case SPLIT_BY_KIND:
383 break;
384 case SPLIT_BY_NAME:
385 retval += "_" + def.get_id().get_name();
386 break;
387 case SPLIT_BY_HEURISTICS:
388 break;
14e21cff 389 case SPLIT_TO_SLICES:
390 break;
970ed795
EL
391 }
392 return retval;
393}
394
395string CodeGenHelper::get_key(Type& type) const {
396 string retval;
397 switch (split_mode) {
398 case SPLIT_NONE:
399 break;
400 case SPLIT_BY_KIND: {
401 Type::typetype_t tt = type.get_typetype();
402 switch(tt) {
403 case Type::T_CHOICE_A:
404 case Type::T_CHOICE_T:
405 case Type::T_SEQOF:
406 case Type::T_SETOF:
407 case Type::T_SEQ_A:
408 case Type::T_SEQ_T:
409 case Type::T_SET_A:
410 case Type::T_SET_T:
411 retval += typetypemap[(int)tt];
412 break;
413 default:
414 // put it into the module (no suffix)
415 break;
416 }
417 break; }
418 case SPLIT_BY_NAME:
419 break;
420 case SPLIT_BY_HEURISTICS:
421 break;
14e21cff 422 case SPLIT_TO_SLICES:
423 break;
970ed795
EL
424 }
425 return retval;
426}
427
428void CodeGenHelper::write_output() {
429 size_t i, j;
430 if (split_mode == SPLIT_BY_KIND) {
431 // Create empty files to have a fix set of files to compile
432 string fname;
433 for (j = 0; j < modules.size(); j++) {
434 for (i = 0; typetypemap[i]; i++) {
435 fname = modules[j]->dispname + typetypemap[i];
436 if (!generated_code.has_key(fname)) {
437 generated_output_t* go = new generated_output_t;
438 go->filename = typetypemap[i];
439 go->modulename = modules[j]->name;
440 go->module_dispname = modules[j]->dispname;
441 go->os.source.includes = mcopystr(
14e21cff 442 "\n//This file is intentionally empty."
970ed795
EL
443 "\n#include <version.h>\n");
444 generated_code.add(fname, go);
445 }
446 }
447 }
14e21cff 448 } else if (split_mode == SPLIT_TO_SLICES && slice_num > 0) {
449 // The strategy is the following:
450 // Goal: Get files with equal size
451 // Get the longest file's length and divide it by slice_num (chunk_size)
452 // We split every file to chunk_size sized chunks
453 size_t max = 0;
454 // Calculate maximum character length
455 for (j = 0; j < generated_code.size(); j++) {
456 update_intervals(&generated_code.get_nth_elem(j)->os);
457 size_t num_of_chars = size_of_sources(&generated_code.get_nth_elem(j)->os);
458 if (max < num_of_chars) {
459 max = num_of_chars;
460 }
461 }
462 // Calculate ideal chunk size
463 size_t chunk_size = max / slice_num;
464 string fname;
465 for (j = 0; j < modules.size(); j++) {
466 generated_output_t *output = generated_code[modules[j]->dispname];
467
468 // Just to be sure that everything is in the right place
469 update_intervals(&output->os);
470
471 // Move static function prototypes to header (no longer static)
472 output->os.header.function_prototypes = mputstr(output->os.header.function_prototypes, output->os.source.static_function_prototypes);
473 Free(output->os.source.static_function_prototypes);
474 output->os.source.static_function_prototypes = NULL;
475
476 output->os.header.function_prototypes = mputstr(output->os.header.function_prototypes, output->os.source.static_conversion_function_prototypes);
477 Free(output->os.source.static_conversion_function_prototypes);
478 output->os.source.static_conversion_function_prototypes = NULL;
479
480 // Move internal class definitions to the header
481 output->os.header.class_defs = mputstr(output->os.header.class_defs, output->os.source.class_defs);
482 Free(output->os.source.class_defs);
483 output->os.source.class_defs = NULL;
484
485 update_intervals(&output->os);
486 size_t num_of_chars = size_of_sources(&output->os);
487 char buffer[13]= ""; // Max is 999999 should be enough (checked in main.cc) | 6 digit + 2 underscore + part
488 // If we need to split
489 if (num_of_chars >= chunk_size) {
490 size_t base_pos = 0;
491 for (unsigned int i = 0; i < slice_num; i++) {
492 if (i == 0) { // The first slice has the module's name
493 fname = output->module_dispname;
494 } else {
495 sprintf(buffer, "_part_%d", (int)i);
496 fname = output->module_dispname + "_" + buffer;
497 }
498 if (i == 0 || !generated_code.has_key(fname)) {
499 generated_output_t* go = new generated_output_t;
500 go->filename = buffer;
501 go->modulename = output->modulename;
502 go->module_dispname = output->module_dispname;
503 size_t act_pos = get_next_chunk_pos(&output->os, &go->os, base_pos, chunk_size);
504 // True if the file is not empty
505 if (act_pos > base_pos) {
506 go->os.source.includes = mputstr(go->os.source.includes, output->os.source.includes);
507 } else {
508 go->os.source.includes = mcopystr(
509 "\n//This file is intentionally empty."
510 "\n#include <version.h>\n");
511 }
512 // First slice: copy header and other properties and replace the original output struct
513 if (i == 0) {
514 go->has_circular_import = output->has_circular_import;
515 go->is_module = output->is_module;
516 go->is_ttcn = output->is_ttcn;
517 go->os.header.class_decls = mputstr(go->os.header.class_decls, output->os.header.class_decls);
518 go->os.header.class_defs = mputstr(go->os.header.class_defs, output->os.header.class_defs);
519 go->os.header.function_prototypes = mputstr(go->os.header.function_prototypes, output->os.header.function_prototypes);
520 go->os.header.global_vars = mputstr(go->os.header.global_vars, output->os.header.global_vars);
521 go->os.header.includes = mputstr(go->os.header.includes, output->os.header.includes);
522 go->os.header.testport_includes = mputstr(go->os.header.testport_includes, output->os.header.testport_includes);
523 go->os.header.typedefs = mputstr(go->os.header.typedefs, output->os.header.typedefs);
524 generated_code[modules[j]->dispname] = go;
525 } else {
526 generated_code.add(fname, go);
527 }
528 base_pos = act_pos;
529 } else {
530 // TODO: error handling: there is a module which has the same name as the
531 // numbered splitted file. splitting by type does not have this error
532 // handling so don't we
533 }
534 }
535 // Extra safety. If something is missing after the splitting, put the remaining
536 // things to the last file. (Should never happen)
537 if (base_pos < num_of_chars) {
538 get_next_chunk_pos(&output->os, &generated_code[fname]->os, base_pos, num_of_chars);
539 }
540 delete output;
541 } else {
542 // Create empty files.
543 for (i = 1; i < slice_num; i++) {
544 sprintf(buffer, "_part_%d", (int)i);
545 fname = output->module_dispname + "_" + buffer;
546 if (!generated_code.has_key(fname)) {
547 generated_output_t* go = new generated_output_t;
548 go->filename = buffer;
549 go->modulename = modules[j]->name;
550 go->module_dispname = modules[j]->dispname;
551 go->os.source.includes = mcopystr(
552 "\n//This file is intentionally empty."
553 "\n#include <version.h>\n");
554 generated_code.add(fname, go);
555 }
556 }
557 }
558 }
970ed795
EL
559 }
560 generated_output_t* go;
561 for (i = 0; i < generated_code.size(); i++) {
562 go = generated_code.get_nth_elem(i);
563 ::write_output(&go->os, go->modulename.c_str(), go->module_dispname.c_str(),
564 go->filename.c_str(), go->is_ttcn, go->has_circular_import, go->is_module);
565 }
566}
567
568CodeGenHelper::~CodeGenHelper() {
569 size_t i;
570 for (i = 0; i < generated_code.size(); i++)
571 delete generated_code.get_nth_elem(i);
572 generated_code.clear();
573 for (i = 0; i < modules.size(); i++)
574 delete modules[i];
575 modules.clear();
576 instance = 0;
577}
578
579}
This page took 0.068007 seconds and 5 git commands to generate.