ccb@204: /* msousa@267: * matiec - a compiler for the programming languages defined in IEC 61131-3 ccb@204: * msousa@417: * Copyright (C) 2009-2012 Mario de Sousa (msousa@fe.up.pt) Edouard@279: * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant msousa@417: * Copyright (C) 2012 Manuele Conti (manuele.conti@sirius-es.it) msousa@417: * Copyright (C) 2012 Matteo Facchinetti (matteo.facchinetti@sirius-es.it) ccb@204: * msousa@267: * This program is free software: you can redistribute it and/or modify msousa@267: * it under the terms of the GNU General Public License as published by msousa@267: * the Free Software Foundation, either version 3 of the License, or msousa@267: * (at your option) any later version. msousa@267: * msousa@267: * This program is distributed in the hope that it will be useful, msousa@267: * but WITHOUT ANY WARRANTY; without even the implied warranty of msousa@267: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the msousa@267: * GNU General Public License for more details. msousa@267: * msousa@267: * You should have received a copy of the GNU General Public License msousa@267: * along with this program. If not, see . msousa@267: * ccb@204: * ccb@204: * This code is made available on the understanding that it will not be ccb@204: * used in safety-critical situations without a full and competent review. ccb@204: */ ccb@204: ccb@204: /* msousa@267: * An IEC 61131-3 compiler. ccb@204: * ccb@204: * Based on the msousa@267: * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) ccb@204: * ccb@204: */ ccb@204: ccb@204: #include "stage3.hh" ccb@204: msousa@443: #include "flow_control_analysis.hh" msousa@417: #include "fill_candidate_datatypes.hh" msousa@417: #include "narrow_candidate_datatypes.hh" msousa@677: #include "forced_narrow_candidate_datatypes.hh" msousa@417: #include "print_datatypes_error.hh" conti@508: #include "lvalue_check.hh" msousa@560: #include "array_range_check.hh" mjsousa@1000: #include "case_elements_check.hh" conti@564: #include "constant_folding.hh" conti@656: #include "declaration_check.hh" msousa@738: #include "enum_declaration_check.hh" mjsousa@959: #include "remove_forward_dependencies.hh" mjsousa@959: msousa@738: msousa@738: msousa@738: static int enum_declaration_check(symbol_c *tree_root){ msousa@738: enum_declaration_check_c enum_declaration_check(NULL); msousa@738: tree_root->accept(enum_declaration_check); msousa@738: return enum_declaration_check.get_error_count(); msousa@738: } msousa@738: msousa@530: mjsousa@986: /* In order to correctly handle variable sized arrays mjsousa@986: * declaration_safety() must only be run after constant folding! mjsousa@986: * NOTE that the dependency does not resides directly in declaration_check_c, mjsousa@986: * but rather indirectly in the call to get_datatype_info_c::is_type_equal() mjsousa@986: * which may in turn call get_datatype_info_c::is_arraytype_equal_relaxed() mjsousa@986: * mjsousa@986: * Example of a variable sized array: mjsousa@986: * VAR_EXTERN CONSTANT max: INT; END_VAR; mjsousa@986: * VAR_EXTERN xx: ARRAY [1..max] OF INT; END_VAR; mjsousa@986: */ conti@656: static int declaration_safety(symbol_c *tree_root){ conti@656: declaration_check_c declaration_check(tree_root); conti@656: tree_root->accept(declaration_check); conti@656: return declaration_check.get_error_count(); conti@656: } msousa@530: msousa@443: static int flow_control_analysis(symbol_c *tree_root){ conti@564: flow_control_analysis_c flow_control_analysis(tree_root); conti@564: tree_root->accept(flow_control_analysis); conti@564: return 0; msousa@443: } msousa@443: msousa@530: msousa@612: /* Constant folding assumes that flow control analysis has been completed! msousa@612: * so be sure to call flow_control_analysis() before calling this function! msousa@612: */ mjsousa@984: static int constant_propagation(symbol_c *tree_root){ mjsousa@984: constant_propagation_c constant_propagation(tree_root); mjsousa@984: tree_root->accept(constant_propagation); mjsousa@984: return constant_propagation.get_error_count(); msousa@612: } msousa@612: msousa@612: msousa@611: /* Type safety analysis assumes that msousa@611: * - flow control analysis msousa@611: * - constant folding (constant check) msousa@611: * has already been completed, so be sure to call those semantic checkers msousa@611: * before calling this function msousa@443: */ msousa@443: static int type_safety(symbol_c *tree_root){ msousa@417: fill_candidate_datatypes_c fill_candidate_datatypes(tree_root); msousa@417: tree_root->accept(fill_candidate_datatypes); msousa@417: narrow_candidate_datatypes_c narrow_candidate_datatypes(tree_root); msousa@417: tree_root->accept(narrow_candidate_datatypes); msousa@444: print_datatypes_error_c print_datatypes_error(tree_root); msousa@417: tree_root->accept(print_datatypes_error); msousa@677: forced_narrow_candidate_datatypes_c forced_narrow_candidate_datatypes(tree_root); msousa@677: tree_root->accept(forced_narrow_candidate_datatypes); msousa@510: return print_datatypes_error.get_error_count(); ccb@204: } ccb@204: msousa@443: msousa@612: /* Left value checking assumes that data type analysis has already been completed, msousa@530: * so be sure to call type_safety() before calling this function msousa@510: */ msousa@510: static int lvalue_check(symbol_c *tree_root){ msousa@510: lvalue_check_c lvalue_check(tree_root); msousa@510: tree_root->accept(lvalue_check); msousa@510: return lvalue_check.get_error_count(); msousa@510: } msousa@510: msousa@612: /* Array range check assumes that constant folding has been completed! msousa@612: * so be sure to call constant_folding() before calling this function! msousa@612: */ msousa@612: static int array_range_check(symbol_c *tree_root){ msousa@560: array_range_check_c array_range_check(tree_root); msousa@560: tree_root->accept(array_range_check); msousa@560: return array_range_check.get_error_count(); conti@559: } conti@559: msousa@443: mjsousa@1000: /* Case options check assumes that constant folding has been completed! mjsousa@1000: * so be sure to call constant_folding() before calling this function! mjsousa@1000: */ mjsousa@1000: static int case_elements_check(symbol_c *tree_root){ mjsousa@1000: case_elements_check_c case_elements_check(tree_root); mjsousa@1000: tree_root->accept(case_elements_check); mjsousa@1000: return case_elements_check.get_error_count(); mjsousa@1000: } mjsousa@1000: mjsousa@959: mjsousa@959: /* Removing forward dependencies only makes sense when stage1_2 is run with the pre-parsing option. mjsousa@959: * This algorithm has no dependencies on other stage 3 algorithms. mjsousa@959: * Typically this is run last, just to show that the remaining algorithms also do not depend on the fact that mjsousa@959: * the library_c (i.e. the source code) does not contain forward dependencies. mjsousa@959: */ mjsousa@959: static int remove_forward_dependencies(symbol_c *tree_root, symbol_c **ordered_tree_root) { mjsousa@959: if (NULL != ordered_tree_root) *ordered_tree_root = tree_root; // by default, consider tree_root already ordered mjsousa@959: if (!runtime_options.pre_parsing) return 0; // No re-ordering necessary, just return mjsousa@959: mjsousa@959: /* We need to re-order the elements in the library, to fix any forward references! */ mjsousa@959: remove_forward_dependencies_c remove_forward_dependencies; mjsousa@959: symbol_c *new_tree_root = remove_forward_dependencies.create_new_tree(tree_root); mjsousa@959: if (NULL == new_tree_root) ERROR; mjsousa@959: if (NULL != ordered_tree_root) *ordered_tree_root = new_tree_root; mjsousa@959: return remove_forward_dependencies.get_error_count(); mjsousa@959: } mjsousa@959: mjsousa@959: mjsousa@959: int stage3(symbol_c *tree_root, symbol_c **ordered_tree_root) { msousa@510: int error_count = 0; msousa@738: error_count += enum_declaration_check(tree_root); msousa@510: error_count += flow_control_analysis(tree_root); mjsousa@984: error_count += constant_propagation(tree_root); mjsousa@986: error_count += declaration_safety(tree_root); msousa@510: error_count += type_safety(tree_root); msousa@510: error_count += lvalue_check(tree_root); msousa@612: error_count += array_range_check(tree_root); mjsousa@1000: error_count += case_elements_check(tree_root); mjsousa@959: error_count += remove_forward_dependencies(tree_root, ordered_tree_root); msousa@510: msousa@510: if (error_count > 0) { msousa@516: fprintf(stderr, "%d error(s) found. Bailing out!\n", error_count); msousa@510: return -1; msousa@510: } msousa@510: return 0; ccb@204: }