parser.y in lrama-0.5.12 vs parser.y in lrama-0.6.0

- old
+ new

@@ -27,10 +27,11 @@ bison_declarations: /* empty */ { result = "" } | bison_declarations bison_declaration bison_declaration: grammar_declaration + | rule_declaration | "%expect" INTEGER { @grammar.expect = val[1] } | "%define" variable value | "%param" params | "%lex-param" params { @@ -200,10 +201,89 @@ token_declaration_list: token_declaration { result = [val[0]] } | token_declaration_list token_declaration { result = val[0].append(val[1]) } token_declaration: id int_opt alias { result = val } + rule_declaration: "%rule" IDENTIFIER "(" rule_args ")" ":" rule_rhs_list + { + builder = Grammar::ParameterizingRuleBuilder.new(val[1].s_value, val[3], val[6]) + @grammar.add_parameterizing_rule_builder(builder) + } + + rule_args: IDENTIFIER { result = [val[0]] } + | rule_args "," IDENTIFIER { result = val[0].append(val[2]) } + + rule_rhs_list: rule_rhs + { + builder = val[0] + result = [builder] + } + | rule_rhs_list "|" rule_rhs + { + builder = val[2] + result = val[0].append(builder) + } + + rule_rhs: /* empty */ + { + reset_precs + result = Grammar::ParameterizingRuleRhsBuilder.new + } + | "%empty" + { + reset_precs + result = Grammar::ParameterizingRuleRhsBuilder.new + } + | rule_rhs symbol named_ref_opt + { + token = val[1] + token.alias_name = val[2] + builder = val[0] + builder.symbols << token + result = builder + } + | rule_rhs IDENTIFIER parameterizing_suffix + { + builder = val[0] + builder.symbols << Lrama::Lexer::Token::InstantiateRule.new(s_value: val[2], location: @lexer.location, args: [val[1]]) + result = builder + } + | rule_rhs IDENTIFIER "(" parameterizing_args ")" + { + builder = val[0] + builder.symbols << Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, location: @lexer.location, args: val[3]) + result = builder + } + | rule_rhs "{" + { + if @prec_seen + on_action_error("multiple User_code after %prec", val[0]) if @code_after_prec + @code_after_prec = true + end + begin_c_declaration("}") + } + C_DECLARATION + { + end_c_declaration + } + "}" named_ref_opt + { + user_code = val[3] + user_code.alias_name = val[6] + builder = val[0] + builder.user_code = user_code + result = builder + } + | rule_rhs "%prec" symbol + { + sym = @grammar.find_symbol_by_id!(val[2]) + @prec_seen = true + builder = val[0] + builder.precedence_sym = sym + result = builder + } + int_opt: # empty | INTEGER alias: # empty | STRING # TODO: change this to string_as_id @@ -324,22 +404,22 @@ token.alias_name = val[2] builder = val[0] builder.add_rhs(token) result = builder } - | rhs IDENTIFIER parameterizing_suffix tag_opt + | rhs symbol parameterizing_suffix tag_opt { - token = Lrama::Lexer::Token::Parameterizing.new(s_value: val[2], location: @lexer.location, args: [val[1]]) + token = Lrama::Lexer::Token::InstantiateRule.new(s_value: val[2], location: @lexer.location, args: [val[1]]) builder = val[0] builder.add_rhs(token) builder.lhs_tag = val[3] builder.line = val[1].first_line result = builder } | rhs IDENTIFIER "(" parameterizing_args ")" tag_opt { - token = Lrama::Lexer::Token::Parameterizing.new(s_value: val[1].s_value, location: @lexer.location, args: val[3]) + token = Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, location: @lexer.location, args: val[3]) builder = val[0] builder.add_rhs(token) builder.lhs_tag = val[5] builder.line = val[1].first_line result = builder @@ -419,20 +499,19 @@ ---- inner include Lrama::Report::Duration def initialize(text, path, debug = false) - @text = text - @path = path + @grammar_file = Lrama::Lexer::GrammarFile.new(path, text) @yydebug = debug @rule_counter = Lrama::Grammar::Counter.new(0) @midrule_action_counter = Lrama::Grammar::Counter.new(1) end def parse report_duration(:parse) do - @lexer = Lrama::Lexer.new(@text) + @lexer = Lrama::Lexer.new(@grammar_file) @grammar = Lrama::Grammar.new(@rule_counter) @precedence_number = 0 reset_precs do_parse @grammar.prepare @@ -445,44 +524,30 @@ @lexer.next_token end def on_error(error_token_id, error_value, value_stack) if error_value.is_a?(Lrama::Lexer::Token) - line = error_value.first_line - first_column = error_value.first_column - last_column = error_value.last_column + location = error_value.location value = "'#{error_value.s_value}'" else - line = @lexer.line - first_column = @lexer.head_column - last_column = @lexer.column + location = @lexer.location value = error_value.inspect end - raise ParseError, <<~ERROR - #{@path}:#{line}:#{first_column}: parse error on value #{value} (#{token_to_str(error_token_id) || '?'}) - #{@text.split("\n")[line - 1]} - #{carrets(first_column, last_column)} - ERROR + error_message = "parse error on value #{value} (#{token_to_str(error_token_id) || '?'})" + + raise_parse_error(error_message, location) end def on_action_error(error_message, error_value) if error_value.is_a?(Lrama::Lexer::Token) - line = error_value.first_line - first_column = error_value.first_column - last_column = error_value.last_column + location = error_value.location else - line = @lexer.line - first_column = @lexer.head_column - last_column = @lexer.column + location = @lexer.location end - raise ParseError, <<~ERROR - #{@path}:#{line}: #{error_message} - #{@text.split("\n")[line - 1]} - #{carrets(first_column, last_column)} - ERROR + raise_parse_error(error_message, location) end private def reset_precs @@ -498,8 +563,8 @@ def end_c_declaration @lexer.status = :initial @lexer.end_symbol = nil end -def carrets(first_column, last_column) - ' ' * (first_column + 1) + '^' * (last_column - first_column) +def raise_parse_error(error_message, location) + raise ParseError, location.generate_error_message(error_message) end