Пример #1
0
    def compose_entry_point(self, given_body):
        """
        Generate an entry point function for the environment model.

        :param given_body: Body of the main function provided by a translator.
        :return: List of C statements of the generated function body.
        """
        ep = Function(self.entry_name, "int {}(void)".format(self.entry_name))
        ep.definition_file = self.entry_file
        body = ['/* EMG_ACTION {' + '"thread": 1, "type": "CONTROL_FUNCTION_BEGIN", "comment": "Entry point \'{0}\'", '
                '"function": "{0}"'.format(self.entry_name) + '} */']

        # Init external allocated pointers
        cnt = 0
        functions = []
        if len(self.__external_allocated.keys()) > 0:
            for file, ext_vars in ((f, v) for f, v in self.__external_allocated.items() if v):
                func = Function('emg_allocate_external_{}'.format(cnt),
                                "void emg_allocate_external_{}(void)".format(cnt))
                func.declaration_files.add(file)
                func.definition_file = file

                init = ["{} = {}();".format(var.name, 'external_allocated_data') for var in ext_vars]
                func.body = init

                self.add_function_definition(func)
                self.add_function_declaration(self.entry_file, func, extern=True)
                functions.append(func)
                cnt += 1

            gl_init = Function('emg_initialize_external_data', 'void emg_initialize_external_data(void)')
            gl_init.declaration_files.add(self.entry_file)
            gl_init.definition_file = self.entry_file
            init_body = ['{}();'.format(func.name) for func in functions]
            gl_init.body = init_body
            self.add_function_definition(gl_init)
            body += [
                '/* Initialize external data */',
                'emg_initialize_external_data();'
            ]

        if self._conf.get("initialize requirements", True):
            body.append('ldv_initialize();')

        comment_data = {'action': 'scenarios'}
        body += [model_comment('ACTION_BEGIN', 'Begin Environment model scenarios', comment_data)] + given_body + \
                [model_comment('ACTION_END', other=comment_data)]

        if self._conf.get("check final state", True):
            body.append('ldv_check_final_state();')

        body += ['return 0;',
                 '/* EMG_ACTION {' +
                 '"comment": "Exit entry point \'{0}\'", "type": "CONTROL_FUNCTION_END", "function": "{0}"'.
                 format(self.entry_name) + '} */']

        ep.body = body
        self.add_function_definition(ep)

        return body
Пример #2
0
 def _replace_comment(self, match):
     arguments = match.groups()
     if arguments[0] == 'callback':
         name = arguments[1]
         cmnt = model_comment('callback', name, {'call': "{}();".format(name)})
         return cmnt
     else:
         raise NotImplementedError("Replacement of {!r} comments is not implemented".format(arguments[0]))
Пример #3
0
def control_function_comment_end(function_name, name):
    """
    Compose a comment at the end of a control function.

    :param function_name: Control function name.
    :param name: Process or Automaton name.
    :return: Model comment string.
    """
    data = {'function': function_name}
    return model_comment('CONTROL_FUNCTION_END', "End of control function based on process {!r}".format(name), data)
Пример #4
0
def control_function_comment_begin(function_name, comment, identifier=None):
    """
    Compose a comment at the beginning of a control function.

    :param function_name: Control function name.
    :param comment: Comment text.
    :param identifier: Thread identifier if necessary.
    :return: Model comment string.
    """
    data = {'function': function_name}
    if isinstance(identifier, int):
        data['thread'] = identifier + 1
    elif identifier is None:
        pass
    else:
        raise ValueError('Unsupported identifier type {}'.format(str(type(identifier).__name__)))
    return model_comment('CONTROL_FUNCTION_BEGIN', comment, data)
Пример #5
0
def action_model_comment(action, text, begin=None):
    """
    Model comment for identifying an action.

    :param action: Action object.
    :param text: Action comment string.
    :param begin: True if this is a comment before the action and False otherwise.
    :return: Model comment string.
    """
    type_comment = 'ACTION'
    if begin is True:
        type_comment += '_BEGIN'
    else:
        type_comment += '_END'
    data = {'name': str(action)}
    if action and action.trace_relevant and begin is True:
        data['relevant'] = True
    return model_comment(type_comment, text, data)
