162306a36Sopenharmony_ci#!/usr/bin/env python3
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0-only
362306a36Sopenharmony_ci#
462306a36Sopenharmony_ci# Copyright (C) 2019-2022 Red Hat, Inc. Daniel Bristot de Oliveira <bristot@kernel.org>
562306a36Sopenharmony_ci#
662306a36Sopenharmony_ci# dot2c: parse an automata in dot file digraph format into a C
762306a36Sopenharmony_ci#
862306a36Sopenharmony_ci# This program was written in the development of this paper:
962306a36Sopenharmony_ci#  de Oliveira, D. B. and Cucinotta, T. and de Oliveira, R. S.
1062306a36Sopenharmony_ci#  "Efficient Formal Verification for the Linux Kernel." International
1162306a36Sopenharmony_ci#  Conference on Software Engineering and Formal Methods. Springer, Cham, 2019.
1262306a36Sopenharmony_ci#
1362306a36Sopenharmony_ci# For further information, see:
1462306a36Sopenharmony_ci#   Documentation/trace/rv/deterministic_automata.rst
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cifrom dot2.automata import Automata
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciclass Dot2c(Automata):
1962306a36Sopenharmony_ci    enum_suffix = ""
2062306a36Sopenharmony_ci    enum_states_def = "states"
2162306a36Sopenharmony_ci    enum_events_def = "events"
2262306a36Sopenharmony_ci    struct_automaton_def = "automaton"
2362306a36Sopenharmony_ci    var_automaton_def = "aut"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci    def __init__(self, file_path):
2662306a36Sopenharmony_ci        super().__init__(file_path)
2762306a36Sopenharmony_ci        self.line_length = 100
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci    def __buff_to_string(self, buff):
3062306a36Sopenharmony_ci        string = ""
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci        for line in buff:
3362306a36Sopenharmony_ci            string = string + line + "\n"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci        # cut off the last \n
3662306a36Sopenharmony_ci        return string[:-1]
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci    def __get_enum_states_content(self):
3962306a36Sopenharmony_ci        buff = []
4062306a36Sopenharmony_ci        buff.append("\t%s%s = 0," % (self.initial_state, self.enum_suffix))
4162306a36Sopenharmony_ci        for state in self.states:
4262306a36Sopenharmony_ci            if state != self.initial_state:
4362306a36Sopenharmony_ci                buff.append("\t%s%s," % (state, self.enum_suffix))
4462306a36Sopenharmony_ci        buff.append("\tstate_max%s" % (self.enum_suffix))
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci        return buff
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci    def get_enum_states_string(self):
4962306a36Sopenharmony_ci        buff = self.__get_enum_states_content()
5062306a36Sopenharmony_ci        return self.__buff_to_string(buff)
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci    def format_states_enum(self):
5362306a36Sopenharmony_ci        buff = []
5462306a36Sopenharmony_ci        buff.append("enum %s {" % self.enum_states_def)
5562306a36Sopenharmony_ci        buff.append(self.get_enum_states_string())
5662306a36Sopenharmony_ci        buff.append("};\n")
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci        return buff
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci    def __get_enum_events_content(self):
6162306a36Sopenharmony_ci        buff = []
6262306a36Sopenharmony_ci        first = True
6362306a36Sopenharmony_ci        for event in self.events:
6462306a36Sopenharmony_ci            if first:
6562306a36Sopenharmony_ci                buff.append("\t%s%s = 0," % (event, self.enum_suffix))
6662306a36Sopenharmony_ci                first = False
6762306a36Sopenharmony_ci            else:
6862306a36Sopenharmony_ci                buff.append("\t%s%s," % (event, self.enum_suffix))
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci        buff.append("\tevent_max%s" % self.enum_suffix)
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci        return buff
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci    def get_enum_events_string(self):
7562306a36Sopenharmony_ci        buff = self.__get_enum_events_content()
7662306a36Sopenharmony_ci        return self.__buff_to_string(buff)
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci    def format_events_enum(self):
7962306a36Sopenharmony_ci        buff = []
8062306a36Sopenharmony_ci        buff.append("enum %s {" % self.enum_events_def)
8162306a36Sopenharmony_ci        buff.append(self.get_enum_events_string())
8262306a36Sopenharmony_ci        buff.append("};\n")
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci        return buff
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci    def get_minimun_type(self):
8762306a36Sopenharmony_ci        min_type = "unsigned char"
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci        if self.states.__len__() > 255:
9062306a36Sopenharmony_ci            min_type = "unsigned short"
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci        if self.states.__len__() > 65535:
9362306a36Sopenharmony_ci            min_type = "unsigned int"
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci        if self.states.__len__() > 1000000:
9662306a36Sopenharmony_ci            raise Exception("Too many states: %d" % self.states.__len__())
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci        return min_type
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci    def format_automaton_definition(self):
10162306a36Sopenharmony_ci        min_type = self.get_minimun_type()
10262306a36Sopenharmony_ci        buff = []
10362306a36Sopenharmony_ci        buff.append("struct %s {" % self.struct_automaton_def)
10462306a36Sopenharmony_ci        buff.append("\tchar *state_names[state_max%s];" % (self.enum_suffix))
10562306a36Sopenharmony_ci        buff.append("\tchar *event_names[event_max%s];" % (self.enum_suffix))
10662306a36Sopenharmony_ci        buff.append("\t%s function[state_max%s][event_max%s];" % (min_type, self.enum_suffix, self.enum_suffix))
10762306a36Sopenharmony_ci        buff.append("\t%s initial_state;" % min_type)
10862306a36Sopenharmony_ci        buff.append("\tbool final_states[state_max%s];" % (self.enum_suffix))
10962306a36Sopenharmony_ci        buff.append("};\n")
11062306a36Sopenharmony_ci        return buff
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci    def format_aut_init_header(self):
11362306a36Sopenharmony_ci        buff = []
11462306a36Sopenharmony_ci        buff.append("static const struct %s %s = {" % (self.struct_automaton_def, self.var_automaton_def))
11562306a36Sopenharmony_ci        return buff
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci    def __get_string_vector_per_line_content(self, buff):
11862306a36Sopenharmony_ci        first = True
11962306a36Sopenharmony_ci        string = ""
12062306a36Sopenharmony_ci        for entry in buff:
12162306a36Sopenharmony_ci            if first:
12262306a36Sopenharmony_ci                string = string + "\t\t\"" + entry
12362306a36Sopenharmony_ci                first = False;
12462306a36Sopenharmony_ci            else:
12562306a36Sopenharmony_ci                string = string + "\",\n\t\t\"" + entry
12662306a36Sopenharmony_ci        string = string + "\""
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci        return string
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci    def get_aut_init_events_string(self):
13162306a36Sopenharmony_ci        return self.__get_string_vector_per_line_content(self.events)
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci    def get_aut_init_states_string(self):
13462306a36Sopenharmony_ci        return self.__get_string_vector_per_line_content(self.states)
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci    def format_aut_init_events_string(self):
13762306a36Sopenharmony_ci        buff = []
13862306a36Sopenharmony_ci        buff.append("\t.event_names = {")
13962306a36Sopenharmony_ci        buff.append(self.get_aut_init_events_string())
14062306a36Sopenharmony_ci        buff.append("\t},")
14162306a36Sopenharmony_ci        return buff
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci    def format_aut_init_states_string(self):
14462306a36Sopenharmony_ci        buff = []
14562306a36Sopenharmony_ci        buff.append("\t.state_names = {")
14662306a36Sopenharmony_ci        buff.append(self.get_aut_init_states_string())
14762306a36Sopenharmony_ci        buff.append("\t},")
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci        return buff
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci    def __get_max_strlen_of_states(self):
15262306a36Sopenharmony_ci        max_state_name = max(self.states, key = len).__len__()
15362306a36Sopenharmony_ci        return max(max_state_name, self.invalid_state_str.__len__())
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci    def __get_state_string_length(self):
15662306a36Sopenharmony_ci        maxlen = self.__get_max_strlen_of_states() + self.enum_suffix.__len__()
15762306a36Sopenharmony_ci        return "%" + str(maxlen) + "s"
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci    def get_aut_init_function(self):
16062306a36Sopenharmony_ci        nr_states = self.states.__len__()
16162306a36Sopenharmony_ci        nr_events = self.events.__len__()
16262306a36Sopenharmony_ci        buff = []
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci        strformat = self.__get_state_string_length()
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci        for x in range(nr_states):
16762306a36Sopenharmony_ci            line = "\t\t{ "
16862306a36Sopenharmony_ci            for y in range(nr_events):
16962306a36Sopenharmony_ci                next_state = self.function[x][y]
17062306a36Sopenharmony_ci                if next_state != self.invalid_state_str:
17162306a36Sopenharmony_ci                    next_state = self.function[x][y] + self.enum_suffix
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci                if y != nr_events-1:
17462306a36Sopenharmony_ci                    line = line + strformat % next_state + ", "
17562306a36Sopenharmony_ci                else:
17662306a36Sopenharmony_ci                    line = line + strformat % next_state + " },"
17762306a36Sopenharmony_ci            buff.append(line)
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci        return self.__buff_to_string(buff)
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci    def format_aut_init_function(self):
18262306a36Sopenharmony_ci        buff = []
18362306a36Sopenharmony_ci        buff.append("\t.function = {")
18462306a36Sopenharmony_ci        buff.append(self.get_aut_init_function())
18562306a36Sopenharmony_ci        buff.append("\t},")
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci        return buff
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci    def get_aut_init_initial_state(self):
19062306a36Sopenharmony_ci        return self.initial_state
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci    def format_aut_init_initial_state(self):
19362306a36Sopenharmony_ci        buff = []
19462306a36Sopenharmony_ci        initial_state = self.get_aut_init_initial_state()
19562306a36Sopenharmony_ci        buff.append("\t.initial_state = " + initial_state + self.enum_suffix + ",")
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci        return buff
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci    def get_aut_init_final_states(self):
20062306a36Sopenharmony_ci        line = ""
20162306a36Sopenharmony_ci        first = True
20262306a36Sopenharmony_ci        for state in self.states:
20362306a36Sopenharmony_ci            if first == False:
20462306a36Sopenharmony_ci                line = line + ', '
20562306a36Sopenharmony_ci            else:
20662306a36Sopenharmony_ci                first = False
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci            if self.final_states.__contains__(state):
20962306a36Sopenharmony_ci                line = line + '1'
21062306a36Sopenharmony_ci            else:
21162306a36Sopenharmony_ci                line = line + '0'
21262306a36Sopenharmony_ci        return line
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci    def format_aut_init_final_states(self):
21562306a36Sopenharmony_ci       buff = []
21662306a36Sopenharmony_ci       buff.append("\t.final_states = { %s }," % self.get_aut_init_final_states())
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci       return buff
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci    def __get_automaton_initialization_footer_string(self):
22162306a36Sopenharmony_ci        footer = "};\n"
22262306a36Sopenharmony_ci        return footer
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci    def format_aut_init_footer(self):
22562306a36Sopenharmony_ci        buff = []
22662306a36Sopenharmony_ci        buff.append(self.__get_automaton_initialization_footer_string())
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci        return buff
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci    def format_invalid_state(self):
23162306a36Sopenharmony_ci        buff = []
23262306a36Sopenharmony_ci        buff.append("#define %s state_max%s\n" % (self.invalid_state_str, self.enum_suffix))
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci        return buff
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci    def format_model(self):
23762306a36Sopenharmony_ci        buff = []
23862306a36Sopenharmony_ci        buff += self.format_states_enum()
23962306a36Sopenharmony_ci        buff += self.format_invalid_state()
24062306a36Sopenharmony_ci        buff += self.format_events_enum()
24162306a36Sopenharmony_ci        buff += self.format_automaton_definition()
24262306a36Sopenharmony_ci        buff += self.format_aut_init_header()
24362306a36Sopenharmony_ci        buff += self.format_aut_init_states_string()
24462306a36Sopenharmony_ci        buff += self.format_aut_init_events_string()
24562306a36Sopenharmony_ci        buff += self.format_aut_init_function()
24662306a36Sopenharmony_ci        buff += self.format_aut_init_initial_state()
24762306a36Sopenharmony_ci        buff += self.format_aut_init_final_states()
24862306a36Sopenharmony_ci        buff += self.format_aut_init_footer()
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci        return buff
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci    def print_model_classic(self):
25362306a36Sopenharmony_ci        buff = self.format_model()
25462306a36Sopenharmony_ci        print(self.__buff_to_string(buff))
255