Skip to content
Snippets Groups Projects
vhdl_parser.py 5.81 KiB
Newer Older
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
Adrian Fiergolski's avatar
Adrian Fiergolski committed
# Copyright (c) 2015 CERN
# Author: # Adrian Fiergolski (Adrian.Fiergolski@cern.ch)
#
# This file is part of Hdlmake.
#
# Hdlmake is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Hdlmake is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Hdlmake.  If not, see <http://www.gnu.org/licenses/>.

from new_dep_solver import DepParser
import logging
Adrian Fiergolski's avatar
Adrian Fiergolski committed
import re
Adrian Fiergolski's avatar
Adrian Fiergolski committed
class VHDLPreprocessor(object):
Adrian Fiergolski's avatar
Adrian Fiergolski committed
    def __init__(self):
        self.vhdl_file = None
Adrian Fiergolski's avatar
Adrian Fiergolski committed
    def remove_comments_and_strings(self, s):
        pattern = re.compile( '--.*?$|".?"', re.DOTALL | re.MULTILINE )  
        return re.sub(pattern,"", s)
    
    def _preporcess_file(self, file_content, file_name, library):
        logging.debug("preprocess file %s (of length %d) in library %s" % (file_name, len(file_content), library) )
        return self.remove_comments_and_strings(file_content)
        
    def preprocess(self, vhdl_file):
        self.vhdl_file = vhdl_file
        file_path = vhdl_file.file_path
        buf = open(file_path, "r").read()
        return self._preporcess_file(file_content = buf, file_name = file_path, library = vhdl_file.library)
        
class VHDLParser(DepParser):
Adrian Fiergolski's avatar
Adrian Fiergolski committed
    
    def __init__(self, dep_file):
        DepParser.__init__(self, dep_file)
        self.preprocessor = VHDLPreprocessor()
    

    def parse(self, dep_file):
        from dep_file import DepRelation
        if dep_file.is_parsed:
            return
        logging.info("Parsing %s" % dep_file.path)
Adrian Fiergolski's avatar
Adrian Fiergolski committed
        
Adrian Fiergolski's avatar
Adrian Fiergolski committed
        buf = self.preprocessor.preprocess(dep_file)
        
        #use packages
        use_pattern = re.compile("^\s*use\s+(\w+)\s*\.\s*(\w+)", re.DOTALL | re.MULTILINE | re.IGNORECASE )
        def do_use(s) :
            if ( s.group(1).lower() == "work" ) : #work is the current library in VHDL
                logging.debug("use package %s.%s" % (dep_file.library, s.group(2) ) )
                dep_file.add_relation(DepRelation("%s.%s" % (dep_file.library, s.group(2).lower() ) , DepRelation.USE, DepRelation.PACKAGE)) 
Adrian Fiergolski's avatar
Adrian Fiergolski committed
            else :
Adrian Fiergolski's avatar
Adrian Fiergolski committed
                logging.debug("use package %s.%s" % (s.group(1), s.group(2)) )
                dep_file.add_relation(DepRelation("%s.%s" % (s.group(1).lower(), s.group(2).lower()), DepRelation.USE, DepRelation.PACKAGE))
        re.subn(use_pattern, do_use, buf)

        #new entity
        entity_pattern = re.compile("^\s*entity\s+(\w+)\s+is\s+(?:port|generic|end)", re.DOTALL | re.MULTILINE | re.IGNORECASE )
        def do_entity(s) :
            logging.debug("found entity %s.%s" % ( dep_file.library, s.group(1) ) )
            dep_file.add_relation(DepRelation("%s.%s" % (dep_file.library, s.group(1).lower()),
Adrian Fiergolski's avatar
Adrian Fiergolski committed
                                              DepRelation.PROVIDE,
                                              DepRelation.ENTITY))
Adrian Fiergolski's avatar
Adrian Fiergolski committed
        re.subn(entity_pattern, do_entity, buf)
        
        #new package
        package_pattern = re.compile("^\s*package\s+(\w+)\s+is",  re.DOTALL | re.MULTILINE | re.IGNORECASE )
        def do_package(s) :
            logging.debug("found package %s.%s" % (dep_file.library, s.group(1) ))
            dep_file.add_relation(DepRelation("%s.%s" % (dep_file.library, s.group(1).lower()),
Adrian Fiergolski's avatar
Adrian Fiergolski committed
                                              DepRelation.PROVIDE,
                                              DepRelation.PACKAGE))
Adrian Fiergolski's avatar
Adrian Fiergolski committed
        re.subn(package_pattern, do_package, buf)
        
        #intantions
        instance_pattern = re.compile("^\s*(\w+)\s*\:\s*(\w+)\s*(?:port\s+map|generic\s+map|\s*;)", re.DOTALL | re.MULTILINE | re.IGNORECASE )
        instance_from_library_pattern = re.compile("^\s*(\w+)\s*\:\s*entity\s*(\w+)\s*\.\s*(\w+)\s*(?:port\s+map|generic\s+map|\s*;)",  re.DOTALL | re.MULTILINE | re.IGNORECASE )
        libraries = set([dep_file.library])
        def do_instance(s) :
Adrian Fiergolski's avatar
Adrian Fiergolski committed
            for lib in libraries :
Adrian Fiergolski's avatar
Adrian Fiergolski committed
                logging.debug("-> instantiates %s.%s as %s" % (lib, s.group(2), s.group(1))  )
                dep_file.add_relation(DepRelation("%s.%s" % (lib, s.group(2).lower()),
Adrian Fiergolski's avatar
Adrian Fiergolski committed
                                                  DepRelation.USE,
                                                  DepRelation.ENTITY))
Adrian Fiergolski's avatar
Adrian Fiergolski committed
        def do_instance_from_library(s) :
            if ( s.group(2).lower() == "work" ) : #work is the current library in VHDL
                logging.debug("-> instantiates %s.%s as %s" % (dep_file.library, s.group(3), s.group(1))  )
                dep_file.add_relation(DepRelation("%s.%s" % (dep_file.library, s.group(3).lower()),
Adrian Fiergolski's avatar
Adrian Fiergolski committed
                                                  DepRelation.USE,
                                                  DepRelation.ENTITY))
            else :
Adrian Fiergolski's avatar
Adrian Fiergolski committed
                logging.debug("-> instantiates %s.%s as %s" % (s.group(2), s.group(3), s.group(1))  )
                dep_file.add_relation(DepRelation("%s.%s" % (s.group(2).lower(), s.group(3).lower()),
Adrian Fiergolski's avatar
Adrian Fiergolski committed
                                                  DepRelation.USE,
                                                  DepRelation.ENTITY))
Adrian Fiergolski's avatar
Adrian Fiergolski committed
        re.subn(instance_pattern, do_instance, buf)
        re.subn(instance_from_library_pattern, do_instance_from_library, buf)
        
        #libraries
        library_pattern = re.compile("^\s*library\s*(\w+)\s*;",  re.DOTALL | re.MULTILINE | re.IGNORECASE )
        def do_library(s) :
            logging.debug("use library %s" % s.group(1))
            libraries.add(s.group(1).lower())
        re.subn(library_pattern, do_library, buf)
        dep_file.is_parsed = True