added any2unistr predefined function (artf724008)
[deliverable/titan.core.git] / compiler2 / ttcn3 / ILT.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 * Feher, Csaba
11 * Forstner, Matyas
12 * Raduly, Csaba
13 * Szabo, Janos Zoltan – initial implementation
14 *
15 ******************************************************************************/
970ed795
EL
16#include "ILT.hh"
17
18namespace Ttcn {
19
20 // =================================
21 // ===== ILT
22 // =================================
23
24 ILT::~ILT()
25 {
26 for(size_t i=0; i<branches.size(); i++)
27 delete branches[i];
28 branches.clear();
29 }
30
31 ILT_branch* ILT::get_as_branch()
32 {
33 FATAL_ERROR("ILT::get_as_branch()");
34 return 0;
35 }
36
37 void ILT::add_branch(ILT_branch *p_branch)
38 {
39 if(!p_branch) FATAL_ERROR("ILT::add_branch()");
40 branches.add(p_branch);
41 ILT_root *my_root = get_my_root();
42 p_branch->set_my_root(my_root);
43 p_branch->set_branch_i(my_root->get_new_branch_num());
44 }
45
46
47 // =================================
48 // ===== ILT_root
49 // =================================
50
51 ILT_root::ILT_root(Statement *p_il)
52 : il(p_il), tmpnum(0), c_l(0), c_b(0)
53 {
54 if(!p_il || p_il->get_statementtype()!=Statement::S_INTERLEAVE)
55 FATAL_ERROR("ILT_root::ILT_root()");
56 mytmpid=p_il->get_my_sb()->get_scope_mod_gen()->get_temporary_id();
57 out_def=memptystr();
58 out_statevars=memptystr();
59 out_code=memptystr();
60 out_branches=memptystr();
61 }
62
63 ILT_root::~ILT_root()
64 {
65 for(size_t i=0; i<state_var_vals.size(); i++)
66 delete state_var_vals[i];
67 state_var_vals.clear();
68 Free(out_def);
69 Free(out_statevars);
70 Free(out_code);
71 Free(out_branches);
72 }
73
74 ILT_root *ILT_root::clone() const
75 {
76 FATAL_ERROR("ILT_root::clone()");
77 }
78
79 ILT_root *ILT_root::get_my_root()
80 {
81 return this;
82 }
83
84 bool ILT_root::is_toplevel()
85 {
86 return true;
87 }
88
89 char*& ILT_root::get_out_def()
90 {
91 return out_def;
92 }
93
94 char*& ILT_root::get_out_code()
95 {
96 return out_code;
97 }
98
99 char*& ILT_root::get_out_branches()
100 {
101 return out_branches;
102 }
103
104 const string& ILT_root::get_my_tmpid()
105 {
106 return mytmpid;
107 }
108
109 size_t ILT_root::get_new_tmpnum()
110 {
111 return tmpnum++;
112 }
113
114 size_t ILT_root::get_new_state_var(bool toplevel)
115 {
116 state_var_vals.add(new size_t(1));
117 size_t newvar=state_var_vals.size()-1;
118 out_statevars=mputprintf(out_statevars, "%s_state[%lu]=%s;\n",
119 mytmpid.c_str(), (unsigned long) newvar, toplevel?"2":"0");
120 return newvar;
121 }
122
123 size_t ILT_root::get_new_state_var_val(size_t p_state_var)
124 {
125 if(p_state_var>=state_var_vals.size())
126 FATAL_ERROR("ILT_root::get_new_state_var_val()");
127 return ++*state_var_vals[p_state_var];
128 }
129
130 size_t ILT_root::get_new_label_num()
131 {
132 return c_l++;
133 }
134
135 char* ILT_root::generate_code(char *str)
136 {
137 // everything starts here: the top-level interleave statement
138 il->ilt_generate_code(this);
139 // generating code for the branches
140 for(size_t i=0; i<branches.size(); i++)
141 branches[i]->ilt_generate_code(this);
142 str=mputstr(str, "{\n"); // (1)
143 // the state vars: definition
144 str=mputprintf(str, "size_t %s_state[%lu];\n",
145 mytmpid.c_str(), (unsigned long) state_var_vals.size());
146 // the state vars: initialization
147 str=mputstr(str, out_statevars);
148 // the alt status flags: definition
149 str=mputprintf(str, "alt_status %s_alt_flag[%lu];\n",
150 mytmpid.c_str(), (unsigned long) (c_b+1));
151 // the definitions
152 str=mputstr(str, out_def);
153 // the core of the interleave
154 str=mputprintf(str, "%s:\n"
155 "for(size_t tmp_i=0; tmp_i<%lu; tmp_i++)"
156 " %s_alt_flag[tmp_i]=ALT_UNCHECKED;\n"
157 "%s_alt_flag[%lu]=ALT_MAYBE;\n"
158 "TTCN_Snapshot::take_new(FALSE);\n"
159 "for( ; ; ) {\n" // (2)
160 "if(", mytmpid.c_str(),
161 (unsigned long) c_b, mytmpid.c_str(),
162 mytmpid.c_str(), (unsigned long) c_b);
163 // checking for final condition
164 for(size_t i=0; i<branches.size(); i++) {
165 ILT_branch *b=branches[i];
166 str=mputprintf(str, "%s%s_state[%lu]==1",
167 i?" && ":"", mytmpid.c_str(), (unsigned long) b->get_my_state_var());
168 }
169 str=mputstr(str, ") break;\n");
170 // the altsteps :)
171 str=mputstr(str, out_code);
172 // checking defaults
173 str=mputprintf(str, "if(%s_alt_flag[%lu]==ALT_MAYBE) {\n"
174 "%s_alt_flag[%lu]=TTCN_Default::try_altsteps();\n"
175 "if(%s_alt_flag[%lu]==ALT_YES || %s_alt_flag[%lu]==ALT_BREAK)"
176 " break;\n"
177 "else if(%s_alt_flag[%lu]==ALT_REPEAT) goto %s;\n"
178 "}\n",
179 mytmpid.c_str(), (unsigned long) c_b,
180 mytmpid.c_str(), (unsigned long) c_b,
181 mytmpid.c_str(), (unsigned long) c_b,
182 mytmpid.c_str(), (unsigned long) c_b,
183 mytmpid.c_str(), (unsigned long) c_b,
184 mytmpid.c_str());
185 str=il->update_location_object(str);
186 // checking deadlock
187 str=mputprintf(str, "for(size_t tmp_i=0; tmp_i<%lu; tmp_i++)"
188 " if(%s_alt_flag[tmp_i]!=ALT_NO) goto %s_newsnapshot;\n",
189 (unsigned long) (c_b+1), mytmpid.c_str(), mytmpid.c_str());
190 str = mputstr(str, "TTCN_error(\"None of the branches can be chosen in the "
191 "interleave statement in file ");
192 str = Code::translate_string(str, il->get_filename());
193 int first_line = il->get_first_line(), last_line = il->get_last_line();
194 if (first_line < last_line) str = mputprintf(str,
195 " between lines %d and %d", first_line, last_line);
196 else str = mputprintf(str, ", line %d", first_line);
197 str = mputprintf(str, ".\");\n"
198 "%s_newsnapshot:\n"
199 "TTCN_Snapshot::take_new(TRUE);\n"
200 "continue;\n", mytmpid.c_str());
201 // the code of branches
202 str=mputstr(str, out_branches);
203 str=mputstr(str, "}\n" // (2)
204 "}\n"); // (1)
205 return str;
206 }
207
208 // =================================
209 // ===== ILT_branch
210 // =================================
211
212 ILT_branch::ILT_branch(branchtype_t p_bt, AltGuard *p_ag,
213 string p_state_cond, size_t p_state_var,
214 size_t p_state_var_val, size_t p_goto_label_num)
215 : branchtype(p_bt), root(0), branch_i((size_t)-1),
216 state_cond(p_state_cond), state_var(p_state_var),
217 state_var_val(p_state_var_val), goto_label_num(p_goto_label_num)
218 {
219 switch(p_bt) {
220 case BT_ALT:
221 case BT_IL:
222 if(!p_ag) FATAL_ERROR("ILT_branch::ILT_branch()");
223 ag=p_ag;
224 // the checker should check this but one never knows :)
225 if(ag->get_type()!=AltGuard::AG_OP)
226 FATAL_ERROR("ILT_branch::ILT_branch()");
227 break;
228 default:
229 FATAL_ERROR("ILT_branch::ILT_branch()");
230 } // switch
231 }
232
233 ILT_branch::ILT_branch(branchtype_t p_bt, Statement *p_stmt,
234 string p_state_cond, size_t p_state_var,
235 size_t p_state_var_val, size_t p_goto_label_num)
236 : branchtype(p_bt), root(0), branch_i((size_t)-1),
237 state_cond(p_state_cond), state_var(p_state_var),
238 state_var_val(p_state_var_val), goto_label_num(p_goto_label_num)
239 {
240 switch(p_bt) {
241 case BT_RECV:
242 if(!p_stmt) FATAL_ERROR("ILT_branch::ILT_branch()");
243 stmt=p_stmt;
244 break;
245 default:
246 FATAL_ERROR("ILT_branch::ILT_branch()");
247 } // switch
248 }
249
250 ILT_branch::~ILT_branch()
251 {
252 // nothing to do
253 }
254
255 ILT_branch *ILT_branch::clone() const
256 {
257 FATAL_ERROR("ILT_branch::clone()");
258 }
259
260 void ILT_branch::set_my_root(ILT_root *p_root)
261 {
262 if(!p_root) FATAL_ERROR("ILT_branch::set_my_root()");
263 root=p_root;
264 }
265
266 ILT_root* ILT_branch::get_my_root()
267 {
268 if (!root) FATAL_ERROR("ILT_branch::get_my_root()");
269 return root;
270 }
271
272 ILT_branch *ILT_branch::get_as_branch()
273 {
274 return this;
275 }
276
277 bool ILT_branch::is_toplevel()
278 {
279 return false;
280 }
281
282 char*& ILT_branch::get_out_def()
283 {
284 return root->get_out_def();
285 }
286
287 char*& ILT_branch::get_out_code()
288 {
289 return root->get_out_code();
290 }
291
292 char*& ILT_branch::get_out_branches()
293 {
294 return root->get_out_branches();
295 }
296
297 const string& ILT_branch::get_my_tmpid()
298 {
299 return root->get_my_tmpid();
300 }
301
302 size_t ILT_branch::get_new_tmpnum()
303 {
304 return root->get_new_tmpnum();
305 }
306
307 size_t ILT_branch::get_new_state_var(bool toplevel)
308 {
309 return root->get_new_state_var(toplevel);
310 }
311
312 size_t ILT_branch::get_new_state_var_val(size_t p_state_var)
313 {
314 return root->get_new_state_var_val(p_state_var);
315 }
316
317 size_t ILT_branch::get_new_label_num()
318 {
319 return root->get_new_label_num();
320 }
321
322 void ILT_branch::ilt_generate_code(ILT *ilt)
323 {
324 const string& mytmpid=get_my_tmpid();
325 char*& out_code=get_out_code();
326 Statement *recv_stmt
327 =branchtype==BT_RECV?stmt:ag->get_guard_stmt();
328 out_code=recv_stmt->update_location_object(out_code);
329 // ALT_UNCHECKED -> ALT_MAYBE or ALT_NO (state vars & guard expr)
330 {
331 out_code=mputprintf(out_code,
332 "if(%s_alt_flag[%lu]==ALT_UNCHECKED) {\n" // (1)
333 "if(",
334 mytmpid.c_str(), (unsigned long) branch_i);
335 if(!state_cond.empty())
336 out_code=mputprintf(out_code, "%s && ", state_cond.c_str());
337 out_code=mputprintf(out_code, "%s_state[%lu]==%lu) {\n", // (2)
338 mytmpid.c_str(), (unsigned long) state_var,
339 (unsigned long) state_var_val);
340 // only alt branch can have guard expression
341 Value *guard_expr=branchtype==BT_ALT?ag->get_guard_expr():0;
342 if(guard_expr) {
343 out_code=guard_expr->update_location_object(out_code);
344 expression_struct expr;
345 Code::init_expr(&expr);
346 guard_expr->generate_code_expr(&expr);
347 out_code=mputstr(out_code, expr.preamble);
348 out_code=mputprintf(out_code,
349 "%s_alt_flag[%lu]=(%s)?ALT_MAYBE:ALT_NO;\n",
350 mytmpid.c_str(), (unsigned long) branch_i,
351 expr.expr);
352 out_code=mputstr(out_code, expr.postamble);
353 Code::free_expr(&expr);
354 } // if guard_expr
355 else out_code=mputprintf(out_code,
356 "%s_alt_flag[%lu]=ALT_MAYBE;\n",
357 mytmpid.c_str(), (unsigned long) branch_i);
358 out_code=mputprintf(out_code,
359 "}\n" // (2)
360 "else %s_alt_flag[%lu]=ALT_NO;\n"
361 "}\n", // (1)
362 mytmpid.c_str(), (unsigned long) branch_i);
363 }
364 // ALT_MAYBE -> ALT_YES or ALT_REPEAT or ALT_NO (guard stmt)
365 {
366 out_code=mputprintf(out_code,
367 "if(%s_alt_flag[%lu]==ALT_MAYBE) {\n", // (1)
368 mytmpid.c_str(), (unsigned long) branch_i);
369 expression_struct expr;
370 Code::init_expr(&expr);
371 recv_stmt->generate_code_expr(&expr);
372 // indicates whether the guard operation might return ALT_REPEAT
373 bool can_repeat=recv_stmt->can_repeat();
374 if(expr.preamble || expr.postamble) {
375 out_code=mputstr(out_code, "{\n");
376 out_code=mputstr(out_code, expr.preamble);
377 }
378 out_code=mputprintf(out_code, "%s_alt_flag[%lu]=%s;\n",
379 mytmpid.c_str(), (unsigned long) branch_i, expr.expr);
380 if(expr.preamble || expr.postamble) {
381 out_code=mputstr(out_code, expr.postamble);
382 out_code=mputstr(out_code, "}\n");
383 }
384 Code::free_expr(&expr);
385 if(can_repeat)
386 out_code=mputprintf(out_code,
387 "if(%s_alt_flag[%lu]==ALT_REPEAT) goto %s;\n",
388 mytmpid.c_str(), (unsigned long) branch_i,
389 mytmpid.c_str());
390 }
391 if(branchtype==BT_RECV)
392 out_code=mputprintf(out_code,
393 "if(%s_alt_flag[%lu]==ALT_YES) goto %s_l%lu;\n",
394 mytmpid.c_str(), (unsigned long) branch_i,
395 mytmpid.c_str(), (unsigned long) goto_label_num);
396 else {
397 out_code=mputprintf(out_code,
398 "if(%s_alt_flag[%lu]==ALT_YES) ",
399 mytmpid.c_str(), (unsigned long) branch_i);
400 // statement block code generation;
401 StatementBlock *block=ag->get_block();
402 bool has_recv=block->has_receiving_stmt();
403 char*& out_stmt=has_recv?get_out_branches():out_code;
404 if(has_recv) {
405 out_code=mputprintf(out_code,
406 "goto %s_branch%lu;\n",
407 mytmpid.c_str(), (unsigned long) branch_i);
408 out_stmt=mputprintf(out_stmt, "%s_branch%lu:\n",
409 mytmpid.c_str(), (unsigned long) branch_i);
410 block->ilt_generate_code(this);
411 }
412 else {
413 out_stmt=mputstr(out_stmt, "{\n"); // (2)
414 out_stmt=block->generate_code(out_stmt);
415 }
416 if(branchtype==BT_IL) {
417 out_stmt=mputprintf(out_stmt, "%s_state[%lu]=1;\n",
418 mytmpid.c_str(), (unsigned long) state_var);
419 if(!ilt->is_toplevel()) {
420 vector<ILT_branch>& ilt_branches = ilt->get_as_branch()->branches;
421 bool use_loop=ilt_branches.size() > 8;
422 size_t bmin=0, bmax=0;
423 if (use_loop) {
424 size_t st_var=ilt_branches[0]->get_my_state_var();
425 bmin=st_var; bmax=st_var;
426 for (size_t i=1; i<ilt_branches.size(); i++) {
427 st_var=ilt_branches[i]->get_my_state_var();
428 if (st_var<bmin) bmin=st_var;
429 if (st_var>bmax) bmax=st_var;
430 }
431 use_loop=(bmax-bmin+1) == ilt_branches.size();
432 }
433 if (use_loop) {
434 out_stmt=mputprintf(out_stmt,
435 "for(size_t tmp_i=%lu; tmp_i<%lu; tmp_i++)"
436 " if (%s_state[tmp_i]!=1) goto %s;\n",
437 (unsigned long) bmin, (unsigned long) bmax+1,
438 mytmpid.c_str(), mytmpid.c_str());
439 } else if (ilt_branches.size() > 1) {
440 // Check if any branches of non top level interleave need to be exe.
441 for(size_t i=0, j=0; i<ilt_branches.size(); i++) {
442 ILT_branch *b=ilt_branches[i];
443 if (b != this)
444 out_stmt=mputprintf(out_stmt, "%s%s_state[%lu]!=1",
445 j++?" || ":"if (", mytmpid.c_str(),
446 (unsigned long) b->get_my_state_var());
447 }
448 out_stmt=mputprintf(out_stmt, ") goto %s;\n", mytmpid.c_str());
449 }
450 // non top level interleave: Handle finish case
451 out_stmt=mputprintf(out_stmt, "goto %s_l%lu;\n",
452 mytmpid.c_str(), (unsigned long) goto_label_num);
453 } else // top level: finish condition is checked at the beginning
454 out_stmt=mputprintf(out_stmt, "goto %s;\n", mytmpid.c_str());
455 } else // not interleave: finish after one branch execution
456 out_stmt=mputprintf(out_stmt, "goto %s_l%lu;\n",
457 mytmpid.c_str(), (unsigned long) goto_label_num);
458 if(!has_recv)
459 out_stmt=mputstr(out_stmt, "}\n"); // (2)
460 }
461 out_code=mputstr(out_code, "}\n"); // (1)
462 // the nested branches
463 for(size_t i=0; i<branches.size(); i++)
464 branches[i]->ilt_generate_code(this);
465 }
466
467} // namespace Ttcn
This page took 0.039834 seconds and 5 git commands to generate.