Commit | Line | Data |
---|---|---|
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 | |
12 | * Zalanyi, Balazs Andor | |
13 | * | |
14 | ******************************************************************************/ | |
970ed795 EL |
15 | #include "CodeGenHelper.hh" |
16 | #include "Code.hh" | |
17 | #include "error.h" | |
18 | #include "main.hh" | |
19 | #include <cstdio> | |
20 | #include <cstring> | |
21 | ||
22 | namespace Common { | |
23 | ||
24 | CodeGenHelper* CodeGenHelper::instance = 0; | |
25 | ||
26 | CodeGenHelper::generated_output_t::generated_output_t() : | |
27 | is_module(false), | |
28 | is_ttcn(true), | |
29 | has_circular_import(false) | |
30 | { | |
31 | Code::init_output(&os); | |
32 | } | |
33 | ||
34 | CodeGenHelper::generated_output_t::~generated_output_t() { | |
35 | Code::free_output(&os); | |
36 | } | |
37 | ||
38 | // from Type.cc | |
39 | const char* const CodeGenHelper::typetypemap[] = { | |
40 | "", /**< undefined */ | |
41 | "", /**< erroneous (e.g. nonexistent reference) */ | |
42 | "", /**< null (ASN.1) */ | |
43 | "", /**< boolean */ | |
44 | "", /**< integer */ | |
45 | "", /**< integer / ASN */ | |
46 | "", /**< real/float */ | |
47 | "", /**< enumerated / ASN */ | |
48 | "", /**< enumerated / TTCN */ | |
49 | "", /**< bitstring */ | |
50 | "", /**< bitstring */ | |
51 | "", /**< hexstring (TTCN-3) */ | |
52 | "", /**< octetstring */ | |
53 | "", /**< charstring (TTCN-3) */ | |
54 | "", /**< universal charstring (TTCN-3) */ | |
55 | "", /**< UTF8String (ASN.1) */ | |
56 | "", /**< NumericString (ASN.1) */ | |
57 | "", /**< PrintableString (ASN.1) */ | |
58 | "", /**< TeletexString (ASN.1) */ | |
59 | "", /**< VideotexString (ASN.1) */ | |
60 | "", /**< IA5String (ASN.1) */ | |
61 | "", /**< GraphicString (ASN.1) */ | |
62 | "", /**< VisibleString (ASN.1) */ | |
63 | "", /**< GeneralString (ASN.1) */ | |
64 | "", /**< UniversalString (ASN.1) */ | |
65 | "", /**< BMPString (ASN.1) */ | |
66 | "", /**< UnrestrictedCharacterString (ASN.1) */ | |
67 | "", /**< UTCTime (ASN.1) */ | |
68 | "", /**< GeneralizedTime (ASN.1) */ | |
69 | "", /** Object descriptor, a kind of string (ASN.1) */ | |
70 | "", /**< object identifier */ | |
71 | "", /**< relative OID (ASN.1) */ | |
72 | "_union", /**< choice /ASN, uses u.secho */ | |
73 | "_union", /**< union /TTCN, uses u.secho */ | |
74 | "_seqof", /**< sequence (record) of */ | |
75 | "_setof", /**< set of */ | |
76 | "_seq", /**< sequence /ASN, uses u.secho */ | |
77 | "_seq", /**< record /TTCN, uses u.secho */ | |
78 | "_set", /**< set /ASN, uses u.secho */ | |
79 | "_set", /**< set /TTCN, uses u.secho */ | |
80 | "", /**< ObjectClassFieldType (ASN.1) */ | |
81 | "", /**< open type (ASN.1) */ | |
82 | "", /**< ANY (deprecated ASN.1) */ | |
83 | "", /**< %EXTERNAL (ASN.1) */ | |
84 | "", /**< EMBEDDED PDV (ASN.1) */ | |
85 | "", /**< referenced */ | |
86 | "", /**< special referenced (by pointer, not by name) */ | |
87 | "", /**< selection type (ASN.1) */ | |
88 | "", /**< verdict type (TTCN-3) */ | |
89 | "", /**< port type (TTCN-3) */ | |
90 | "", /**< component type (TTCN-3) */ | |
91 | "", /**< address type (TTCN-3) */ | |
92 | "", /**< default type (TTCN-3) */ | |
93 | "", /**< array (TTCN-3), uses u.array */ | |
94 | "", /**< signature (TTCN-3) */ | |
95 | "", /**< function reference (TTCN-3) */ | |
96 | "", /**< altstep reference (TTCN-3) */ | |
97 | "", /**< testcase reference (TTCN-3) */ | |
98 | "", /**< anytype (TTCN-3) */ | |
99 | 0 | |
100 | }; | |
101 | ||
102 | CodeGenHelper::CodeGenHelper() : | |
103 | split_mode(SPLIT_NONE) | |
104 | { | |
105 | if (instance != 0) | |
106 | FATAL_ERROR("Attempted to create a second code generator."); | |
107 | instance = this; | |
108 | } | |
109 | ||
110 | CodeGenHelper& CodeGenHelper::GetInstance() { | |
111 | if (instance == 0) | |
112 | FATAL_ERROR("Trying to access to the already destroyed code generator."); | |
113 | return *instance; | |
114 | } | |
115 | ||
116 | void CodeGenHelper::set_split_mode(split_type st) { | |
117 | split_mode = st; | |
118 | } | |
119 | ||
120 | bool CodeGenHelper::set_split_mode(const char* type) { | |
121 | if (strcmp(type, "none") == 0) | |
122 | split_mode = SPLIT_NONE; | |
123 | else if (strcmp(type, "type") == 0) | |
124 | split_mode = SPLIT_BY_KIND; | |
125 | else | |
126 | return false; | |
127 | return true; | |
128 | } | |
129 | ||
130 | CodeGenHelper::split_type CodeGenHelper::get_split_mode() const { | |
131 | return split_mode; | |
132 | } | |
133 | ||
134 | void CodeGenHelper::add_module(const string& name, const string& dispname, | |
135 | bool is_ttcn, bool has_circular_import) { | |
136 | generated_output_t* go = new generated_output_t; | |
137 | go->filename.clear(); | |
138 | go->modulename = name; | |
139 | go->module_dispname = dispname; | |
140 | go->is_module = true; | |
141 | go->is_ttcn = is_ttcn; | |
142 | go->has_circular_import = has_circular_import; | |
143 | generated_code.add(dispname, go); | |
144 | module_names_t* mod_names = new module_names_t; | |
145 | mod_names->name = name; | |
146 | mod_names->dispname = dispname; | |
147 | modules.add(mod_names); | |
148 | } | |
149 | ||
150 | output_struct* CodeGenHelper::get_outputstruct(const string& name) { | |
151 | return &generated_code[name]->os; | |
152 | } | |
153 | ||
154 | void CodeGenHelper::set_current_module(const string& name) { | |
155 | current_module = name; | |
156 | } | |
157 | ||
158 | output_struct* CodeGenHelper::get_outputstruct(Ttcn::Definition* def) { | |
159 | string key = get_key(*def); | |
160 | const string& new_name = current_module + key; | |
161 | if (!generated_code.has_key(new_name)) { | |
162 | generated_output_t* go = new generated_output_t; | |
163 | go->filename = key; | |
164 | go->modulename = generated_code[current_module]->modulename; | |
165 | go->module_dispname = generated_code[current_module]->module_dispname; | |
166 | generated_code.add(new_name, go); | |
167 | go->os.source.includes = mprintf("\n#include \"%s.hh\"\n" | |
168 | , current_module.c_str()); | |
169 | } | |
170 | return &generated_code[new_name]->os; | |
171 | } | |
172 | ||
173 | output_struct* CodeGenHelper::get_outputstruct(Type* type) { | |
174 | string key = get_key(*type); | |
175 | const string& new_name = current_module + key; | |
176 | if (!generated_code.has_key(new_name)) { | |
177 | generated_output_t* go = new generated_output_t; | |
178 | go->filename = key; | |
179 | go->modulename = generated_code[current_module]->modulename; | |
180 | go->module_dispname = generated_code[current_module]->module_dispname; | |
181 | generated_code.add(new_name, go); | |
182 | go->os.source.includes = mprintf("\n#include \"%s.hh\"\n" | |
183 | , current_module.c_str()); | |
184 | } | |
185 | return &generated_code[new_name]->os; | |
186 | } | |
187 | ||
188 | output_struct* CodeGenHelper::get_current_outputstruct() { | |
189 | return &generated_code[current_module]->os; | |
190 | } | |
191 | ||
192 | void CodeGenHelper::transfer_value(char* &dst, char* &src) { | |
193 | dst = mputstr(dst, src); | |
194 | Free(src); | |
195 | src = 0; | |
196 | } | |
197 | ||
198 | void CodeGenHelper::finalize_generation(Type* type) { | |
199 | string key = get_key(*type); | |
200 | if (key.empty()) return; | |
201 | ||
202 | output_struct& dst = *get_current_outputstruct(); | |
203 | output_struct& src = *get_outputstruct(current_module + key); | |
204 | // key is not empty so these can never be the same | |
205 | ||
206 | transfer_value(dst.header.includes, src.header.includes); | |
207 | transfer_value(dst.header.class_decls, src.header.class_decls); | |
208 | transfer_value(dst.header.typedefs, src.header.typedefs); | |
209 | transfer_value(dst.header.class_defs, src.header.class_defs); | |
210 | transfer_value(dst.header.function_prototypes, src.header.function_prototypes); | |
211 | transfer_value(dst.header.global_vars, src.header.global_vars); | |
212 | transfer_value(dst.header.testport_includes, src.header.testport_includes); | |
213 | ||
214 | transfer_value(dst.source.global_vars, src.source.global_vars); | |
215 | ||
216 | transfer_value(dst.functions.pre_init, src.functions.pre_init); | |
217 | transfer_value(dst.functions.post_init, src.functions.post_init); | |
218 | ||
219 | transfer_value(dst.functions.set_param, src.functions.set_param); | |
3abe9331 | 220 | transfer_value(dst.functions.get_param, src.functions.get_param); |
970ed795 EL |
221 | transfer_value(dst.functions.log_param, src.functions.log_param); |
222 | transfer_value(dst.functions.init_comp, src.functions.init_comp); | |
223 | transfer_value(dst.functions.start, src.functions.start); | |
224 | transfer_value(dst.functions.control, src.functions.control); | |
225 | } | |
226 | ||
227 | string CodeGenHelper::get_key(Ttcn::Definition& def) const { | |
228 | string retval; | |
229 | switch (split_mode) { | |
230 | case SPLIT_NONE: | |
231 | // returns the current module | |
232 | break; | |
233 | case SPLIT_BY_KIND: | |
234 | break; | |
235 | case SPLIT_BY_NAME: | |
236 | retval += "_" + def.get_id().get_name(); | |
237 | break; | |
238 | case SPLIT_BY_HEURISTICS: | |
239 | break; | |
240 | } | |
241 | return retval; | |
242 | } | |
243 | ||
244 | string CodeGenHelper::get_key(Type& type) const { | |
245 | string retval; | |
246 | switch (split_mode) { | |
247 | case SPLIT_NONE: | |
248 | break; | |
249 | case SPLIT_BY_KIND: { | |
250 | Type::typetype_t tt = type.get_typetype(); | |
251 | switch(tt) { | |
252 | case Type::T_CHOICE_A: | |
253 | case Type::T_CHOICE_T: | |
254 | case Type::T_SEQOF: | |
255 | case Type::T_SETOF: | |
256 | case Type::T_SEQ_A: | |
257 | case Type::T_SEQ_T: | |
258 | case Type::T_SET_A: | |
259 | case Type::T_SET_T: | |
260 | retval += typetypemap[(int)tt]; | |
261 | break; | |
262 | default: | |
263 | // put it into the module (no suffix) | |
264 | break; | |
265 | } | |
266 | break; } | |
267 | case SPLIT_BY_NAME: | |
268 | break; | |
269 | case SPLIT_BY_HEURISTICS: | |
270 | break; | |
271 | } | |
272 | return retval; | |
273 | } | |
274 | ||
275 | void CodeGenHelper::write_output() { | |
276 | size_t i, j; | |
277 | if (split_mode == SPLIT_BY_KIND) { | |
278 | // Create empty files to have a fix set of files to compile | |
279 | string fname; | |
280 | for (j = 0; j < modules.size(); j++) { | |
281 | for (i = 0; typetypemap[i]; i++) { | |
282 | fname = modules[j]->dispname + typetypemap[i]; | |
283 | if (!generated_code.has_key(fname)) { | |
284 | generated_output_t* go = new generated_output_t; | |
285 | go->filename = typetypemap[i]; | |
286 | go->modulename = modules[j]->name; | |
287 | go->module_dispname = modules[j]->dispname; | |
288 | go->os.source.includes = mcopystr( | |
289 | "\n//This file intentionally empty." | |
290 | "\n#include <version.h>\n"); | |
291 | generated_code.add(fname, go); | |
292 | } | |
293 | } | |
294 | } | |
295 | } | |
296 | generated_output_t* go; | |
297 | for (i = 0; i < generated_code.size(); i++) { | |
298 | go = generated_code.get_nth_elem(i); | |
299 | ::write_output(&go->os, go->modulename.c_str(), go->module_dispname.c_str(), | |
300 | go->filename.c_str(), go->is_ttcn, go->has_circular_import, go->is_module); | |
301 | } | |
302 | } | |
303 | ||
304 | CodeGenHelper::~CodeGenHelper() { | |
305 | size_t i; | |
306 | for (i = 0; i < generated_code.size(); i++) | |
307 | delete generated_code.get_nth_elem(i); | |
308 | generated_code.clear(); | |
309 | for (i = 0; i < modules.size(); i++) | |
310 | delete modules[i]; | |
311 | modules.clear(); | |
312 | instance = 0; | |
313 | } | |
314 | ||
315 | } |