Module: Racc

Defined in:
lib/racc/info.rb,
lib/racc/iset.rb,
lib/racc/state.rb,
lib/racc/parser.rb,
lib/racc/parser.rb,
lib/racc/grammar.rb,
lib/racc/exception.rb,
lib/racc/debugflags.rb,
lib/racc/sourcetext.rb,
lib/racc/parser-text.rb,
lib/racc/logfilegenerator.rb,
lib/racc/grammarfileparser.rb,
lib/racc/parserfilegenerator.rb,
lib/racc/statetransitiontable.rb,
cparse/cparse.c

Overview

Copyright © 1999-2006 Minero Aoki

This program is free software. You can distribute/modify this program under the same terms of ruby. see the file “COPYING”.

++

Defined Under Namespace

Classes: Accept, ActionTable, CompileError, CparseParams, DebugFlags, Error, Goto, Grammar, GrammarFileParser, GrammarFileScanner, ISet, Item, LocationPointer, LogFileGenerator, OrMark, ParseError, Parser, ParserClassGenerator, ParserFileGenerator, Prec, RRconflict, Reduce, Rule, SRconflict, Shift, SourceText, State, StateTransitionTable, StateTransitionTableGenerator, States, Sym, SymbolTable, UserAction

Constant Summary collapse

VERSION =
'1.6.2'
Version =
VERSION
'Copyright (c) 1999-2006 Minero Aoki'
Racc_No_Extensions =

:nodoc:

false
PARSER_TEXT =
"# frozen_string_literal: false\n#--\n# Copyright (c) 1999-2006 Minero Aoki\n#\n# This program is free software.\n# You can distribute/modify this program under the same terms of ruby.\n#\n# As a special exception, when this code is copied by Racc\n# into a Racc output file, you may use that output file\n# without restriction.\n#++\n\nrequire 'racc/info'\n\nunless defined?(NotImplementedError)\n  NotImplementedError = NotImplementError # :nodoc:\nend\n\nmodule Racc\n  class ParseError < StandardError; end\nend\nunless defined?(::ParseError)\n  ParseError = Racc::ParseError # :nodoc:\nend\n\n# Racc is a LALR(1) parser generator.\n# It is written in Ruby itself, and generates Ruby programs.\n#\n# == Command-line Reference\n#\n#     racc [-o<var>filename</var>] [--output-file=<var>filename</var>]\n#          [-e<var>rubypath</var>] [--executable=<var>rubypath</var>]\n#          [-v] [--verbose]\n#          [-O<var>filename</var>] [--log-file=<var>filename</var>]\n#          [-g] [--debug]\n#          [-E] [--embedded]\n#          [-l] [--no-line-convert]\n#          [-c] [--line-convert-all]\n#          [-a] [--no-omit-actions]\n#          [-C] [--check-only]\n#          [-S] [--output-status]\n#          [--version] [--copyright] [--help] <var>grammarfile</var>\n#\n# [+grammarfile+]\n#   Racc grammar file. Any extension is permitted.\n# [-o+outfile+, --output-file=+outfile+]\n#   A filename for output. default is <+filename+>.tab.rb\n# [-O+filename+, --log-file=+filename+]\n#   Place logging output in file +filename+.\n#   Default log file name is <+filename+>.output.\n# [-e+rubypath+, --executable=+rubypath+]\n#   output executable file(mode 755). where +path+ is the Ruby interpreter.\n# [-v, --verbose]\n#   verbose mode. create +filename+.output file, like yacc's y.output file.\n# [-g, --debug]\n#   add debug code to parser class. To display debuggin information,\n#   use this '-g' option and set @yydebug true in parser class.\n# [-E, --embedded]\n#   Output parser which doesn't need runtime files (racc/parser.rb).\n# [-C, --check-only]\n#   Check syntax of racc grammar file and quit.\n# [-S, --output-status]\n#   Print messages time to time while compiling.\n# [-l, --no-line-convert]\n#   turns off line number converting.\n# [-c, --line-convert-all]\n#   Convert line number of actions, inner, header and footer.\n# [-a, --no-omit-actions]\n#   Call all actions, even if an action is empty.\n# [--version]\n#   print Racc version and quit.\n# [--copyright]\n#   Print copyright and quit.\n# [--help]\n#   Print usage and quit.\n#\n# == Generating Parser Using Racc\n#\n# To compile Racc grammar file, simply type:\n#\n#   $ racc parse.y\n#\n# This creates Ruby script file \"parse.tab.y\". The -o option can change the output filename.\n#\n# == Writing A Racc Grammar File\n#\n# If you want your own parser, you have to write a grammar file.\n# A grammar file contains the name of your parser class, grammar for the parser,\n# user code, and anything else.\n# When writing a grammar file, yacc's knowledge is helpful.\n# If you have not used yacc before, Racc is not too difficult.\n#\n# Here's an example Racc grammar file.\n#\n#   class Calcparser\n#   rule\n#     target: exp { print val[0] }\n#\n#     exp: exp '+' exp\n#        | exp '*' exp\n#        | '(' exp ')'\n#        | NUMBER\n#   end\n#\n# Racc grammar files resemble yacc files.\n# But (of course), this is Ruby code.\n# yacc's $$ is the 'result', $0, $1... is\n# an array called 'val', and $-1, $-2... is an array called '_values'.\n#\n# See the {Grammar File Reference}[rdoc-ref:lib/racc/rdoc/grammar.en.rdoc] for\n# more information on grammar files.\n#\n# == Parser\n#\n# Then you must prepare the parse entry method. There are two types of\n# parse methods in Racc, Racc::Parser#do_parse and Racc::Parser#yyparse\n#\n# Racc::Parser#do_parse is simple.\n#\n# It's yyparse() of yacc, and Racc::Parser#next_token is yylex().\n# This method must returns an array like [TOKENSYMBOL, ITS_VALUE].\n# EOF is [false, false].\n# (TOKENSYMBOL is a Ruby symbol (taken from String#intern) by default.\n# If you want to change this, see the grammar reference.\n#\n# Racc::Parser#yyparse is little complicated, but useful.\n# It does not use Racc::Parser#next_token, instead it gets tokens from any iterator.\n#\n# For example, <code>yyparse(obj, :scan)</code> causes\n# calling +obj#scan+, and you can return tokens by yielding them from +obj#scan+.\n#\n# == Debugging\n#\n# When debugging, \"-v\" or/and the \"-g\" option is helpful.\n#\n# \"-v\" creates verbose log file (.output).\n# \"-g\" creates a \"Verbose Parser\".\n# Verbose Parser prints the internal status when parsing.\n# But it's _not_ automatic.\n# You must use -g option and set +@yydebug+ to +true+ in order to get output.\n# -g option only creates the verbose parser.\n#\n# === Racc reported syntax error.\n#\n# Isn't there too many \"end\"?\n# grammar of racc file is changed in v0.10.\n#\n# Racc does not use '%' mark, while yacc uses huge number of '%' marks..\n#\n# === Racc reported \"XXXX conflicts\".\n#\n# Try \"racc -v xxxx.y\".\n# It causes producing racc's internal log file, xxxx.output.\n#\n# === Generated parsers does not work correctly\n#\n# Try \"racc -g xxxx.y\".\n# This command let racc generate \"debugging parser\".\n# Then set @yydebug=true in your parser.\n# It produces a working log of your parser.\n#\n# == Re-distributing Racc runtime\n#\n# A parser, which is created by Racc, requires the Racc runtime module;\n# racc/parser.rb.\n#\n# Ruby 1.8.x comes with Racc runtime module,\n# you need NOT distribute Racc runtime files.\n#\n# If you want to include the Racc runtime module with your parser.\n# This can be done by using '-E' option:\n#\n#   $ racc -E -omyparser.rb myparser.y\n#\n# This command creates myparser.rb which `includes' Racc runtime.\n# Only you must do is to distribute your parser file (myparser.rb).\n#\n# Note: parser.rb is ruby license, but your parser is not.\n# Your own parser is completely yours.\nmodule Racc\n\n  unless defined?(Racc_No_Extensions)\n    Racc_No_Extensions = false # :nodoc:\n  end\n\n  class Parser\n\n    Racc_Runtime_Version = ::Racc::VERSION\n    Racc_Runtime_Core_Version_R = ::Racc::VERSION\n\n    begin\n      if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == 'jruby'\n        require 'jruby'\n        require 'racc/cparse-jruby.jar'\n        com.headius.racc.Cparse.new.load(JRuby.runtime, false)\n      else\n        require 'racc/cparse'\n      end\n\n      unless new.respond_to?(:_racc_do_parse_c, true)\n        raise LoadError, 'old cparse.so'\n      end\n      if Racc_No_Extensions\n        raise LoadError, 'selecting ruby version of racc runtime core'\n      end\n\n      Racc_Main_Parsing_Routine    = :_racc_do_parse_c # :nodoc:\n      Racc_YY_Parse_Method         = :_racc_yyparse_c # :nodoc:\n      Racc_Runtime_Core_Version    = Racc_Runtime_Core_Version_C # :nodoc:\n      Racc_Runtime_Type            = 'c' # :nodoc:\n    rescue LoadError\n      Racc_Main_Parsing_Routine    = :_racc_do_parse_rb\n      Racc_YY_Parse_Method         = :_racc_yyparse_rb\n      Racc_Runtime_Core_Version    = Racc_Runtime_Core_Version_R\n      Racc_Runtime_Type            = 'ruby'\n    end\n\n    def Parser.racc_runtime_type # :nodoc:\n      Racc_Runtime_Type\n    end\n\n    def _racc_setup\n      @yydebug = false unless self.class::Racc_debug_parser\n      @yydebug = false unless defined?(@yydebug)\n      if @yydebug\n        @racc_debug_out = $stderr unless defined?(@racc_debug_out)\n        @racc_debug_out ||= $stderr\n      end\n      arg = self.class::Racc_arg\n      arg[13] = true if arg.size < 14\n      arg\n    end\n\n    def _racc_init_sysvars\n      @racc_state  = [0]\n      @racc_tstack = []\n      @racc_vstack = []\n\n      @racc_t = nil\n      @racc_val = nil\n\n      @racc_read_next = true\n\n      @racc_user_yyerror = false\n      @racc_error_status = 0\n    end\n\n    # The entry point of the parser. This method is used with #next_token.\n    # If Racc wants to get token (and its value), calls next_token.\n    #\n    # Example:\n    #     def parse\n    #       @q = [[1,1],\n    #             [2,2],\n    #             [3,3],\n    #             [false, '$']]\n    #       do_parse\n    #     end\n    #\n    #     def next_token\n    #       @q.shift\n    #     end\n    class_eval %{\n    def do_parse\n      \#{Racc_Main_Parsing_Routine}(_racc_setup(), false)\n    end\n    }\n\n    # The method to fetch next token.\n    # If you use #do_parse method, you must implement #next_token.\n    #\n    # The format of return value is [TOKEN_SYMBOL, VALUE].\n    # +token-symbol+ is represented by Ruby's symbol by default, e.g. :IDENT\n    # for 'IDENT'.  \";\" (String) for ';'.\n    #\n    # The final symbol (End of file) must be false.\n    def next_token\n      raise NotImplementedError, \"\#{self.class}\\#next_token is not defined\"\n    end\n\n    def _racc_do_parse_rb(arg, in_debug)\n      action_table, action_check, action_default, action_pointer,\n      _,            _,            _,              _,\n      _,            _,            token_table,    * = arg\n\n      _racc_init_sysvars\n      tok = act = i = nil\n\n      catch(:racc_end_parse) {\n        while true\n          if i = action_pointer[@racc_state[-1]]\n            if @racc_read_next\n              if @racc_t != 0   # not EOF\n                tok, @racc_val = next_token()\n                unless tok      # EOF\n                  @racc_t = 0\n                else\n                  @racc_t = (token_table[tok] or 1)   # error token\n                end\n                racc_read_token(@racc_t, tok, @racc_val) if @yydebug\n                @racc_read_next = false\n              end\n            end\n            i += @racc_t\n            unless i >= 0 and\n                   act = action_table[i] and\n                   action_check[i] == @racc_state[-1]\n              act = action_default[@racc_state[-1]]\n            end\n          else\n            act = action_default[@racc_state[-1]]\n          end\n          while act = _racc_evalact(act, arg)\n            ;\n          end\n        end\n      }\n    end\n\n    # Another entry point for the parser.\n    # If you use this method, you must implement RECEIVER#METHOD_ID method.\n    #\n    # RECEIVER#METHOD_ID is a method to get next token.\n    # It must 'yield' the token, which format is [TOKEN-SYMBOL, VALUE].\n    class_eval %{\n    def yyparse(recv, mid)\n      \#{Racc_YY_Parse_Method}(recv, mid, _racc_setup(), false)\n    end\n    }\n\n    def _racc_yyparse_rb(recv, mid, arg, c_debug)\n      action_table, action_check, action_default, action_pointer,\n      _,            _,            _,              _,\n      _,            _,            token_table,    * = arg\n\n      _racc_init_sysvars\n\n      catch(:racc_end_parse) {\n        until i = action_pointer[@racc_state[-1]]\n          while act = _racc_evalact(action_default[@racc_state[-1]], arg)\n            ;\n          end\n        end\n        recv.__send__(mid) do |tok, val|\n          unless tok\n            @racc_t = 0\n          else\n            @racc_t = (token_table[tok] or 1)   # error token\n          end\n          @racc_val = val\n          @racc_read_next = false\n\n          i += @racc_t\n          unless i >= 0 and\n                 act = action_table[i] and\n                 action_check[i] == @racc_state[-1]\n            act = action_default[@racc_state[-1]]\n          end\n          while act = _racc_evalact(act, arg)\n            ;\n          end\n\n          while !(i = action_pointer[@racc_state[-1]]) ||\n                ! @racc_read_next ||\n                @racc_t == 0  # $\n            unless i and i += @racc_t and\n                   i >= 0 and\n                   act = action_table[i] and\n                   action_check[i] == @racc_state[-1]\n              act = action_default[@racc_state[-1]]\n            end\n            while act = _racc_evalact(act, arg)\n              ;\n            end\n          end\n        end\n      }\n    end\n\n    ###\n    ### common\n    ###\n\n    def _racc_evalact(act, arg)\n      action_table, action_check, _, action_pointer,\n      _,            _,            _, _,\n      _,            _,            _, shift_n,\n      reduce_n,     * = arg\n      nerr = 0   # tmp\n\n      if act > 0 and act < shift_n\n        #\n        # shift\n        #\n        if @racc_error_status > 0\n          @racc_error_status -= 1 unless @racc_t <= 1 # error token or EOF\n        end\n        @racc_vstack.push @racc_val\n        @racc_state.push act\n        @racc_read_next = true\n        if @yydebug\n          @racc_tstack.push @racc_t\n          racc_shift @racc_t, @racc_tstack, @racc_vstack\n        end\n\n      elsif act < 0 and act > -reduce_n\n        #\n        # reduce\n        #\n        code = catch(:racc_jump) {\n          @racc_state.push _racc_do_reduce(arg, act)\n          false\n        }\n        if code\n          case code\n          when 1 # yyerror\n            @racc_user_yyerror = true   # user_yyerror\n            return -reduce_n\n          when 2 # yyaccept\n            return shift_n\n          else\n            raise '[Racc Bug] unknown jump code'\n          end\n        end\n\n      elsif act == shift_n\n        #\n        # accept\n        #\n        racc_accept if @yydebug\n        throw :racc_end_parse, @racc_vstack[0]\n\n      elsif act == -reduce_n\n        #\n        # error\n        #\n        case @racc_error_status\n        when 0\n          unless arg[21]    # user_yyerror\n            nerr += 1\n            on_error @racc_t, @racc_val, @racc_vstack\n          end\n        when 3\n          if @racc_t == 0   # is $\n            # We're at EOF, and another error occurred immediately after\n            # attempting auto-recovery\n            throw :racc_end_parse, nil\n          end\n          @racc_read_next = true\n        end\n        @racc_user_yyerror = false\n        @racc_error_status = 3\n        while true\n          if i = action_pointer[@racc_state[-1]]\n            i += 1   # error token\n            if  i >= 0 and\n                (act = action_table[i]) and\n                action_check[i] == @racc_state[-1]\n              break\n            end\n          end\n          throw :racc_end_parse, nil if @racc_state.size <= 1\n          @racc_state.pop\n          @racc_vstack.pop\n          if @yydebug\n            @racc_tstack.pop\n            racc_e_pop @racc_state, @racc_tstack, @racc_vstack\n          end\n        end\n        return act\n\n      else\n        raise \"[Racc Bug] unknown action \#{act.inspect}\"\n      end\n\n      racc_next_state(@racc_state[-1], @racc_state) if @yydebug\n\n      nil\n    end\n\n    def _racc_do_reduce(arg, act)\n      _,          _,            _,            _,\n      goto_table, goto_check,   goto_default, goto_pointer,\n      nt_base,    reduce_table, _,            _,\n      _,          use_result,   * = arg\n\n      state = @racc_state\n      vstack = @racc_vstack\n      tstack = @racc_tstack\n\n      i = act * -3\n      len       = reduce_table[i]\n      reduce_to = reduce_table[i+1]\n      method_id = reduce_table[i+2]\n      void_array = []\n\n      tmp_t = tstack[-len, len] if @yydebug\n      tmp_v = vstack[-len, len]\n      tstack[-len, len] = void_array if @yydebug\n      vstack[-len, len] = void_array\n      state[-len, len]  = void_array\n\n      # tstack must be updated AFTER method call\n      if use_result\n        vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0])\n      else\n        vstack.push __send__(method_id, tmp_v, vstack)\n      end\n      tstack.push reduce_to\n\n      racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug\n\n      k1 = reduce_to - nt_base\n      if i = goto_pointer[k1]\n        i += state[-1]\n        if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1\n          return curstate\n        end\n      end\n      goto_default[k1]\n    end\n\n    # This method is called when a parse error is found.\n    #\n    # ERROR_TOKEN_ID is an internal ID of token which caused error.\n    # You can get string representation of this ID by calling\n    # #token_to_str.\n    #\n    # ERROR_VALUE is a value of error token.\n    #\n    # value_stack is a stack of symbol values.\n    # DO NOT MODIFY this object.\n    #\n    # This method raises ParseError by default.\n    #\n    # If this method returns, parsers enter \"error recovering mode\".\n    def on_error(t, val, vstack)\n      raise ParseError, sprintf(\"\\nparse error on value %s (%s)\",\n                                val.inspect, token_to_str(t) || '?')\n    end\n\n    # Enter error recovering mode.\n    # This method does not call #on_error.\n    def yyerror\n      throw :racc_jump, 1\n    end\n\n    # Exit parser.\n    # Return value is +Symbol_Value_Stack[0]+.\n    def yyaccept\n      throw :racc_jump, 2\n    end\n\n    # Leave error recovering mode.\n    def yyerrok\n      @racc_error_status = 0\n    end\n\n    # For debugging output\n    def racc_read_token(t, tok, val)\n      @racc_debug_out.print 'read    '\n      @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') '\n      @racc_debug_out.puts val.inspect\n      @racc_debug_out.puts\n    end\n\n    def racc_shift(tok, tstack, vstack)\n      @racc_debug_out.puts \"shift   \#{racc_token2str tok}\"\n      racc_print_stacks tstack, vstack\n      @racc_debug_out.puts\n    end\n\n    def racc_reduce(toks, sim, tstack, vstack)\n      out = @racc_debug_out\n      out.print 'reduce '\n      if toks.empty?\n        out.print ' <none>'\n      else\n        toks.each {|t| out.print ' ', racc_token2str(t) }\n      end\n      out.puts \" --> \#{racc_token2str(sim)}\"\n      racc_print_stacks tstack, vstack\n      @racc_debug_out.puts\n    end\n\n    def racc_accept\n      @racc_debug_out.puts 'accept'\n      @racc_debug_out.puts\n    end\n\n    def racc_e_pop(state, tstack, vstack)\n      @racc_debug_out.puts 'error recovering mode: pop token'\n      racc_print_states state\n      racc_print_stacks tstack, vstack\n      @racc_debug_out.puts\n    end\n\n    def racc_next_state(curstate, state)\n      @racc_debug_out.puts  \"goto    \#{curstate}\"\n      racc_print_states state\n      @racc_debug_out.puts\n    end\n\n    def racc_print_stacks(t, v)\n      out = @racc_debug_out\n      out.print '        ['\n      t.each_index do |i|\n        out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')'\n      end\n      out.puts ' ]'\n    end\n\n    def racc_print_states(s)\n      out = @racc_debug_out\n      out.print '        ['\n      s.each {|st| out.print ' ', st }\n      out.puts ' ]'\n    end\n\n    def racc_token2str(tok)\n      self.class::Racc_token_to_s_table[tok] or\n          raise \"[Racc Bug] can't convert token \#{tok} to string\"\n    end\n\n    # Convert internal ID of token symbol to the string.\n    def token_to_str(t)\n      self.class::Racc_token_to_s_table[t]\n    end\n\n  end\n\nend\n\n"