vhdl_parser 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []