* Balasko, Jeno
* Baranyi, Botond
* Raduly, Csaba
+ * Szabo, Bence Janos
* Zalanyi, Balazs Andor
*
******************************************************************************/
#include <cstring>
namespace Common {
-
+
CodeGenHelper* CodeGenHelper::instance = 0;
CodeGenHelper::generated_output_t::generated_output_t() :
};
CodeGenHelper::CodeGenHelper() :
- split_mode(SPLIT_NONE)
+ split_mode(SPLIT_NONE),
+ slice_num(1)
{
if (instance != 0)
FATAL_ERROR("Attempted to create a second code generator.");
void CodeGenHelper::set_split_mode(split_type st) {
split_mode = st;
+
+ if (split_mode == SPLIT_TO_SLICES) {
+ split_to_slices = true;
+ } else {
+ split_to_slices = false;
+ }
}
bool CodeGenHelper::set_split_mode(const char* type) {
- if (strcmp(type, "none") == 0)
+ int n;
+ if (strcmp(type, "none") == 0) {
split_mode = SPLIT_NONE;
- else if (strcmp(type, "type") == 0)
+ split_to_slices = false;
+ } else if (strcmp(type, "type") == 0) {
split_mode = SPLIT_BY_KIND;
- else
+ split_to_slices = false;
+ } else if ((n = atoi(type))) {
+ size_t length = strlen(type);
+ for (int i=0;i<length; i++) {
+ if (!isdigit(type[i])) {
+ ERROR("The number argument of -U must be a valid number.");
+ break;
+ }
+ }
+ split_mode = SPLIT_TO_SLICES;
+ if (n < 1 || n > 999999) {
+ ERROR("The number argument of -U must be between 1 and 999999.");
+ return false;
+ }
+ slice_num = n;
+ split_to_slices = slice_num > 1; // slice_num == 1 has no effect
+ } else
return false;
return true;
}
current_module = name;
}
+void CodeGenHelper::update_intervals(output_struct* const output) {
+ if(instance->split_mode != SPLIT_TO_SLICES) return;
+
+ size_t tmp;
+
+ // 1. check if some characters are added to the charstring
+ // 2. increment size variable
+ // 3. if size is bigger than the array's size, then double the array size
+ // 4. store new end position
+
+ // class_defs are not counted as they will be in the header
+ tmp = mstrlen(output->source.function_bodies);
+ if (output->intervals.function_bodies[output->intervals.function_bodies_size] < tmp) {
+ output->intervals.function_bodies_size++;
+ if (output->intervals.function_bodies_size > output->intervals.function_bodies_max_size) {
+ output->intervals.function_bodies_max_size *= 2;
+ output->intervals.function_bodies = (size_t*)Realloc(output->intervals.function_bodies, output->intervals.function_bodies_max_size * sizeof(size_t));
+ }
+ output->intervals.function_bodies[output->intervals.function_bodies_size] = tmp;
+ }
+ tmp = mstrlen(output->source.methods);
+ if (output->intervals.methods[output->intervals.methods_size] < tmp) {
+ output->intervals.methods_size++;
+ if (output->intervals.methods_size > output->intervals.methods_max_size) {
+ output->intervals.methods_max_size *= 2;
+ output->intervals.methods = (size_t*)Realloc(output->intervals.methods, output->intervals.methods_max_size * sizeof(size_t));
+ }
+ output->intervals.methods[output->intervals.methods_size] = tmp;
+ }
+ tmp = mstrlen(output->source.static_conversion_function_bodies);
+ if (output->intervals.static_conversion_function_bodies[output->intervals.static_conversion_function_bodies_size] < tmp) {
+ output->intervals.static_conversion_function_bodies_size++;
+ if (output->intervals.static_conversion_function_bodies_size > output->intervals.static_conversion_function_bodies_max_size) {
+ output->intervals.static_conversion_function_bodies_max_size *= 2;
+ 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));
+ }
+ output->intervals.static_conversion_function_bodies[output->intervals.static_conversion_function_bodies_size] = tmp;
+ }
+ tmp = mstrlen(output->source.static_function_bodies);
+ if (output->intervals.static_function_bodies[output->intervals.static_function_bodies_size] < tmp) {
+ output->intervals.static_function_bodies_size++;
+ if (output->intervals.static_function_bodies_size > output->intervals.static_function_bodies_max_size) {
+ output->intervals.static_function_bodies_max_size *= 2;
+ output->intervals.static_function_bodies = (size_t*)Realloc(output->intervals.static_function_bodies, output->intervals.static_function_bodies_max_size * sizeof(size_t));
+ }
+ output->intervals.static_function_bodies[output->intervals.static_function_bodies_size] = tmp;
+ }
+}
+//Advised to call update_intervals before this
+size_t CodeGenHelper::size_of_sources(output_struct * const output) {
+ size_t size = 0;
+ // Calculate global var and string literals size
+ output->intervals.pre_things_size = mstrlen(output->source.global_vars) + mstrlen(output->source.string_literals);
+
+ // Class_defs, static_conversion_function_prototypes, static_function_prototypes are in the header,
+ // and includes are not counted
+ size = output->intervals.pre_things_size +
+ output->intervals.function_bodies[output->intervals.function_bodies_size] +
+ output->intervals.methods[output->intervals.methods_size] +
+ output->intervals.static_conversion_function_bodies[output->intervals.static_conversion_function_bodies_size] +
+ output->intervals.static_function_bodies[output->intervals.static_function_bodies_size];
+ return size;
+}
+
+size_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) {
+ size_t pos = 0; // Holds the position from the beginning
+
+ pos += from->intervals.pre_things_size;
+
+ if (pos > base_pos) {
+ to->source.global_vars = mputstr(to->source.global_vars, from->source.global_vars);
+ to->source.string_literals = mputstr(to->source.string_literals, from->source.string_literals);
+ }
+
+ get_chunk_from_poslist(from->source.methods, to->source.methods, from->intervals.methods, from->intervals.methods_size, base_pos, chunk_size, pos);
+ 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);
+ 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);
+ 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);
+
+ return pos;
+}
+//if from null return.
+void 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) {
+ if (from == NULL) return;
+ // If we have enough to form a chunk
+
+ // pos is unsigned so it can't be negative
+ if (pos > base_pos && pos - base_pos >= chunk_size) return;
+
+ size_t tmp = pos;
+
+ pos += interval_array[interval_array_size];
+
+ if (pos > base_pos) { // If we haven't finished with this interval_array
+ if (pos - base_pos >= chunk_size) { // It is a good chunk, but make it more precise because it may be too big
+ int ind = 0;
+ for (int i = 0; i <= interval_array_size; i++) {
+ if (tmp + interval_array[i] <= base_pos) { // Find the pos where we left off
+ ind = i;
+ } else if (tmp + interval_array[i] - base_pos >= chunk_size) {
+ // Found the first optimal position that is a good chunk
+ to = mputstrn(to, from + interval_array[ind], interval_array[i] - interval_array[ind]);
+ pos = tmp + interval_array[i];
+ return;
+ }
+ }
+ } else { // We can't form a new chunk from the remaining characters
+ int ind = 0;
+ for (int i = 0; i <= interval_array_size; i++) {
+ if (tmp + interval_array[i] <= base_pos) {
+ ind = i;
+ } else {
+ break;
+ }
+ }
+ // Put the remaining characters
+ to = mputstrn(to, from + interval_array[ind], interval_array[interval_array_size] - interval_array[ind]);
+ pos = tmp + interval_array[interval_array_size];
+ }
+ }
+}
+
output_struct* CodeGenHelper::get_outputstruct(Ttcn::Definition* def) {
string key = get_key(*def);
const string& new_name = current_module + key;
break;
case SPLIT_BY_HEURISTICS:
break;
+ case SPLIT_TO_SLICES:
+ break;
}
return retval;
}
break;
case SPLIT_BY_HEURISTICS:
break;
+ case SPLIT_TO_SLICES:
+ break;
}
return retval;
}
go->modulename = modules[j]->name;
go->module_dispname = modules[j]->dispname;
go->os.source.includes = mcopystr(
- "\n//This file intentionally empty."
+ "\n//This file is intentionally empty."
"\n#include <version.h>\n");
generated_code.add(fname, go);
}
}
}
+ } else if (split_mode == SPLIT_TO_SLICES && slice_num > 0) {
+ // The strategy is the following:
+ // Goal: Get files with equal size
+ // Get the longest file's length and divide it by slice_num (chunk_size)
+ // We split every file to chunk_size sized chunks
+ size_t max = 0;
+ // Calculate maximum character length
+ for (j = 0; j < generated_code.size(); j++) {
+ update_intervals(&generated_code.get_nth_elem(j)->os);
+ size_t num_of_chars = size_of_sources(&generated_code.get_nth_elem(j)->os);
+ if (max < num_of_chars) {
+ max = num_of_chars;
+ }
+ }
+ // Calculate ideal chunk size
+ size_t chunk_size = max / slice_num;
+ string fname;
+ for (j = 0; j < modules.size(); j++) {
+ generated_output_t *output = generated_code[modules[j]->dispname];
+
+ // Just to be sure that everything is in the right place
+ update_intervals(&output->os);
+
+ // Move static function prototypes to header (no longer static)
+ output->os.header.function_prototypes = mputstr(output->os.header.function_prototypes, output->os.source.static_function_prototypes);
+ Free(output->os.source.static_function_prototypes);
+ output->os.source.static_function_prototypes = NULL;
+
+ output->os.header.function_prototypes = mputstr(output->os.header.function_prototypes, output->os.source.static_conversion_function_prototypes);
+ Free(output->os.source.static_conversion_function_prototypes);
+ output->os.source.static_conversion_function_prototypes = NULL;
+
+ // Move internal class definitions to the header
+ output->os.header.class_defs = mputstr(output->os.header.class_defs, output->os.source.class_defs);
+ Free(output->os.source.class_defs);
+ output->os.source.class_defs = NULL;
+
+ update_intervals(&output->os);
+ size_t num_of_chars = size_of_sources(&output->os);
+ char buffer[13]= ""; // Max is 999999 should be enough (checked in main.cc) | 6 digit + 2 underscore + part
+ // If we need to split
+ if (num_of_chars >= chunk_size) {
+ size_t base_pos = 0;
+ for (unsigned int i = 0; i < slice_num; i++) {
+ if (i == 0) { // The first slice has the module's name
+ fname = output->module_dispname;
+ } else {
+ sprintf(buffer, "_part_%d", (int)i);
+ fname = output->module_dispname + "_" + buffer;
+ }
+ if (i == 0 || !generated_code.has_key(fname)) {
+ generated_output_t* go = new generated_output_t;
+ go->filename = buffer;
+ go->modulename = output->modulename;
+ go->module_dispname = output->module_dispname;
+ size_t act_pos = get_next_chunk_pos(&output->os, &go->os, base_pos, chunk_size);
+ // True if the file is not empty
+ if (act_pos > base_pos) {
+ go->os.source.includes = mputstr(go->os.source.includes, output->os.source.includes);
+ } else {
+ go->os.source.includes = mcopystr(
+ "\n//This file is intentionally empty."
+ "\n#include <version.h>\n");
+ }
+ // First slice: copy header and other properties and replace the original output struct
+ if (i == 0) {
+ go->has_circular_import = output->has_circular_import;
+ go->is_module = output->is_module;
+ go->is_ttcn = output->is_ttcn;
+ go->os.header.class_decls = mputstr(go->os.header.class_decls, output->os.header.class_decls);
+ go->os.header.class_defs = mputstr(go->os.header.class_defs, output->os.header.class_defs);
+ go->os.header.function_prototypes = mputstr(go->os.header.function_prototypes, output->os.header.function_prototypes);
+ go->os.header.global_vars = mputstr(go->os.header.global_vars, output->os.header.global_vars);
+ go->os.header.includes = mputstr(go->os.header.includes, output->os.header.includes);
+ go->os.header.testport_includes = mputstr(go->os.header.testport_includes, output->os.header.testport_includes);
+ go->os.header.typedefs = mputstr(go->os.header.typedefs, output->os.header.typedefs);
+ generated_code[modules[j]->dispname] = go;
+ } else {
+ generated_code.add(fname, go);
+ }
+ base_pos = act_pos;
+ } else {
+ // TODO: error handling: there is a module which has the same name as the
+ // numbered splitted file. splitting by type does not have this error
+ // handling so don't we
+ }
+ }
+ // Extra safety. If something is missing after the splitting, put the remaining
+ // things to the last file. (Should never happen)
+ if (base_pos < num_of_chars) {
+ get_next_chunk_pos(&output->os, &generated_code[fname]->os, base_pos, num_of_chars);
+ }
+ delete output;
+ } else {
+ // Create empty files.
+ for (i = 1; i < slice_num; i++) {
+ sprintf(buffer, "_part_%d", (int)i);
+ fname = output->module_dispname + "_" + buffer;
+ if (!generated_code.has_key(fname)) {
+ generated_output_t* go = new generated_output_t;
+ go->filename = buffer;
+ go->modulename = modules[j]->name;
+ go->module_dispname = modules[j]->dispname;
+ go->os.source.includes = mcopystr(
+ "\n//This file is intentionally empty."
+ "\n#include <version.h>\n");
+ generated_code.add(fname, go);
+ }
+ }
+ }
+ }
}
generated_output_t* go;
for (i = 0; i < generated_code.size(); i++) {