Example #1
0
	def _parse_file(self, filename):
		"""
		"""
		logging.debug("Parse %s" % filename)
		try:
			# read the time of the last change
			self.modify_time = max(self.modify_time, os.stat(filename).st_mtime)
			
			# parse the xml-file
			xmltree = et.parse(filename).getroot()
		except OSError as e:
			raise ParserException(e)
		except (xml.parsers.expat.ExpatError, xml.etree.ElementTree.ParseError) as e:
			raise ParserException("while parsing xml-file '%s': %s" % (filename, e))
		
		try:
			import lxml.etree		# for validating
			
			# validate against the embedded DTD file
			try:
				parser = lxml.etree.XMLParser(dtd_validation=True)
				dummy = lxml.etree.parse(filename, parser)
			except lxml.etree.XMLSyntaxError as e:
				raise ParserException("Validation error in '%s': %s" % (filename, e))
			else:
				logging.debug("Validation OK!")
		except ImportError as e:
			logging.warning("Warning: couldn't load 'lxml' module. No validation done!")
		
		# search for include and reference nodes and parse
		# the specified files first
		for node in xmltree.findall('include'):
			include_file = node.text
			if not os.path.isabs(include_file):
				include_file = os.path.join(self.include_path, include_file)
			self.include_path = os.path.dirname(os.path.abspath(include_file))
			self._parse_file(include_file)
		
		self._parse_types(xmltree)
		self._evaluate_types(xmltree)
		self._create_type_hierarchy()
		
		self._parse_events(xmltree)
		self._check_events()
		
		self._parse_components(xmltree)
		self._evaluate_components(xmltree)
		
		self._parse_container(xmltree)
		
		# create expanded versions for all types and components
		for type in self.tree.types:
			type.flattened()
		for component in self.tree.components:
			component.flattened()
		self.tree.components.updateIndex()
		
		for container in self.tree.container:
			container.updateIndex()
Example #2
0
    def _makeRelativeToPlatform(self, file_name):
        """
		All file names are relative to the xml device
		description file.
		This function makes them relative to the platform directory.
		That makes a lot of sense because the generated files are going
		to retain the same structure in this context (this sentence
		admittedly does not make as much sense...)
		"""
        # Check if we need to go up directories (if path starts with '../')
        go_up = 0
        if file_name.startswith(
                './'):  # do not know why you would want to do this
            file_name = file_name[
                2:]  # but whatever => go ahead (btw. this code was written at 1:00 am)
        while file_name.startswith('../'):
            go_up = go_up + 1
            file_name = file_name[3:]
        path_length = len(self.path.split(os.sep))
        if go_up > path_length:
            raise ParserException(
                "Illegal file name: %s. Must not leave the platform directory."
                % (file_name))
        path = os.sep.join(self.path.split(os.sep)[:(path_length - go_up)])
        file_name = os.path.join(path, file_name)
        return file_name
Example #3
0
 def __addExtending(self, extending):
     for struct in self.extending:
         if struct.typeIdentifier == extending.typeIdentifier:
             raise ParserException(
                 "Duplicate TypeIdentifier '%s' in Struct group extending '%s'. ('%s' and '%s')"
                 % (extending.typeIdentifier.name, self.name, struct.name,
                    extending.name))
     self.extending.append(extending)
Example #4
0
 def evaluate(self, tree):
     self.description = xml_utils.get_description(self.node)
     self.string = xml_utils.get_string(self.node)
     self.unit = self.node.get('unit')
     try:
         self.subtype = SubType(self.node.get('type'), tree.types)
     except ParserException as e:
         raise ParserException("Error in definition of typedef '%s': %s" %
                               (self.name, e))
Example #5
0
	def _check_events(self):
		eventIds = {}
		for event in self.tree.events:
			id = event.id
			if id in eventIds:
				raise ParserException("Duplicate Event-Identifier, '0x%02x' is used for '%s' and '%s'!"	% 
						(id, event.name, eventIds[id].name))
			else:
				eventIds[id] = event
