conti@748: /* conti@748: * matiec - a compiler for the programming languages defined in IEC 61131-3 conti@748: * conti@748: * Copyright (C) 2009-2012 Mario de Sousa (msousa@fe.up.pt) conti@748: * Copyright (C) 2012 Manuele Conti (conti.ma@alice.it) conti@748: * conti@748: * conti@748: * This program is free software: you can redistribute it and/or modify conti@748: * it under the terms of the GNU General Public License as published by conti@748: * the Free Software Foundation, either version 3 of the License, or conti@748: * (at your option) any later version. conti@748: * conti@748: * This program is distributed in the hope that it will be useful, conti@748: * but WITHOUT ANY WARRANTY; without even the implied warranty of conti@748: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the conti@748: * GNU General Public License for more details. conti@748: * conti@748: * You should have received a copy of the GNU General Public License conti@748: * along with this program. If not, see . conti@748: * conti@748: * conti@748: * This code is made available on the understanding that it will not be conti@748: * used in safety-critical situations without a full and competent review. conti@748: */ conti@748: conti@748: /* conti@748: * An IEC 61131-3 compiler. conti@748: * conti@748: * Based on the conti@748: * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) conti@748: * conti@748: */ conti@748: conti@748: #include conti@748: #include "create_enumtype_conversion_functions.hh" conti@748: conti@748: /* set to 1 to see debug info during execution */ conti@748: static const int debug = 0; conti@748: msousa@756: msousa@756: /* msousa@756: * The create_enumtype_conversion_functions_c class generates ST source code! msousa@756: * This code is in actual fact datatype conversion functions between user defined msousa@756: * enumerated datatypes, and some basic datatypes. msousa@756: * msousa@756: * These conversion functions cannot be implemented the normal way (i.e. in the standard library) msousa@756: * since they convert from/to a datatype that is defined by the user. So, we generate these conversions msousa@756: * functions on the fly! msousa@756: * (to get an idea of what the generated code looks like, see the comments in create_enumtype_conversion_functions.cc) msousa@756: * msousa@756: * Currently, we support conversion between the user defined enumerated datatype and STRING, msousa@756: * SINT, INT, DINT, LINT, USINT, UINT, UDINT, ULINT (basically the ANY_INT) msousa@756: * msousa@756: * ST source code is generated when the method get_declaration() is called. since the msousa@756: * create_enumtype_conversion_functions_c inherits from the iterator visitor, this method may be msousa@756: * passed either the root of an abstract syntax tree, or sub-tree of the AST. msousa@756: * msousa@756: * This class will iterate through that AST, and for each enumerated type declaration, will msousa@756: * create the apropriate conversion functions. msousa@756: */ msousa@756: msousa@756: create_enumtype_conversion_functions_c *create_enumtype_conversion_functions_c::singleton = NULL; msousa@756: msousa@756: create_enumtype_conversion_functions_c:: create_enumtype_conversion_functions_c(symbol_c *ignore) {} msousa@756: create_enumtype_conversion_functions_c::~create_enumtype_conversion_functions_c(void) {} msousa@756: msousa@756: msousa@756: std::string &create_enumtype_conversion_functions_c::get_declaration(symbol_c *symbol) { msousa@756: if (NULL == singleton) singleton = new create_enumtype_conversion_functions_c(NULL); msousa@756: if (NULL == singleton) ERROR_MSG("Out of memory. Bailing out!\n"); msousa@756: msousa@756: singleton->text = ""; msousa@756: if (NULL != symbol) msousa@756: symbol->accept(*singleton); msousa@756: msousa@756: return singleton->text; msousa@756: } msousa@756: mjsousa@958: /* As the name of derived datatypes and POUs are still stored as identifiers in the respective datatype and POU declaration, */ mjsousa@958: /* only the indintifier_c visitor should be necessary! */ mjsousa@958: void *create_enumtype_conversion_functions_c::visit( identifier_c *symbol) {currentToken = symbol->value; return NULL;} mjsousa@958: void *create_enumtype_conversion_functions_c::visit( poutype_identifier_c *symbol) {ERROR; return NULL;} mjsousa@958: void *create_enumtype_conversion_functions_c::visit(derived_datatype_identifier_c *symbol) {ERROR; return NULL;} mjsousa@958: conti@748: conti@748: /**********************/ conti@748: /* B 1.3 - Data types */ conti@748: /**********************/ conti@748: /********************************/ conti@748: /* B 1.3.3 - Derived data types */ conti@748: /********************************/ conti@748: void *create_enumtype_conversion_functions_c::visit(enumerated_type_declaration_c *symbol) { conti@748: std::string enumerateName; conti@748: std::string functionName; conti@748: std::list enumerateValues; conti@748: conti@748: symbol->enumerated_type_name->accept(*this); conti@748: enumerateName = currentToken; conti@748: conti@748: symbol->enumerated_spec_init->accept(*this); conti@748: enumerateValues = currentTokenList; conti@748: conti@748: printStringToEnum (enumerateName, enumerateValues); conti@748: printEnumToString (enumerateName, enumerateValues); conti@748: for (size_t s = 8; s <= 64; s*= 2) { conti@748: printIntegerToEnum (enumerateName, enumerateValues, true , s); conti@748: printEnumToInteger (enumerateName, enumerateValues, true , s); conti@748: printIntegerToEnum (enumerateName, enumerateValues, false, s); conti@748: printEnumToInteger (enumerateName, enumerateValues, false, s); conti@748: } conti@748: if (debug) std::cout << text << std::endl; conti@748: conti@748: return NULL; conti@748: } conti@748: conti@748: void *create_enumtype_conversion_functions_c::visit(enumerated_value_list_c *symbol) { conti@748: list_c *list; conti@748: conti@748: currentTokenList.clear(); conti@748: list = (list_c *)symbol; conti@748: for (int i = 0; i < list->n; i++) { msousa@1041: list->get_element(i)->accept(*this); conti@748: currentTokenList.push_back(currentToken); conti@748: } conti@748: conti@748: return NULL; conti@748: } conti@748: conti@748: /* conti@748: * getIntegerName function generate a integer data name from signed and size. conti@748: */ conti@748: std::string create_enumtype_conversion_functions_c::getIntegerName(bool isSigned, size_t size) { conti@748: std::string integerType = ""; conti@748: if (! isSigned) { conti@748: integerType = "U"; conti@748: } conti@748: switch(size) { conti@748: case 8 : integerType += "S"; break; conti@748: case 16: break; conti@748: case 32: integerType += "D"; break; conti@748: case 64: integerType += "L"; break; conti@748: default: break; conti@748: } conti@748: integerType +="INT"; conti@748: conti@748: return integerType; conti@748: } conti@748: conti@748: /* conti@748: * printStringToEnum function print conversion function from STRING to : conti@748: * ST Output: conti@748: * conti@748: conti@748: FUNCTION STRING_TO_ : conti@748: VAR_INPUT conti@748: IN: STRING; conti@748: END_VAR conti@748: IF IN = '' THEN conti@765: STRING_TO_ := #; conti@748: RETURN; conti@748: END_IF; conti@748: ... conti@748: IF IN = '' THEN conti@765: STRING_TO_ := #; conti@748: RETURN; conti@748: END_IF; conti@754: ENO := FALSE; conti@748: END_FUNCTION conti@748: conti@749: Note: if you change code below remember to update this comment. conti@748: */ conti@748: void create_enumtype_conversion_functions_c::printStringToEnum (std::string &enumerateName, std::list &enumerateValues) { conti@748: std::list ::const_iterator itr; conti@748: std::string functionName; conti@748: conti@748: functionName = "STRING_TO_" + enumerateName; conti@748: text += "FUNCTION " + functionName + " : " + enumerateName; conti@748: text += "\nVAR_INPUT\nIN : STRING;\nEND_VAR\n"; conti@748: for (itr = enumerateValues.begin(); itr != enumerateValues.end(); ++itr) { conti@748: std::string value = *itr; conti@748: text += "IF IN = '" + value + "' THEN\n"; conti@765: text += " " + functionName + " := " + enumerateName + "#" + value + ";\n"; conti@754: text += " RETURN;\n"; conti@748: text += "END_IF;\n"; conti@748: } conti@754: text += "ENO := FALSE;\n"; conti@748: text += "END_FUNCTION\n\n"; conti@748: } conti@748: conti@748: /* conti@748: * printEnumToString function print conversion function from to STRING: conti@748: * ST Output: conti@748: * conti@748: conti@748: FUNCTION _TO_STRING : STRING conti@748: VAR_INPUT conti@748: IN: ; conti@748: END_VAR conti@765: IF IN = # THEN conti@764: _TO_STRING := '#'; conti@748: RETURN; conti@748: END_IF; conti@748: ... conti@765: IF IN = # THEN conti@764: _TO_STRING := '#'; conti@748: RETURN; conti@748: END_IF; conti@754: ENO := FALSE; conti@748: END_FUNCTION conti@748: conti@749: Note: if you change code below remember to update this comment. conti@748: */ conti@748: void create_enumtype_conversion_functions_c::printEnumToString (std::string &enumerateName, std::list &enumerateValues) { conti@748: std::list ::const_iterator itr; conti@748: std::string functionName; conti@748: conti@748: functionName = enumerateName + "_TO_STRING"; conti@748: text += "FUNCTION " + functionName + " : STRING"; conti@748: text += "\nVAR_INPUT\nIN : " + enumerateName + ";\nEND_VAR\n"; conti@748: for (itr = enumerateValues.begin(); itr != enumerateValues.end(); ++itr) { conti@748: std::string value = *itr; conti@765: text += "IF IN = " + enumerateName + "#" + value + " THEN\n"; conti@764: text += " " + functionName + " := '" + enumerateName + "#" + value + "';\n"; conti@748: text += " RETURN;\n"; conti@748: text += "END_IF;\n"; conti@748: } conti@754: text += "ENO := FALSE;\n"; conti@748: text += "END_FUNCTION\n\n"; conti@748: } conti@748: conti@748: /* conti@748: * printIntegerToEnum function print conversion function from to : conti@748: * ST Output: conti@748: * conti@748: conti@748: FUNCTION _TO_ : conti@748: VAR_INPUT conti@748: IN: ; conti@748: END_VAR conti@748: IF IN = 1 THEN conti@765: _TO_ := #; conti@748: RETURN; conti@748: END_IF; conti@748: ... conti@748: IF IN = N THEN conti@765: _TO_ := #; conti@748: RETURN; conti@748: END_IF; conti@754: ENO := FALSE; conti@748: END_FUNCTION conti@748: conti@749: Note: if you change code below remember to update this comment. conti@748: */ conti@748: void create_enumtype_conversion_functions_c::printIntegerToEnum (std::string &enumerateName, std::list &enumerateValues, bool isSigned, size_t size) { conti@748: std::list ::const_iterator itr; conti@748: std::string functionName; conti@748: std::string integerType; conti@748: int count; conti@748: conti@748: integerType = getIntegerName(isSigned, size); conti@748: functionName = integerType + "_TO_" + enumerateName; conti@748: text += "FUNCTION " + functionName + " : " + enumerateName; conti@748: text += "\nVAR_INPUT\nIN : " + integerType + ";\nEND_VAR\n"; conti@748: count = 0; conti@748: for (itr = enumerateValues.begin(); itr != enumerateValues.end(); ++itr) { conti@748: std::string value = *itr; conti@748: std::stringstream out; conti@748: out << count; conti@748: text += "IF IN = " + out.str() + " THEN\n"; conti@765: text += " " + functionName + " := " + enumerateName + "#" + value + ";\n"; conti@748: text += " RETURN;\n"; conti@748: text += "END_IF;\n"; conti@748: count++; conti@748: } conti@754: text += "ENO := FALSE;\n"; conti@748: text += "END_FUNCTION\n\n"; conti@748: } conti@748: conti@748: /* conti@748: * printEnumToInteger function print conversion function from to : conti@748: * ST Output: conti@748: * conti@748: conti@748: FUNCTION _TO_ : conti@748: VAR_INPUT conti@748: IN: ; conti@748: END_VAR conti@765: IF IN = # THEN conti@748: _TO_ := 1; conti@748: RETURN; conti@748: END_IF; conti@748: ... conti@765: IF IN = # THEN conti@748: _TO_ := N; conti@748: RETURN; conti@748: END_IF; conti@754: ENO := FALSE; conti@748: END_FUNCTION conti@748: conti@749: Note: if you change code below remember to update this comment. conti@748: */ conti@748: void create_enumtype_conversion_functions_c::printEnumToInteger (std::string &enumerateName, std::list &enumerateValues, bool isSigned, size_t size) { conti@748: std::list ::const_iterator itr; conti@748: std::string functionName; conti@748: std::string integerType; conti@748: int count; conti@748: conti@748: integerType = getIntegerName(isSigned, size); conti@748: functionName = enumerateName + "_TO_" + integerType; conti@748: text += "FUNCTION " + functionName + " : " + integerType; conti@748: text += "\nVAR_INPUT\nIN : " + enumerateName + ";\nEND_VAR\n"; conti@748: count = 0; conti@748: for (itr = enumerateValues.begin(); itr != enumerateValues.end(); ++itr) { conti@748: std::string value = *itr; conti@748: std::stringstream out; conti@748: out << count; conti@765: text += "IF IN = " + enumerateName + "#" + value + " THEN\n"; conti@748: text += " " + functionName + " := " + out.str() + ";\n"; conti@748: text += " RETURN;\n"; conti@748: text += "END_IF;\n"; conti@748: count++; conti@748: } conti@754: text += "ENO := FALSE;\n"; conti@748: text += "END_FUNCTION\n\n"; conti@748: } conti@748: conti@748: conti@748: