home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ruby164.zip / rbemx164.zip / ruby / share / doc / racc-1.3.9 / misc / y2racc < prev   
Text File  |  2001-04-07  |  6KB  |  336 lines

  1. #!/usr/local/bin/ruby
  2. #
  3. # y2racc  --  yacc to racc converter
  4. #
  5. #   Copyright (c) 1999-2001 Minero Aoki <aamine@dp.u-netsurf.ne.jp>
  6. #
  7. #   This program is free software.
  8. #   You can distribute/modify this program under the terms of
  9. #   the GNU Lesser General Public Lisence version 2 or later.
  10. #
  11.  
  12. require 'getopts'
  13. require 'strscan'
  14. require 'amstd/bug'
  15.  
  16.  
  17. unless defined? StringScanner_C or
  18.        $".include? 'strscan.so' then
  19.   $stderr.puts "#{$0}: fatal: NEVER USE ruby-level strscan with y2racc"
  20.   exit 3
  21. end
  22.  
  23. class Y
  24.  
  25.   Version = '1.1.0'
  26.  
  27.  
  28.   def initialize( cname )
  29.     @cname = cname
  30.     @prectab = []
  31.     @start = nil
  32.     @tokens = []
  33.     @grammer = []
  34.  
  35.     @header = nil
  36.     @footer = nil
  37.   end
  38.  
  39.   COMMENT = %r</\*[^*]*\*+(?:[^/*][^*]*\*+)*/>
  40.  
  41.   #
  42.   # parse
  43.   #
  44.  
  45.   def parse( f, fname )
  46.     @fname = fname
  47.     str = f.read
  48.     s = StringScanner.new( str )
  49.  
  50.     procdef s
  51.     procrule s
  52.   end
  53.  
  54.  
  55.   def procdef( s )
  56.     skip_until_percent s
  57.     until s.empty? do
  58.       if t = s.scan( /(left|right|nonassoc|token|start)\b/ ) then
  59.         send 'proc_' + t, get_tokens( s )
  60.  
  61.       elsif s.skip %r<(?:
  62.             type | union | expect | thong | binary |
  63.             semantic_parser | pure_parser | no_lines |
  64.             raw | token_table                          )\b>x then
  65.         skip_until_percent s
  66.  
  67.       elsif s.skip /\{/
  68.         @header = s.scan_until( /\%\}/ )
  69.         @header.chop!; @header.chop!   # %}
  70.         skip_until_percent s
  71.  
  72.       elsif s.skip /\%/ then   # %%
  73.         return
  74.  
  75.       else
  76.         bug!
  77.       end
  78.     end
  79.   end
  80.  
  81.   def skip_until_percent( s )
  82.     until s.empty? do
  83.       s.skip /[^\%\/]+/
  84.       if t = s.scan( COMMENT ) then
  85.         ;
  86.       elsif s.getch == '/' then
  87.         ;
  88.       else
  89.         return
  90.       end
  91.     end
  92.   end
  93.  
  94.   def get_tokens( s )
  95.     ret = []
  96.     until s.empty? do
  97.       s.skip /\s+/
  98.       next if s.skip COMMENT
  99.  
  100.       if t = s.scan( /'((?:[^'\\]+|\\.)*)'/ ) then
  101.         ret.push t
  102.       elsif t = s.scan( /"((?:[^"\\]+|\\.)*)"/ ) then
  103.         ret.push t
  104.       elsif s.skip /\%/ then
  105.         break
  106.       elsif t = s.scan( /\S+/ ) then
  107.         ret.push t
  108.       else
  109.         bug!
  110.       end
  111.     end
  112.  
  113.     ret
  114.   end
  115.  
  116.   def proc_left( arr )
  117.     @prectab.push ['left', arr]
  118.   end
  119.  
  120.   def proc_right( arr )
  121.     @prectab.push ['right', arr]
  122.   end
  123.  
  124.   def proc_nonassoc( arr )
  125.     @prectab.push ['nonassoc', arr]
  126.   end
  127.  
  128.   def proc_token( arr )
  129.     if /\A\<.*\>\z/ === arr[0] then
  130.       arr.shift
  131.     end
  132.     @tokens.concat arr
  133.   end
  134.  
  135.   def proc_start( arr )
  136.     @start = arr[0]
  137.   end
  138.  
  139.   ###
  140.  
  141.   STRINGq = /'(?:[^'\\]+|\\.)*'/
  142.   STRINGQ = /"(?:[^"\\]+|\\.)*"/
  143.  
  144.   def procrule( s )
  145.     @text = []
  146.  
  147.     until s.empty? do
  148.       if t = s.scan( /[^%'"{\/]+/ ) then
  149.         @text.push t
  150.         break if s.empty?
  151.       end
  152.  
  153.       if s.skip /\{/ then
  154.         if $OPT_A then
  155.           skip_action s
  156.         else
  157.           scan_action s
  158.         end
  159.       elsif t = s.scan( STRINGq ) then @text.push t
  160.       elsif t = s.scan( STRINGQ ) then @text.push t
  161.       elsif t = s.scan( COMMENT ) then @text.push t
  162.       elsif s.skip /%prec\b/      then @text.push '='
  163.       elsif s.skip /%%/           then
  164.         if $OPT_u then
  165.           @footer = s.rest
  166.         end
  167.         break
  168.       else
  169.         @text.push s.getch
  170.       end
  171.     end
  172.   end
  173.  
  174.   def skip_action( s )
  175.     @text, save = [], @text
  176.     scan_action s
  177.     @text = save
  178.     #@text.push "{\n                # action\n            }"
  179.     @text.push "{  }"
  180.   end
  181.  
  182.   def scan_action( s )
  183.     @text.push '{'
  184.  
  185.     nest = 1
  186.     until s.empty? do
  187.       if t = s.scan( /[^{'"}\/]+/ ) then
  188.         @text.push t
  189.         break if s.empty?
  190.       end
  191.       if t = s.scan( COMMENT ) then
  192.         @text.push t
  193.         next
  194.       end
  195.  
  196.       c = s.getch
  197.       @text.push c
  198.       case c
  199.       when '{'
  200.         nest += 1
  201.       when '}'
  202.         nest -= 1
  203.         if nest == 0 then
  204.           return
  205.         end
  206.       else
  207.         ;
  208.       end
  209.     end
  210.  
  211.     $stderr.puts "warning: unterminated action in #{@fname}"
  212.   end
  213.  
  214.  
  215.   #
  216.   # output
  217.   #
  218.  
  219.   def output( f )
  220.     f.print <<SRC
  221. #
  222. # converted from "#{@fname}" by y2racc version #{Version}
  223. #
  224.  
  225. class #{@cname}
  226.  
  227. SRC
  228.     f.print 'token'
  229.     total = 0
  230.     @tokens.each do |t|
  231.       if total > 60 then
  232.         f.print "\n     "
  233.         total = 0
  234.       end
  235.       total += f.write( " #{t}" )
  236.     end
  237.     f.puts
  238.     f.puts
  239.  
  240.     unless @prectab.empty? then
  241.       f.puts 'preclow'
  242.       @prectab.each do |type, toks|
  243.         f.printf "  %-8s %s\n", type, toks.join(' ') unless toks.empty?
  244.       end
  245.       f.puts 'prechigh'
  246.       f.puts
  247.     end
  248.  
  249.     if @start then
  250.       f.puts "start #{@start}"
  251.       f.puts
  252.     end
  253.  
  254.     f.puts 'rule'
  255.     @text.each {|t| f.print t }
  256.     f.puts
  257.     f.puts 'end'
  258.  
  259.     if not $OPT_H and @header then
  260.       f.puts
  261.       f.puts '---- header'
  262.       f.puts @header
  263.     end
  264.     if not $OPT_u and @footer then
  265.       f.puts
  266.       f.puts '---- footer'
  267.       f.puts @footer
  268.     end
  269.   end
  270.  
  271. end
  272.  
  273.  
  274. def usage( stat = 1 )
  275.   if stat != 0 then
  276.     $stderr.puts "#{File.basename $0}: wrong option"
  277.   end
  278.   $stderr.print <<MSG
  279.  
  280. y2racc version #{Y::Version}
  281.  
  282. usage:
  283.  
  284.     y2racc [-AC] [-c classname] [-o outfile] yaccfile
  285.  
  286.     -o <file>    name of output file  [r.<inputfile>]
  287.     -c <name>    name of parser class [MyParser]
  288.     -u           output also user code (%%....)
  289.     -H           cut off header (%{....%})
  290.     -A           cut off actions
  291.     -U           cut off user code (%%....) (default)
  292.  
  293. MSG
  294.   exit stat
  295. end
  296.  
  297.  
  298. unless getopts( 'uAHU', 'c:', 'o:', 'version', 'copyright', 'help' ) then
  299.   usage 1
  300. end
  301. if $OPT_U then
  302.   $OPT_u = false
  303. end
  304. if $OPT_version then
  305.   $stderr.puts "y2racc version #{Y::Version}"
  306.   exit 0
  307. end
  308. if $OPT_help then
  309.   usage 0
  310. end
  311. if $OPT_copyright then
  312.   $stderr.puts 'Copyright (c) 2000 Minero Aoki <aamine@dp.u-netsurf.ne.jp>'
  313.   exit 0
  314. end
  315. unless ARGV.size == 1 then
  316.   usage 1
  317. end
  318.  
  319.  
  320. cname = $OPT_c || 'MyParser'
  321. fname = ARGV[0]
  322. outf = $OPT_o || 'r.' + fname
  323.  
  324. y = Y.new( cname )
  325. begin
  326.   File.open( fname ) do |f|
  327.     y.parse f, fname
  328.   end
  329. rescue Errno::ENOENT
  330.   $stderr.puts "no such file: #{fname}"
  331.   exit 1
  332. end
  333. File.open( outf, 'w' ) do |f|
  334.   y.output f
  335. end
  336.