Пример #6
0
    def __init__(self, logger, conf, source, cmodel, entry_fsa, model_fsa,
                 event_fsa):
        """
        Initialize new FSA translation object. During the initialization an enviornment model in form of finite
        state machines with process-like actions is translated to C code. Translation includes the following steps:
        each pair label-interface is translated in a separate variable, each action is translated in code blocks
        (aux functions can be additionally generated), for each automaton a control function is generated, control
        functions for event modeling are called in a specific entry point function and control functions for function
        modeling are called insted of modelled functions. This class has an abstract methods to provide ability to
        implement different translation.

        :param logger: Logger object.
        :param conf: Configuration properties dictionary.
        :param source: Source collection object.
        :param cmodel: CModel object.
        :param entry_fsa: An entry point Automaton object.
        :param model_fsa: List with Automaton objects which correspond to function models.
        :param event_fsa:  List with Automaton objects for event modeling.
        """
        self._cmodel = cmodel
        self._entry_fsa = entry_fsa
        self._model_fsa = model_fsa
        self._event_fsa = event_fsa
        self._conf = conf
        self._source = source
        self._logger = logger
        self._structures = sortedcontainers.SortedDict()
        self._control_functions = sortedcontainers.SortedDict()
        self._logger.info("Include extra header files if necessary")
        conf.setdefault('do not skip signals', False)

        # Get from unused interfaces
        for process in (a.process for a in self._model_fsa + self._event_fsa
                        if len(a.process.headers) > 0):
            self._cmodel.add_headers(process.file,
                                     sorted(process.headers, key=len))

        # Generates base code blocks
        self._logger.info("Start the preparation of actions code")
        for automaton in self._event_fsa + self._model_fsa + [self._entry_fsa]:
            self._logger.debug(
                "Generate code for instance {!r} of process {!r} of categorty {!r}"
                .format(str(automaton), automaton.process.name,
                        automaton.process.category))
            for action in automaton.process.actions.filter(include={Action}):
                self._compose_action(action, automaton)

        # Start generators of control functions
        for automaton in self._event_fsa + self._model_fsa + [self._entry_fsa]:
            self._compose_control_function(automaton)

        # Generate aspects with kernel models
        for automaton in self._model_fsa:
            aspect_code = [
                model_comment(
                    'FUNCTION_MODEL',
                    'Perform the model code of the function {!r}'.format(
                        automaton.process.name))
            ]
            function_obj = self._source.get_source_function(
                automaton.process.name)
            params = []
            for position, param in enumerate(
                    function_obj.declaration.parameters):
                if isinstance(param, str):
                    params.append(param)
                else:
                    params.append('$arg{}'.format(str(position + 1)))

            if not params and function_obj.declaration.return_value == 'void':
                arguments = []
                ret_expression = ''
            elif not params:
                arguments = []
                ret_expression = 'return '
            elif function_obj.declaration.return_value == 'void':
                arguments = params
                ret_expression = ''
            else:
                ret_expression = 'return '
                arguments = params

            if arguments and '...' == arguments[-1]:
                arguments = arguments[:-1]

            invoke = '{}{}({});'.format(ret_expression,
                                        self._control_function(automaton).name,
                                        ', '.join(arguments))
            aspect_code.append(invoke)

            self._cmodel.add_function_model(function_obj, aspect_code)

        # Generate entry point function
        self._entry_point()

        # Add types
        for pair in self._structures.values():
            file, decl = pair
            self._cmodel.types.setdefault(file, list())
            if decl not in self._cmodel.types[file]:
                self._cmodel.types[file].append(decl)

        return
Пример #7
0
    def _compose_control_function(self, automaton):
        self._logger.info('Generate state-based control function for automaton {} based on process {} of category {}'.
                          format(automaton.identifier, automaton.process.name, automaton.process.category))

        # Get function prototype
        cf = self._control_function(automaton)
        cf.definition_file = automaton.process.file

        # Do process initialization
        model_flag = True
        if automaton not in self._model_fsa:
            model_flag = False
            v_code = ["/* Control function based on process '{}' generated for interface category '{}' */".
                      format(automaton.process.name, automaton.process.category)]
            f_code = []
            tab = 0
            state_chains = self.__state_chains(automaton)

            if len(state_chains) == 0:
                f_code.append('/* Empty control function */')
            else:
                if len(state_chains) == 1:
                    new_v_code, new_f_code = self.__state_chain_code(automaton,
                                                                     list(state_chains.values())[0])
                    v_code.extend(new_v_code)
                    f_code.extend(['\t' * tab + stm for stm in new_f_code])
                else:
                    f_code.append('\t' * tab + 'switch ({}) '.format(self.__state_variable(automaton).name) + '{')
                    tab += 1
                    for case in sorted(list(state_chains.keys())):
                        f_code.append('\t' * tab + 'case {}: '.format(case) + '{')
                        tab += 1
                        new_v_code, new_f_code = self.__state_chain_code(automaton, state_chains[case])
                        v_code.extend(new_v_code)
                        f_code.extend(['\t' * tab + stm for stm in new_f_code])
                        f_code.append('\t' * tab + 'break;')
                        tab -= 1
                        f_code.append('\t' * tab + '}')
                    f_code.append('\t' * tab + 'default: ldv_assume(0);')
                    tab -= 1
                    f_code.append('\t' * tab + '}')

            # Add comments
            comment_data = {'name': 'var_init'}
            # TODO: Reimplement this
            v_code = [model_comment('CONTROL_FUNCTION_INIT_BEGIN', 'Declare auxiliary variables.', comment_data)] + \
                     v_code + \
                     [model_comment('CONTROL_FUNCTION_INIT_END', 'Declare auxiliary variables.', comment_data)]
            v_code.insert(0, control_function_comment_begin(cf.name, automaton.process.comment, automaton.identifier))
            f_code.append(control_function_comment_end(cf.name, automaton.process.category))

            # Add loop for nested case
            cf.body.extend(v_code + f_code)
            self._cmodel.add_global_variable(self.__state_variable(automaton), automaton.process.file, extern=False,
                                             initialize=True)
        else:
            # Generate function body
            label_based_function(self._conf, self._source, automaton, cf, model_flag)

        # Add function to source code to print
        self._cmodel.add_function_definition(cf)
        if model_flag:
            for file in self._source.get_source_function(automaton.process.name).declaration_files:
                self._cmodel.add_function_declaration(file, cf, extern=True)
        else:
            for var in automaton.variables():
                self._cmodel.add_global_variable(var, automaton.process.file, initialize=False)
        return
Пример #8
0
def label_based_function(conf, analysis, automaton, cf, model=True):
    v_code, f_code = list(), list()

    # Determine returning expression for reuse
    if not conf.get('direct control functions calls') and not model:
        ret_expression = 'return 0;'
    else:
        ret_expression = 'return;'

    if model:
        kfunction_obj = analysis.get_source_function(automaton.process.name)
        if kfunction_obj.declaration.return_value != 'void':
            ret_expression = None

    # Then add memory external allocation marks
    f_code.extend(initialize_automaton_variables(conf, automaton))

    # Initialize variables
    # First add variables declarations
    for var in automaton.variables(only_used=True):
        scope = {automaton.process.file} if automaton.process.file else None
        v_code.append(var.declare(scope=scope) + ';')

    # After that assign explicit values
    for var in (v for v in automaton.variables(only_used=True) if v.value):
        f_code.append("{} = {};".format(var.name, var.value))

    # Intialize repeat counters
    for behaviour in (
            b for b in automaton.process.actions.behaviour()
            if isinstance(b, Behaviour) and isinstance(
                b.description, Subprocess) and isinstance(b.repeat, int)):
        var = __repeate_subprocess_var_name(automaton, behaviour)
        v_code.append("int {} = {};".format(var, behaviour.repeat))

    main_v_code, main_f_code = __subprocess_code(
        automaton, automaton.process.actions.initial_action)
    v_code += main_v_code
    f_code += main_f_code + ["/* End of the process */"]
    if ret_expression:
        f_code.append(ret_expression)

    processed = set()
    for subp in automaton.process.actions.filter(include={Subprocess}):
        if subp.name not in processed:
            first_actual_state = subp.action
            sp_v_code, sp_f_code = __subprocess_code(automaton,
                                                     first_actual_state)

            v_code.extend(sp_v_code)
            f_code.extend([
                '', '/* Subprocess {} */'.format(subp.name),
                'emg_{}_{}:'.format(str(subp.name), str(automaton))
            ])
            f_code.extend(sp_f_code)
            f_code.append("/* End of the subprocess '{}' */".format(subp.name))
            if ret_expression:
                f_code.append(ret_expression)
            processed.add(subp.name)

    comment_data = {'name': 'aux_variables_declaration'}
    v_code = [model_comment('ACTION_BEGIN', 'Declare auxiliary variables.', comment_data)] + \
             v_code + \
             [model_comment('ACTION_END', other=comment_data)]
    if model:
        name = automaton.process.name
        v_code.insert(
            0,
            control_function_comment_begin(cf.name, automaton.process.comment))
    else:
        name = '{}({})'.format(automaton.process.name,
                               automaton.process.category)
        v_code.insert(
            0,
            control_function_comment_begin(cf.name, automaton.process.comment,
                                           automaton.identifier))
    f_code.append(control_function_comment_end(cf.name, name))
    cf.body.extend(v_code + f_code)

    return cf.name