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 =
'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"