stage3/case_elements_check.cc
changeset 1000 556b74055518
child 1041 56ebe2a31b5b
equal deleted inserted replaced
999:dd50a82ae8da 1000:556b74055518
       
     1 /*
       
     2  *  matiec - a compiler for the programming languages defined in IEC 61131-3
       
     3  *
       
     4  *  Copyright (C) 2015  Mario de Sousa (msousa@fe.up.pt)
       
     5  *
       
     6  *
       
     7  *  This program is free software: you can redistribute it and/or modify
       
     8  *  it under the terms of the GNU General Public License as published by
       
     9  *  the Free Software Foundation, either version 3 of the License, or
       
    10  *  (at your option) any later version.
       
    11  *
       
    12  *  This program is distributed in the hope that it will be useful,
       
    13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    15  *  GNU General Public License for more details.
       
    16  *
       
    17  *  You should have received a copy of the GNU General Public License
       
    18  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
       
    19  *
       
    20  *
       
    21  * This code is made available on the understanding that it will not be
       
    22  * used in safety-critical situations without a full and competent review.
       
    23  */
       
    24 
       
    25 /*
       
    26  * An IEC 61131-3 compiler.
       
    27  *
       
    28  * Based on the
       
    29  * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
       
    30  *
       
    31  */
       
    32 
       
    33 
       
    34 /*
       
    35  * Case Options Checking:
       
    36  *   - Check whether the options in a case statement are repeated, either directly, or in a range.
       
    37  *       For example:
       
    38  *         case var of
       
    39  *           1: ...   <- OK
       
    40  *           2: ...   <- OK
       
    41  *           1: ...   <- OK (not an error), but produce a warning due to repeated '1'!
       
    42  *           0..8: ...<- OK (not an error), but produce a warning cue to repeated '1' and '2'!
       
    43  */
       
    44 
       
    45 
       
    46 #include "case_elements_check.hh"
       
    47 
       
    48 
       
    49 #define FIRST_(symbol1, symbol2) (((symbol1)->first_order < (symbol2)->first_order)   ? (symbol1) : (symbol2))
       
    50 #define  LAST_(symbol1, symbol2) (((symbol1)->last_order  > (symbol2)->last_order)    ? (symbol1) : (symbol2))
       
    51 
       
    52 #define STAGE3_ERROR(error_level, symbol1, symbol2, ...) {                                                                  \
       
    53   if (current_display_error_level >= error_level) {                                                                         \
       
    54     fprintf(stderr, "%s:%d-%d..%d-%d: error: ",                                                                             \
       
    55             FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column,\
       
    56                                                  LAST_(symbol1,symbol2) ->last_line,  LAST_(symbol1,symbol2) ->last_column);\
       
    57     fprintf(stderr, __VA_ARGS__);                                                                                           \
       
    58     fprintf(stderr, "\n");                                                                                                  \
       
    59     error_count++;                                                                                                     \
       
    60   }                                                                                                                         \
       
    61 }
       
    62 
       
    63 
       
    64 #define STAGE3_WARNING(symbol1, symbol2, ...) {                                                                             \
       
    65     fprintf(stderr, "%s:%d-%d..%d-%d: warning: ",                                                                           \
       
    66             FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column,\
       
    67                                                  LAST_(symbol1,symbol2) ->last_line,  LAST_(symbol1,symbol2) ->last_column);\
       
    68     fprintf(stderr, __VA_ARGS__);                                                                                           \
       
    69     fprintf(stderr, "\n");                                                                                                  \
       
    70     warning_found = true;                                                                                                   \
       
    71 }
       
    72 
       
    73 
       
    74 #define GET_CVALUE(dtype, symbol)             ((symbol)->const_value._##dtype.get())
       
    75 #define VALID_CVALUE(dtype, symbol)           ((symbol)->const_value._##dtype.is_valid())
       
    76 
       
    77 
       
    78 
       
    79 
       
    80 case_elements_check_c::case_elements_check_c(symbol_c *ignore) {
       
    81   warning_found = false;
       
    82   error_count = 0;
       
    83   current_display_error_level = 0;
       
    84 }
       
    85 
       
    86 
       
    87 
       
    88 case_elements_check_c::~case_elements_check_c(void) {
       
    89 }
       
    90 
       
    91 
       
    92 
       
    93 int case_elements_check_c::get_error_count() {
       
    94   return error_count;
       
    95 }
       
    96 
       
    97 
       
    98 
       
    99 
       
   100 /* compare two integer constants, and determins if s1 < s2 */
       
   101 static bool less_than(symbol_c *s1, symbol_c *s2) {
       
   102   if (   (VALID_CVALUE( int64, s1))
       
   103       && (VALID_CVALUE( int64, s2))
       
   104       && (  GET_CVALUE( int64, s1) < GET_CVALUE( int64, s2)))
       
   105     return true;
       
   106   
       
   107   if (   (VALID_CVALUE(uint64, s1))
       
   108       && (VALID_CVALUE(uint64, s2))
       
   109       && (  GET_CVALUE(uint64, s1) < GET_CVALUE(uint64, s2)))
       
   110     return true;
       
   111   
       
   112   if (   (VALID_CVALUE( int64, s1))
       
   113       && (VALID_CVALUE(uint64, s2))
       
   114       && (  GET_CVALUE( int64, s1) < 0))
       
   115     return true;
       
   116   
       
   117   return false;
       
   118 }
       
   119 
       
   120 
       
   121 
       
   122 void case_elements_check_c::check_subr_subr(symbol_c *s1, symbol_c *s2) {
       
   123   subrange_c *sub1 = dynamic_cast<subrange_c *>(s1);
       
   124   subrange_c *sub2 = dynamic_cast<subrange_c *>(s2);
       
   125   
       
   126   if ((NULL == sub1) || (NULL == sub2)) return;
       
   127   symbol_c *l1 = sub1->lower_limit;
       
   128   symbol_c *u1 = sub1->upper_limit;
       
   129   symbol_c *l2 = sub2->lower_limit;
       
   130   symbol_c *u2 = sub2->upper_limit;
       
   131   
       
   132   if (less_than(u1, l2))  return; // no overlap!
       
   133   if (less_than(u2, l1))  return; // no overlap!
       
   134 
       
   135   if (   (VALID_CVALUE( int64, l1) || (VALID_CVALUE(uint64, l1)))
       
   136       && (VALID_CVALUE( int64, l2) || (VALID_CVALUE(uint64, l2)))
       
   137       && (VALID_CVALUE( int64, u1) || (VALID_CVALUE(uint64, u1)))
       
   138       && (VALID_CVALUE( int64, u2) || (VALID_CVALUE(uint64, u2))))
       
   139     STAGE3_WARNING(s1, s2, "Elements in CASE options have overlapping ranges.");
       
   140 }
       
   141 
       
   142 
       
   143 
       
   144 
       
   145 void case_elements_check_c::check_subr_symb(symbol_c *s1, symbol_c *s2) {
       
   146   subrange_c *subr = NULL;
       
   147   symbol_c   *symb = NULL;
       
   148   if ((subr = dynamic_cast<subrange_c *>(s1)) != NULL) {symb = s2;}
       
   149   if ((subr = dynamic_cast<subrange_c *>(s2)) != NULL) {symb = s1;}
       
   150   
       
   151   if ((NULL == subr) || (NULL == symb)) return;
       
   152   symbol_c   *lowl = subr->lower_limit;
       
   153   symbol_c   *uppl = subr->upper_limit;
       
   154   
       
   155   if (   (VALID_CVALUE(int64, symb))
       
   156       && (VALID_CVALUE(int64, lowl))
       
   157       && (VALID_CVALUE(int64, uppl))
       
   158       && (  GET_CVALUE(int64, symb) >= GET_CVALUE(int64, lowl))
       
   159       && (  GET_CVALUE(int64, symb) <= GET_CVALUE(int64, uppl)))
       
   160     {STAGE3_WARNING(s1, s2, "Element in CASE option falls within range of another element."); return;}
       
   161     
       
   162   if (   (VALID_CVALUE(uint64, symb))
       
   163       && (VALID_CVALUE( int64, lowl))
       
   164       && (VALID_CVALUE(uint64, uppl))
       
   165       && (  GET_CVALUE( int64, lowl) < 0)
       
   166       && (  GET_CVALUE(uint64, symb) <= GET_CVALUE(uint64, uppl)))
       
   167     {STAGE3_WARNING(s1, s2, "Element in CASE option falls within range of another element."); return;}
       
   168 
       
   169   if (   (VALID_CVALUE(uint64, symb))
       
   170       && (VALID_CVALUE(uint64, lowl))
       
   171       && (VALID_CVALUE(uint64, uppl))
       
   172       && (  GET_CVALUE(uint64, symb) >= GET_CVALUE(uint64, lowl))
       
   173       && (  GET_CVALUE(uint64, symb) <= GET_CVALUE(uint64, uppl)))
       
   174     {STAGE3_WARNING(s1, s2, "Element in CASE option falls within range of another element."); return;}
       
   175 }
       
   176 
       
   177 
       
   178 
       
   179 
       
   180 #include <typeinfo>
       
   181 void case_elements_check_c::check_symb_symb(symbol_c *s1, symbol_c *s2) {
       
   182   if (   (dynamic_cast<subrange_c *>(s1) != NULL)
       
   183       || (dynamic_cast<subrange_c *>(s2) != NULL)) 
       
   184     return; // only run this test if neither s1 nor s2 are subranges!
       
   185   
       
   186   if (   (s1->const_value.is_const() && s2->const_value.is_const() && (s1->const_value == s2->const_value))  // if const, then compare const values (using overloaded '==' operator!)
       
   187       || (compare_identifiers(s1, s2) == 0))  // if token_c, compare tokens! (compare_identifiers() returns 0 when equal tokens!, -1 when either is not token_c)
       
   188     STAGE3_WARNING(s1, s2, "Duplicate element found in CASE options.");
       
   189 }
       
   190 
       
   191 
       
   192 
       
   193 
       
   194 
       
   195 
       
   196 
       
   197 
       
   198 
       
   199 /***************************************/
       
   200 /* B.3 - Language ST (Structured Text) */
       
   201 /***************************************/
       
   202 /********************/
       
   203 /* B 3.2 Statements */
       
   204 /********************/
       
   205 /********************************/
       
   206 /* B 3.2.3 Selection Statements */
       
   207 /********************************/
       
   208 /* CASE expression OF case_element_list ELSE statement_list END_CASE */
       
   209 // SYM_REF3(case_statement_c, expression, case_element_list, statement_list)
       
   210 void *case_elements_check_c::visit(case_statement_c *symbol) {
       
   211   std::vector<symbol_c *> case_elements_list_local = case_elements_list; // Required when source code contains CASE inside another CASE !
       
   212 
       
   213   case_elements_list.clear();
       
   214   symbol->case_element_list->accept(*this); // will fill up the case_elements_list with all the elements in the case!
       
   215   
       
   216   // OK, now check whether we have any overlappings...
       
   217   std::vector<symbol_c *>::iterator s1 = case_elements_list.begin();
       
   218   for (  ; s1 != case_elements_list.end(); s1++) {
       
   219     std::vector<symbol_c *>::iterator s2 = s1;
       
   220     s2++; // do not compare the value with itself!
       
   221     for (; s2 != case_elements_list.end(); s2++) {
       
   222       // Check for overlapping elements
       
   223       check_subr_subr(*s1, *s2);
       
   224       check_subr_symb(*s1, *s2);
       
   225       check_symb_symb(*s2, *s1);
       
   226     }
       
   227   }
       
   228   
       
   229   case_elements_list = case_elements_list_local;
       
   230   return NULL;
       
   231 }
       
   232 
       
   233 /* helper symbol for case_statement */
       
   234 // SYM_LIST(case_element_list_c)
       
   235 // void *case_elements_check_c::visit(case_element_list_c *symbol) // not needed! We inherit from iterator_visitor_c
       
   236 
       
   237 /*  case_list ':' statement_list */
       
   238 // SYM_REF2(case_element_c, case_list, statement_list)
       
   239 // void *case_elements_check_c::visit(case_element_c *symbol) // not needed! We inherit from iterator_visitor_c
       
   240 
       
   241 
       
   242 // SYM_LIST(case_list_c)
       
   243 void *case_elements_check_c::visit(case_list_c *symbol) {
       
   244   for (int i = 0; i < symbol->n; i++)
       
   245     case_elements_list.push_back(symbol->elements[i]);
       
   246   return NULL;
       
   247 }
       
   248 
       
   249