#!/usr/bin/ruby1.9.1 require "pp" $regname = ARGV[0] $mode = :def re = %r<(?x) ^ \s* (?: (?'start'\d{1,2}) (?:\s+|\s*:\s*) (?'stop'\d{1,2}) | (?'something'\d{1,4}) )? \s+ (?'acronym'[\w\d_]+?)? \s* $ > current = start = stop = nil def valid_bitnumber(current, new) return (new == 31 or new == 15 or new == 7) if not current return current == new end def warning(current, start, line) expected = current expected ||= "7, 15 or 31" $stderr.puts "WARNING: Expected bit #{expected} but got bit #{start} in line \"#{line.chomp}\"" end total_width = 0 acronym_begin = nil # First pass: get lines lines = [] lines << $_ until STDIN.gets.chomp.empty? # Second pass: parse lines lines2 = [] lines.each do |line| m = re.match line if not m $stderr.puts "WARNING: Invalid line: #{line}" next end start = stop = nil if m[:start] start = m[:start].to_i if not valid_bitnumber(current, start) warning current, start, line end stop = m["stop"].to_i elsif m[:something] start = m[:something].to_i if not valid_bitnumber(current, start) start, stop = m[:something].scan(/^(\d{1,2})(\d{1,2})$/).first start, stop = start.to_i, stop.to_i start, stop = stop, start if start < stop if not valid_bitnumber(current, start) warning current, start, line end else stop = start end end if start and stop current = stop - 1 width = start - stop + 1 total_width += width end lines2 << { :line => line, :acronym => (m[:acronym] or "") , :start => start, :stop => stop, :width => width } end # Third pass: assemble cut up field names lines3 = [] lines2.length.times do |i| if lines2[i][:start] and lines2[i][:stop] lines3 << lines2[i] else prev = lines3[-1] cur = lines2[i] next_ = lines2[i+1] if prev and next_ puts "WARNING: the copy-paste resulte is ambiguous:" puts "----" print prev[:line] print cur[:line] print next_[:line] puts "----" puts "Are the field names" print ' (1) "' print prev[:acronym] + cur[:acronym] print '" and "' print next_[:acronym] puts '"' print ' (2) "' print prev[:acronym] print '" and "' print cur[:acronym] + next_[:acronym] puts '"' num = nil loop do print "Choice: " num = STDIN.gets.to_i break if num == 1 or num == 2 end if num == 1 prev[:acronym] = prev[:acronym] + cur[:acronym] else next_[:acronym] = cur[:acronym] + next_[:acronym] end elsif prev prev[:acronym] = prev[:acronym] + cur[:acronym] elsif next_ next_[:acronym] = cur[:acronym] + next_[:acronym] else puts "WARNING: WTF? line #{i} has no prev nor next line" pp lines pp lines2 pp lines3 end end end lines3.each do |line| acronym, start, stop, width = line[:acronym], line[:start], line[:stop], line[:width] name = (acronym =~ /reserved|rsvd/i ? "" : ($regname ? $regname + "_" : "") + acronym) if $mode == :struct tabs = "\t" * [2 - name.length / 8, 0].max puts "\t#{name}#{tabs}:#{width}," elsif $mode == :def if name != "" tabs = "\t" * [2 - name.length / 8, 1].max puts "#define #{name}#{tabs}#{stop}" end end end if total_width != 8 and total_width != 16 and total_width != 32 $stderr.puts "WARNING: Total register width is #{total_width} bits" end