Example #6
0
    def evaluate(self, tree):
        if self.node is None:
            return

        self.description = xml_utils.get_description(self.node)
        self.string = xml_utils.get_string(self.node)
        for node in self.node.findall('element'):
            try:
                self.elements.append(self.Element(node, tree))
            except ParserException as e:
                raise ParserException(
                    "Error in definition of struct '%s': %s!" % (self.name, e))

        basetype = self.node.get('extends')
        if basetype is not None:
            try:
                self.extends = tree.types[basetype]
                if not self.extends.isStruct:
                    raise ParserException(
                        "Struct '%s' is derived from non struct '%s'!" %
                        (self.name, self.extends.name))
                if self.extends.extends:
                    raise ParserException(
                        "Struct '%s' extends struct '%s'. Structs are only allowed to extend from those Structs, which do not extend anything!"
                        % (self.name, self.extends.name))
                self.__typeIdentifierName = self.node.get('typeIdentifier')
                if self.__typeIdentifierName is None:
                    raise ParserException(
                        "Struct '%s' does extend '%s', but does not provide the attribute 'typeIdentifier'!"
                        % (self.name, self.extends.name))

            except KeyError:
                raise ParserException(
                    "Unknown super type '%s' in struct '%s'!" %
                    (basetype, self.name))
        self.node = None
Example #7
0
        def __init__(self, node):
            """ Constructor
			
			The name of the element has to be all upper case with underscores.
			"""
            self.name = node.get('name')
            if not re.match("^[0-9A-Z_]*$", self.name):
                raise ParserException(
                    "Attribute name of element in enum has to be UPPER_UNDERSCORE_STYLE (found: '%s')"
                    % (self.name))

            self.string = node.get('string')
            if self.string is None:
                self.string = self.name

            self.description = xml_utils.get_description(node)
            self.string = xml_utils.get_string(node)

            value = node.get('value')
            self.value = None if (value is None) else int(value, 0)
Example #8
0
    def __init__(self, value, types):
        """ Constructor
		
		Keyword Arguments:
		value	-- type name
		types	-- list of all available types
		"""
        self.raw = value
        if value.endswith(']'):
            self.isArray = True
            self.name, number = value.split('[')
            self.count = number[:-1]
        else:
            self.isArray = False
            self.count = 1
            self.name = value

        try:
            self.type = types[self.name]
        except KeyError:
            raise ParserException("Unknown type '%s'" % self.name)
        self.size = None
Example #9
0
    def __init__(self, node, tree):
        """ Constructor
		
		Keyword arguments:
		node	--	XML node defining this event
		tree	--	currently evaluted communication structure tree
		"""
        self.name = node.get('name')
        utils.check_name(self.name)

        self.id = xml_utils.get_identifier(node)
        self.description = xml_utils.get_description(node)
        self.rate = node.get('rate')

        type = node.get('type')
        if type is None:
            self.type = None
        else:
            try:
                self.type = tree.types[type]
            except KeyError as e:
                raise ParserException(
                    "Type '%s' is not defined. Used by Event '%s')" %
                    (type, self.name))
