1 /* |
|
2 * (c) 2003 Mario de Sousa |
|
3 * |
|
4 * Offered to the public under the terms of the GNU General Public License |
|
5 * as published by the Free Software Foundation; either version 2 of the |
|
6 * License, or (at your option) any later version. |
|
7 * |
|
8 * This program is distributed in the hope that it will be useful, but |
|
9 * WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|
11 * Public License for more details. |
|
12 * |
|
13 * This code is made available on the understanding that it will not be |
|
14 * used in safety-critical situations without a full and competent review. |
|
15 */ |
|
16 |
|
17 /* |
|
18 * An IEC 61131-3 IL and ST compiler. |
|
19 * |
|
20 * Based on the |
|
21 * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) |
|
22 * |
|
23 */ |
|
24 |
|
25 |
|
26 /* |
|
27 * Declare temporary variables to be later used as output parameters |
|
28 * in function calls for which not all output parameters were |
|
29 * defined in the original (st or il) source code. |
|
30 * |
|
31 * This is part of the 4th stage that generates |
|
32 * a c++ source program equivalent to the IL and ST |
|
33 * code. |
|
34 */ |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 class temp_var_name_c { |
|
40 private: |
|
41 int counter; |
|
42 |
|
43 public: |
|
44 void reset(void) {counter = 0;} |
|
45 temp_var_name_c(void) {reset();} |
|
46 |
|
47 public: |
|
48 std::string *new_name(void) { |
|
49 std::string *new_str = new std::string(TEMP_VAR); |
|
50 /* yikes!!! How to convert an int to a string elegantly??? |
|
51 * Right now I (Mario) can only think of snprintf() |
|
52 * C++ must have a more elegant method! |
|
53 */ |
|
54 int int_str_size = snprintf(NULL, 0, "%d", counter); |
|
55 if (int_str_size <= 0) ERROR; |
|
56 char *int_str = (char *)malloc(int_str_size+1); |
|
57 if (snprintf(int_str, int_str_size+1, "%d", counter++) >= int_str_size+1) ERROR; |
|
58 *new_str += int_str; |
|
59 free(int_str); |
|
60 return new_str; |
|
61 } |
|
62 |
|
63 }; |
|
64 |
|
65 |
|
66 |
|
67 /***********************************************************************/ |
|
68 /***********************************************************************/ |
|
69 /***********************************************************************/ |
|
70 /***********************************************************************/ |
|
71 |
|
72 |
|
73 |
|
74 /* Some function calls in the body of functions or function blocks |
|
75 * may leave some parameters to their default values, and |
|
76 * ignore some output parameters of the function being called. |
|
77 * Our conversion of ST functions to C++ does not contemplate that, |
|
78 * i.e. each called function must get all it's input and output |
|
79 * parameters set correctly. |
|
80 * For input parameters we merely need to call the function with |
|
81 * the apropriate default value, but for output parameters |
|
82 * we must create temporary variables to hold the output value. |
|
83 * |
|
84 * We declare all the temporary output variables at the begining of |
|
85 * the body of each function or function block, and use them as |
|
86 * in function calls later on as they become necessary... |
|
87 * Note that we cannot create these variables just before a function |
|
88 * call, as the function call itself may be integrated within an |
|
89 * expression, or another function call! |
|
90 * |
|
91 * The variables are declared in the exact same order in which they |
|
92 * will be used later on during the function calls, which allows us |
|
93 * to simply re-create the name that was used for the temporary variable |
|
94 * instead of keeping it in some list. |
|
95 * The names are recreated by the temp_var_name_factory, after reset() |
|
96 * has been called! |
|
97 * |
|
98 * This function will genertae code similar to... |
|
99 * |
|
100 * INT __TMP_0 = 23; |
|
101 * REAL __TMP_1 = 45.5; |
|
102 * ... |
|
103 */ |
|
104 |
|
105 class generate_c_tempvardecl_c: generate_c_typedecl_c { |
|
106 public: |
|
107 generate_c_tempvardecl_c(stage4out_c *s4o_ptr): generate_c_typedecl_c(s4o_ptr) {} |
|
108 |
|
109 void generate(symbol_c *body, temp_var_name_c *temp_var_name_factory) { |
|
110 temp_var_name_factory->reset(); |
|
111 function_call_iterator_c fcall_iterator(body); |
|
112 for(symbol_c *finvocation = NULL; (finvocation = fcall_iterator.next()) != NULL;) { |
|
113 /* get the name of the next function that gets called */ |
|
114 identifier_c *fcalled_name = fcall_iterator.fname(); |
|
115 /* get that function's declaration... */ |
|
116 function_declaration_c *fdecl = function_symtable.find_value(fcalled_name); |
|
117 if (fdecl == function_symtable.end_value()) { |
|
118 function_type_t function_type = get_function_type(fcalled_name); |
|
119 if (function_type == function_none) ERROR; |
|
120 return; |
|
121 } |
|
122 /* create iterator to iterate through each of the called function's parameters... */ |
|
123 function_param_iterator_c fp_iterator(fdecl); |
|
124 |
|
125 /* iterate through each of the called function's parameters... */ |
|
126 identifier_c *param_name = NULL; |
|
127 function_call_param_iterator_c function_call_param_iterator(finvocation); |
|
128 for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { |
|
129 |
|
130 function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); |
|
131 if (param_direction == function_param_iterator_c::direction_in) |
|
132 /* ignore input only parameters... |
|
133 * we do not need to create temporary variables for these! |
|
134 */ |
|
135 continue; |
|
136 |
|
137 /* Get the value from a foo(<param_name> = <param_value>) style call */ |
|
138 symbol_c *param_value = function_call_param_iterator.search(param_name); |
|
139 |
|
140 /* Get the value from a foo(<param_value>) style call */ |
|
141 if (param_value == NULL) |
|
142 param_value = function_call_param_iterator.next(); |
|
143 |
|
144 if (param_value != NULL) |
|
145 /* ignore output parameters to which a variable is passed... |
|
146 * we do not need to create temporary variables for these! |
|
147 */ |
|
148 continue; |
|
149 |
|
150 symbol_c *param_type = fp_iterator.param_type(); |
|
151 |
|
152 /* get the parameter's default value */ |
|
153 param_value = fp_iterator.default_value(); |
|
154 |
|
155 /* If no default value specified in function declaration, |
|
156 * get the default value of this variable's type |
|
157 */ |
|
158 if (param_value == NULL) |
|
159 param_value = (symbol_c *)param_type->accept(*type_initial_value_c::instance()); |
|
160 if (param_value == NULL) ERROR; |
|
161 |
|
162 /* now declare a temporary variable, with the correct default value... */ |
|
163 s4o.print(s4o.indent_spaces); |
|
164 param_type->accept(*this); |
|
165 s4o.print(" "); |
|
166 |
|
167 std::string *temp_var_name = temp_var_name_factory->new_name(); |
|
168 s4o.print(*temp_var_name); |
|
169 delete temp_var_name; |
|
170 |
|
171 s4o.print(" = "); |
|
172 param_value->accept(*this); |
|
173 s4o.print(";\n"); |
|
174 } |
|
175 } |
|
176 temp_var_name_factory->reset(); |
|
177 s4o.print("\n"); |
|
178 } |
|
179 }; |
|