#!/usr/bin/ruby $script_call = $0 + " " + ARGV.join(" ") $indirs = [ "src/drc/drc/built-in-macros", "src/lvs/lvs/built-in-macros" ] $loc = "about" $outfiles = "src/lay/lay/doc" def create_ref(mod, s) if s =~ /(.*)::(.*)#(.*)/ "#{s}" elsif s =~ /(.*)::(.*)/ "#{s}" elsif s =~ /(.*)#(.*)/ if $2 != "" "#{s}" else "#{$1}" end else "#{s}" end end def create_class_doc_ref(s) "#{s}" end def escape(mod, s) s.gsub("&", "&"). gsub("<", "<"). gsub(">", ">"). gsub(/\\([\w:#]+)/) { create_ref(mod, $1) }. gsub(/RBA::([\w#]+)/) { create_class_doc_ref($1) } end def unescape(s) s.gsub("&", "&").gsub("<", "<").gsub(">", ">") end class DocItem attr_accessor :brief attr_accessor :synopsis attr_accessor :name attr_accessor :doc attr_accessor :mod def initialize(mod, block) @paragraphs = [] para = nil self.synopsis = [] self.mod = mod in_code = false block.each do |b| if in_code if b =~ /@\/code/ in_code = false end para.push(b) elsif b =~ /^@brief\s+(.*?)\s*$/ self.brief = $1 elsif b =~ /^@name\s+(.*?)\s*$/ self.name = $1 elsif b =~ /^@synopsis\s+(.*?)\s*$/ self.synopsis.push($1) elsif b =~ /^@scope/ # ignore scope commands elsif b =~ /^\s*$/ para && @paragraphs.push(para) para = nil else para ||= [] para.push(b) if b =~ /@code/ in_code = true end end end self.name || raise("Doc block without name") para && @paragraphs.push(para) end def produce_doc if @paragraphs.empty? return "" end doc = "

\n" @paragraphs.each_with_index do |p, i| i > 0 && doc += "

\n" p.each do |pp| doc += escape(self.mod, pp). gsub(/\\@/, "&at;"). gsub(/\s*@code\s*/, "

").
              gsub(/\s*@\/code\s*/, "
"). gsub(/@img\((.*)\)\s*/) { "" }. gsub(/@\/img\s*/, ""). gsub(/@(\w+)\s*/) { "<" + $1 + ">" }. gsub(/@\/(\w+)\s*/) { "" }. gsub(/&at;/, "@") doc += "\n" end end doc += "

\n" end end class Scope < DocItem def initialize(mod, block) super(mod, block) @items = {} end def merge(other) if !self.brief self.brief = other.brief self.doc = other.doc self.synopsis = other.synopsis end end def add_doc_item(mod, block) item = DocItem::new(mod, block) @items[item.name] = item end alias :super_produce_doc :produce_doc def produce_doc doc = < HEAD doc += "\n" doc += "" + escape(self.mod, self.brief) + "\n" doc += "\n" doc += super_produce_doc doc += "\n" @items.keys.sort.each do |item_key| item = @items[item_key] item.name || raise("Missing @name for item #{item_key}") item.brief || raise("Missing @brief for item #{item_key}") doc += "" doc += "

\"" + escape(self.mod, item.name) + "\" - " + escape(self.mod, item.brief) + "

\n" doc += "\n" if ! item.synopsis.empty? doc += "

Usage:

\n" doc += "
    \n" item.synopsis.each do |s| doc += "
  • " + escape(self.mod, s) + "
  • \n" end doc += "
\n" end doc += item.produce_doc end doc += "
\n" doc end end class Collector def initialize(mod, title) @mod = mod @title = title end def add_block(block) if block.find { |l| l =~ /^@scope/ } # is a scope block @scopes ||= {} scope = Scope::new(@mod, block) if ! @scopes[scope.name] @current_scope = scope @scopes[scope.name] = scope else @current_scope = @scopes[scope.name] @current_scope.merge(scope) end else @current_scope && @current_scope.add_doc_item(@mod, block) end end def produce_doc @scopes.keys.sort.each do |k| suffix = k.downcase outfile = $outfiles + "/" + $loc + "/" + @mod + "_ref_" + suffix + ".xml" File.open(outfile, "w") do |file| file.write(@scopes[k].produce_doc) puts "---> #{outfile} written." end end end def produce_index outfile = $outfiles + "/" + $loc + "/" + @mod + "_ref.xml" File.open(outfile, "w") do |file| doc = < HEAD doc += "\n" doc += "#{escape(@mod, @title)}\n" doc += "\n" doc += "\n" @scopes.keys.sort.each do |k| suffix = k.downcase doc += "\n" end doc += "\n" doc += "\n" file.write(doc) end puts "---> Index file #{outfile} written." end end collectors = { "DRC" => Collector::new("drc", "DRC Reference"), "LVS" => Collector::new("lvs", "LVS Reference") } $indirs.each do |indir| Dir.entries(indir).each do |p| if p !~ /\.rb$/ next end infile = File.join(indir, p) puts "Extracting doc from #{infile} .." File.open(infile, "r") do |file| block = [] collector = nil line = 0 file.each_line do |l| line += 1 begin l = unescape(l) if ! collector collectors.each do |k,c| if l =~ /^\s*#\s*%#{k}%/ collector = c l = nil block = [] break end end end if l if l =~ /^\s*#\s*(.*)\s*$/ collector && block.push($1) elsif l =~ /^\s*$/ collector && collector.add_block(block) collector = nil end end rescue => ex puts "ERROR in line #{line}:\n" + ex.to_s puts ex.backtrace # @@@ exit 1 end end end end end collectors.each do |k,collector| collector.produce_doc collector.produce_index end