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.
@@ -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,5 @@
1
+ class String
2
+ def is_numeric?
3
+ true if Float(self) rescue false
4
+ end
5
+ 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: []