#!/usr/bin/python3.8 """ @file mib_datapool_parser.py @brief Parses the global datapools and generates the corresponding source file optionally. Python 3.8 required. @details Used by the MIB Exporter, inherits generic File Parser. @author R. Mueller @date 03.01.2020 """ import re from enum import Enum from datetime import date from parserbase.mib_parser import FileParser from utility.mib_csv_writer import CsvWriter from utility.mib_printer import Printer from utility.mib_file_management import copy_file DATE_TODAY = date.today() DATAPOOL_FILE = "../../config/dataPool/dataPoolInit.h" DATAPOOL_CSV_NAME = "mib_datapool.csv" CPP_FILE_NAME = "dataPoolInit.cpp" WRITE_CSV_FILE = True COPY_CSV_FILE = True WRITE_CPP_FILE = True COPY_CPP_FILE = False CPP_COPY_DESTINATION = "../../config/dataPool/" DATAPOOL_HEADER_COLUMNS = ["Pool ID", "Group", "Name", "Code Name", "Size", "Type", "Unit"] class DatapoolColumns(Enum): """ Specifies order of MIB columns """ POOL_ID = 0 GROUP = 1 NAME = 2 CODE_NAME = 3 SIZE = 4 TYPE = 5 UNIT = 6 Clmns = DatapoolColumns def main(): """ This main is run if the datapool parser is to be run separately. :return: """ file_list = [DATAPOOL_FILE] print("DatapoolParser: Parsing datapool header file:") print(file_list[0]) datapool_parser = DatapoolParser(file_list) datapool_table = datapool_parser.parse_files() Printer.print_content(datapool_table, "DatapoolParser: Printing datapool variable table:") dh_command_writer = CsvWriter(DATAPOOL_CSV_NAME, datapool_table, DATAPOOL_HEADER_COLUMNS) if WRITE_CSV_FILE: dh_command_writer.write_to_csv() if COPY_CSV_FILE: dh_command_writer.move_csv("..") if WRITE_CPP_FILE: datapool_parser.write_data_pool_init_cpp() print("DatapoolParser: C++ File was created.") if COPY_CPP_FILE: copy_file(CPP_FILE_NAME, CPP_COPY_DESTINATION) print("DatapoolParser: Generated C++ file was copied to " + CPP_COPY_DESTINATION) class DatapoolParser(FileParser): """ This parser reads the central datapool header file. It can optionally generate the corresponding source file (C++11 needed). Instantiate the class by supplying a number of files to parse and call the parse_files() method :return: """ def __init__(self, file_list): super().__init__(file_list) # this table includes the current new table entry, # which will be updated for target parameter self.dict_entry_list = list(range(Clmns.__len__())) self.cpp_file_information_list = [] self.parse_success = False self.parse_for_datapool_entries = False self.prev_group = "" def _handle_file_parsing(self, file_name: str, *args, **kwargs): file = open(file_name, "r") print("Parsing " + file_name + " ...") linecount = 1 for line in file.readlines(): self.__handle_line_reading(line) linecount = linecount + 1 def _post_parsing_operation(self): if len(self.mib_table) > 0: self.parse_success = True def write_data_pool_init_cpp(self): """ Writes the data pool CPP source file if the parsing was successfull :param copy_cpp: :param cpp_file_name: :param cpp_copy_destination: :return: """ if not self.parse_success: print("Datapool Parser: MIB Table is empty, no data to write CPP file") return cpp_file = open(CPP_FILE_NAME, "w") current_date = DATE_TODAY.strftime("%d.%m.%Y") header = "/**\n * @file\tdataPoolInit.cpp\n *\n * @brief\tAuto-Generated datapool " \ "initialization\n * @date\t" + current_date +\ "\n */\n#include " \ "\n\nvoid datapool::dataPoolInit(poolMap * poolMap) {\n" cpp_file.write(header) entries_len = self.index + 1 for index in range(1, entries_len): self.__handle_entry_write(cpp_file, index) tail = "\n}\n" cpp_file.write(tail) cpp_file.close() def __handle_line_reading(self, line): if self.parse_for_datapool_entries: if not self.__scan_for_pool_variable(line): self.__scan_for_export_string(line) if not self.parse_for_datapool_entries: datapool_start = re.search(r'[\s]*enum[\w_ ]*[\s]*{', line) if datapool_start: self.parse_for_datapool_entries = True else: self.__scan_for_datapool_end(line) def __scan_for_export_string(self, line): export_string_match = re.search(r'[/*!>< ]*\[EXPORT\][ :]*([^\n]*)', line, re.IGNORECASE) if export_string_match: self.__handle_export_string_match(export_string_match.group(1)) return export_string_match def __handle_export_string_match(self, string): group_match = re.search(r'\[GROUP\][\s]*([^\n\*]*)', string, re.IGNORECASE) if group_match: self.dict_entry_list[Clmns.GROUP.value] = group_match.group(1).rstrip() def __scan_for_pool_variable(self, line): pool_var_match = re.search(r'[\s]*([\w]*)[ =]*([\w]*)(?:,)?[\s]*([^\n]*)', line) if pool_var_match: if pool_var_match.group(1) == "": return False self.__handle_pool_var_match(pool_var_match) return pool_var_match def __handle_pool_var_match(self, pool_var_match): if re.search(r'NO_PARAMETER', pool_var_match.group(0)): return self.dict_entry_list[Clmns.CODE_NAME.value] = pool_var_match.group(1) self.dict_entry_list[Clmns.POOL_ID.value] = pool_var_match.group(2) export_string_match = re.search(r'[/!< ]*\[EXPORT\][: ]*([^\n]*)', pool_var_match.group(3), re.IGNORECASE) if export_string_match: self.__handle_pool_var_export_string(export_string_match.group(1)) datapool_tuple = tuple(self.dict_entry_list) self.index = self.index + 1 self.mib_table.update({self.index: datapool_tuple}) self.dict_entry_list[Clmns.SIZE.value] = "" self.dict_entry_list[Clmns.TYPE.value] = "" self.dict_entry_list[Clmns.NAME.value] = "" self.dict_entry_list[Clmns.UNIT.value] = "" def __handle_pool_var_export_string(self, string): extracted_entries = re.findall(r'(?:\[([\w]*)\][\s]*([^\[]*))?', string) if extracted_entries: extraced_entries_len = len(extracted_entries) - 1 for group_index in range(extraced_entries_len): (group_name, group_content) = extracted_entries[group_index] group_content = group_content.rstrip() if group_name.casefold() == "name": self.dict_entry_list[Clmns.NAME.value] = group_content elif group_name.casefold() == "size": self.dict_entry_list[Clmns.SIZE.value] = group_content elif group_name.casefold() == "type": self.dict_entry_list[Clmns.TYPE.value] = group_content elif group_name.casefold() == "unit": self.dict_entry_list[Clmns.UNIT.value] = group_content def __scan_for_datapool_end(self, line): datapool_end = re.search(r'}[\s]*;', line) if datapool_end: self.parse_for_datapool_entries = False def __handle_entry_write(self, cpp_file, index): current_mib_entry = self.mib_table.get(index) (_, current_group, _, current_code_name, current_size, current_type, _) = current_mib_entry if current_group != self.prev_group: cpp_file.write("\n\t/* " + current_group + " */\n") self.prev_group = current_group current_pool_entry_init_value = "{" if current_size == "": print("Size is unknown for a pool entry. Please specify in header file !") return current_size = int(current_size) for count in range(current_size): current_pool_entry_init_value = current_pool_entry_init_value + "0" if count != current_size - 1: current_pool_entry_init_value = current_pool_entry_init_value + ", " current_pool_entry_init_value = current_pool_entry_init_value + "}" entry_string = "\tpoolMap->emplace(datapool::" + current_code_name + \ ",\n\t\t\tnew PoolEntry<" + current_type + ">(" + \ current_pool_entry_init_value + "," + str(current_size) + "));\n" cpp_file.write(entry_string) if __name__ == "__main__": main()