From 4cd1a01d75684357e561d989ede5083362f0f5de Mon Sep 17 00:00:00 2001 From: ydah Date: Fri, 8 Nov 2024 01:51:39 +0900 Subject: [PATCH] Add warning output when using %require, which exists only for compatibility with Bison This PR adds a warning output when using %require, which exists only for compatibility with Bison. see: https://www.gnu.org/software/bison/manual/html_node/Require-Decl.html --- lib/lrama/parser.rb | 9 ++- parser.y | 2 +- spec/fixtures/common/basic.y | 2 - spec/fixtures/common/nullable.y | 2 - spec/fixtures/context/basic.y | 2 - spec/lrama/context_spec.rb | 4 +- spec/lrama/lexer_spec.rb | 30 ++++----- spec/lrama/parser_spec.rb | 114 +++++++++++++++++++------------- 8 files changed, 92 insertions(+), 73 deletions(-) diff --git a/lib/lrama/parser.rb b/lib/lrama/parser.rb index 62c9ba64..2c3c17a6 100644 --- a/lib/lrama/parser.rb +++ b/lib/lrama/parser.rb @@ -909,7 +909,7 @@ def raise_parse_error(error_message, location) 0, 66, :_reduce_10, 0, 67, :_reduce_11, 5, 58, :_reduce_12, - 2, 58, :_reduce_none, + 2, 58, :_reduce_13, 1, 72, :_reduce_14, 2, 72, :_reduce_15, 1, 59, :_reduce_none, @@ -1299,7 +1299,12 @@ def _reduce_12(val, _values, result) end .,., -# reduce 13 omitted +module_eval(<<'.,.,', 'parser.y', 23) + def _reduce_13(val, _values, result) + warn '%require is provided for compatibility with Bison and can be removed after migration to Lrama.' + result + end +.,., module_eval(<<'.,.,', 'parser.y', 54) def _reduce_14(val, _values, result) diff --git a/parser.y b/parser.y index c95f60b7..574510d7 100644 --- a/parser.y +++ b/parser.y @@ -21,7 +21,7 @@ rule { @grammar.prologue = val[2].s_value } - | "%require" STRING + | "%require" STRING { warn '%require is provided for compatibility with Bison and can be removed after migration to Lrama.' } bison_declaration: grammar_declaration | "%expect" INTEGER { @grammar.expect = val[1] } diff --git a/spec/fixtures/common/basic.y b/spec/fixtures/common/basic.y index c38b7b10..4b4f87c4 100644 --- a/spec/fixtures/common/basic.y +++ b/spec/fixtures/common/basic.y @@ -2,8 +2,6 @@ * This is comment for this file. */ -%require "3.0" - %{ // Prologue %} diff --git a/spec/fixtures/common/nullable.y b/spec/fixtures/common/nullable.y index 4ffcf1aa..2b92d6bd 100644 --- a/spec/fixtures/common/nullable.y +++ b/spec/fixtures/common/nullable.y @@ -2,8 +2,6 @@ * This is comment for this file. */ -%require "3.0" - %{ // Prologue %} diff --git a/spec/fixtures/context/basic.y b/spec/fixtures/context/basic.y index 31f5f701..e08eef19 100644 --- a/spec/fixtures/context/basic.y +++ b/spec/fixtures/context/basic.y @@ -2,8 +2,6 @@ * This is comment for this file. */ -%require "3.0" - %{ // Prologue %} diff --git a/spec/lrama/context_spec.rb b/spec/lrama/context_spec.rb index 027d204c..74edaae7 100644 --- a/spec/lrama/context_spec.rb +++ b/spec/lrama/context_spec.rb @@ -98,8 +98,8 @@ expect(context.yytname[context.yytranslate[11]]).to eq("\"escaped vertical tab\"") expect(context.yytname[context.yytranslate[258]]).to eq("keyword_class") expect(context.yyrline).to eq([ - 0, 64, 64, 65, 66, 69, 71, 71, 74, 77, - 78, 81, 84, 87 + 0, 62, 62, 63, 64, 67, 69, 69, 72, 75, + 76, 79, 82, 85 ]) expect(context.yytname).to eq([ "\"EOI\"", "error", "\"invalid token\"", "\"backslash\"", diff --git a/spec/lrama/lexer_spec.rb b/spec/lrama/lexer_spec.rb index f0037567..d02d850e 100644 --- a/spec/lrama/lexer_spec.rb +++ b/spec/lrama/lexer_spec.rb @@ -11,15 +11,13 @@ grammar_file = Lrama::Lexer::GrammarFile.new(path, text) lexer = Lrama::Lexer.new(grammar_file) - expect(lexer.next_token).to eq(['%require', '%require']) - expect(lexer.next_token).to eq([:STRING, '"3.0"']) expect(lexer.next_token).to eq(['%{', '%{']) lexer.status = :c_declaration lexer.end_symbol = '%}' token = lexer.next_token expect(token).to eq([:C_DECLARATION, token_class::UserCode.new(s_value: "\n// Prologue\n")]) - expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 7, first_column: 2, last_line: 9, last_column: 0) + expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 5, first_column: 2, last_line: 7, last_column: 0) lexer.status = :initial expect(lexer.next_token).to eq(['%}', '%}']) @@ -37,7 +35,7 @@ lexer.end_symbol = '}' token = lexer.next_token expect(token).to eq([:C_DECLARATION, token_class::UserCode.new(s_value: "\n print_int();\n")]) - expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 15, first_column: 10, last_line: 17, last_column: 0) + expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 13, first_column: 10, last_line: 15, last_column: 0) lexer.status = :initial expect(lexer.next_token).to eq(['}', '}']) @@ -49,7 +47,7 @@ lexer.end_symbol = '}' token = lexer.next_token expect(token).to eq([:C_DECLARATION, token_class::UserCode.new(s_value: "\n print_token();\n")]) - expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 18, first_column: 10, last_line: 20, last_column: 0) + expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 16, first_column: 10, last_line: 18, last_column: 0) lexer.status = :initial expect(lexer.next_token).to eq(['}', '}']) @@ -62,7 +60,7 @@ lexer.end_symbol = '}' token = lexer.next_token expect(token).to eq([:C_DECLARATION, token_class::UserCode.new(s_value: 'struct lex_params *p')]) - expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 22, first_column: 12, last_line: 22, last_column: 32) + expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 20, first_column: 12, last_line: 20, last_column: 32) lexer.status = :initial expect(lexer.next_token).to eq(['}', '}']) @@ -73,7 +71,7 @@ lexer.end_symbol = '}' token = lexer.next_token expect(token).to eq([:C_DECLARATION, token_class::UserCode.new(s_value: 'struct parse_params *p')]) - expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 23, first_column: 14, last_line: 23, last_column: 36) + expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 21, first_column: 14, last_line: 21, last_column: 36) lexer.status = :initial expect(lexer.next_token).to eq(['}', '}']) @@ -84,7 +82,7 @@ lexer.end_symbol = '}' token = lexer.next_token expect(token).to eq([:C_DECLARATION, token_class::UserCode.new(s_value: "\n initial_action_func(@$);\n")]) - expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 26, first_column: 1, last_line: 28, last_column: 0) + expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 24, first_column: 1, last_line: 26, last_column: 0) lexer.status = :initial expect(lexer.next_token).to eq(['}', '}']) @@ -96,7 +94,7 @@ lexer.end_symbol = '}' token = lexer.next_token expect(token).to eq([:C_DECLARATION, token_class::UserCode.new(s_value: "\n int i;\n long l;\n char *str;\n")]) - expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 30, first_column: 8, last_line: 34, last_column: 0) + expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 28, first_column: 8, last_line: 32, last_column: 0) lexer.status = :initial expect(lexer.next_token).to eq(['}', '}']) @@ -175,7 +173,7 @@ lexer.end_symbol = '}' token = lexer.next_token expect(token).to eq([:C_DECLARATION, token_class::UserCode.new(s_value: " code 1 ")]) - expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 63, first_column: 11, last_line: 63, last_column: 19) + expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 61, first_column: 11, last_line: 61, last_column: 19) lexer.status = :initial expect(lexer.next_token).to eq(['}', '}']) @@ -187,7 +185,7 @@ lexer.end_symbol = '}' token = lexer.next_token expect(token).to eq([:C_DECLARATION, token_class::UserCode.new(s_value: " code 2 ")]) - expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 64, first_column: 23, last_line: 64, last_column: 31) + expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 62, first_column: 23, last_line: 62, last_column: 31) lexer.status = :initial expect(lexer.next_token).to eq(['}', '}']) @@ -200,7 +198,7 @@ lexer.end_symbol = '}' token = lexer.next_token expect(token).to eq([:C_DECLARATION, token_class::UserCode.new(s_value: " code 3 ")]) - expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 64, first_column: 58, last_line: 64, last_column: 66) + expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 62, first_column: 58, last_line: 62, last_column: 66) lexer.status = :initial expect(lexer.next_token).to eq(['}', '}']) @@ -214,7 +212,7 @@ lexer.end_symbol = '}' token = lexer.next_token expect(token).to eq([:C_DECLARATION, token_class::UserCode.new(s_value: " code 4 ")]) - expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 65, first_column: 23, last_line: 65, last_column: 31) + expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 63, first_column: 23, last_line: 63, last_column: 31) lexer.status = :initial expect(lexer.next_token).to eq(['}', '}']) @@ -227,7 +225,7 @@ lexer.end_symbol = '}' token = lexer.next_token expect(token).to eq([:C_DECLARATION, token_class::UserCode.new(s_value: " code 5 ")]) - expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 65, first_column: 58, last_line: 65, last_column: 66) + expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 63, first_column: 58, last_line: 63, last_column: 66) lexer.status = :initial expect(lexer.next_token).to eq(['}', '}']) @@ -273,15 +271,13 @@ grammar_file = Lrama::Lexer::GrammarFile.new(path, text) lexer = Lrama::Lexer.new(grammar_file) - expect(lexer.next_token).to eq(['%require', '%require']) - expect(lexer.next_token).to eq([:STRING, '"3.0"']) expect(lexer.next_token).to eq(['%{', '%{']) lexer.status = :c_declaration lexer.end_symbol = '%}' token = lexer.next_token expect(token).to eq([:C_DECLARATION, token_class::UserCode.new(s_value: "\n// Prologue\n")]) - expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 7, first_column: 2, last_line: 9, last_column: 0) + expect(token[1].location).to eq Lrama::Lexer::Location.new(grammar_file: grammar_file, first_line: 5, first_column: 2, last_line: 7, last_column: 0) lexer.status = :initial expect(lexer.next_token).to eq(['%}', '%}']) diff --git a/spec/lrama/parser_spec.rb b/spec/lrama/parser_spec.rb index 8b14ee5f..5e7a7da4 100644 --- a/spec/lrama/parser_spec.rb +++ b/spec/lrama/parser_spec.rb @@ -63,12 +63,12 @@ Printer.new( ident_or_tags: [T::Tag.new(s_value: "")], token_code: T::UserCode.new(s_value: "\n print_int();\n"), - lineno: 15 + lineno: 13 ), Printer.new( ident_or_tags: [T::Ident.new(s_value: "tNUMBER"), T::Ident.new(s_value: "tSTRING")], token_code: T::UserCode.new(s_value: "\n print_token();\n"), - lineno: 18 + lineno: 16 ), ]) expect(grammar.lex_param).to eq("struct lex_params *p") @@ -117,7 +117,7 @@ [ T::Ident.new(s_value: "class"), ], - 57, + 55, ], [ T::Ident.new(s_value: "program"), @@ -125,7 +125,7 @@ T::Char.new(s_value: "'+'"), T::Ident.new(s_value: "strings_1"), ], - 58, + 56, ], [ T::Ident.new(s_value: "program"), @@ -133,7 +133,7 @@ T::Char.new(s_value: "'-'"), T::Ident.new(s_value: "strings_2"), ], - 59, + 57, ], [ T::Ident.new(s_value: "class"), @@ -144,7 +144,7 @@ grammar.find_symbol_by_s_value!("tPLUS"), T::UserCode.new(s_value: " code 1 "), ], - 62, + 60, ], [ T::Ident.new(s_value: "class"), @@ -157,7 +157,7 @@ T::UserCode.new(s_value: " code 3 "), grammar.find_symbol_by_s_value!("tEQ"), ], - 64, + 62, ], [ T::Ident.new(s_value: "class"), @@ -170,35 +170,35 @@ T::UserCode.new(s_value: " code 5 "), grammar.find_symbol_by_s_value!("'>'"), ], - 65, + 63, ], [ T::Ident.new(s_value: "strings_1"), [ T::Ident.new(s_value: "string_1"), ], - 68, + 66, ], [ T::Ident.new(s_value: "strings_2"), [ T::Ident.new(s_value: "string_1"), ], - 71, + 69, ], [ T::Ident.new(s_value: "strings_2"), [ T::Ident.new(s_value: "string_2"), ], - 72, + 70, ], [ T::Ident.new(s_value: "string_1"), [ T::Ident.new(s_value: "string"), ], - 75, + 73, ], [ T::Ident.new(s_value: "string_2"), @@ -206,21 +206,21 @@ T::Ident.new(s_value: "string"), T::Char.new(s_value: "'+'"), ], - 78, + 76, ], [ T::Ident.new(s_value: "string"), [ T::Ident.new(s_value: "tSTRING") ], - 81, + 79, ], [ T::Ident.new(s_value: "unused"), [ T::Ident.new(s_value: "tNUMBER") ], - 84, + 82, ], ]) expect(grammar.rules).to eq([ @@ -234,7 +234,7 @@ token_code: nil, nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("EOI"), - lineno: 57, + lineno: 55, ), Rule.new( id: 1, @@ -245,7 +245,7 @@ token_code: nil, nullable: false, precedence_sym: nil, - lineno: 57, + lineno: 55, ), Rule.new( id: 2, @@ -257,7 +257,7 @@ token_code: nil, nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("'+'"), - lineno: 58, + lineno: 56, ), Rule.new( id: 3, @@ -269,7 +269,7 @@ token_code: nil, nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("'-'"), - lineno: 59, + lineno: 57, ), Rule.new( id: 4, @@ -282,7 +282,7 @@ token_code: T::UserCode.new(s_value: " code 1 "), nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("tPLUS"), - lineno: 62, + lineno: 60, ), Rule.new( id: 5, @@ -292,7 +292,7 @@ position_in_original_rule_rhs: 1, nullable: true, precedence_sym: nil, - lineno: 64, + lineno: 62, ), Rule.new( id: 6, @@ -302,7 +302,7 @@ position_in_original_rule_rhs: 5, nullable: true, precedence_sym: nil, - lineno: 64, + lineno: 62, ), Rule.new( id: 7, @@ -318,7 +318,7 @@ token_code: nil, nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("tEQ"), - lineno: 64, + lineno: 62, ), Rule.new( id: 8, @@ -328,7 +328,7 @@ position_in_original_rule_rhs: 1, nullable: true, precedence_sym: nil, - lineno: 65, + lineno: 63, ), Rule.new( id: 9, @@ -338,7 +338,7 @@ position_in_original_rule_rhs: 5, nullable: true, precedence_sym: nil, - lineno: 65, + lineno: 63, ), Rule.new( id: 10, @@ -354,7 +354,7 @@ token_code: nil, nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("'>'"), - lineno: 65, + lineno: 63, ), Rule.new( id: 11, @@ -365,7 +365,7 @@ token_code: nil, nullable: false, precedence_sym: nil, - lineno: 68, + lineno: 66, ), Rule.new( id: 12, @@ -376,7 +376,7 @@ token_code: nil, nullable: false, precedence_sym: nil, - lineno: 71, + lineno: 69, ), Rule.new( id: 13, @@ -387,7 +387,7 @@ token_code: nil, nullable: false, precedence_sym: nil, - lineno: 72, + lineno: 70, ), Rule.new( id: 14, @@ -398,7 +398,7 @@ token_code: nil, nullable: false, precedence_sym: nil, - lineno: 75, + lineno: 73, ), Rule.new( id: 15, @@ -410,7 +410,7 @@ token_code: nil, nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("'+'"), - lineno: 78, + lineno: 76, ), Rule.new( id: 16, @@ -421,7 +421,7 @@ token_code: nil, nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("tSTRING"), - lineno: 81, + lineno: 79, ), Rule.new( id: 17, @@ -432,7 +432,7 @@ token_code: nil, nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("tNUMBER"), - lineno: 84, + lineno: 82, ), ]) end @@ -464,7 +464,7 @@ token_code: nil, nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("YYEOF"), - lineno: 15, + lineno: 13, ), Rule.new( id: 1, @@ -475,7 +475,7 @@ token_code: nil, nullable: true, precedence_sym: nil, - lineno: 15, + lineno: 13, ), Rule.new( id: 2, @@ -487,7 +487,7 @@ token_code: nil, nullable: false, precedence_sym: nil, - lineno: 17, + lineno: 15, ), Rule.new( id: 3, @@ -499,7 +499,7 @@ token_code: nil, nullable: true, precedence_sym: nil, - lineno: 18, + lineno: 16, ), Rule.new( id: 4, @@ -508,7 +508,7 @@ token_code: nil, nullable: true, precedence_sym: nil, - lineno: 19, + lineno: 17, ), Rule.new( id: 5, @@ -519,7 +519,7 @@ token_code: nil, nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("tNUMBER"), - lineno: 22, + lineno: 20, ), Rule.new( id: 6, @@ -528,7 +528,7 @@ token_code: nil, nullable: true, precedence_sym: nil, - lineno: 24, + lineno: 22, ), Rule.new( id: 7, @@ -539,7 +539,7 @@ token_code: nil, nullable: false, precedence_sym: nil, - lineno: 25, + lineno: 23, ), Rule.new( id: 8, @@ -548,7 +548,7 @@ token_code: nil, nullable: true, precedence_sym: nil, - lineno: 28, + lineno: 26, ), Rule.new( id: 9, @@ -559,7 +559,7 @@ token_code: nil, nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("';'"), - lineno: 29, + lineno: 27, ), Rule.new( id: 10, @@ -568,7 +568,7 @@ token_code: nil, nullable: true, precedence_sym: nil, - lineno: 32, + lineno: 30, ), Rule.new( id: 11, @@ -579,7 +579,7 @@ token_code: nil, nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("'.'"), - lineno: 33, + lineno: 31, ), ]) end @@ -3711,6 +3711,30 @@ class : keyword_class tSTRING keyword_end { code 1 } end end end + + describe "%require" do + it "can parse and show warning" do + y = <<~INPUT + %{ + // Prologue + %} + + %require "3.0" + + %% + + program: /* empty */ + ; + INPUT + original_stderr = $stderr + $stderr = StringIO.new + grammar = Lrama::Parser.new(y, "parse.y").parse + grammar.prepare + grammar.validate! + expect($stderr.string).to eq("%require is provided for compatibility with Bison and can be removed after migration to Lrama.\n") + $stderr = original_stderr + end + end end describe "#fill_symbol_number" do