Example #10
0
    def create_hierarchy(self):
        """ Create hierarchy
		
		For this method self.size = 0 is used as sepecial value to detect
		loops in the definition of types. In normal operation size will never be
		zero, only during hierarchy creation.
		"""
        if self.level is not None:
            return

        self.size = 0
        size = 0
        self.level = 0
        for element in self.elements:
            if element.size == 0:
                raise ParserException(
                    "Loop in the definition of '%s' and '%s' detected!" %
                    (self.name, self.element.name))
            element.create_hierarchy()

            size += element.size
            self.level = max(self.level, element.level)

        if self.extends is not None:
            if self.extends.size == 0:
                raise ParserException(
                    "Loop in the definition of '%s' and '%s' detected!" %
                    (self.name, self.extends.name))
            self.extends.create_hierarchy()
            typeIdentifierStructElement = self.extends.elements[0]
            if not typeIdentifierStructElement.subtype.type.isEnum:
                raise ParserException("Struct '%s' is extended by Struct '%s'. "  \
                 "Structs which are extended by other must have an element named " \
                 "'type' of any enum type as their first element! It is used for " \
                 "type distinguishing at runtime." \
                  % (self.extends.name, self.name))
            if not typeIdentifierStructElement.name == 'type':
                raise ParserException("Struct '%s' is extended by Struct '%s'. Structs" \
                 "which are extended by other must have an element named 'type' as" \
                 "their first element! It is used for type distinguishing at runtime." \
                  % (self.extends.name, self.name))

            for enumElement in typeIdentifierStructElement.subtype.type.elements:
                if enumElement.name == self.__typeIdentifierName:
                    self.typeIdentifier = enumElement
                    break
            if not self.typeIdentifier:
                raise ParserException("Struct '%s' extends Struct '%s', but it's " \
                 "typeIdentifier '%s' is not member of enum '%s' which is the " \
                 "type of '%s.type'."
                  % (self.name, self.extends.name, self.__typeIdentifierName,
                   typeIdentifierStructElement.subtype.type.name, self.extends.name))

            self.extends.__addExtending(self)
            size += self.extends.size
            self.level = max(self.level, self.extends.level)

        if size > 48:
            raise ParserException("Struct '%s' is with %i Byte too big. The maximum " \
             "packet size is 48 Byte!" % (self.name, size))

        self.size = size
        self.level += 1
Example #11
0
    def getBuildList(
            self,
            platform_path,
            device_id,
            source_file_extentions=['.cpp', '.c', '.sx', '.S', '.h', '.hpp']):
        """
		The data is put into a list of the format:
		[ ['static_file_name', 'static_output_file_name'],
		['template_src_file','template_target_file',{'Dict': 'a', 'of': 'b', 'defines': 's'}]]
		Note: all file paths are relative to the platform path.
		"""
        # Turn Device String into Device Identifier
        if isinstance(device_id, str):
            device_id = DeviceIdentifier(device_id)
        # Initialize Return List
        build = []
        # Check if there is a driver file and open
        if self.filename != None:
            try:
                f = os.path.join(platform_path, self.filename)
                xmltree = et.parse(f).getroot()
            except OSError as e:
                raise ParserException(e)
            except (xml.parsers.expat.ExpatError,
                    xml.etree.ElementTree.ParseError) as e:
                raise ParserException("while parsing xml-file '%s': %s" %
                                      (f, e))
            # TODO: Validate
            node = xmltree[0]
            # Check if name and type match
            # If they do not, why should everything else be correct?....
            if node.get('type') != self.type:
                raise ParserException(
                    "Error: Driver: Type in device file (%s) and type in driver file (%s) do not match. File: %s"
                    % (self.type, node.get('type'), f))
            if node.get('name') != self.name:
                raise ParserException(
                    "Error: Driver: Name in device file (%s) and name in driver file (%s) do not match. File: %s"
                    % (self.name, node.get('name'), f))
            # Do we only have one default instance?
            if self.instances == None:
                self._parseDriverXml(device_id, node, 'default', build, {})
            else:  # handle several or at least one specific instance
                # Initialize Internal Target File Dictionary
                targets = {}
                for instance in self.instances:
                    self._parseDriverXml(device_id, node, instance, build,
                                         targets)
        else:  # if no xml driver file exists, just add all files that look like source files
            # Query all files in directory
            dir = os.path.join(platform_path, self.path)
            if not os.path.exists(dir):
                self.log.warn(
                    "'%s' implementation for target '%s' does not exist!" %
                    (self.path, device_id.string))
                return build
            for source_file in os.listdir(dir):
                # Detect Static Source and Header Files
                if os.path.splitext(source_file)[1] in source_file_extentions:
                    source_file = self._makeRelativeToPlatform(source_file)
                    build.append([source_file, source_file])
                # Detect Template Files
                elif os.path.splitext(source_file)[1] == '.in':
                    template = self._makeRelativeToPlatform(source_file)
                    output = self._makeRelativeToPlatform(source_file[:-3])
                    substitutions = self.substitutions
                    substitutions.update({'output': os.path.split(output)[1]})
                    build.append([template, output, self.substitutions])
        return build
