Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VHDL parser from andres manelli's fork for entity parsing support #4

Merged
merged 6 commits into from
Nov 29, 2021
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 136 additions & 32 deletions hdlparse/vhdl_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
import os
import re
from pprint import pprint

from hdlparse.minilexer import MiniLexer

"""VHDL documentation parser"""
'''VHDL documentation parser'''
Paebbels marked this conversation as resolved.
Show resolved Hide resolved

vhdl_tokens = {
'root': [
Expand All @@ -34,13 +33,13 @@
(r'subtype\s+(\w+)\s+is\s+(\w+)', 'subtype'),
(r'constant\s+(\w+)\s+:\s+(\w+)', 'constant'),
(r'type\s+(\w+)\s*is', 'type', 'type_decl'),
(r'end\s+package', None, '#pop'),
(r'end\s+\w+\s*;', None, '#pop'),
(r'--#(.*)\n', 'metacomment'),
(r'/\*', 'block_comment', 'block_comment'),
(r'--.*\n', None),
],
'package_body': [
(r'end\s+package\s+body', None, '#pop'),
(r'end\s+\w+\s*;', None, '#pop'),
(r'--#(.*)\n', 'metacomment'),
(r'/\*', 'block_comment', 'block_comment'),
(r'--.*\n', None),
Expand Down Expand Up @@ -86,13 +85,16 @@
(r'--.*\n', None),
],
'entity': [
(r'end\s+entity\s*;', 'end_entity', '#pop'),
(r'generic\s*\(', None, 'generic_list'),
(r'port\s*\(', None, 'port_list'),
(r'end\s+\w+\s*;', 'end_entity', '#pop'),
(r'/\*', 'block_comment', 'block_comment'),
(r'--.*\n', None),
],
'architecture': [
(r'end\s+architecture\s*;', 'end_arch', '#pop'),
(r'end\s+\w+\s*;', 'end_arch', '#pop'),
(r'/\*', 'block_comment', 'block_comment'),
(r'type\s+(\w+)\s*is', 'type', 'type_decl'),
(r'--.*\n', None),
],
'generic_list': [
Expand All @@ -104,9 +106,12 @@
(r'--.*\n', None),
],
'generic_param_type': [
(r'\s*(\w+)\s*', 'generic_param_type'),
(r'\s*(\w+)[ \t\r\f\v]*', 'generic_param_type'),
(r'\s*;\s*', None, '#pop'),
(r"\s*:=\s*([\w']+)", 'generic_param_default'),
(r'\)\s*;\s*--(.*)\n', 'line_comment', '#pop:2'),
(r'\n\s*\)\s*;\s*--(.*)\n', 'generic_list_comment', '#pop:2'),
(r'\n\s*', None),
(r'\)\s*;', 'end_generic', '#pop:2'),
(r'--#(.*)\n', 'metacomment'),
(r'/\*', 'block_comment', 'block_comment'),
Expand All @@ -119,24 +124,29 @@
(r'--#\s*{{(.*)}}\n', 'section_meta'),
(r'--#(.*)\n', 'metacomment'),
(r'/\*', 'block_comment', 'block_comment'),
(r'--.*\n', None),
(r'--(.*)\n', 'line_comment'),
],
'port_param_type': [
(r'\s*(in|out|inout|buffer)\s+(\w+)\s*\(', 'port_array_param_type', 'array_range'),
(r'\s*(in|out|inout|buffer)\s+(\w+)\s*', 'port_param_type'),
(r'\s*(in|out|inout|buffer)\s+(\w+)[ \t\r\f\v]*', 'port_param_type'),
(r'\s*;\s*', None, '#pop'),
(r"\s*:=\s*([\w']+)", 'port_param_default'),
(r'--(.*)\n', 'line_comment'),
(r'\)\s*;\s*--(.*)\n', 'line_comment', '#pop:2'),
(r'\n\s*\)\s*;\s*--(.*)\n', 'port_list_comment', '#pop:2'),
(r'\n\s*', None),
(r'\)\s*;', 'end_port', '#pop:2'),
(r'--#(.*)\n', 'metacomment'),
(r'/\*', 'block_comment', 'block_comment'),
(r'--.*\n', None),
],
'array_range': [
(r'\(', 'open_paren', 'nested_parens'),
(r'\s*([\w\+\-\*/\s]+)(\s+(?:down)?to)\s+([\w\+\-\*/\s]+)', 'array_range_val'),
(r'\)', 'array_range_end', '#pop'),
],
'nested_parens': [
(r'\(', 'open_paren', 'nested_parens'),
(r'\s*([\w\+\-\*/\s]+)(\s+(?:down)?to)\s+([\w\+\-\*/\s]+)', 'array_range_val'),
(r'\)', 'close_paren', '#pop'),
],
'block_comment': [
Expand Down Expand Up @@ -170,26 +180,53 @@ class VhdlParameter(object):
data_type (str): Type name for the parameter
default_value (str): Default value of the parameter
desc (str): Description from object metacomments
param_desc (str): Description of the parameter
"""

def __init__(self, name, mode=None, data_type=None, default_value=None, desc=None):
def __init__(self, name, mode=None, data_type=None, default_value=None, desc=None, param_desc=None):
self.name = name
self.mode = mode
self.data_type = data_type
self.default_value = default_value
self.desc = desc
self.param_desc = None

def __str__(self):
if self.mode is not None:
param = '{} : {} {}'.format(self.name, self.mode, self.data_type)
param = '{} : {} {}'.format(self.name, self.mode, self.data_type.name + self.data_type.arange)
else:
param = '{} : {}'.format(self.name, self.data_type)
param = '{} : {}'.format(self.name, self.data_type.name + self.data_type.arange)
if self.default_value is not None:
param = '{} := {}'.format(param, self.default_value)
if self.param_desc is not None:
param = '{} --{}'.format(param, self.param_desc)
return param

def __repr__(self):
return "VhdlParameter('{}', '{}', '{}')".format(self.name, self.mode, self.data_type)
return "VhdlParameter('{}', '{}', '{}')".format(self.name, self.mode,
self.data_type.name + self.data_type.arange)


class VhdlParameterType(object):
"""Parameter type definition

Args:
name (str): Name of the type
direction(str): "to" or "downto"
r_bound (str): A simple expression based on digits or variable names
l_bound (str): A simple expression based on digits or variable names
arange (str): Original array range string
"""

def __init__(self, name, direction="", r_bound="", l_bound="", arange=""):
self.name = name
self.direction = direction.strip()
self.r_bound = r_bound.strip()
self.l_bound = l_bound.strip()
self.arange = arange

def __repr__(self):
return "VhdlParameterType('{}','{}')".format(self.name, self.arange)


class VhdlPackage(VhdlObject):
Expand Down Expand Up @@ -307,6 +344,32 @@ def __repr__(self):
return "VhdlProcedure('{}')".format(self.name)


class VhdlEntity(VhdlObject):
"""Entity declaration
Args:
name (str): Name of the entity
ports (list of VhdlParameter): Port parameters to the entity
generics (list of VhdlParameter): Generic parameters to the entity
sections (list of str): Metacomment sections
desc (str, optional): Description from object metacomments
"""

def __init__(self, name, ports, generics=None, sections=None, desc=None):
VhdlObject.__init__(self, name, desc)
self.kind = 'entity'
self.generics = generics if generics is not None else []
self.ports = ports
self.sections = sections if sections is not None else {}

def __repr__(self):
return "VhdlEntity('{}')".format(self.name)

def dump(self):
print('VHDL entity: {}'.format(self.name))
for p in self.ports:
print('\t{} ({}), {} ({})'.format(p.name, type(p.name), p.data_type, type(p.data_type)))


class VhdlComponent(VhdlObject):
"""Component declaration

Expand Down Expand Up @@ -373,18 +436,19 @@ def parse_vhdl(text):
ports = []
sections = []
port_param_index = 0
last_item = None
last_items = []
array_range_start_pos = 0

objects = []

for pos, action, groups in lex.run(text):
if action == 'metacomment':
realigned = re.sub(r'^#+', lambda m: ' ' * len(m.group(0)), groups[0])
if last_item is None:
if not last_items:
metacomments.append(realigned)
else:
last_item.desc = realigned
for i in last_items:
i.desc = realigned
if action == 'section_meta':
sections.append((port_param_index, groups[0]))

Expand Down Expand Up @@ -441,6 +505,15 @@ def parse_vhdl(text):
kind = None
name = None

elif action == 'entity':
kind = 'entity'
name = groups[0]
generics = []
ports = []
param_items = []
sections = []
port_param_index = 0

elif action == 'component':
kind = 'component'
name = groups[0]
Expand All @@ -455,11 +528,17 @@ def parse_vhdl(text):

elif action == 'generic_param_type':
ptype = groups[0]

last_items = []
for i in param_items:
generics.append(VhdlParameter(i, 'in', ptype))
p = VhdlParameter(i, 'in', VhdlParameterType(ptype))
generics.append(p)
last_items.append(p)

param_items = []
last_item = generics[-1]

elif action == 'generic_param_default':
for i in last_items:
i.default_value = groups[0]

elif action == 'port_param':
param_items.append(groups[0])
Expand All @@ -468,29 +547,46 @@ def parse_vhdl(text):
elif action == 'port_param_type':
mode, ptype = groups

last_items = []
for i in param_items:
ports.append(VhdlParameter(i, mode, ptype))
p = VhdlParameter(i, mode, VhdlParameterType(ptype))
ports.append(p)
last_items.append(p)

param_items = []
last_item = ports[-1]

elif action == 'port_param_default':
for i in last_items:
i.default_value = groups[0]

elif action == 'port_array_param_type':
mode, ptype = groups
array_range_start_pos = pos[1]

elif action == 'array_range_val':
l_bound, direction, r_bound = groups

elif action == 'array_range_end':
arange = text[array_range_start_pos:pos[0] + 1]

last_items = []
for i in param_items:
ports.append(VhdlParameter(i, mode, ptype + arange))
p = VhdlParameter(i, mode, VhdlParameterType(ptype, direction, r_bound, l_bound, arange))
ports.append(p)
last_items.append(p)

param_items = []
last_item = ports[-1]

elif action == 'end_entity':
vobj = VhdlEntity(name, ports, generics, dict(sections), metacomments)
objects.append(vobj)
last_items = []
metacomments = []

elif action == 'end_component':
vobj = VhdlComponent(name, cur_package, ports, generics, dict(sections), metacomments)
objects.append(vobj)
last_item = None
last_items = []
metacomments = []

elif action == 'package':
Expand All @@ -503,7 +599,7 @@ def parse_vhdl(text):
saved_type = groups[0]

elif action in (
'array_type', 'file_type', 'access_type', 'record_type', 'range_type', 'enum_type', 'incomplete_type'):
'array_type', 'file_type', 'access_type', 'record_type', 'range_type', 'enum_type', 'incomplete_type'):
vobj = VhdlType(saved_type, cur_package, action, metacomments)
objects.append(vobj)
kind = None
Expand All @@ -524,6 +620,11 @@ def parse_vhdl(text):
name = None
metacomments = []

elif action == 'line_comment':
for i in last_items:
if not i.param_desc:
i.param_desc = groups[0]

return objects


Expand Down Expand Up @@ -591,7 +692,8 @@ class VhdlExtractor(object):
"""

def __init__(self, array_types=set()):
self.array_types = {'std_ulogic_vector', 'std_logic_vector', 'signed', 'unsigned', 'bit_vector'}
self.array_types = set(('std_ulogic_vector', 'std_logic_vector',
'signed', 'unsigned', 'bit_vector'))

self.array_types |= array_types
self.object_cache = {}
Expand Down Expand Up @@ -720,21 +822,23 @@ def register_array_types_from_sources(self, source_files):

if __name__ == '__main__':
ve = VhdlExtractor()
code = """
code = '''
package foo is
function afunc(q,w,e : std_ulogic; h,j,k : unsigned) return std_ulogic;

procedure aproc( r,t,y : in std_ulogic; u,i,o : out signed);

component acomp is
port (
a,b,c : in std_ulogic;
f,g,h : inout bit
);
a,b,c : in std_ulogic; -- no default value
f,g,h : inout bit := '1'; -- bit ports
v : in std_logic_vector(lBound -1 downto 0) -- array range
); -- port list comment

end component;

end package;
"""
'''

objs = ve.extract_objects_from_source(code)

Expand Down