|
1 /* |
|
2 * matiec - a compiler for the programming languages defined in IEC 61131-3 |
|
3 * |
|
4 * Copyright (C) 2012 Mario de Sousa (msousa@fe.up.pt) |
|
5 * |
|
6 * This program is free software: you can redistribute it and/or modify |
|
7 * it under the terms of the GNU General Public License as published by |
|
8 * the Free Software Foundation, either version 3 of the License, or |
|
9 * (at your option) any later version. |
|
10 * |
|
11 * This program is distributed in the hope that it will be useful, |
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 * GNU General Public License for more details. |
|
15 * |
|
16 * You should have received a copy of the GNU General Public License |
|
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
18 * |
|
19 * |
|
20 * This code is made available on the understanding that it will not be |
|
21 * used in safety-critical situations without a full and competent review. |
|
22 */ |
|
23 |
|
24 /* |
|
25 * An IEC 61131-3 compiler. |
|
26 * |
|
27 * Based on the |
|
28 * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) |
|
29 * |
|
30 */ |
|
31 |
|
32 |
|
33 /* Declaration sequence is a source code part needed to declare variables. |
|
34 * There are some checks we need to do before start with other analysis: |
|
35 * |
|
36 * - Check external option redefinition. |
|
37 * - Check external data type redefinition. |
|
38 * - Check initial values consistently with the data types of the variables/data types being declared. |
|
39 * - Check whether a function block uses a CONSTANT qualifier as described in 2.5.2.1. |
|
40 * |
|
41 */ |
|
42 |
|
43 |
|
44 #include "enum_declaration_check.hh" |
|
45 |
|
46 |
|
47 |
|
48 #define FIRST_(symbol1, symbol2) (((symbol1)->first_order < (symbol2)->first_order) ? (symbol1) : (symbol2)) |
|
49 #define LAST_(symbol1, symbol2) (((symbol1)->last_order > (symbol2)->last_order) ? (symbol1) : (symbol2)) |
|
50 |
|
51 #define STAGE3_ERROR(error_level, symbol1, symbol2, ...) { \ |
|
52 if (current_display_error_level >= error_level) { \ |
|
53 fprintf(stderr, "%s:%d-%d..%d-%d: error: ", \ |
|
54 FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column,\ |
|
55 LAST_(symbol1,symbol2) ->last_line, LAST_(symbol1,symbol2) ->last_column);\ |
|
56 fprintf(stderr, __VA_ARGS__); \ |
|
57 fprintf(stderr, "\n"); \ |
|
58 error_count++; \ |
|
59 } \ |
|
60 } |
|
61 |
|
62 |
|
63 #define STAGE3_WARNING(symbol1, symbol2, ...) { \ |
|
64 fprintf(stderr, "%s:%d-%d..%d-%d: warning: ", \ |
|
65 FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column,\ |
|
66 LAST_(symbol1,symbol2) ->last_line, LAST_(symbol1,symbol2) ->last_column);\ |
|
67 fprintf(stderr, __VA_ARGS__); \ |
|
68 fprintf(stderr, "\n"); \ |
|
69 warning_found = true; \ |
|
70 } |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 /*****************************************************/ |
|
80 /* */ |
|
81 /* A small helper class... */ |
|
82 /* */ |
|
83 /*****************************************************/ |
|
84 |
|
85 /* Add to the local_enumerated_value_symtable the local enum value constants */ |
|
86 |
|
87 |
|
88 class populate_enumvalue_symtable_c: public iterator_visitor_c { |
|
89 private: |
|
90 symbol_c *current_enumerated_type; |
|
91 symbol_c::enumvalue_symtable_t *enumvalue_symtable; |
|
92 |
|
93 private: |
|
94 int &error_count; |
|
95 int ¤t_display_error_level; |
|
96 |
|
97 public: |
|
98 populate_enumvalue_symtable_c(int &error_count_, int ¤t_display_error_level_) |
|
99 : error_count(error_count_), current_display_error_level(current_display_error_level_) { |
|
100 current_enumerated_type = NULL; |
|
101 enumvalue_symtable = NULL; |
|
102 }; |
|
103 ~populate_enumvalue_symtable_c(void) {} |
|
104 |
|
105 void populate(symbol_c::enumvalue_symtable_t *symtable, symbol_c *symbol) { |
|
106 enumvalue_symtable = symtable; |
|
107 symbol->accept(*this); |
|
108 enumvalue_symtable = NULL; |
|
109 } |
|
110 |
|
111 protected: |
|
112 /*************************/ |
|
113 /* B.1 - Common elements */ |
|
114 /*************************/ |
|
115 /**********************/ |
|
116 /* B.1.3 - Data types */ |
|
117 /**********************/ |
|
118 /********************************/ |
|
119 /* B 1.3.3 - Derived data types */ |
|
120 /********************************/ |
|
121 /* enumerated_type_name ':' enumerated_spec_init */ |
|
122 void *visit(enumerated_type_declaration_c *symbol) { |
|
123 current_enumerated_type = symbol; |
|
124 symbol->enumerated_spec_init->accept(*this); |
|
125 current_enumerated_type = NULL; |
|
126 return NULL; |
|
127 } |
|
128 |
|
129 /* enumerated_specification ASSIGN enumerated_value */ |
|
130 void *visit(enumerated_spec_init_c *symbol) { |
|
131 if (NULL == current_enumerated_type) |
|
132 current_enumerated_type = symbol; |
|
133 symbol->enumerated_specification->accept(*this); |
|
134 /* DO NOT visit the symbol->enumerated_value !!! */ |
|
135 current_enumerated_type = NULL; |
|
136 return NULL; |
|
137 } |
|
138 |
|
139 /* [enumerated_type_name '#'] identifier */ |
|
140 void *visit(enumerated_value_c *symbol) { |
|
141 token_c *value = dynamic_cast <token_c *>(symbol->value); |
|
142 if (NULL == value) ERROR; |
|
143 const char *value_str = value->value; |
|
144 |
|
145 if (current_enumerated_type == NULL) ERROR; |
|
146 /* this is really an ERROR! The initial value may use the syntax NUM_TYPE#enum_value, but in that case we should not have reached this visit method !! */ |
|
147 if (symbol->type != NULL) ERROR; |
|
148 |
|
149 symbol_c::enumvalue_symtable_t::iterator lower = enumvalue_symtable->lower_bound(value_str); |
|
150 symbol_c::enumvalue_symtable_t::iterator upper = enumvalue_symtable->upper_bound(value_str); |
|
151 for (; lower != upper; lower++) |
|
152 if (lower->second == current_enumerated_type) { |
|
153 /* The same identifier is used more than once as an enumerated value/constant inside the same enumerated datat type! */ |
|
154 STAGE3_ERROR(0, symbol, symbol, "Duplicate identifier in enumerated data type."); |
|
155 return NULL; /* No need to insert it! It is already in the table! */ |
|
156 } |
|
157 |
|
158 /* add it to the local symbol table. */ |
|
159 enumvalue_symtable->insert(std::pair<const char *, symbol_c *>(value_str, current_enumerated_type)); |
|
160 return NULL; |
|
161 } |
|
162 }; // class populate_enumvalue_symtable_c |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 enum_declaration_check_c::enum_declaration_check_c(symbol_c *ignore) { |
|
175 error_count = 0; |
|
176 current_display_error_level = 0; |
|
177 global_enumvalue_symtable = NULL; |
|
178 populate_enumvalue_symtable = new populate_enumvalue_symtable_c(error_count, current_display_error_level); |
|
179 } |
|
180 |
|
181 enum_declaration_check_c::~enum_declaration_check_c(void) {} |
|
182 |
|
183 int enum_declaration_check_c::get_error_count() {return error_count;} |
|
184 |
|
185 |
|
186 /***************************/ |
|
187 /* B 0 - Programming Model */ |
|
188 /***************************/ |
|
189 void *enum_declaration_check_c::visit(library_c *symbol) { |
|
190 global_enumvalue_symtable = &(symbol->enumvalue_symtable); |
|
191 iterator_visitor_c::visit(symbol); // fall back to base class |
|
192 return NULL; |
|
193 } |
|
194 |
|
195 |
|
196 |
|
197 /**********************/ |
|
198 /* B.1.3 - Data types */ |
|
199 /**********************/ |
|
200 void *enum_declaration_check_c::visit(data_type_declaration_c *symbol) { |
|
201 if (NULL == global_enumvalue_symtable) ERROR; |
|
202 populate_enumvalue_symtable->populate(global_enumvalue_symtable, symbol); |
|
203 return NULL; |
|
204 } |
|
205 |
|
206 /*********************/ |
|
207 /* B 1.5.1 Functions */ |
|
208 /*********************/ |
|
209 void *enum_declaration_check_c::visit(function_declaration_c *symbol) { |
|
210 populate_enumvalue_symtable->populate(&(symbol->enumvalue_symtable), symbol->var_declarations_list); |
|
211 return NULL; |
|
212 } |
|
213 |
|
214 /***************************/ |
|
215 /* B 1.5.2 Function blocks */ |
|
216 /***************************/ |
|
217 void *enum_declaration_check_c::visit(function_block_declaration_c *symbol) { |
|
218 populate_enumvalue_symtable->populate(&(symbol->enumvalue_symtable), symbol->var_declarations); |
|
219 return NULL; |
|
220 } |
|
221 |
|
222 /**********************/ |
|
223 /* B 1.5.3 - Programs */ |
|
224 /**********************/ |
|
225 void *enum_declaration_check_c::visit(program_declaration_c *symbol) { |
|
226 populate_enumvalue_symtable->populate(&(symbol->enumvalue_symtable), symbol->var_declarations); |
|
227 return NULL; |
|
228 } |
|
229 |
|
230 /********************************/ |
|
231 /* B 1.7 Configuration elements */ |
|
232 /********************************/ |
|
233 void *enum_declaration_check_c::visit(configuration_declaration_c *symbol) { |
|
234 if (NULL != symbol->global_var_declarations) |
|
235 populate_enumvalue_symtable->populate(&(symbol->enumvalue_symtable), symbol->global_var_declarations); |
|
236 if (NULL != symbol->resource_declarations) |
|
237 /* May reference either a list of resource_declaration_c, or a single_resource_declaration_c */ |
|
238 populate_enumvalue_symtable->populate(&(symbol->enumvalue_symtable), symbol->resource_declarations); |
|
239 |
|
240 return NULL; |
|
241 } |
|
242 |
|
243 |
|
244 void *enum_declaration_check_c::visit(resource_declaration_c *symbol) { |
|
245 if (NULL != symbol->global_var_declarations) |
|
246 populate_enumvalue_symtable->populate(&(symbol->enumvalue_symtable), symbol->global_var_declarations); |
|
247 return NULL; |
|
248 } |
|
249 |
|
250 |
|
251 void *enum_declaration_check_c::visit(single_resource_declaration_c *symbol) { |
|
252 /* do NOT visit! */ |
|
253 return NULL; |
|
254 } |