#!/usr/bin/python # -*- coding: utf-8 -*- # # Copyright (c) 2013 CERN # Author: Tomasz Wlostowski (tomasz.wlostowski@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 def _remove_gaps(buf, delims, gap_chars, lower_strings=False): da = {} for d in delims: da[d] = False prev_is_gap = False buf2 = "" lines = [] for c in buf: for d in delims: if c == d: da[d] = not da[d] within_string = any(da.values()) and not (c in delims) if not within_string: if(c in gap_chars): if(not prev_is_gap): prev_is_gap = True buf2 += " " else: prev_is_gap = False buf2 += c if c == ";" or c == "\n": lines.append(buf2) buf2 = "" else: buf2 += c prev_is_gap = False return lines class VHDLParser(DepParser): def parse(self, dep_file): from dep_file import DepRelation if dep_file.is_parsed: return logging.info("Parsing %s" % dep_file.path) content = open(dep_file.file_path, "r") buf = "" # stage 1: strip comments for l in content.readlines(): ci = l.find("--") if ci == 0: continue while ci > 0: quotes = l[:ci].count('"') # ignore comments in strings if quotes % 2 == 0: l = l[:ci-1] break ci = l.find("--", ci+1) buf += l # stage 2: remove spaces, crs, lfs, strip strings (we don't need them) buf2 = "" string_literal = char_literal = False prev_is_gap = False gap_chars = " \r\n\t" lines = [] for c in buf: if c == '"' and not char_literal: string_literal = not string_literal if c == "'" and not string_literal: char_literal = not char_literal within_string = (string_literal or char_literal) and (c != '"') and (c != "'") if(not within_string): if(c in gap_chars): if(not prev_is_gap): prev_is_gap = True buf2 += " " else: prev_is_gap = False buf2 += c.lower() if (c == ";" or buf2[-8:] == "generate") : lines.append(buf2) buf2 = "" else: prev_is_gap = False import re patterns = { "use": "^ *use +(\w+) *\. *(\w+) *\. *\w+ *;", "entity": "^ *entity +(\w+) +is +(port|generic|end)", "package": "^ *package +(\w+) +is", "arch_begin": "^ *architecture +(\w+) +of +(\w+) +is +", "arch_end": "^ *end +(\w+) +;", "instance": "^ *(\w+) *\: *(\w+) *(port *map|generic *map| *;)", "instance_from_library": "^ *(\w+) *\: *entity *(\w+) *\. *(\w+) *(port *map|generic *map| *;)" } compiled_patterns = map(lambda p: (p, re.compile(patterns[p])), patterns) within_architecture = False for l in lines: matches = filter(lambda (k, v): v is not None, map(lambda (k, v): (k, re.match(v, l.lower())), compiled_patterns)) if(not len(matches)): continue what, g = matches[0] switch = { if(what == "use"): if ( g.group(1).lower() == "work" ) : logging.debug("use package %s.%s" % (dep_file.library, g.group(2)) ) dep_file.add_relation(DepRelation("%s.%s" % (dep_file.library, g.group(2)) , DepRelation.USE, DepRelation.PACKAGE)) #work is a current library in VHDL else : logging.debug("use package %s.%s" % (g.group(1), g.group(2)) ) dep_file.add_relation(DepRelation("%s.%s" % (g.group(1), g.group(2)), DepRelation.USE, DepRelation.PACKAGE)) elif(what == "entity"): logging.debug("found entity %s.%s" % ( dep_file.library, g.group(1) ) ) dep_file.add_relation(DepRelation("%s.%s" % (dep_file.library, g.group(1)), DepRelation.PROVIDE, DepRelation.ENTITY)) elif(what == "package"): logging.debug("found package %s.%s" % (dep_file.library, g.group(1) )) dep_file.add_relation(DepRelation("%s.%s" % (dep_file.library, g.group(1)), DepRelation.PROVIDE, DepRelation.PACKAGE)) elif(what == "arch_begin"): arch_name = g.group(1) within_architecture = True elif(what == "arch_end" and within_architecture and g.group(1) == arch_name): within_architecture = False elif( what in ["instance", "instance_from_library"] and within_architecture): logging.debug("-> instantiates %s.%s as %s" % (dep_file.library, g.group(2), g.group(1)) ) dep_file.add_relation(DepRelation("%s.%s" % (dep_file.library, g.group(2)), DepRelation.USE, DepRelation.ENTITY)) dep_file.is_parsed = True