diff --git a/Steepfile b/Steepfile index bdc40f48..f731326c 100644 --- a/Steepfile +++ b/Steepfile @@ -7,6 +7,7 @@ target :lib do check "lib/lrama/grammar/code/printer_code.rb" check "lib/lrama/grammar/code.rb" check "lib/lrama/grammar/counter.rb" + check "lib/lrama/grammar/parser_state.rb" check "lib/lrama/grammar/percent_code.rb" check "lib/lrama/grammar/precedence.rb" check "lib/lrama/grammar/printer.rb" @@ -15,6 +16,9 @@ target :lib do check "lib/lrama/lexer/token/char.rb" check "lib/lrama/lexer/token/ident.rb" check "lib/lrama/lexer/token/parameterizing.rb" + check "lib/lrama/lexer/token/parser_state_pop.rb" + check "lib/lrama/lexer/token/parser_state_push.rb" + check "lib/lrama/lexer/token/parser_state_set.rb" check "lib/lrama/lexer/token/tag.rb" check "lib/lrama/lexer/token/user_code.rb" check "lib/lrama/lexer/location.rb" diff --git a/lib/lrama/grammar.rb b/lib/lrama/grammar.rb index 7b1a4034..9b1f652a 100644 --- a/lib/lrama/grammar.rb +++ b/lib/lrama/grammar.rb @@ -2,6 +2,7 @@ require "lrama/grammar/code" require "lrama/grammar/counter" require "lrama/grammar/error_token" +require "lrama/grammar/parser_state" require "lrama/grammar/percent_code" require "lrama/grammar/precedence" require "lrama/grammar/printer" @@ -16,7 +17,7 @@ module Lrama # Grammar is the result of parsing an input grammar file class Grammar - attr_reader :percent_codes, :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux + attr_reader :percent_codes, :parser_states, :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux attr_accessor :union, :expect, :printers, :error_tokens, :lex_param, :parse_param, :initial_action, @@ -31,6 +32,7 @@ def initialize(rule_counter) @percent_codes = [] @printers = [] @error_tokens = [] + @parser_states = [] @symbols = [] @types = [] @rule_builders = [] @@ -58,6 +60,10 @@ def add_error_token(ident_or_tags:, token_code:, lineno:) @error_tokens << ErrorToken.new(ident_or_tags: ident_or_tags, token_code: token_code, lineno: lineno) end + def add_parser_state(state_id, state_list) + @parser_states << ParserState.new(state_id: state_id, state_list: state_list) + end + def add_term(id:, alias_name: nil, tag: nil, token_id: nil, replace: false) if token_id && (sym = @symbols.find {|s| s.token_id == token_id }) if replace @@ -186,7 +192,7 @@ def find_symbol_by_id(id) end def find_symbol_by_id!(id) - find_symbol_by_id(id) || (raise "Symbol not found: #{id}") + find_symbol_by_id(id) || (raise "Symbol not found: #{id.s_value}") end def find_symbol_by_number!(number) diff --git a/lib/lrama/grammar/parser_state.rb b/lib/lrama/grammar/parser_state.rb new file mode 100644 index 00000000..27bab607 --- /dev/null +++ b/lib/lrama/grammar/parser_state.rb @@ -0,0 +1,138 @@ +module Lrama + class Grammar + class ParserState + attr_reader :state_id, :state_list + + def initialize(state_id:, state_list:) + @state_id = state_id + @state_list = state_list + end + + def enum_definition + <<~ENUM + enum #{enum_name} + { + #{enum_body} + }; + typedef enum #{enum_name} #{enum_type}; + + static const char *const #{enum_name_table_name}[] = { + #{int_to_name.join(", ")} + }; + + YY_ATTRIBUTE_UNUSED + static const char * + #{enum_name}_name (#{enum_type} num) + { + return #{enum_name_table_name}[num]; + } + + # define #{state_name_macro}(value) #{enum_name}_name (value) + # define #{current_state_name_macro} #{state_name_macro} (*#{stack_prefix}_p) + ENUM + end + + def state_name_macro + "YY_STATE_#{state_name.upcase}_NAME" + end + + def current_state_name_macro + "YY_CURRENT_STATE_#{state_name.upcase}_NAME" + end + + def states_functions + <<~FUNC + # define YYPUSH_STATE_#{state_name.upcase}(value) \\ + do \\ + { \\ + if (#{stack_prefix} + #{states_stack_size_name} - 1 <= #{stack_prefix}_p) \\ + YYSTATE_STACK_INCREASE (#{stack_prefix}_a, #{stack_prefix}, #{stack_prefix}_p, #{states_stack_size_name}, "#{state_name}"); \\ + YYDPRINTF ((stderr, "Push %s to #{state_name}\\n", #{state_name_macro} (value))); \\ + *++#{stack_prefix}_p = value; \\ + } \\ + while (0) + + # define YYPOP_STATE_#{state_name.upcase}() \\ + do \\ + { \\ + YYDPRINTF ((stderr, "Pop #{state_name}\\n")); \\ + if (#{stack_prefix}_p != #{stack_prefix}) \\ + { \\ + #{stack_prefix}_p -= 1; \\ + } \\ + else \\ + { \\ + YYDPRINTF ((stderr, "Try to pop empty #{state_name} stack\\n")); \\ + } \\ + } \\ + while (0) + + # define YYSET_STATE_#{state_name.upcase}(value) \\ + do \\ + { \\ + YYDPRINTF ((stderr, "Set %s to #{state_name}\\n", #{state_name_macro} (value))); \\ + *#{stack_prefix}_p = value; \\ + } \\ + while (0) + + # define YY_STATE_#{state_name.upcase} #{stack_prefix}_p + FUNC + end + + def states_clean_up_stack + <<~CODE + if (#{stack_prefix} != #{stack_prefix}_a) + YYSTACK_FREE (#{stack_prefix}); + CODE + end + + def states_stack_size_name + "#{stack_prefix}_stacksize" + end + + def states_stacks + <<~STACKS + /* Current size of state stack size */ + YYPTRDIFF_T #{states_stack_size_name} = YYINITDEPTH; + + /* The parser state stack (#{stack_prefix}): array, bottom, top. */ + int #{stack_prefix}_a[YYINITDEPTH]; + int *#{stack_prefix} = #{stack_prefix}_a; + int *#{stack_prefix}_p = #{stack_prefix}; + STACKS + end + + def state_name + state_id.s_value + end + + def enum_name + "yyparser_state_#{state_name}" + end + + def enum_type + "#{enum_name}_t" + end + + def enum_body + state_list.map do |state| + state.s_value + end.join(",\n ") + end + + def int_to_name + state_list.map do |state| + "\"#{state.s_value}\"" + end << "YY_NULLPTR" + end + + def enum_name_table_name + "#{enum_name}_names" + end + + def stack_prefix + "yyparser_state_#{state_name}" + end + end + end +end diff --git a/lib/lrama/grammar/rule_builder.rb b/lib/lrama/grammar/rule_builder.rb index 7a2cf752..c074c635 100644 --- a/lib/lrama/grammar/rule_builder.rb +++ b/lib/lrama/grammar/rule_builder.rb @@ -114,6 +114,12 @@ def process_rhs @parameterizing_rules << r end @replaced_rhs << parameterizing.build_token + when Lrama::Lexer::Token::ParserStatePop + process_parser_state_token(token, "parser_state_pop_", "YYPOP_STATE_#{token.s_value.upcase}();", i) + when Lrama::Lexer::Token::ParserStatePush + process_parser_state_token(token, "parser_state_push_", "YYPUSH_STATE_#{token.s_value.upcase}(#{token.state.s_value});", i) + when Lrama::Lexer::Token::ParserStateSet + process_parser_state_token(token, "parser_state_set_", "YYSET_STATE_#{token.s_value.upcase}(#{token.state.s_value});", i) when Lrama::Lexer::Token::UserCode prefix = token.referred ? "@" : "$@" new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + @midrule_action_counter.increment.to_s) @@ -132,6 +138,20 @@ def process_rhs end end + def process_parser_state_token(token, prefix, code, position_in_original_rule_rhs) + new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + token.s_value + @midrule_action_counter.increment.to_s) + user_code = Lrama::Lexer::Token::UserCode.new(s_value: code, location: token.location) + + @replaced_rhs << new_token + rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, position_in_original_rule_rhs, skip_preprocess_references: true) + rule_builder.lhs = new_token + rule_builder.user_code = user_code + rule_builder.complete_input + rule_builder.setup_rules + + @rule_builders_for_derived_rules << rule_builder + end + def numberize_references # Bison n'th component is 1-origin (rhs + [user_code]).compact.each.with_index(1) do |token, i| diff --git a/lib/lrama/lexer.rb b/lib/lrama/lexer.rb index 18d702a4..8f56683d 100644 --- a/lib/lrama/lexer.rb +++ b/lib/lrama/lexer.rb @@ -28,6 +28,10 @@ class Lexer %error-token %empty %code + %parser-state-push + %parser-state-pop + %parser-state-set + %parser-state ) def initialize(text) diff --git a/lib/lrama/lexer/token.rb b/lib/lrama/lexer/token.rb index b82f86bb..f7ba4597 100644 --- a/lib/lrama/lexer/token.rb +++ b/lib/lrama/lexer/token.rb @@ -1,6 +1,9 @@ require 'lrama/lexer/token/char' require 'lrama/lexer/token/ident' require 'lrama/lexer/token/parameterizing' +require 'lrama/lexer/token/parser_state_pop' +require 'lrama/lexer/token/parser_state_push' +require 'lrama/lexer/token/parser_state_set' require 'lrama/lexer/token/tag' require 'lrama/lexer/token/user_code' diff --git a/lib/lrama/lexer/token/parser_state_pop.rb b/lib/lrama/lexer/token/parser_state_pop.rb new file mode 100644 index 00000000..ac2c020b --- /dev/null +++ b/lib/lrama/lexer/token/parser_state_pop.rb @@ -0,0 +1,8 @@ +module Lrama + class Lexer + class Token + class ParserStatePop < Token + end + end + end +end diff --git a/lib/lrama/lexer/token/parser_state_push.rb b/lib/lrama/lexer/token/parser_state_push.rb new file mode 100644 index 00000000..a665d884 --- /dev/null +++ b/lib/lrama/lexer/token/parser_state_push.rb @@ -0,0 +1,9 @@ +module Lrama + class Lexer + class Token + class ParserStatePush < Token + attr_accessor :state + end + end + end +end diff --git a/lib/lrama/lexer/token/parser_state_set.rb b/lib/lrama/lexer/token/parser_state_set.rb new file mode 100644 index 00000000..f31271b4 --- /dev/null +++ b/lib/lrama/lexer/token/parser_state_set.rb @@ -0,0 +1,9 @@ +module Lrama + class Lexer + class Token + class ParserStateSet < Token + attr_accessor :state + end + end + end +end diff --git a/lib/lrama/output.rb b/lib/lrama/output.rb index f6720850..4fd82508 100644 --- a/lib/lrama/output.rb +++ b/lib/lrama/output.rb @@ -358,6 +358,34 @@ def percent_code(name) end.join end + def has_parser_states? + !@grammar.parser_states.empty? + end + + def parser_states_enums + @grammar.parser_states.map do |ps| + ps.enum_definition + end + end + + def parser_states_stacks + @grammar.parser_states.map do |ps| + ps.states_stacks + end + end + + def parser_states_functions + @grammar.parser_states.map do |ps| + ps.states_functions + end + end + + def parser_states_clean_up_stack + @grammar.parser_states.map do |ps| + ps.states_clean_up_stack + end + end + private def eval_template(file, path) diff --git a/lib/lrama/parser.rb b/lib/lrama/parser.rb index 3737e062..606e88d2 100644 --- a/lib/lrama/parser.rb +++ b/lib/lrama/parser.rb @@ -658,7 +658,7 @@ def token_to_str(t) module Lrama class Parser < Racc::Parser -module_eval(<<'...end parser.y/module_eval...', 'parser.y', 413) +module_eval(<<'...end parser.y/module_eval...', 'parser.y', 446) include Lrama::Report::Duration @@ -749,257 +749,281 @@ def carrets(first_column, last_column) ##### State transition tables begin ### racc_action_table = [ - 82, 42, 83, 137, 42, 65, 137, 38, 65, 136, - 42, 6, 41, 7, 42, 56, 41, 139, 65, 61, - 139, 135, 42, 42, 41, 41, 20, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 140, 38, 3, 140, - 84, 42, 77, 41, 8, 42, 68, 41, 170, 42, - 68, 41, 32, 171, 68, 39, 20, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 9, 42, 45, 41, - 12, 13, 14, 15, 16, 17, 45, 45, 18, 19, - 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 42, 48, 41, 151, 49, 68, 152, 153, 154, 42, - 42, 41, 41, 65, 163, 42, 42, 41, 41, 65, - 163, 42, 42, 41, 41, 65, 163, 42, 42, 41, - 41, 65, 163, 42, 42, 41, 41, 65, 163, 42, - 42, 41, 41, 65, 163, 42, 42, 41, 41, 65, - 65, 42, 42, 41, 41, 65, 65, 42, 42, 41, - 41, 65, 65, 42, 42, 41, 41, 65, 65, 42, - 42, 41, 41, 50, 51, 52, 53, 74, 78, 80, - 85, 85, 85, 87, 93, 97, 98, 101, 101, 101, - 101, 106, 107, 109, 111, 112, 113, 114, 115, 118, - 121, 122, 125, 126, 127, 129, 142, 144, 145, 146, - 147, 148, 125, 80, 158, 159, 168, 174, 80 ] + 84, 43, 85, 145, 39, 67, 43, 188, 145, 144, + 67, 43, 6, 42, 7, 3, 58, 147, 43, 8, + 42, 143, 147, 70, 189, 33, 21, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 163, 148, 149, 40, + 150, 151, 148, 149, 86, 150, 151, 39, 43, 43, + 42, 42, 79, 67, 63, 46, 46, 164, 165, 166, + 43, 43, 42, 42, 46, 70, 70, 49, 50, 21, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 9, + 43, 51, 42, 12, 13, 14, 15, 16, 17, 52, + 53, 18, 19, 54, 55, 20, 21, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 43, 43, 42, 42, + 43, 70, 42, 76, 67, 178, 43, 43, 42, 42, + 67, 178, 43, 43, 42, 42, 67, 178, 43, 43, + 42, 42, 67, 178, 43, 43, 42, 42, 67, 178, + 43, 43, 42, 42, 67, 178, 43, 43, 42, 42, + 67, 67, 43, 43, 42, 42, 67, 67, 43, 43, + 42, 42, 67, 67, 43, 43, 42, 42, 67, 67, + 43, 43, 42, 42, 43, 80, 42, 82, 87, 87, + 87, 89, 91, 96, 100, 101, 104, 104, 104, 104, + 109, 110, 112, 114, 117, 118, 119, 120, 121, 124, + 127, 128, 131, 132, 133, 135, 137, 138, 153, 155, + 156, 157, 158, 159, 160, 131, 82, 170, 171, 172, + 173, 174, 183, 184, 185, 186, 191, 192, 193, 195, + 196, 197, 82, 199, 200 ] racc_action_check = [ - 40, 124, 40, 124, 149, 124, 149, 9, 149, 123, - 25, 2, 25, 2, 26, 25, 26, 124, 26, 26, - 149, 123, 13, 55, 13, 55, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 124, 33, 1, 149, - 40, 27, 33, 27, 3, 28, 27, 28, 166, 29, - 28, 29, 7, 166, 29, 12, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 4, 56, 14, 56, - 4, 4, 4, 4, 4, 4, 15, 16, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 30, 17, 30, 137, 18, 30, 137, 137, 137, 146, - 67, 146, 67, 146, 146, 147, 68, 147, 68, 147, - 147, 148, 93, 148, 93, 148, 148, 160, 95, 160, - 95, 160, 160, 164, 101, 164, 101, 164, 164, 165, - 103, 165, 103, 165, 165, 60, 61, 60, 61, 60, - 61, 98, 100, 98, 100, 98, 100, 119, 140, 119, - 140, 119, 140, 151, 171, 151, 171, 151, 171, 116, - 120, 116, 120, 20, 22, 23, 24, 31, 36, 37, - 44, 46, 47, 48, 54, 58, 59, 66, 71, 72, - 73, 79, 80, 86, 88, 89, 90, 91, 92, 96, - 104, 105, 106, 107, 108, 110, 128, 130, 131, 132, - 133, 134, 135, 138, 141, 143, 156, 172, 174 ] + 41, 130, 41, 130, 9, 130, 161, 181, 161, 129, + 161, 26, 2, 26, 2, 1, 26, 130, 28, 3, + 28, 129, 161, 28, 181, 7, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 145, 130, 130, 12, + 130, 130, 161, 161, 41, 161, 161, 34, 13, 27, + 13, 27, 34, 27, 27, 14, 15, 145, 145, 145, + 29, 30, 29, 30, 16, 29, 30, 17, 18, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 4, + 57, 19, 57, 4, 4, 4, 4, 4, 4, 21, + 23, 4, 4, 24, 25, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 31, 58, 31, 58, + 158, 31, 158, 32, 158, 158, 159, 69, 159, 69, + 159, 159, 160, 70, 160, 70, 160, 160, 175, 96, + 175, 96, 175, 175, 179, 98, 179, 98, 179, 179, + 180, 104, 180, 104, 180, 180, 62, 63, 62, 63, + 62, 63, 101, 103, 101, 103, 101, 103, 125, 148, + 125, 148, 125, 148, 163, 189, 163, 189, 163, 189, + 106, 122, 106, 122, 126, 37, 126, 38, 45, 47, + 48, 49, 51, 56, 60, 61, 68, 73, 74, 75, + 81, 82, 88, 90, 91, 92, 93, 94, 95, 99, + 107, 108, 109, 110, 111, 113, 115, 116, 134, 136, + 138, 139, 140, 141, 142, 143, 146, 149, 150, 151, + 152, 154, 168, 170, 171, 172, 184, 185, 186, 190, + 191, 193, 195, 196, 197 ] racc_action_pointer = [ - nil, 38, 1, 44, 57, nil, nil, 45, nil, 3, - nil, nil, 49, 19, 49, 57, 58, 86, 75, nil, - 144, nil, 145, 146, 147, 7, 11, 38, 42, 46, - 87, 165, nil, 33, nil, nil, 146, 126, nil, nil, - -5, nil, nil, nil, 151, nil, 152, 153, 154, nil, - nil, nil, nil, nil, 166, 20, 64, nil, 169, 168, - 132, 133, nil, nil, nil, nil, 169, 97, 103, nil, - nil, 170, 171, 172, nil, nil, nil, nil, nil, 148, - 177, nil, nil, nil, nil, nil, 181, nil, 182, 183, - 184, 185, 186, 109, nil, 115, 182, nil, 138, nil, - 139, 121, nil, 127, 179, 189, 157, 149, 192, nil, - 193, nil, nil, nil, nil, nil, 156, nil, nil, 144, - 157, nil, nil, -13, -2, nil, nil, nil, 176, nil, - 177, 178, 179, 180, 181, 167, nil, 57, 160, nil, - 145, 184, nil, 185, nil, nil, 96, 102, 108, 1, - nil, 150, nil, nil, nil, nil, 204, nil, nil, nil, - 114, nil, nil, nil, 120, 126, 11, nil, nil, nil, - nil, 151, 187, nil, 165, nil ] + nil, 15, 2, 19, 70, nil, nil, 18, nil, 0, + nil, nil, 33, 45, 36, 37, 45, 62, 49, 76, + nil, 70, nil, 71, 74, 75, 8, 46, 15, 57, + 58, 103, 111, nil, 43, nil, nil, 150, 130, nil, + nil, -5, nil, nil, nil, 159, nil, 160, 161, 162, + nil, 159, nil, nil, nil, nil, 175, 77, 104, nil, + 178, 177, 143, 144, nil, nil, nil, nil, 178, 114, + 120, nil, nil, 179, 180, 181, nil, nil, nil, nil, + nil, 154, 186, nil, nil, nil, nil, nil, 190, nil, + 191, 189, 193, 194, 195, 196, 126, nil, 132, 192, + nil, 149, nil, 150, 138, nil, 167, 189, 199, 164, + 155, 202, nil, 203, nil, 182, 166, nil, nil, nil, + nil, nil, 168, nil, nil, 155, 171, nil, nil, -16, + -2, nil, nil, nil, 188, nil, 189, nil, 205, 191, + 192, 193, 194, 177, nil, 13, 169, nil, 156, 194, + 195, 196, 200, nil, 201, nil, nil, nil, 107, 113, + 119, 3, nil, 161, nil, nil, nil, nil, 220, nil, + 218, 219, 220, nil, nil, 125, nil, nil, nil, 131, + 137, -17, nil, nil, 185, 203, 187, nil, nil, 162, + 209, 225, nil, 226, nil, 185, 209, 210, nil, nil, + nil ] racc_action_default = [ - -2, -111, -8, -111, -111, -3, -4, -111, 176, -111, - -9, -10, -111, -111, -111, -111, -111, -111, -111, -22, - -111, -26, -111, -111, -111, -111, -111, -111, -111, -111, - -111, -111, -7, -98, -73, -75, -111, -95, -97, -11, - -102, -71, -72, -101, -13, -62, -14, -15, -111, -19, - -23, -27, -30, -33, -36, -42, -111, -45, -48, -37, - -52, -111, -55, -57, -58, -110, -38, -65, -111, -68, - -70, -39, -40, -41, -5, -1, -74, -99, -76, -111, - -111, -12, -103, -104, -105, -59, -111, -16, -111, -111, - -111, -111, -111, -111, -46, -43, -50, -49, -111, -56, - -53, -111, -69, -66, -111, -111, -81, -111, -111, -63, - -111, -20, -24, -28, -31, -34, -44, -47, -51, -54, - -67, -6, -100, -77, -78, -82, -96, -60, -111, -17, - -111, -111, -111, -111, -111, -81, -80, -71, -95, -86, - -111, -111, -64, -111, -21, -25, -111, -111, -111, -79, - -84, -111, -90, -91, -92, -83, -111, -89, -61, -18, - -29, -106, -108, -109, -32, -35, -111, -93, -87, -107, - -85, -111, -111, -94, -95, -88 ] + -2, -119, -8, -119, -119, -3, -4, -119, 201, -119, + -9, -10, -119, -119, -119, -119, -119, -119, -119, -119, + -23, -119, -27, -119, -119, -119, -119, -119, -119, -119, + -119, -119, -119, -7, -102, -74, -76, -119, -99, -101, + -11, -106, -72, -73, -105, -13, -63, -14, -15, -119, + -19, -119, -24, -28, -31, -34, -37, -43, -119, -46, + -49, -38, -53, -119, -56, -58, -59, -118, -39, -66, + -119, -69, -71, -40, -41, -42, -5, -1, -75, -103, + -77, -119, -119, -12, -107, -108, -109, -60, -119, -16, + -119, -114, -119, -119, -119, -119, -119, -47, -44, -51, + -50, -119, -57, -54, -119, -70, -67, -119, -119, -82, + -119, -119, -64, -119, -20, -119, -115, -116, -25, -29, + -32, -35, -45, -48, -52, -55, -68, -6, -104, -78, + -79, -83, -100, -61, -119, -17, -119, -22, -119, -119, + -119, -119, -119, -82, -81, -72, -99, -87, -119, -119, + -119, -119, -119, -65, -119, -21, -117, -26, -119, -119, + -119, -80, -85, -119, -94, -95, -96, -84, -119, -90, + -119, -119, -119, -62, -18, -30, -110, -112, -113, -33, + -36, -119, -97, -88, -119, -119, -119, -111, -86, -119, + -119, -119, -92, -119, -98, -99, -119, -119, -89, -91, + -93 ] racc_goto_table = [ - 62, 79, 43, 60, 103, 55, 94, 102, 34, 1, - 124, 44, 46, 47, 58, 2, 70, 70, 70, 70, - 169, 160, 164, 165, 169, 169, 66, 71, 72, 73, - 4, 33, 76, 75, 99, 62, 95, 120, 100, 149, - 5, 31, 104, 102, 58, 58, 94, 10, 11, 40, - 81, 110, 143, 88, 130, 89, 70, 70, 131, 90, - 102, 132, 91, 133, 92, 134, 54, 94, 59, 96, - 117, 108, 62, 116, 99, 119, 141, 86, 128, 123, - 150, 166, 58, 156, 58, 172, 105, nil, nil, nil, - 70, nil, 70, 99, nil, nil, nil, nil, 138, nil, - nil, nil, 155, nil, nil, 58, nil, nil, nil, 70, - nil, nil, nil, nil, 157, nil, nil, nil, nil, nil, - nil, nil, nil, 138, nil, 167, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, 175, nil, - nil, nil, nil, nil, nil, 173 ] + 64, 81, 44, 62, 97, 57, 105, 106, 130, 35, + 68, 73, 74, 75, 1, 60, 2, 72, 72, 72, + 72, 187, 45, 47, 48, 187, 187, 175, 179, 180, + 4, 34, 77, 5, 78, 102, 64, 98, 32, 103, + 107, 126, 161, 105, 10, 97, 60, 60, 11, 41, + 83, 115, 113, 154, 90, 136, 92, 139, 72, 72, + 93, 140, 94, 105, 141, 95, 142, 56, 61, 97, + 99, 123, 111, 152, 64, 122, 102, 125, 88, 134, + 129, 162, 181, 168, 190, 60, 108, 60, 116, nil, + nil, nil, nil, 72, nil, 72, nil, nil, 102, nil, + nil, nil, nil, 146, nil, nil, nil, nil, nil, 167, + nil, 60, nil, nil, nil, 72, nil, nil, nil, nil, + nil, 169, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 146, nil, 182, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, 198, nil, + nil, nil, 194 ] racc_goto_check = [ - 37, 48, 33, 36, 43, 31, 32, 44, 45, 1, - 50, 13, 13, 13, 33, 2, 33, 33, 33, 33, - 56, 19, 19, 19, 56, 56, 30, 30, 30, 30, - 3, 4, 45, 5, 37, 37, 31, 43, 36, 50, - 6, 7, 8, 44, 33, 33, 32, 9, 10, 11, - 12, 14, 15, 16, 17, 20, 33, 33, 21, 22, - 44, 23, 24, 25, 26, 27, 28, 32, 29, 34, - 35, 39, 37, 31, 37, 36, 40, 41, 42, 49, - 51, 52, 33, 53, 33, 54, 55, nil, nil, nil, - 33, nil, 33, 37, nil, nil, nil, nil, 37, nil, - nil, nil, 48, nil, nil, 33, nil, nil, nil, 33, - nil, nil, nil, nil, 37, nil, nil, nil, nil, nil, - nil, nil, nil, 37, nil, 37, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, 48, nil, - nil, nil, nil, nil, nil, 37 ] + 38, 49, 34, 37, 33, 32, 45, 44, 51, 46, + 31, 31, 31, 31, 1, 34, 2, 34, 34, 34, + 34, 57, 13, 13, 13, 57, 57, 20, 20, 20, + 3, 4, 5, 6, 46, 38, 38, 32, 7, 37, + 8, 44, 51, 45, 9, 33, 34, 34, 10, 11, + 12, 14, 15, 16, 17, 18, 21, 22, 34, 34, + 23, 24, 25, 45, 26, 27, 28, 29, 30, 33, + 35, 36, 40, 41, 38, 32, 38, 37, 42, 43, + 50, 52, 53, 54, 55, 34, 56, 34, 58, nil, + nil, nil, nil, 34, nil, 34, nil, nil, 38, nil, + nil, nil, nil, 38, nil, nil, nil, nil, nil, 49, + nil, 34, nil, nil, nil, 34, nil, nil, nil, nil, + nil, 38, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 38, nil, 38, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, 49, nil, + nil, nil, 38 ] racc_goto_pointer = [ - nil, 9, 15, 28, 22, 0, 38, 35, -32, 43, - 44, 36, 10, -3, -36, -77, 4, -57, nil, -125, - 5, -54, 8, -52, 10, -51, 11, -50, 41, 42, - -1, -20, -49, -11, 11, -26, -23, -26, nil, -14, - -51, 32, -31, -64, -60, -1, nil, nil, -36, -27, - -96, -57, -70, -56, -83, 9, -140 ] + nil, 14, 16, 28, 22, -2, 31, 32, -36, 40, + 44, 36, 9, 8, -40, -37, -82, 4, -59, nil, + -131, 4, -61, 7, -58, 8, -56, 10, -55, 41, + 41, -18, -21, -53, -11, 10, -28, -24, -27, nil, + -15, -60, 32, -33, -63, -63, 0, nil, nil, -37, + -29, -101, -64, -81, -64, -99, 7, -154, -3 ] racc_goto_default = [ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 36, nil, nil, nil, nil, nil, nil, nil, 21, nil, + 37, nil, nil, nil, nil, nil, nil, nil, nil, 22, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, 57, 63, nil, nil, nil, 162, 64, nil, - nil, nil, nil, 67, 69, nil, 35, 37, nil, nil, - nil, nil, nil, nil, nil, nil, 161 ] + nil, nil, nil, 59, 65, nil, nil, nil, 177, 66, + nil, nil, nil, nil, 69, 71, nil, 36, 38, nil, + nil, nil, nil, nil, nil, nil, nil, 176, nil ] racc_reduce_table = [ 0, 0, :racc_error, - 5, 47, :_reduce_none, - 0, 48, :_reduce_none, - 2, 48, :_reduce_none, - 0, 53, :_reduce_4, - 0, 54, :_reduce_5, - 5, 52, :_reduce_6, + 5, 51, :_reduce_none, + 0, 52, :_reduce_none, 2, 52, :_reduce_none, - 0, 49, :_reduce_8, - 2, 49, :_reduce_none, - 1, 55, :_reduce_none, - 2, 55, :_reduce_11, - 3, 55, :_reduce_none, - 2, 55, :_reduce_none, - 2, 55, :_reduce_14, - 2, 55, :_reduce_15, - 0, 60, :_reduce_16, - 0, 61, :_reduce_17, - 7, 55, :_reduce_18, - 0, 62, :_reduce_19, - 0, 63, :_reduce_20, - 6, 55, :_reduce_21, - 1, 55, :_reduce_none, - 0, 66, :_reduce_23, - 0, 67, :_reduce_24, - 6, 56, :_reduce_25, - 1, 56, :_reduce_none, - 0, 68, :_reduce_27, - 0, 69, :_reduce_28, - 7, 56, :_reduce_none, - 0, 70, :_reduce_30, - 0, 71, :_reduce_31, - 7, 56, :_reduce_32, - 0, 72, :_reduce_33, - 0, 73, :_reduce_34, - 7, 56, :_reduce_35, - 2, 64, :_reduce_none, - 2, 64, :_reduce_37, - 2, 64, :_reduce_38, - 2, 64, :_reduce_39, - 2, 64, :_reduce_40, - 2, 64, :_reduce_41, - 1, 74, :_reduce_42, - 2, 74, :_reduce_43, - 3, 74, :_reduce_44, - 1, 77, :_reduce_45, - 2, 77, :_reduce_46, - 3, 78, :_reduce_47, - 0, 80, :_reduce_none, - 1, 80, :_reduce_none, - 0, 81, :_reduce_none, - 1, 81, :_reduce_none, - 1, 75, :_reduce_52, - 2, 75, :_reduce_53, - 3, 75, :_reduce_54, - 1, 82, :_reduce_55, - 2, 82, :_reduce_56, - 1, 83, :_reduce_none, - 1, 83, :_reduce_none, - 0, 85, :_reduce_59, - 0, 86, :_reduce_60, - 6, 59, :_reduce_61, - 0, 87, :_reduce_62, - 0, 88, :_reduce_63, - 5, 59, :_reduce_64, - 1, 76, :_reduce_65, - 2, 76, :_reduce_66, - 3, 76, :_reduce_67, - 1, 89, :_reduce_68, - 2, 89, :_reduce_69, - 1, 90, :_reduce_none, - 1, 79, :_reduce_71, - 1, 79, :_reduce_72, - 1, 50, :_reduce_none, - 2, 50, :_reduce_none, - 1, 91, :_reduce_none, - 2, 91, :_reduce_none, - 4, 92, :_reduce_77, - 1, 95, :_reduce_78, - 3, 95, :_reduce_79, - 2, 95, :_reduce_none, - 0, 96, :_reduce_81, - 1, 96, :_reduce_82, - 3, 96, :_reduce_83, - 3, 96, :_reduce_84, - 5, 96, :_reduce_85, - 0, 99, :_reduce_86, - 0, 100, :_reduce_87, - 7, 96, :_reduce_88, - 3, 96, :_reduce_89, - 1, 97, :_reduce_none, - 1, 97, :_reduce_none, - 1, 97, :_reduce_none, - 1, 98, :_reduce_93, - 3, 98, :_reduce_94, - 0, 94, :_reduce_none, - 3, 94, :_reduce_96, - 1, 93, :_reduce_none, - 0, 51, :_reduce_none, - 0, 101, :_reduce_99, - 3, 51, :_reduce_100, - 1, 57, :_reduce_none, - 0, 58, :_reduce_none, - 1, 58, :_reduce_none, - 1, 58, :_reduce_none, - 1, 58, :_reduce_none, - 1, 65, :_reduce_106, - 2, 65, :_reduce_107, + 0, 57, :_reduce_4, + 0, 58, :_reduce_5, + 5, 56, :_reduce_6, + 2, 56, :_reduce_none, + 0, 53, :_reduce_8, + 2, 53, :_reduce_none, + 1, 59, :_reduce_none, + 2, 59, :_reduce_11, + 3, 59, :_reduce_none, + 2, 59, :_reduce_none, + 2, 59, :_reduce_14, + 2, 59, :_reduce_15, + 0, 65, :_reduce_16, + 0, 66, :_reduce_17, + 7, 59, :_reduce_18, + 0, 67, :_reduce_19, + 0, 68, :_reduce_20, + 6, 59, :_reduce_21, + 5, 59, :_reduce_22, + 1, 59, :_reduce_none, + 0, 71, :_reduce_24, + 0, 72, :_reduce_25, + 6, 60, :_reduce_26, + 1, 60, :_reduce_none, + 0, 73, :_reduce_28, + 0, 74, :_reduce_29, + 7, 60, :_reduce_none, + 0, 75, :_reduce_31, + 0, 76, :_reduce_32, + 7, 60, :_reduce_33, + 0, 77, :_reduce_34, + 0, 78, :_reduce_35, + 7, 60, :_reduce_36, + 2, 69, :_reduce_none, + 2, 69, :_reduce_38, + 2, 69, :_reduce_39, + 2, 69, :_reduce_40, + 2, 69, :_reduce_41, + 2, 69, :_reduce_42, + 1, 79, :_reduce_43, + 2, 79, :_reduce_44, + 3, 79, :_reduce_45, + 1, 82, :_reduce_46, + 2, 82, :_reduce_47, + 3, 83, :_reduce_48, + 0, 85, :_reduce_none, + 1, 85, :_reduce_none, + 0, 86, :_reduce_none, + 1, 86, :_reduce_none, + 1, 80, :_reduce_53, + 2, 80, :_reduce_54, + 3, 80, :_reduce_55, + 1, 87, :_reduce_56, + 2, 87, :_reduce_57, + 1, 88, :_reduce_none, + 1, 88, :_reduce_none, + 0, 90, :_reduce_60, + 0, 91, :_reduce_61, + 6, 63, :_reduce_62, + 0, 92, :_reduce_63, + 0, 93, :_reduce_64, + 5, 63, :_reduce_65, + 1, 81, :_reduce_66, + 2, 81, :_reduce_67, + 3, 81, :_reduce_68, + 1, 94, :_reduce_69, + 2, 94, :_reduce_70, + 1, 95, :_reduce_none, + 1, 84, :_reduce_72, + 1, 84, :_reduce_73, + 1, 54, :_reduce_none, + 2, 54, :_reduce_none, + 1, 96, :_reduce_none, + 2, 96, :_reduce_none, + 4, 97, :_reduce_78, + 1, 100, :_reduce_79, + 3, 100, :_reduce_80, + 2, 100, :_reduce_none, + 0, 101, :_reduce_82, + 1, 101, :_reduce_83, + 3, 101, :_reduce_84, + 3, 101, :_reduce_85, + 5, 101, :_reduce_86, + 0, 104, :_reduce_87, + 0, 105, :_reduce_88, + 7, 101, :_reduce_89, + 3, 101, :_reduce_90, + 7, 101, :_reduce_91, + 5, 101, :_reduce_92, + 7, 101, :_reduce_93, 1, 102, :_reduce_none, 1, 102, :_reduce_none, - 1, 84, :_reduce_110 ] - -racc_reduce_n = 111 - -racc_shift_n = 176 + 1, 102, :_reduce_none, + 1, 103, :_reduce_97, + 3, 103, :_reduce_98, + 0, 99, :_reduce_none, + 3, 99, :_reduce_100, + 1, 98, :_reduce_none, + 0, 55, :_reduce_none, + 0, 106, :_reduce_103, + 3, 55, :_reduce_104, + 1, 61, :_reduce_none, + 0, 62, :_reduce_none, + 1, 62, :_reduce_none, + 1, 62, :_reduce_none, + 1, 62, :_reduce_none, + 1, 70, :_reduce_110, + 2, 70, :_reduce_111, + 1, 107, :_reduce_none, + 1, 107, :_reduce_none, + 0, 64, :_reduce_none, + 1, 64, :_reduce_none, + 1, 108, :_reduce_116, + 3, 108, :_reduce_117, + 1, 89, :_reduce_118 ] + +racc_reduce_n = 119 + +racc_shift_n = 201 racc_token_table = { false => 0, @@ -1024,32 +1048,36 @@ def carrets(first_column, last_column) "{" => 19, "}" => 20, "%initial-action" => 21, - ";" => 22, - "%union" => 23, - "%destructor" => 24, - "%printer" => 25, - "%error-token" => 26, - "%token" => 27, - "%type" => 28, - "%left" => 29, - "%right" => 30, - "%precedence" => 31, - "%nonassoc" => 32, - ":" => 33, - "|" => 34, - "%empty" => 35, - "(" => 36, - ")" => 37, - "%prec" => 38, - "?" => 39, - "+" => 40, - "*" => 41, - "," => 42, - "[" => 43, - "]" => 44, - "{...}" => 45 } - -racc_nt_base = 46 + "%parser-state" => 22, + "(" => 23, + ")" => 24, + ";" => 25, + "%union" => 26, + "%destructor" => 27, + "%printer" => 28, + "%error-token" => 29, + "%token" => 30, + "%type" => 31, + "%left" => 32, + "%right" => 33, + "%precedence" => 34, + "%nonassoc" => 35, + ":" => 36, + "|" => 37, + "%empty" => 38, + "%prec" => 39, + "%parser-state-push" => 40, + "," => 41, + "%parser-state-pop" => 42, + "%parser-state-set" => 43, + "?" => 44, + "+" => 45, + "*" => 46, + "[" => 47, + "]" => 48, + "{...}" => 49 } + +racc_nt_base = 50 racc_use_result_var = true @@ -1093,6 +1121,9 @@ def carrets(first_column, last_column) "\"{\"", "\"}\"", "\"%initial-action\"", + "\"%parser-state\"", + "\"(\"", + "\")\"", "\";\"", "\"%union\"", "\"%destructor\"", @@ -1107,13 +1138,14 @@ def carrets(first_column, last_column) "\":\"", "\"|\"", "\"%empty\"", - "\"(\"", - "\")\"", "\"%prec\"", + "\"%parser-state-push\"", + "\",\"", + "\"%parser-state-pop\"", + "\"%parser-state-set\"", "\"?\"", "\"+\"", "\"*\"", - "\",\"", "\"[\"", "\"]\"", "\"{...}\"", @@ -1131,6 +1163,7 @@ def carrets(first_column, last_column) "variable", "value", "params", + "identifier_list_opt", "@3", "@4", "@5", @@ -1173,7 +1206,8 @@ def carrets(first_column, last_column) "@19", "@20", "@21", - "generic_symlist_item" ] + "generic_symlist_item", + "identifier_list" ] Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor) Racc_debug_parser = true @@ -1305,19 +1339,19 @@ def _reduce_21(val, _values, result) end .,., -# reduce 22 omitted - -module_eval(<<'.,.,', 'parser.y', 74) - def _reduce_23(val, _values, result) - begin_c_declaration("}") +module_eval(<<'.,.,', 'parser.y', 72) + def _reduce_22(val, _values, result) + @grammar.add_parser_state(val[1], val[3]) result end .,., +# reduce 23 omitted + module_eval(<<'.,.,', 'parser.y', 78) def _reduce_24(val, _values, result) - end_c_declaration + begin_c_declaration("}") result end @@ -1325,6 +1359,14 @@ def _reduce_24(val, _values, result) module_eval(<<'.,.,', 'parser.y', 82) def _reduce_25(val, _values, result) + end_c_declaration + + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 86) + def _reduce_26(val, _values, result) @grammar.set_union( Grammar::Code::NoReferenceCode.new(type: :union, token_code: val[3]), val[3].line @@ -1334,44 +1376,44 @@ def _reduce_25(val, _values, result) end .,., -# reduce 26 omitted +# reduce 27 omitted -module_eval(<<'.,.,', 'parser.y', 90) - def _reduce_27(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 94) + def _reduce_28(val, _values, result) begin_c_declaration("}") result end .,., -module_eval(<<'.,.,', 'parser.y', 94) - def _reduce_28(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 98) + def _reduce_29(val, _values, result) end_c_declaration result end .,., -# reduce 29 omitted +# reduce 30 omitted -module_eval(<<'.,.,', 'parser.y', 99) - def _reduce_30(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 103) + def _reduce_31(val, _values, result) begin_c_declaration("}") result end .,., -module_eval(<<'.,.,', 'parser.y', 103) - def _reduce_31(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 107) + def _reduce_32(val, _values, result) end_c_declaration result end .,., -module_eval(<<'.,.,', 'parser.y', 107) - def _reduce_32(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 111) + def _reduce_33(val, _values, result) @grammar.add_printer( ident_or_tags: val[6], token_code: val[3], @@ -1382,24 +1424,24 @@ def _reduce_32(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 115) - def _reduce_33(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 119) + def _reduce_34(val, _values, result) begin_c_declaration("}") result end .,., -module_eval(<<'.,.,', 'parser.y', 119) - def _reduce_34(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 123) + def _reduce_35(val, _values, result) end_c_declaration result end .,., -module_eval(<<'.,.,', 'parser.y', 123) - def _reduce_35(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 127) + def _reduce_36(val, _values, result) @grammar.add_error_token( ident_or_tags: val[6], token_code: val[3], @@ -1410,10 +1452,10 @@ def _reduce_35(val, _values, result) end .,., -# reduce 36 omitted +# reduce 37 omitted -module_eval(<<'.,.,', 'parser.y', 133) - def _reduce_37(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 137) + def _reduce_38(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| @grammar.add_type(id: id, tag: hash[:tag]) @@ -1424,8 +1466,8 @@ def _reduce_37(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 141) - def _reduce_38(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 145) + def _reduce_39(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| sym = @grammar.add_term(id: id) @@ -1438,8 +1480,8 @@ def _reduce_38(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 151) - def _reduce_39(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 155) + def _reduce_40(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| sym = @grammar.add_term(id: id) @@ -1452,8 +1494,8 @@ def _reduce_39(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 161) - def _reduce_40(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 165) + def _reduce_41(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| sym = @grammar.add_term(id: id) @@ -1466,8 +1508,8 @@ def _reduce_40(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 171) - def _reduce_41(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 175) + def _reduce_42(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| sym = @grammar.add_term(id: id) @@ -1480,8 +1522,8 @@ def _reduce_41(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 182) - def _reduce_42(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 186) + def _reduce_43(val, _values, result) val[0].each {|token_declaration| @grammar.add_term(id: token_declaration[0], alias_name: token_declaration[2], token_id: token_declaration[1], tag: nil, replace: true) } @@ -1490,8 +1532,8 @@ def _reduce_42(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 188) - def _reduce_43(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 192) + def _reduce_44(val, _values, result) val[1].each {|token_declaration| @grammar.add_term(id: token_declaration[0], alias_name: token_declaration[2], token_id: token_declaration[1], tag: val[0], replace: true) } @@ -1500,8 +1542,8 @@ def _reduce_43(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 194) - def _reduce_44(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 198) + def _reduce_45(val, _values, result) val[2].each {|token_declaration| @grammar.add_term(id: token_declaration[0], alias_name: token_declaration[2], token_id: token_declaration[1], tag: val[1], replace: true) } @@ -1510,88 +1552,80 @@ def _reduce_44(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 199) - def _reduce_45(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 203) + def _reduce_46(val, _values, result) result = [val[0]] result end .,., -module_eval(<<'.,.,', 'parser.y', 200) - def _reduce_46(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 204) + def _reduce_47(val, _values, result) result = val[0].append(val[1]) result end .,., -module_eval(<<'.,.,', 'parser.y', 202) - def _reduce_47(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 206) + def _reduce_48(val, _values, result) result = val result end .,., -# reduce 48 omitted - # reduce 49 omitted # reduce 50 omitted # reduce 51 omitted -module_eval(<<'.,.,', 'parser.y', 212) - def _reduce_52(val, _values, result) +# reduce 52 omitted + +module_eval(<<'.,.,', 'parser.y', 216) + def _reduce_53(val, _values, result) result = [{tag: nil, tokens: val[0]}] result end .,., -module_eval(<<'.,.,', 'parser.y', 216) - def _reduce_53(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 220) + def _reduce_54(val, _values, result) result = [{tag: val[0], tokens: val[1]}] result end .,., -module_eval(<<'.,.,', 'parser.y', 220) - def _reduce_54(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 224) + def _reduce_55(val, _values, result) result = val[0].append({tag: val[1], tokens: val[2]}) result end .,., -module_eval(<<'.,.,', 'parser.y', 223) - def _reduce_55(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 227) + def _reduce_56(val, _values, result) result = [val[0]] result end .,., -module_eval(<<'.,.,', 'parser.y', 224) - def _reduce_56(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 228) + def _reduce_57(val, _values, result) result = val[0].append(val[1]) result end .,., -# reduce 57 omitted - # reduce 58 omitted -module_eval(<<'.,.,', 'parser.y', 231) - def _reduce_59(val, _values, result) - begin_c_declaration("}") - - result - end -.,., +# reduce 59 omitted module_eval(<<'.,.,', 'parser.y', 235) def _reduce_60(val, _values, result) - end_c_declaration + begin_c_declaration("}") result end @@ -1599,7 +1633,7 @@ def _reduce_60(val, _values, result) module_eval(<<'.,.,', 'parser.y', 239) def _reduce_61(val, _values, result) - result = val[0].append(val[3]) + end_c_declaration result end @@ -1607,7 +1641,7 @@ def _reduce_61(val, _values, result) module_eval(<<'.,.,', 'parser.y', 243) def _reduce_62(val, _values, result) - begin_c_declaration("}") + result = val[0].append(val[3]) result end @@ -1615,7 +1649,7 @@ def _reduce_62(val, _values, result) module_eval(<<'.,.,', 'parser.y', 247) def _reduce_63(val, _values, result) - end_c_declaration + begin_c_declaration("}") result end @@ -1623,15 +1657,15 @@ def _reduce_63(val, _values, result) module_eval(<<'.,.,', 'parser.y', 251) def _reduce_64(val, _values, result) - result = [val[2]] + end_c_declaration result end .,., -module_eval(<<'.,.,', 'parser.y', 256) +module_eval(<<'.,.,', 'parser.y', 255) def _reduce_65(val, _values, result) - result = [{tag: nil, tokens: val[0]}] + result = [val[2]] result end @@ -1639,7 +1673,7 @@ def _reduce_65(val, _values, result) module_eval(<<'.,.,', 'parser.y', 260) def _reduce_66(val, _values, result) - result = [{tag: val[0], tokens: val[1]}] + result = [{tag: nil, tokens: val[0]}] result end @@ -1647,52 +1681,60 @@ def _reduce_66(val, _values, result) module_eval(<<'.,.,', 'parser.y', 264) def _reduce_67(val, _values, result) - result = val[0].append({tag: val[1], tokens: val[2]}) + result = [{tag: val[0], tokens: val[1]}] result end .,., -module_eval(<<'.,.,', 'parser.y', 267) +module_eval(<<'.,.,', 'parser.y', 268) def _reduce_68(val, _values, result) - result = [val[0]] + result = val[0].append({tag: val[1], tokens: val[2]}) + result end .,., -module_eval(<<'.,.,', 'parser.y', 268) +module_eval(<<'.,.,', 'parser.y', 271) def _reduce_69(val, _values, result) + result = [val[0]] + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 272) + def _reduce_70(val, _values, result) result = val[0].append(val[1]) result end .,., -# reduce 70 omitted +# reduce 71 omitted -module_eval(<<'.,.,', 'parser.y', 272) - def _reduce_71(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 276) + def _reduce_72(val, _values, result) on_action_error("ident after %prec", val[0]) if @prec_seen result end .,., -module_eval(<<'.,.,', 'parser.y', 273) - def _reduce_72(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 277) + def _reduce_73(val, _values, result) on_action_error("char after %prec", val[0]) if @prec_seen result end .,., -# reduce 73 omitted - # reduce 74 omitted # reduce 75 omitted # reduce 76 omitted -module_eval(<<'.,.,', 'parser.y', 283) - def _reduce_77(val, _values, result) +# reduce 77 omitted + +module_eval(<<'.,.,', 'parser.y', 287) + def _reduce_78(val, _values, result) lhs = val[0] lhs.alias_name = val[1] val[3].each do |builder| @@ -1705,8 +1747,8 @@ def _reduce_77(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 294) - def _reduce_78(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 298) + def _reduce_79(val, _values, result) builder = val[0] if !builder.line builder.line = @lexer.line - 1 @@ -1717,8 +1759,8 @@ def _reduce_78(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 302) - def _reduce_79(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 306) + def _reduce_80(val, _values, result) builder = val[2] if !builder.line builder.line = @lexer.line - 1 @@ -1729,10 +1771,10 @@ def _reduce_79(val, _values, result) end .,., -# reduce 80 omitted +# reduce 81 omitted -module_eval(<<'.,.,', 'parser.y', 312) - def _reduce_81(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 316) + def _reduce_82(val, _values, result) reset_precs result = Grammar::RuleBuilder.new(@rule_counter, @midrule_action_counter) @@ -1740,8 +1782,8 @@ def _reduce_81(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 317) - def _reduce_82(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 321) + def _reduce_83(val, _values, result) reset_precs result = Grammar::RuleBuilder.new(@rule_counter, @midrule_action_counter) @@ -1749,8 +1791,8 @@ def _reduce_82(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 322) - def _reduce_83(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 326) + def _reduce_84(val, _values, result) token = val[1] token.alias_name = val[2] builder = val[0] @@ -1761,8 +1803,8 @@ def _reduce_83(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 330) - def _reduce_84(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 334) + def _reduce_85(val, _values, result) token = Lrama::Lexer::Token::Parameterizing.new(s_value: val[2], location: @lexer.location, args: [val[1]]) builder = val[0] builder.add_rhs(token) @@ -1772,8 +1814,8 @@ def _reduce_84(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 337) - def _reduce_85(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 341) + def _reduce_86(val, _values, result) token = Lrama::Lexer::Token::Parameterizing.new(s_value: val[1].s_value, location: @lexer.location, args: val[3]) builder = val[0] builder.add_rhs(token) @@ -1783,8 +1825,8 @@ def _reduce_85(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 344) - def _reduce_86(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 348) + def _reduce_87(val, _values, result) if @prec_seen on_action_error("multiple User_code after %prec", val[0]) if @code_after_prec @code_after_prec = true @@ -1795,16 +1837,16 @@ def _reduce_86(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 352) - def _reduce_87(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 356) + def _reduce_88(val, _values, result) end_c_declaration result end .,., -module_eval(<<'.,.,', 'parser.y', 356) - def _reduce_88(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 360) + def _reduce_89(val, _values, result) token = val[3] token.alias_name = val[6] builder = val[0] @@ -1815,8 +1857,8 @@ def _reduce_88(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 364) - def _reduce_89(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 368) + def _reduce_90(val, _values, result) sym = @grammar.find_symbol_by_id!(val[2]) @prec_seen = true builder = val[0] @@ -1827,41 +1869,76 @@ def _reduce_89(val, _values, result) end .,., -# reduce 90 omitted +module_eval(<<'.,.,', 'parser.y', 376) + def _reduce_91(val, _values, result) + token = Lrama::Lexer::Token::ParserStatePush.new(s_value: val[3].s_value, location: val[3].location) + token.state = val[5] + builder = val[0] + builder.add_rhs(token) + result = builder + + result + end +.,., -# reduce 91 omitted +module_eval(<<'.,.,', 'parser.y', 384) + def _reduce_92(val, _values, result) + token = Lrama::Lexer::Token::ParserStatePop.new(s_value: val[3].s_value, location: val[3].location) + builder = val[0] + builder.add_rhs(token) + result = builder -# reduce 92 omitted + result + end +.,., -module_eval(<<'.,.,', 'parser.y', 375) +module_eval(<<'.,.,', 'parser.y', 391) def _reduce_93(val, _values, result) + token = Lrama::Lexer::Token::ParserStateSet.new(s_value: val[3].s_value, location: val[3].location) + token.state = val[5] + builder = val[0] + builder.add_rhs(token) + result = builder + + result + end +.,., + +# reduce 94 omitted + +# reduce 95 omitted + +# reduce 96 omitted + +module_eval(<<'.,.,', 'parser.y', 402) + def _reduce_97(val, _values, result) result = [val[0]] result end .,., -module_eval(<<'.,.,', 'parser.y', 376) - def _reduce_94(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 403) + def _reduce_98(val, _values, result) result = val[0].append(val[2]) result end .,., -# reduce 95 omitted +# reduce 99 omitted -module_eval(<<'.,.,', 'parser.y', 379) - def _reduce_96(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 406) + def _reduce_100(val, _values, result) result = val[1].s_value result end .,., -# reduce 97 omitted +# reduce 101 omitted -# reduce 98 omitted +# reduce 102 omitted -module_eval(<<'.,.,', 'parser.y', 386) - def _reduce_99(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 413) + def _reduce_103(val, _values, result) begin_c_declaration('\Z') @grammar.epilogue_first_lineno = @lexer.line + 1 @@ -1869,8 +1946,8 @@ def _reduce_99(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 391) - def _reduce_100(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 418) + def _reduce_104(val, _values, result) end_c_declaration @grammar.epilogue = val[2].s_value @@ -1878,36 +1955,54 @@ def _reduce_100(val, _values, result) end .,., -# reduce 101 omitted +# reduce 105 omitted -# reduce 102 omitted +# reduce 106 omitted -# reduce 103 omitted +# reduce 107 omitted -# reduce 104 omitted +# reduce 108 omitted -# reduce 105 omitted +# reduce 109 omitted -module_eval(<<'.,.,', 'parser.y', 402) - def _reduce_106(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 429) + def _reduce_110(val, _values, result) result = [val[0]] result end .,., -module_eval(<<'.,.,', 'parser.y', 403) - def _reduce_107(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 430) + def _reduce_111(val, _values, result) result = val[0].append(val[1]) result end .,., -# reduce 108 omitted +# reduce 112 omitted -# reduce 109 omitted +# reduce 113 omitted -module_eval(<<'.,.,', 'parser.y', 408) - def _reduce_110(val, _values, result) +# reduce 114 omitted + +# reduce 115 omitted + +module_eval(<<'.,.,', 'parser.y', 438) + def _reduce_116(val, _values, result) + result = [val[0]] + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 439) + def _reduce_117(val, _values, result) + result = val[0].append(val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 441) + def _reduce_118(val, _values, result) result = Lrama::Lexer::Token::Ident.new(s_value: val[0]) result end diff --git a/parser.y b/parser.y index fd98ad8b..57398e64 100644 --- a/parser.y +++ b/parser.y @@ -68,6 +68,10 @@ rule { @grammar.initial_action = Grammar::Code::InitialActionCode.new(type: :initial_action, token_code: val[3]) } + | "%parser-state" IDENTIFIER "(" identifier_list_opt ")" + { + @grammar.add_parser_state(val[1], val[3]) + } | ";" grammar_declaration: "%union" "{" @@ -368,6 +372,29 @@ rule builder.precedence_sym = sym result = builder } + | rhs "%parser-state-push" "(" IDENTIFIER "," IDENTIFIER ")" + { + token = Lrama::Lexer::Token::ParserStatePush.new(s_value: val[3].s_value, location: val[3].location) + token.state = val[5] + builder = val[0] + builder.add_rhs(token) + result = builder + } + | rhs "%parser-state-pop" "(" IDENTIFIER ")" + { + token = Lrama::Lexer::Token::ParserStatePop.new(s_value: val[3].s_value, location: val[3].location) + builder = val[0] + builder.add_rhs(token) + result = builder + } + | rhs "%parser-state-set" "(" IDENTIFIER "," IDENTIFIER ")" + { + token = Lrama::Lexer::Token::ParserStateSet.new(s_value: val[3].s_value, location: val[3].location) + token.state = val[5] + builder = val[0] + builder.add_rhs(token) + result = builder + } parameterizing_suffix: "?" | "+" @@ -406,6 +433,12 @@ rule generic_symlist_item: symbol | TAG + identifier_list_opt: # empty + | identifier_list + + identifier_list: IDENTIFIER { result = [val[0]] } + | identifier_list "," IDENTIFIER { result = val[0].append(val[2]) } + string_as_id: STRING { result = Lrama::Lexer::Token::Ident.new(s_value: val[0]) } end diff --git a/sig/lrama/grammar.rbs b/sig/lrama/grammar.rbs index 241a09a1..e38092b9 100644 --- a/sig/lrama/grammar.rbs +++ b/sig/lrama/grammar.rbs @@ -1,5 +1,7 @@ module Lrama class Grammar + attr_reader parser_states: Array[ParserState] + def numberize_references: (Lexer::Token lhs, Array[Lexer::Token] rhs, Array[Reference]) -> void end end diff --git a/sig/lrama/grammar/parser_state.rbs b/sig/lrama/grammar/parser_state.rbs new file mode 100644 index 00000000..35dbb69b --- /dev/null +++ b/sig/lrama/grammar/parser_state.rbs @@ -0,0 +1,24 @@ +module Lrama + class Grammar + class ParserState + attr_reader state_id: Lexer::Token::Ident + attr_reader state_list: Array[Lexer::Token::Ident] + + def initialize: (state_id: Lexer::Token::Ident, state_list: Array[Lexer::Token::Ident]) -> void + + def enum_definition: () -> String + def state_name_macro: () -> String + def current_state_name_macro: () -> String + def states_functions: () -> String + def states_stack_size_name: () -> String + def states_stacks: () -> String + def state_name: () -> String + def enum_name: () -> String + def enum_type: () -> String + def enum_body: () -> String + def int_to_name: () -> Array[String] + def enum_name_table_name: () -> String + def stack_prefix: () -> String + end + end +end diff --git a/sig/lrama/grammar/rule_builder.rbs b/sig/lrama/grammar/rule_builder.rbs index b0a5b4e9..b24203eb 100644 --- a/sig/lrama/grammar/rule_builder.rbs +++ b/sig/lrama/grammar/rule_builder.rbs @@ -34,6 +34,7 @@ module Lrama def preprocess_references: () -> void def build_rules: () -> void def process_rhs: () -> void + def process_parser_state_token: (Lexer::Token, String, String, Integer) -> void def numberize_references: () -> void def flush_user_code: () -> void end diff --git a/sig/lrama/lexer/token/parser_state_pop.rbs b/sig/lrama/lexer/token/parser_state_pop.rbs new file mode 100644 index 00000000..ac2c020b --- /dev/null +++ b/sig/lrama/lexer/token/parser_state_pop.rbs @@ -0,0 +1,8 @@ +module Lrama + class Lexer + class Token + class ParserStatePop < Token + end + end + end +end diff --git a/sig/lrama/lexer/token/parser_state_push.rbs b/sig/lrama/lexer/token/parser_state_push.rbs new file mode 100644 index 00000000..a68f10f3 --- /dev/null +++ b/sig/lrama/lexer/token/parser_state_push.rbs @@ -0,0 +1,9 @@ +module Lrama + class Lexer + class Token + class ParserStatePush < Token + attr_accessor state: Token + end + end + end +end diff --git a/sig/lrama/lexer/token/parser_state_set.rbs b/sig/lrama/lexer/token/parser_state_set.rbs new file mode 100644 index 00000000..181f3131 --- /dev/null +++ b/sig/lrama/lexer/token/parser_state_set.rbs @@ -0,0 +1,9 @@ +module Lrama + class Lexer + class Token + class ParserStateSet < Token + attr_accessor state: Token + end + end + end +end diff --git a/spec/fixtures/integration/parser_state.l b/spec/fixtures/integration/parser_state.l new file mode 100644 index 00000000..899934dc --- /dev/null +++ b/spec/fixtures/integration/parser_state.l @@ -0,0 +1,85 @@ +%option noinput nounput noyywrap never-interactive yylineno bison-bridge bison-locations + +%{ + +#include +#include +#include "parser_state.h" + +int yycolumn = 0; + +#define YY_USER_ACTION \ + yylloc->first_line = yylloc->last_line = yylineno; \ + yylloc->first_column = yycolumn; \ + yylloc->last_column = yycolumn + yyleng; \ + yycolumn += yyleng; \ + +%} + +NUMBER [0-9]+ + +%% + +{NUMBER} { + yylval->i = atoi(yytext); + return NUM; +} + +[+\-\*\/\(\)] { + return yytext[0]; +} + +[\n|\r\n] {} + +[[:space:]] {} + +"begin" { + return keyword_begin; +} + +"end" { + return keyword_end; +} + +"rescue" { + return keyword_rescue; +} + +"else" { + return keyword_else; +} + +"ensure" { + return keyword_ensure; +} + +"class" { + return keyword_class; +} + +"def" { + return keyword_def; +} + +[A-Z]+ { + yylval->str = strdup(yytext); + fprintf(stderr, "%s\n", yytext); + return cname; +} + +[a-z][a-z0-9]+ { + yylval->str = strdup(yytext); + fprintf(stderr, "%s\n", yytext); + return fname; +} + +<> { + return(YYEOF); +} + +. { + fprintf(stderr, "Illegal character '%s'\n", yytext); + return(YYEOF); +} + +%% diff --git a/spec/fixtures/integration/parser_state.y b/spec/fixtures/integration/parser_state.y new file mode 100644 index 00000000..d13c481f --- /dev/null +++ b/spec/fixtures/integration/parser_state.y @@ -0,0 +1,130 @@ +%{ + +#define YYDEBUG 1 + +#include +#include "parser_state.h" +#include "parser_state-lexer.h" + +static int yyerror(YYLTYPE *loc, const char *str); + +%} + +%union { + int i; + char *str; +} + +%expect 0 + +%parser-state in_rescue (before_rescue, after_rescue, after_else, after_ensure) +%parser-state in_def (in_def, not_in_def) +%parser-state in_class (in_class, not_in_class) + +%token keyword_begin keyword_end keyword_rescue keyword_else keyword_ensure keyword_class keyword_def +%token NUM +%token cname fname +%token tLSHFT "<<" + +%% + +program : %parser-state-set(in_rescue, before_rescue) + %parser-state-set(in_def, not_in_def) + %parser-state-set(in_class, not_in_class) + { + printf("0 => in_def: %s, in_class: %s.\n", YY_CURRENT_STATE_IN_DEF_NAME, YY_CURRENT_STATE_IN_CLASS_NAME); + } + { + printf("0 => %s\n", YY_CURRENT_STATE_IN_RESCUE_NAME); + } + bodystmt + { + printf("1 => %s\n", YY_CURRENT_STATE_IN_RESCUE_NAME); + } + ; + +bodystmt : compstmt + { printf("2 => %s\n", YY_CURRENT_STATE_IN_RESCUE_NAME); } + opt_rescue + { printf("3 => %s\n", YY_CURRENT_STATE_IN_RESCUE_NAME); } + opt_else + { printf("4 => %s\n", YY_CURRENT_STATE_IN_RESCUE_NAME); } + opt_ensure + { printf("5 => %s\n", YY_CURRENT_STATE_IN_RESCUE_NAME); } + ; + +opt_rescue : keyword_rescue %parser-state-push(in_rescue, after_rescue) + { printf("6 => %s\n", YY_CURRENT_STATE_IN_RESCUE_NAME); } + compstmt %parser-state-pop(in_rescue) + { printf("7 => %s\n", YY_CURRENT_STATE_IN_RESCUE_NAME); } + | /* empty */ + ; + +opt_else : keyword_else %parser-state-set(in_rescue, after_else) compstmt + | /* empty */ + ; + +opt_ensure : keyword_ensure %parser-state-set(in_rescue, after_ensure) compstmt + | /* empty */ + ; + +compstmt : stmts + ; + +stmts : /* empty */ + | stmt + | stmts ';' stmt + ; + +stmt : primary + | keyword_begin bodystmt keyword_end + ; + +primary : NUM { printf("NUM => %d\n", $1); } + | keyword_class + %parser-state-push(in_def, not_in_def) + %parser-state-push(in_class, in_class) + cname + { + printf("1. cname => %s. in_def: %s, in_class: %s.\n", $4, YY_CURRENT_STATE_IN_DEF_NAME, YY_CURRENT_STATE_IN_CLASS_NAME); + } + compstmt + keyword_end + %parser-state-pop(in_def) + %parser-state-pop(in_class) + { + printf("2. cname => %s. in_def: %s, in_class: %s.\n", $4, YY_CURRENT_STATE_IN_DEF_NAME, YY_CURRENT_STATE_IN_CLASS_NAME); + } + | keyword_def + %parser-state-push(in_def, in_def) + %parser-state-push(in_class, not_in_class) + fname + { + printf("1. fname => %s. in_def: %s, in_class: %s.\n", $4, YY_CURRENT_STATE_IN_DEF_NAME, YY_CURRENT_STATE_IN_CLASS_NAME); + } + compstmt + keyword_end + %parser-state-pop(in_def) + %parser-state-pop(in_class) + { + printf("2. fname => %s. in_def: %s, in_class: %s.\n", $4, YY_CURRENT_STATE_IN_DEF_NAME, YY_CURRENT_STATE_IN_CLASS_NAME); + } + ; + +%% + +static int yyerror(YYLTYPE *loc, const char *str) { + fprintf(stderr, "parse error: %s\\n", str); + return 0; +} + +int main(int argc, char *argv[]) { + yydebug = 1; + + if (argc == 2) { + yy_scan_string(argv[1]); + } + + yyparse(); + return 0; +} diff --git a/spec/lrama/grammar/parser_state_spec.rb b/spec/lrama/grammar/parser_state_spec.rb new file mode 100644 index 00000000..2e63bb71 --- /dev/null +++ b/spec/lrama/grammar/parser_state_spec.rb @@ -0,0 +1,177 @@ +RSpec.describe Lrama::Grammar::ParserState do + let(:location) { Lrama::Lexer::Location.new(first_line: 1, first_column: 0, last_line: 1, last_column: 0) } + let(:state_id) { Lrama::Lexer::Token::Ident.new(s_value: "in_rescue", location: location) } + let(:state_list) do + [ + Lrama::Lexer::Token::Ident.new(s_value: "before_rescue", location: location), + Lrama::Lexer::Token::Ident.new(s_value: "after_rescue", location: location), + Lrama::Lexer::Token::Ident.new(s_value: "after_else", location: location), + Lrama::Lexer::Token::Ident.new(s_value: "after_ensure", location: location) + ] + end + let(:parser_state) { Lrama::Grammar::ParserState.new(state_id: state_id, state_list: state_list) } + + describe "#enum_definition" do + it "returns enum definition" do + expect(parser_state.enum_definition).to eq <<~ENUM + enum yyparser_state_in_rescue + { + before_rescue, + after_rescue, + after_else, + after_ensure + }; + typedef enum yyparser_state_in_rescue yyparser_state_in_rescue_t; + + static const char *const yyparser_state_in_rescue_names[] = { + "before_rescue", "after_rescue", "after_else", "after_ensure", YY_NULLPTR + }; + + YY_ATTRIBUTE_UNUSED + static const char * + yyparser_state_in_rescue_name (yyparser_state_in_rescue_t num) + { + return yyparser_state_in_rescue_names[num]; + } + + # define YY_STATE_IN_RESCUE_NAME(value) yyparser_state_in_rescue_name (value) + # define YY_CURRENT_STATE_IN_RESCUE_NAME YY_STATE_IN_RESCUE_NAME (*yyparser_state_in_rescue_p) + ENUM + end + end + + describe "#state_name_macro" do + it "returns name of state name macro" do + expect(parser_state.state_name_macro).to eq "YY_STATE_IN_RESCUE_NAME" + end + end + + describe "#current_state_name_macro" do + it "returns name of current state name macro" do + expect(parser_state.current_state_name_macro).to eq "YY_CURRENT_STATE_IN_RESCUE_NAME" + end + end + + describe "#states_functions" do + it "returns states functions" do + expect(parser_state.states_functions).to eq <<~FUNC + # define YYPUSH_STATE_IN_RESCUE(value) \\ + do \\ + { \\ + if (yyparser_state_in_rescue + yyparser_state_in_rescue_stacksize - 1 <= yyparser_state_in_rescue_p) \\ + YYSTATE_STACK_INCREASE (yyparser_state_in_rescue_a, yyparser_state_in_rescue, yyparser_state_in_rescue_p, yyparser_state_in_rescue_stacksize, "in_rescue"); \\ + YYDPRINTF ((stderr, "Push %s to in_rescue\\n", YY_STATE_IN_RESCUE_NAME (value))); \\ + *++yyparser_state_in_rescue_p = value; \\ + } \\ + while (0) + + # define YYPOP_STATE_IN_RESCUE() \\ + do \\ + { \\ + YYDPRINTF ((stderr, "Pop in_rescue\\n")); \\ + if (yyparser_state_in_rescue_p != yyparser_state_in_rescue) \\ + { \\ + yyparser_state_in_rescue_p -= 1; \\ + } \\ + else \\ + { \\ + YYDPRINTF ((stderr, "Try to pop empty in_rescue stack\\n")); \\ + } \\ + } \\ + while (0) + + # define YYSET_STATE_IN_RESCUE(value) \\ + do \\ + { \\ + YYDPRINTF ((stderr, "Set %s to in_rescue\\n", YY_STATE_IN_RESCUE_NAME (value))); \\ + *yyparser_state_in_rescue_p = value; \\ + } \\ + while (0) + + # define YY_STATE_IN_RESCUE yyparser_state_in_rescue_p + FUNC + end + end + + describe "#states_clean_up_stack" do + it "returns states clean up codes" do + expect(parser_state.states_clean_up_stack).to eq <<~CODE + if (yyparser_state_in_rescue != yyparser_state_in_rescue_a) + YYSTACK_FREE (yyparser_state_in_rescue); + CODE + end + end + + describe "#states_stack_size_name" do + it "returns states stack size name" do + expect(parser_state.states_stack_size_name).to eq "yyparser_state_in_rescue_stacksize" + end + end + + describe "#states_stacks" do + it "returns states stacks" do + expect(parser_state.states_stacks).to eq <<~STACKS + /* Current size of state stack size */ + YYPTRDIFF_T yyparser_state_in_rescue_stacksize = YYINITDEPTH; + + /* The parser state stack (yyparser_state_in_rescue): array, bottom, top. */ + int yyparser_state_in_rescue_a[YYINITDEPTH]; + int *yyparser_state_in_rescue = yyparser_state_in_rescue_a; + int *yyparser_state_in_rescue_p = yyparser_state_in_rescue; + STACKS + end + end + + describe "#state_name" do + it "returns state name" do + expect(parser_state.state_name).to eq "in_rescue" + end + end + + describe "#enum_name" do + it "returns enum name" do + expect(parser_state.enum_name).to eq "yyparser_state_in_rescue" + end + end + + describe "#enum_type" do + it "returns enum type" do + expect(parser_state.enum_type).to eq "yyparser_state_in_rescue_t" + end + end + + describe "#enum_body" do + it "returns enum body" do + expect(parser_state.enum_body).to eq <<~BODY.chomp + before_rescue, + after_rescue, + after_else, + after_ensure + BODY + end + end + + describe "#int_to_name" do + it "returns int to name table" do + expect(parser_state.int_to_name).to eq [ + "\"before_rescue\"", + "\"after_rescue\"", + "\"after_else\"", + "\"after_ensure\"", + "YY_NULLPTR" + ] + end + end + + describe "#enum_name_table_name" do + it "returns table name" do + expect(parser_state.enum_name_table_name).to eq "yyparser_state_in_rescue_names" + end + end + + describe "#stack_prefix" do + it "returns prefix" do + expect(parser_state.stack_prefix).to eq "yyparser_state_in_rescue" + end + end +end diff --git a/spec/lrama/integration_spec.rb b/spec/lrama/integration_spec.rb index f6dab4de..81841026 100644 --- a/spec/lrama/integration_spec.rb +++ b/spec/lrama/integration_spec.rb @@ -9,7 +9,7 @@ def exec_command(command) raise "#{command} failed." unless $?.success? end - def test_parser(parser_name, input, expected, lrama_command_args: [], debug: false) + def test_parser(parser_name, input, expected, lrama_command_args: [], gcc_options: "", debug: false) tmpdir = Dir.tmpdir grammar_file_path = fixture_path("integration/#{parser_name}.y") lexer_file_path = fixture_path("integration/#{parser_name}.l") @@ -28,7 +28,7 @@ def test_parser(parser_name, input, expected, lrama_command_args: [], debug: fal Lrama::Command.new.run(%W[-H#{parser_h_path} -o#{parser_c_path}] + lrama_command_args + %W[#{grammar_file_path}]) exec_command("#{flex} --header-file=#{lexer_h_path} -o #{lexer_c_path} #{lexer_file_path}") - exec_command("gcc -Wall -ggdb3 -I#{tmpdir} #{parser_c_path} #{lexer_c_path} -o #{obj_path}") + exec_command("gcc -Wall -ggdb3 #{gcc_options} -I#{tmpdir} #{parser_c_path} #{lexer_c_path} -o #{obj_path}") out = err = status = nil @@ -116,6 +116,130 @@ def generate_object(grammar_file_path, c_path, obj_path, command_args: []) end end + describe "parser state" do + it "prints current 'in_rescue' state" do + input = <<~INPUT + def m1 + class A + class B + def m2 + end + end + end + end + INPUT + + expected = <<~OUTPUT + 0 => in_def: not_in_def, in_class: not_in_class. + 0 => before_rescue + 1. fname => m1. in_def: in_def, in_class: not_in_class. + 1. cname => A. in_def: not_in_def, in_class: in_class. + 1. cname => B. in_def: not_in_def, in_class: in_class. + 1. fname => m2. in_def: in_def, in_class: not_in_class. + 2. fname => m2. in_def: not_in_def, in_class: in_class. + 2. cname => B. in_def: not_in_def, in_class: in_class. + 2. cname => A. in_def: in_def, in_class: not_in_class. + 2. fname => m1. in_def: not_in_def, in_class: not_in_class. + 2 => before_rescue + 3 => before_rescue + 4 => before_rescue + 5 => before_rescue + 1 => before_rescue + OUTPUT + + test_parser("parser_state", input, expected) + test_parser("parser_state", input, expected, gcc_options: "-DYYINITDEPTH") + + + # See: https://github.com/ruby/ruby/commit/eaa0fbf9b956fa25e73c3d55e2eba8887324e233 + input = <<~INPUT + begin + 1 + rescue + 2 + else + 3 + ensure + 4 + end + INPUT + + expected = <<~OUTPUT + 0 => in_def: not_in_def, in_class: not_in_class. + 0 => before_rescue + NUM => 1 + 2 => before_rescue + 6 => after_rescue + NUM => 2 + 7 => before_rescue + 3 => before_rescue + NUM => 3 + 4 => after_else + NUM => 4 + 5 => after_ensure + 2 => after_ensure + 3 => after_ensure + 4 => after_ensure + 5 => after_ensure + 1 => after_ensure + OUTPUT + + test_parser("parser_state", input, expected) + + + input = <<~INPUT + begin + 1 + rescue + begin + 2 + rescue + 3 + else + 4 + ensure + 5 + end + else + 6 + ensure + 7 + end + INPUT + + expected = <<~OUTPUT + 0 => in_def: not_in_def, in_class: not_in_class. + 0 => before_rescue + NUM => 1 + 2 => before_rescue + 6 => after_rescue + NUM => 2 + 2 => after_rescue + 6 => after_rescue + NUM => 3 + 7 => after_rescue + 3 => after_rescue + NUM => 4 + 4 => after_else + NUM => 5 + 5 => after_ensure + 7 => before_rescue + 3 => before_rescue + NUM => 6 + 4 => after_else + NUM => 7 + 5 => after_ensure + 2 => after_ensure + 3 => after_ensure + 4 => after_ensure + 5 => after_ensure + 1 => after_ensure + OUTPUT + + test_parser("parser_state", input, expected) + end + end + describe "sample files" do let(:c_path) { Dir.tmpdir + "/test.c" } let(:obj_path) { Dir.tmpdir + "/test" } diff --git a/template/bison/yacc.c b/template/bison/yacc.c index 0e17b46f..23a171f3 100644 --- a/template/bison/yacc.c +++ b/template/bison/yacc.c @@ -461,6 +461,9 @@ union yyalloc /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK <%= output.yymaxutok %> +<%- output.parser_states_enums.each do |enum| -%> +<%= enum %> +<%- end -%> /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ @@ -1150,7 +1153,50 @@ yydestruct (const char *yymsg, YY_IGNORE_MAYBE_UNINITIALIZED_END } +/*------------------------. +| State stack functions. | +`------------------------*/ + +<%- if output.has_parser_states? -%> +#if !defined YYSTACK_RELOCATE +#define YYSTATE_STACK_INCREASE(stack_array, stack_bottom, stack_top, new_stack_size, name) \ + do \ + { \ + YYNOMEM; \ + } \ + while (0) +#else +#define YYSTATE_STACK_INCREASE(stack_array, stack_bottom, stack_top, stack_size, name) \ + do \ + { \ + { \ + YYPTRDIFF_T current_stack_size = stack_top - stack_bottom + 1; \ + if (YYMAXDEPTH <= stack_size) \ + YYNOMEM; \ + stack_size *= 2; \ + if (YYMAXDEPTH < stack_size) \ + stack_size = YYMAXDEPTH; \ + { \ + int *prev_bottom = stack_bottom; \ + int *new_stack = (int *) YYMALLOC (sizeof (int *) * stack_size); \ + if (!new_stack) \ + YYNOMEM; \ + YYCOPY (new_stack, stack_bottom, current_stack_size); \ + stack_bottom = new_stack; \ + stack_top = stack_bottom + current_stack_size - 1; \ + if (prev_bottom != stack_array) \ + YYSTACK_FREE (prev_bottom); \ + YYDPRINTF ((stderr, "State stack size increased to %ld (%s)\n", YY_CAST (long, current_stack_size), name)); \ + } \ + } \ + } \ + while (0) +#endif +<%- end -%> +<%- output.parser_states_functions.each do |func| -%> +<%= func %> +<%- end -%> <%- if output.error_recovery -%> #ifndef YYMAXREPAIR @@ -1512,6 +1558,10 @@ YYLTYPE yylloc = yyloc_default; YYLTYPE *yyls = yylsa; YYLTYPE *yylsp = yyls; + <%- output.parser_states_stacks.each do |states_stacks| -%> + <%= states_stacks %> + <%- end -%> + int yyn; /* The return value of yyparse. */ int yyresult; @@ -2039,6 +2089,9 @@ YYLTYPE yylloc = yyloc_default; #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); +<%- output.parser_states_clean_up_stack.each do |clean_up| -%> +<%= clean_up %> +<%- end -%> #endif if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg);