Class: Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/Parser.rb

Overview

This class handles all parsing operations for this application. It makes extensive use of the ParseHelper module to accomplish this.

Instance Method Summary collapse

Instance Method Details

#parse(filearray) ⇒ Object

Takes an array of lines (filearray) - presumably from an EDF file - and parses them, dynamically creating a data structure by defining the connections between Inst objects as they are created.



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/Parser.rb', line 5

def parse(filearray)
  # read through our array to find and store the start and end points
  filearray.each_with_index do |line,index|
    line.strip!
    # store linecounts as indexes into the array (zero based)
    @startline = index if line =~ /interface/
    if line =~ /design root/
      @endline = index - 2 
      break
    end
  end

  # chop invalid parts off of array
  filearray = filearray.slice(@startline..@endline)

  arrplace = 0
  arrlength = filearray.length - 1
  valid_edf = []
  tmpstr = ""
  @insts = {}
  while arrplace <= arrlength
    # see if we have a keyword on the current line  
    if filearray[arrplace] =~ /\A\(port\s+|\A\(instance|\A\(net/
      # we do, see if its parens are matched
      if ParseHelper.parens_check(filearray[arrplace])
        # they are, so put the string into the array
        valid_edf << filearray[arrplace]
      else
        # they are not, so write the array location to a temp string
        tmpstr << filearray[arrplace]
        # see if we are at the end of the array
        break if arrplace + 1 >= arrlength
        # if not keep trying to match parens
        arrplace += 1
        tmpstr << filearray[arrplace]
        # replace this with paren check
        while !ParseHelper.parens_check(tmpstr)
          break if arrplace + 1 >= arrlength
          arrplace += 1
          tmpstr << filearray[arrplace]
        end
        valid_edf << tmpstr
        tmpstr = ""
      end
      # look at next place
      arrplace += 1
    else
      arrplace += 1
    end
  end

  valid_edf.each do |l|
    # for the first keyword port
    if l =~ /\A\(port\s+/
      # if there are multiple members
      if l =~ /(\w+)(\s+)(\d+)(\(direction)(\s)(input|output)/
        instnum = $3.to_i
        insttype = $6.capitalize
        instname = $1.downcase
        # generate names for each member
        inames = ParseHelper.member_inst_names(instnum,instname)
        # puts "Creating #{instnum} Insts of type #{insttype} named #{inames.join(", ")}"
        # create the inst objects of the proper type and store in insts hash
        inames.each do |i|
          @insts[i] = Object.const_get(insttype).new(i)
        end
      # if there are no members
      elsif l =~ /(\w+)(\s)(\(direction)(\s)(input|output)/
        insttype = $5.capitalize
        instname = $1.downcase
        # puts "Creating an Inst of type #{insttype} named #{instname}"
        # create the inst objects of the proper type and store in insts hash
        @insts["#{instname}"] = Object.const_get(insttype).new(instname)
      else
        throw "Error Parsing Ports"
      end
    # for the second keyword, "instance"
    elsif l =~ /(\A\(instance\s+)(\w+)(\(viewRef)(\s)(viewnamedefault\(cellRef)(\s)(\w+)/
      insttype = $7.capitalize
      instname = $2.downcase
      # create the inst objects of the proper type and store them in the hash
      # puts "Creating an Inst of type #{insttype} named #{instname}"
      @insts["#{instname}"] = Object.const_get(insttype).new(instname)
    elsif l =~ /(\A\(net\sNet\d+\(joined)(.*)/
      # get the names for the joined ports in individual arrays
      # make this get_port_names method modify names for bufz ports on the fly
      ports = ParseHelper.get_port_names($2,@insts)
      # look for output ports to find the master
      # if inst type is bufz then automatically set it as a masterport
      # I have the inst name and the port name availible to me separately
      outputports = []
      inputports = []
      unless ports.length <= 1
      ports.each do |p|
        # split portnames into inst name and port name
        splitport = ParseHelper.portname_split(p) 
        # if the portname is out we have a bufz output port
        if splitport[1] == "out"
          # we know this is an output so add it to output
          outputports << p
        # otherwise check to see if this might be a output port of another type
        elsif @insts[splitport[0]].get_port(splitport[1]).type == "out"
          # we know this is an output so add it to output
          outputports << p
        else
          # otherwise it is an input
          inputports << p
        end
      end
      
      # this assumes there is only one input port
      # since bufz is treated as a unit this should be true
      # if it is not there will be errors - but they will be the fault
      # of the circuit designer
      op = ParseHelper.portname_split(outputports.first)
      inputports.each do |p|
        # puts "Cross-Connecting #{op} to #{p}"
        # convert port names to separate inst names and port names
        ip = ParseHelper.portname_split(p)
        # cross connect ports
        # puts "connecting #{ip[0]} on #{ip[1]} to #{op[0]} on #{op[1]}"
        @insts[ip[0]].get_port(ip[1]).add_connection(@insts[op[0]].get_port(op[1]))
        # puts "connecting #{op[0]} on #{op[1]} to #{ip[0]} on #{ip[1]}"
        @insts[op[0]].get_port(op[1]).add_connection(@insts[ip[0]].get_port(ip[1]))
      end
      end
    else
      throw "Error Parsing Nets/Instances"
    end
  end
  @insts
end