Example #12
0
    def _parseDriverXml(self, device_id, driver_node, instance_id, build_list,
                        targets):
        # First parse parameters:
        for node in driver_node:
            if node.tag == 'parameter':
                p = Parameter(node, self.log)
                # 1.) search for user parameters
                value = p.getValueFromUserParameterDict(
                    self.user_parameters, instance_id)
                # 2.) if none are found search for parameters in driver file
                if value == None:
                    value = p.getValueFromParameterDict(
                        self.device_parameters, instance_id)
                # 3.) else use the default value
                if value == None:
                    value = p.default
                # 4.) add value found to the substitution dict
                p.addValueToSubstitutions(self.substitutions, value)

            elif node.tag not in ['static', 'template']:
                f = DeviceElementBase(self, node)
                if f.appliesTo(device_id, self.properties):
                    self.log.debug(
                        "Found driver file substitution '%s' with value '%s'. In '%s/%s' driver xml"
                        % (node.tag, node.text, self.type, self.name))
                    self.substitutions.update({node.tag: node.text})

        # Then parse needed static/template files
        for node in driver_node:
            # Skip PArameters:
            if node.tag == 'parameter':
                continue

            # Check if instance id fits:
            if node.get('instances') != None and instance_id != None:
                if instance_id not in node.get('instances').split(','):
                    continue

            if node.text == None or len(node.text) <= 0:
                self.log.error("Empty '%s' node in '%s/%s' driver xml." %
                               (node.tag, self.type, self.name))
                raise ParserException(
                    "Error: Empty '%s' node in '%s/%s' driver xml." %
                    (node.tag, self.type, self.name))

            f = DeviceElementBase(self, node)
            if not f.appliesTo(device_id, self.properties):
                self.log.info(
                    "Tag '%s' does not apply to target '%s'. In '%s/%s' driver xml."
                    % (node.tag, device_id.string, self.type, self.name))
            else:
                file_name = node.text.strip()

                if node.tag == 'static':
                    if file_name not in build_list:  # if it has not been added before
                        static = file_name
                        output = node.get('out')
                        if output == None or len(
                                output) <= 0:  # if no out attribute was found
                            output = static
                        static = self._makeRelativeToPlatform(static)
                        output = self._makeRelativeToPlatform(output)
                        if self._checkTarget([static, output], targets):
                            build_list.append([static,
                                               output])  # => add static file

                elif node.tag == 'template':
                    template = file_name
                    output = node.get('out')
                    if output == None or len(
                            output) <= 0:  # if no out attribute was found
                        output = template
                        if output.endswith('.in'):
                            output = output[:-3]
                    else:  # replace '{{id}}' with id
                        output = output.replace('{{id}}', instance_id.lower())
                    template = self._makeRelativeToPlatform(template)
                    output = self._makeRelativeToPlatform(output)
                    if instance_id.isdigit():
                        sub_instance_id = int(instance_id)
                    else:
                        sub_instance_id = instance_id
                    substitutions = dict(self.substitutions)
                    if 'parameters' in substitutions:
                        substitutions['parameters'] = dict(
                            substitutions['parameters'])
                    # substitutions['parameters'] = dict(substitutions['parameters'])
                    if node.get('instances') != None:
                        substitutions.update({'id': sub_instance_id})
                    substitutions.update({'output': os.path.split(output)[1]})
                    # self.log.debug("%s->%s: substitutions: %s" % (template, output, substitutions))
                    template_file = [template, output, substitutions]
                    if self._checkTarget(template_file, targets):
                        build_list.append(
                            template_file
                        )  # always append template files since they will get a different id