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