From 8c6bb8918adbece06be9c941d186e25cc678897e Mon Sep 17 00:00:00 2001 From: donker <donker@astron.nl> Date: Mon, 1 May 2023 08:34:48 +0200 Subject: [PATCH] RTSD-79, add vhdl_style script --- vhdl_style_fix.py | 217 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100755 vhdl_style_fix.py diff --git a/vhdl_style_fix.py b/vhdl_style_fix.py new file mode 100755 index 0000000000..84ac58002c --- /dev/null +++ b/vhdl_style_fix.py @@ -0,0 +1,217 @@ +#!/usr/bin/python3 +from collections import OrderedDict +from argparse import ArgumentParser, RawTextHelpFormatter +from textwrap import dedent +from copy import copy + + +def main(): + with open(args.filename, 'r') as fd: + old_data = fd.read() + + parse = ParseData(old_data) + parse.parse() + new_data = parse.get_data() + + if old_data != new_data: + print(f"fix {args.filename}") + with open(args.filename, 'w') as fd: + fd.write(new_data) + + +class ParseData: + def __init__(self, data): + self.types = Types() + self.operators = Operators() + self.reserved_words = ReservedWords() + + self._comment = False + self._block_begin = ['--'] #, 'entity', 'generic', 'port', 'architecture'] + self._block_end = [');', 'end'] + self._data = data + self._new_data = [] + self._last_ch = '' + self._word = '' + self._operator = '' + self._is_block_word = False + self._blocks = [] + self._last_block = 'empty' + self._indent = 0 + + def get_data(self): + return ''.join(self._new_data) + + # handle _word + def add_to_word(self, ch): + self._word += ch + self._is_block_word = self._word in self._block_begin + + def get_word(self): + return self._word + + def clear_word(self): + self._word = '' + self._is_block_word = False + + def is_block_word(self): + return self._is_block_word + + # handle _operator + def add_to_operator(self, ch): + self._operator += ch + + def get_operator(self): + return self._operator + + def clear_operator(self): + self._operator = '' + + # handle _blocks info + def add_block(self, block): + self._blocks.append(block) + self._last_block = block + + def delete_last_block(self): + self._blocks.pop() + try: + self._last_block = self._blocks[-1] + except IndexError: + self._last_block = 'empty' + + def last_block(self): + return self._last_block + + # handle new_data + def add_new_data(self, word): + for ch in word: + self._new_data.append(ch) + + # parse data + def parse(self): + for ch in self._data: + + # '--' is comment + if self._comment is True: + if ch == "\n": + self._comment = False + self.add_new_data(ch) + continue + + # if ch == "\n": + # self.add_new_data("\n") + # continue + + if self.get_operator() and (ch.isidentifier() or ch.isspace()): + self.add_new_data(self.get_operator()) + self.clear_operator() + + if ch.isidentifier(): + self.add_to_word(ch) + continue + + if self.get_word(): + if self.types.is_valid(self.get_word()): # check if in types + self.add_new_data(self.get_word().lower()) + elif self.operators.is_valid(self.get_word()): # check if in operators + self.add_new_data(self.get_word().lower()) + elif self.reserved_words.is_valid(self.get_word()): # check if in reserved words + self.add_new_data(self.get_word().lower()) + else: + self.add_new_data(self.get_word()) + self.clear_word() + + if self.operators.is_valid(ch): + self.add_to_operator(ch) + if self.get_operator() == '--': + self.add_new_data(self.get_operator()) + self.clear_operator() + self._comment = True + continue + + if self.get_operator(): + self.add_new_data(self.get_operator()) + self.clear_operator() + + self.add_new_data(ch) + + if self.is_block_word(): + self.add_block(self.get_word()) + continue + + +class Entity: + """ + entity [name] is + generic ( + [g_*] : [type] := [val]; -- info + [g_*] : [type] := [val] -- info + ); + port ( + [port] : [dir] [type] := [val]; + [port] : [dir] [type] := [val] + ); + end [name]; + """ + def __init__(self): + pass + + +class Types: + def __init__(self): + self.types = ["bit", "bit_vector", "integer", "natural", "positive", "boolean", "string", + "character", "real", "time", "delay_length", + "std_ulogic", "std_ulogic_vector", "std_logic", "std_logic_vector"] + + def is_valid(self, val): + if val.lower() in self.types: + return True + return False + + +class Operators: + def __init__(self): + self.operators = ["**", "abs", "not", "*", "/", "mod", "rem", "+", "-", "+", "-", "&", + "sll", "srl", "sla", "sra", "rol", "ror", "=", "/=", "<", "<=", ">", + ">=", "and", "or", "nand", "nor", "xor", "xnor"] + + def is_valid(self, val): + if val.lower() in self.operators: + return True + return False + + +class ReservedWords: + def __init__(self): + self.reserved_words = ["abs", "access", "after", "alias", "all", "and", "architecture", + "array", "assert", "attribute", "begin", "block", "body", "buffer", + "bus", "case", "component", "configuration", "constant", "disconnect", + "downto", "else", "elsif", "end", "entity", "exit", "file", "for", + "function", "generate", "generic", "group", "guarded", "if", "impure", + "in", "inertial", "inout", "is", "label", "library", "linkage", "literal", + "loop", "map", "mod", "nand", "new", "next", "nor", "not", "null", "of", + "on", "open", "or", "others", "out", "package", "port", "postponed", + "procedure", "process", "pure", "range", "record", "register", "reject", + "rem", "report", "return", "rol", "ror", "select", "severity", "signal", + "shared", "sla", "sll", "sra", "srl", "subtype", "then", "to", "transport", + "type", "unaffected", "units", "until", "use", "variable", "wait", "when", + "while", "with", "xnor", "xor"] + + def is_valid(self, val): + if val.lower() in self.reserved_words: + return True + return False + + +if __name__ == "__main__": + # Parse command line arguments + parser = ArgumentParser( + description="".join(dedent("""\ + vhdl style fixer: + * vhdl_style_fix.py filename -h + \n""")), + formatter_class=RawTextHelpFormatter) + parser.add_argument('filename', type=str, help="filename to fix") + parser.add_argument('-v', '--verbose', action='store_true', help="verbose output") + args = parser.parse_args() + + main() -- GitLab