vhdl_parser 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/vhdl_parser.rb +115 -0
- data/lib/vhdl_parser/entity.rb +67 -0
- data/lib/vhdl_parser/extractor.rb +64 -0
- data/lib/vhdl_parser/generic.rb +28 -0
- data/lib/vhdl_parser/magic.rb +5 -0
- data/lib/vhdl_parser/package.rb +22 -0
- data/lib/vhdl_parser/port.rb +27 -0
- data/lib/vhdl_parser/utility.rb +34 -0
- metadata +53 -0
data/lib/vhdl_parser.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'vhdl_parser/magic'
|
2
|
+
require 'vhdl_parser/utility'
|
3
|
+
require 'vhdl_parser/extractor'
|
4
|
+
require 'vhdl_parser/entity'
|
5
|
+
require 'vhdl_parser/port'
|
6
|
+
require 'vhdl_parser/generic'
|
7
|
+
require 'vhdl_parser/package'
|
8
|
+
|
9
|
+
|
10
|
+
module VHDL_Parser
|
11
|
+
|
12
|
+
class << self
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.parse_file(filename)
|
16
|
+
string = File.read(filename)
|
17
|
+
self.parse(string)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.parse(vhdl_string)
|
21
|
+
info = vhdl_string.match /entity\s+(.*)\s+is\s+(?:generic\s*\((.*)\);)?\s*port\s*\((.*)\);\s*end\s*\1;/im
|
22
|
+
|
23
|
+
generics = info[2].split("\n").compact.delete_if { |s| s.strip.empty? }
|
24
|
+
generics.map! { |s| s.strip!}
|
25
|
+
generics.delete_if { |l| l.match /^--/}
|
26
|
+
|
27
|
+
ports = info[3].split("\n").compact.delete_if { |s| s.strip.empty? }
|
28
|
+
ports.map! { |s| s.strip!}
|
29
|
+
ports.delete_if { |l| l.match /^--/}
|
30
|
+
|
31
|
+
@entity = Entity.new
|
32
|
+
@entity.name = info[1]
|
33
|
+
|
34
|
+
|
35
|
+
self.parse_generics(generics)
|
36
|
+
self.parse_ports(ports)
|
37
|
+
|
38
|
+
@entity.process_generics
|
39
|
+
|
40
|
+
return @entity
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.parse_package_file(filename)
|
44
|
+
string = File.read(filename)
|
45
|
+
self.parse_package(string)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.parse_package(string)
|
49
|
+
package = Package.new
|
50
|
+
|
51
|
+
constants = Extractor.extract_package_constants(string)
|
52
|
+
constants.each do |c|
|
53
|
+
package.constants[c[0]] = c[2]
|
54
|
+
end
|
55
|
+
package.process
|
56
|
+
package
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def self.parse_generics(generic_array)
|
62
|
+
generic_array.each do |g|
|
63
|
+
names = Extractor.extract_name(g)
|
64
|
+
names.each do |n|
|
65
|
+
generic = Generic.new
|
66
|
+
generic.name = n
|
67
|
+
generic.type = Extractor.extract_type(g)
|
68
|
+
|
69
|
+
if generic.type == "integer"
|
70
|
+
sizes = Extractor.extract_range(g)
|
71
|
+
else
|
72
|
+
sizes = Extractor.extract_size(g)
|
73
|
+
end
|
74
|
+
|
75
|
+
unless sizes.nil?
|
76
|
+
generic.left = sizes[1]
|
77
|
+
generic.size_dir = sizes[2]
|
78
|
+
generic.right = sizes[3]
|
79
|
+
end
|
80
|
+
|
81
|
+
generic.comment = Extractor.extract_comment(g)
|
82
|
+
|
83
|
+
generic.value = Extractor.extract_value(g)
|
84
|
+
|
85
|
+
@entity.generics.push generic
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.parse_ports(port_array)
|
91
|
+
port_array.each do |l|
|
92
|
+
names = Extractor.extract_name(l)
|
93
|
+
names.each do |n|
|
94
|
+
port = Port.new
|
95
|
+
port.name = n
|
96
|
+
port.direction = Extractor.extract_direction(l)
|
97
|
+
port.type = Extractor.extract_type(l)
|
98
|
+
if port.type == "integer"
|
99
|
+
sizes = Extractor.extract_range(l)
|
100
|
+
else
|
101
|
+
sizes = Extractor.extract_size(l)
|
102
|
+
end
|
103
|
+
|
104
|
+
unless sizes.nil?
|
105
|
+
port.left = sizes[1]
|
106
|
+
port.size_dir = sizes[2]
|
107
|
+
port.right = sizes[3]
|
108
|
+
end
|
109
|
+
port.comment = Extractor.extract_comment(l)
|
110
|
+
@entity.ports.push(port)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module VHDL_Parser
|
2
|
+
class Entity
|
3
|
+
|
4
|
+
attr_accessor :name
|
5
|
+
attr_reader :ports, :generics
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@ports = Array.new
|
9
|
+
@generics = Array.new
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
out = name + "\n"
|
15
|
+
@generics.each { |p| out += "\t" + p.to_s}
|
16
|
+
out += "\n\n"
|
17
|
+
@ports.each { |p| out += "\t" + p.to_s}
|
18
|
+
out
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def merge_package(package)
|
23
|
+
# TODO: do some type checking
|
24
|
+
@generics.each do |g|
|
25
|
+
package.constants.each do |k,v|
|
26
|
+
unless g.value.nil?
|
27
|
+
g.value = Utility.sub_constants(g.value, k, v)
|
28
|
+
end
|
29
|
+
|
30
|
+
unless g.left.nil?
|
31
|
+
g.left = Utility.sub_constants(g.left, k, v)
|
32
|
+
end
|
33
|
+
|
34
|
+
unless g.right.nil?
|
35
|
+
g.right = Utility.sub_constants(g.right, k, v)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
@ports.each do |p|
|
41
|
+
package.constants.each do |k,v|
|
42
|
+
unless p.left.nil?
|
43
|
+
p.left = Utility.sub_constants(p.left, k, v)
|
44
|
+
end
|
45
|
+
|
46
|
+
unless p.right.nil?
|
47
|
+
p.right = Utility.sub_constants(p.right, k, v)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def process_generics
|
54
|
+
@ports.each do |p|
|
55
|
+
@generics.each do |g|
|
56
|
+
unless p.left.nil?
|
57
|
+
p.left = Utility.sub_constants(p.left, g.name, g.value)
|
58
|
+
end
|
59
|
+
unless p.right.nil?
|
60
|
+
p.right = Utility.sub_constants(p.right, g.name, g.value)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module VHDL_Parser
|
2
|
+
class Extractor
|
3
|
+
|
4
|
+
def self.extract_name(string)
|
5
|
+
names = string.split(":").map! { |e| e.strip}
|
6
|
+
names[0].split(/\s*,\s*/)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.extract_direction(string)
|
10
|
+
res = string.match(/:\s*(in|out|inout)/)
|
11
|
+
if res[1]
|
12
|
+
return res[1]
|
13
|
+
end
|
14
|
+
""
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.extract_type(string)
|
18
|
+
res = string.match(/:\s*(?:in|out|inout)?\s+(\w+)/i)
|
19
|
+
if res[1]
|
20
|
+
return res[1]
|
21
|
+
end
|
22
|
+
""
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.extract_size(string)
|
26
|
+
res = string.match(/\((.*?)\s+(downto|to)\s+(.+?)\)/i)
|
27
|
+
if res
|
28
|
+
return res
|
29
|
+
end
|
30
|
+
""
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.extract_range(string)
|
34
|
+
res = string.match(/range\s+(.*?)\s+(downto|to)\s+([-a-z0-9_]*)/i)
|
35
|
+
if res
|
36
|
+
return res
|
37
|
+
end
|
38
|
+
""
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.extract_comment(string)
|
42
|
+
res = string.match(/--(.*)$/)
|
43
|
+
if res && res[0]
|
44
|
+
return res[0]
|
45
|
+
end
|
46
|
+
""
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.extract_package_constants(string)
|
50
|
+
body = string.match(/package\s+(.*)\s+is\s+(.*)\s*end\s*\1;/im)
|
51
|
+
name = body[1]
|
52
|
+
constants = body[2]
|
53
|
+
constants.scan /constant\s+(\w+)\s*:\s*(\w+)\s*:=\s*(.*);/i
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.extract_value(string)
|
57
|
+
res = string.match /:=\s*([xo"0-9a-z_]*)/i
|
58
|
+
if res && res[1]
|
59
|
+
return res[1]
|
60
|
+
end
|
61
|
+
""
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module VHDL_Parser
|
2
|
+
class Generic
|
3
|
+
attr_accessor :name, :value, :type, :size, :left, :right, :size_dir, :comment
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@left = 0
|
7
|
+
@right = 0
|
8
|
+
@size_dir = "downto"
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
name.ljust(15) + "\t" +
|
13
|
+
type + " " +
|
14
|
+
size + "\t:= " +
|
15
|
+
value + "\t" +
|
16
|
+
comment +
|
17
|
+
"\n"
|
18
|
+
end
|
19
|
+
|
20
|
+
def size
|
21
|
+
unless @left.nil?
|
22
|
+
"(#{@left} #{@size_dir} #{@right})"
|
23
|
+
else
|
24
|
+
""
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module VHDL_Parser
|
2
|
+
class Package
|
3
|
+
|
4
|
+
attr_accessor :constants
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@constants = Hash.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
@constants.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
def process
|
15
|
+
@constants.each do |k,v|
|
16
|
+
@constants.each do |k2,v2|
|
17
|
+
@constants[k2] = Utility.sub_constants(v2, k, v)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module VHDL_Parser
|
2
|
+
class Port
|
3
|
+
attr_accessor :name, :direction, :comment, :type, :size, :left, :right, :size_dir
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@left = 0
|
7
|
+
@right = 0
|
8
|
+
@size_dir = "downto"
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
name.ljust(15) + "\t" +
|
13
|
+
direction + "\t" +
|
14
|
+
type + " " +
|
15
|
+
size + "\t" +
|
16
|
+
comment + "\n"
|
17
|
+
end
|
18
|
+
|
19
|
+
def size
|
20
|
+
unless @left.nil?
|
21
|
+
"(#{@left} #{@size_dir} #{@right})"
|
22
|
+
else
|
23
|
+
""
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module VHDL_Parser
|
2
|
+
class Utility
|
3
|
+
def self.sub_constants(target, key, value)
|
4
|
+
# first get all the words of the size. That could be
|
5
|
+
# a number or a constant.
|
6
|
+
words = target.to_s.scan /\w+/
|
7
|
+
ret = ""
|
8
|
+
words.each do |w|
|
9
|
+
# if a word matches the key and it's not numeric, it must
|
10
|
+
# be a constant that we want to replace
|
11
|
+
if w.eql?(key) and not w.is_numeric?
|
12
|
+
# so replace it here with the given value
|
13
|
+
ret = target.gsub(w,value).to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# now eval the result. If a constant has been replaced with a
|
18
|
+
# value, it could be something like "8-1", so eval that into 7.
|
19
|
+
# In case it's still a constant, catch the NameError but ignore it;
|
20
|
+
# chances are the constant will be replaced later.
|
21
|
+
begin
|
22
|
+
# since we're eval'ing here, do some basic cleanup to prevent badness.
|
23
|
+
# Specifically, replace anything that's not a number or basic math
|
24
|
+
# function with 'xx', since those should trigger the exception anyway.
|
25
|
+
foreval = ret.gsub(/[^-+*\/\d\(\)\s]/,'xx')
|
26
|
+
ret = eval(foreval)
|
27
|
+
rescue NameError => e
|
28
|
+
end
|
29
|
+
# if nothing was replaced, we get nil, so instead of returning nil,
|
30
|
+
# just return the original target, meaning this was just a noop.
|
31
|
+
ret.nil? ? target.to_s : ret
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vhdl_parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Christoph Koehler
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-30 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! "VHDL Parser parses an VHDL entity and provides a Ruby\n interface
|
15
|
+
to access all its information."
|
16
|
+
email: christoph@zerodeviation.net
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/vhdl_parser/entity.rb
|
22
|
+
- lib/vhdl_parser/extractor.rb
|
23
|
+
- lib/vhdl_parser/generic.rb
|
24
|
+
- lib/vhdl_parser/magic.rb
|
25
|
+
- lib/vhdl_parser/package.rb
|
26
|
+
- lib/vhdl_parser/port.rb
|
27
|
+
- lib/vhdl_parser/utility.rb
|
28
|
+
- lib/vhdl_parser.rb
|
29
|
+
homepage: http://rubygems.org/gems/vhdl_parser
|
30
|
+
licenses: []
|
31
|
+
post_install_message: Hi there
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubyforge_project:
|
49
|
+
rubygems_version: 1.8.23
|
50
|
+
signing_key:
|
51
|
+
specification_version: 3
|
52
|
+
summary: VHDL Entity Parser
|
53
|
+
test_files: []
|