From 3684a27209a2eec29eead007347a1d495dbb9edd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 1 Apr 2025 11:35:49 +0900 Subject: [PATCH] tools/lrama: update to lrama 0.7.0; close #6384 --- tools/lrama/NEWS.md | 377 +++- tools/lrama/exe/lrama | 1 + tools/lrama/lib/lrama.rb | 39 +- tools/lrama/lib/lrama/bitmap.rb | 7 +- tools/lrama/lib/lrama/command.rb | 25 +- tools/lrama/lib/lrama/context.rb | 20 +- tools/lrama/lib/lrama/counterexamples.rb | 60 +- .../lib/lrama/counterexamples/derivation.rb | 13 +- .../lib/lrama/counterexamples/example.rb | 13 +- tools/lrama/lib/lrama/counterexamples/path.rb | 6 + .../lrama/counterexamples/production_path.rb | 2 + .../lib/lrama/counterexamples/start_path.rb | 2 + .../lib/lrama/counterexamples/state_item.rb | 2 + .../lrama/counterexamples/transition_path.rb | 2 + .../lrama/lib/lrama/counterexamples/triple.rb | 2 + tools/lrama/lib/lrama/diagnostics.rb | 36 + tools/lrama/lib/lrama/digraph.rb | 32 + tools/lrama/lib/lrama/grammar.rb | 92 +- tools/lrama/lib/lrama/grammar/auxiliary.rb | 2 + tools/lrama/lib/lrama/grammar/binding.rb | 63 +- tools/lrama/lib/lrama/grammar/code.rb | 12 +- .../lib/lrama/grammar/code/destructor_code.rb | 2 + .../lrama/grammar/code/initial_action_code.rb | 2 + .../lrama/grammar/code/no_reference_code.rb | 2 + .../lib/lrama/grammar/code/printer_code.rb | 2 + .../lib/lrama/grammar/code/rule_action.rb | 10 +- tools/lrama/lib/lrama/grammar/counter.rb | 2 + tools/lrama/lib/lrama/grammar/destructor.rb | 2 + tools/lrama/lib/lrama/grammar/error_token.rb | 2 + .../lib/lrama/grammar/parameterizing_rule.rb | 2 + .../grammar/parameterizing_rule/resolver.rb | 8 +- .../lrama/grammar/parameterizing_rule/rhs.rb | 9 +- .../lrama/grammar/parameterizing_rule/rule.rb | 6 + tools/lrama/lib/lrama/grammar/percent_code.rb | 2 + tools/lrama/lib/lrama/grammar/precedence.rb | 2 + tools/lrama/lib/lrama/grammar/printer.rb | 2 + tools/lrama/lib/lrama/grammar/reference.rb | 2 + tools/lrama/lib/lrama/grammar/rule.rb | 21 +- tools/lrama/lib/lrama/grammar/rule_builder.rb | 145 +- tools/lrama/lib/lrama/grammar/symbol.rb | 2 + tools/lrama/lib/lrama/grammar/symbols.rb | 2 + .../lib/lrama/grammar/symbols/resolver.rb | 10 +- tools/lrama/lib/lrama/grammar/type.rb | 2 + tools/lrama/lib/lrama/grammar/union.rb | 2 + tools/lrama/lib/lrama/grammar_validator.rb | 37 + tools/lrama/lib/lrama/lexer.rb | 29 +- tools/lrama/lib/lrama/lexer/grammar_file.rb | 11 +- tools/lrama/lib/lrama/lexer/location.rb | 20 +- tools/lrama/lib/lrama/lexer/token.rb | 28 +- tools/lrama/lib/lrama/lexer/token/char.rb | 3 + tools/lrama/lib/lrama/lexer/token/ident.rb | 3 + .../lib/lrama/lexer/token/instantiate_rule.rb | 9 +- tools/lrama/lib/lrama/lexer/token/tag.rb | 6 +- .../lrama/lib/lrama/lexer/token/user_code.rb | 12 +- .../lrama/lib/lrama/{warning.rb => logger.rb} | 22 +- tools/lrama/lib/lrama/option_parser.rb | 99 +- tools/lrama/lib/lrama/options.rb | 8 +- tools/lrama/lib/lrama/output.rb | 107 +- tools/lrama/lib/lrama/parser.rb | 1590 ++++++++--------- tools/lrama/lib/lrama/report.rb | 6 +- tools/lrama/lib/lrama/report/duration.rb | 2 + tools/lrama/lib/lrama/report/profile.rb | 2 + tools/lrama/lib/lrama/state.rb | 301 +++- tools/lrama/lib/lrama/state/reduce.rb | 6 +- .../lib/lrama/state/reduce_reduce_conflict.rb | 2 + .../lib/lrama/state/resolved_conflict.rb | 4 +- tools/lrama/lib/lrama/state/shift.rb | 2 + .../lib/lrama/state/shift_reduce_conflict.rb | 2 + tools/lrama/lib/lrama/states.rb | 123 +- tools/lrama/lib/lrama/states/item.rb | 16 +- tools/lrama/lib/lrama/states_reporter.rb | 79 +- tools/lrama/lib/lrama/trace_reporter.rb | 45 + tools/lrama/lib/lrama/version.rb | 4 +- tools/lrama/template/bison/yacc.c | 45 +- 74 files changed, 2345 insertions(+), 1327 deletions(-) create mode 100644 tools/lrama/lib/lrama/diagnostics.rb create mode 100644 tools/lrama/lib/lrama/grammar_validator.rb rename tools/lrama/lib/lrama/{warning.rb => logger.rb} (52%) create mode 100644 tools/lrama/lib/lrama/trace_reporter.rb diff --git a/tools/lrama/NEWS.md b/tools/lrama/NEWS.md index e652091ae..dcf40b50b 100644 --- a/tools/lrama/NEWS.md +++ b/tools/lrama/NEWS.md @@ -1,12 +1,327 @@ # NEWS for Lrama +## Lrama 0.7.0 (2025-01-21) + +## [EXPERIMENTAL] Support the generation of the IELR(1) parser described in this paper + +Support the generation of the IELR(1) parser described in this paper. +https://www.sciencedirect.com/science/article/pii/S0167642309001191 + +If you use IELR(1) parser, you can write the following directive in your grammar file. + +```yacc +%define lr.type ielr +``` + +But, currently IELR(1) parser is experimental feature. If you find any bugs, please report it to us. Thank you. + +## Support `-t` option as same as `--debug` option + +Support to `-t` option as same as `--debug` option. +These options align with Bison behavior. So same as `--debug` option. + +## Trace only explicit rules + +Support to trace only explicit rules. +If you use `--trace=rules` option, it shows include mid-rule actions. If you want to show only explicit rules, you can use `--trace=only-explicit-rules` option. + +Example: + +```yacc +%{ +%} +%union { + int i; +} +%token number +%type program +%% +program : number { printf("%d", $1); } number { $$ = $1 + $3; } + ; +%% +``` + +Result of `--trace=rules`: + +```console +$ exe/lrama --trace=rules sample.y +Grammar rules: +$accept -> program YYEOF +$@1 -> ε +program -> number $@1 number +``` + +Result of `--trace=only-explicit-rules`: + +```console +$ exe/lrama --trace=explicit-rules sample.y +Grammar rules: +$accept -> program YYEOF +program -> number number +``` + +## Lrama 0.6.11 (2024-12-23) + +### Add support for %type declarations using %nterm in Nonterminal Symbols + +Allow to use `%nterm` in Nonterminal Symbols for `%type` declarations. + +```yacc +%nterm nonterminal… +``` + +This directive is also supported for compatibility with Bison, and only non-terminal symbols are allowed. In other words, definitions like the following will result in an error: + +```yacc +%{ +// Prologue +%} + +%token EOI 0 "EOI" +%nterm EOI + +%% + +program: /* empty */ + ; +``` + +It show an error message like the following: + +```command +❯ exe/lrama nterm.y +nterm.y:6:7: symbol EOI redeclared as a nonterminal +%nterm EOI + ^^^ +``` + +## Lrama 0.6.10 (2024-09-11) + +### Aliased Named References for actions of RHS in parameterizing rules + +Allow to use aliased named references for actions of RHS in parameterizing rules. + +```yacc +%rule sum(X, Y): X[summand] '+' Y[addend] { $$ = $summand + $addend } + ; +``` + +https://github.com/ruby/lrama/pull/410 + +### Named References for actions of RHS in parameterizing rules caller side + +Allow to use named references for actions of RHS in parameterizing rules caller side. + +```yacc +opt_nl: '\n'?[nl] { $$ = $nl; } + ; +``` + +https://github.com/ruby/lrama/pull/414 + +### Widen the definable position of parameterizing rules + +Allow to define parameterizing rules in the middle of the grammar. + +```yacc +%rule defined_option(X): /* empty */ + | X + ; + +%% + +program : defined_option(number) + | defined_list(number) + ; + +%rule defined_list(X): /* empty */ /* <--- here */ + | defined_list(X) number + ; +``` + +https://github.com/ruby/lrama/pull/420 + +### Report unused terminal symbols + +Support to report unused terminal symbols. +Run `exe/lrama --report=terms` to show unused terminal symbols. + +```console +$ exe/lrama --report=terms sample/calc.y + 11 Unused Terms + 0 YYerror + 1 YYUNDEF + 2 '\\\\' + 3 '\\13' + 4 keyword_class2 + 5 tNUMBER + 6 tPLUS + 7 tMINUS + 8 tEQ + 9 tEQEQ + 10 '>' +``` + +https://github.com/ruby/lrama/pull/439 + +### Report unused rules + +Support to report unused rules. +Run `exe/lrama --report=rules` to show unused rules. + +```console +$ exe/lrama --report=rules sample/calc.y + 3 Unused Rules + 0 unused_option + 1 unused_list + 2 unused_nonempty_list +``` + +https://github.com/ruby/lrama/pull/441 + +### Ensure compatibility with Bison for `%locations` directive + +Support `%locations` directive to ensure compatibility with Bison. +Change to `%locations` directive not set by default. + +https://github.com/ruby/lrama/pull/446 + +### Diagnostics report for parameterizing rules redefine + +Support to warning redefined parameterizing rules. +Run `exe/lrama -W` or `exe/lrama --warnings` to show redefined parameterizing rules. + +```console +$ exe/lrama -W sample/calc.y +parameterizing rule redefined: redefined_method(X) +parameterizing rule redefined: redefined_method(X) +``` + +https://github.com/ruby/lrama/pull/448 + +### Support `-v` and `--verbose` option + +Support to `-v` and `--verbose` option. +These options align with Bison behavior. So same as '--report=state' option. + +https://github.com/ruby/lrama/pull/457 + +## Lrama 0.6.9 (2024-05-02) + +### Callee side tag specification of parameterizing rules + +Allow to specify tag on callee side of parameterizing rules. + +```yacc +%union { + int i; +} + +%rule with_tag(X) : X { $$ = $1; } + ; +``` + +### Named References for actions of RHS in parameterizing rules + +Allow to use named references for actions of RHS in parameterizing rules. + +```yacc +%rule option(number): /* empty */ + | number { $$ = $number; } + ; +``` + +## Lrama 0.6.8 (2024-04-29) + +### Nested parameterizing rules with tag + +Allow to nested parameterizing rules with tag. + +```yacc +%union { + int i; +} + +%rule nested_nested_option(X): /* empty */ + | X + ; + +%rule nested_option(X): /* empty */ + | nested_nested_option(X) + ; + +%rule option(Y): /* empty */ + | nested_option(Y) + ; +``` + +## Lrama 0.6.7 (2024-04-28) + +### RHS of user defined parameterizing rules contains `'symbol'?`, `'symbol'+` and `'symbol'*`. + +User can use `'symbol'?`, `'symbol'+` and `'symbol'*` in RHS of user defined parameterizing rules. + +``` +%rule with_word_seps(X): /* empty */ + | X ' '+ + ; +``` + +## Lrama 0.6.6 (2024-04-27) + +### Trace actions + +Support trace actions for debugging. +Run `exe/lrama --trace=actions` to show grammar rules with actions. + +```console +$ exe/lrama --trace=actions sample/calc.y +Grammar rules with actions: +$accept -> list, YYEOF {} +list -> ε {} +list -> list, LF {} +list -> list, expr, LF { printf("=> %d\n", $2); } +expr -> NUM {} +expr -> expr, '+', expr { $$ = $1 + $3; } +expr -> expr, '-', expr { $$ = $1 - $3; } +expr -> expr, '*', expr { $$ = $1 * $3; } +expr -> expr, '/', expr { $$ = $1 / $3; } +expr -> '(', expr, ')' { $$ = $2; } +``` + +### Inlining + +Support inlining for rules. +The `%inline` directive causes all references to symbols to be replaced with its definition. + +```yacc +%rule %inline op: PLUS { + } + | TIMES { * } + ; + +%% + +expr : number { $$ = $1; } + | expr op expr { $$ = $1 $2 $3; } + ; +``` + +as same as + +```yacc +expr : number { $$ = $1; } + | expr '+' expr { $$ = $1 + $3; } + | expr '*' expr { $$ = $1 * $3; } + ; +``` + ## Lrama 0.6.5 (2024-03-25) ### Typed Midrule Actions User can specify the type of mid rule action by tag (``) instead of specifying it with in an action. -``` +```yacc primary: k_case expr_value terms? { $$ = p->case_labels; @@ -21,7 +336,7 @@ primary: k_case expr_value terms? can be written as -``` +```yacc primary: k_case expr_value terms? { $$ = p->case_labels; @@ -46,7 +361,7 @@ Bison supports this feature from 3.1. Support `preceded`, `terminated` and `delimited` rules. -``` +```text program: preceded(opening, X) // Expanded to @@ -73,7 +388,7 @@ program: delimited_opening_X_closing delimited_opening_X_closing: opening X closing ``` - +https://github.com/ruby/lrama/pull/382 ### Support `%destructor` declaration @@ -82,7 +397,7 @@ In general, these resources are freed by actions or after parsing. However if syntax error happens in parsing, these codes may not be executed. Codes associated to `%destructor` are executed when semantic value is popped from the stack by an error. -``` +```yacc %token NUM %type expr2 %type expr @@ -102,7 +417,7 @@ Codes associated to `%destructor` are executed when semantic value is popped fro Bison supports this feature from 1.75b. - +https://github.com/ruby/lrama/pull/385 ## Lrama 0.6.3 (2024-02-15) @@ -130,7 +445,7 @@ Lrama provides these five callbacks. Registered functions are called when each e User also needs to access semantic value of their stack in grammar action. `$:n` provides the way to access to it. `$:n` is translated to the minus index from the top of the stack. For example -``` +```yacc primary: k_if expr_value then compstmt if_tail k_end { /*% ripper: if!($:2, $:4, $:5) %*/ @@ -138,7 +453,7 @@ primary: k_if expr_value then compstmt if_tail k_end } ``` - +https://github.com/ruby/lrama/pull/367 ## Lrama 0.6.2 (2024-01-27) @@ -147,7 +462,7 @@ primary: k_if expr_value then compstmt if_tail k_end If `%no-stdlib` directive is set, Lrama doesn't load Lrama standard library for parameterizing rules, stdlib.y. - +https://github.com/ruby/lrama/pull/344 ## Lrama 0.6.1 (2024-01-13) @@ -155,7 +470,7 @@ parameterizing rules, stdlib.y. Allow to pass an instantiated rule to other parameterizing rules. -``` +```yacc %rule constant(X) : X ; @@ -172,7 +487,7 @@ program : option(constant(number)) // Nested rule Allow to use nested parameterizing rules when define parameterizing rules. -``` +```yacc %rule option(x) : /* empty */ | X ; @@ -191,7 +506,7 @@ program : double_opt(number) %% ``` - +https://github.com/ruby/lrama/pull/337 ## Lrama 0.6.0 (2023-12-25) @@ -199,7 +514,7 @@ program : double_opt(number) Allow to define parameterizing rule by `%rule` directive. -``` +```yacc %rule pair(X, Y): X Y { $$ = $1 + $2; } ; @@ -213,7 +528,7 @@ stmt: pair(ODD, EVEN) ; ``` - +https://github.com/ruby/lrama/pull/285 ## Lrama 0.5.11 (2023-12-02) @@ -222,7 +537,7 @@ stmt: pair(ODD, EVEN) Allow to specify type of rules by specifying tag, `` in below example. Tag is post-modification style. -``` +```yacc %union { int i; } @@ -234,7 +549,7 @@ program : option(number) ; ``` - +https://github.com/ruby/lrama/pull/272 ## Lrama 0.5.10 (2023-11-18) @@ -242,13 +557,13 @@ program : option(number) Support function call style parameterizing rules for `option`, `nonempty_list` and `list`. - +https://github.com/ruby/lrama/pull/197 ### Parameterizing rules (separated_list) Support `separated_list` and `separated_nonempty_list` parameterizing rules. -``` +```text program: separated_list(',', number) // Expanded to @@ -270,7 +585,7 @@ separated_nonempty_list_number: number separated_nonempty_list_number: separated_nonempty_list_number ',' number ``` - +https://github.com/ruby/lrama/pull/204 ## Lrama 0.5.9 (2023-11-05) @@ -279,7 +594,7 @@ separated_nonempty_list_number: separated_nonempty_list_number ',' number Parameterizing rules are template of rules. It's very common pattern to write "list" grammar rule like: -``` +```yacc opt_args: /* none */ | args ; @@ -294,18 +609,18 @@ Lrama supports these suffixes: - `+`: nonempty list - `*`: list -Idea of Parameterizing rules comes from Menhir LR(1) parser generator (). +Idea of Parameterizing rules comes from Menhir LR(1) parser generator (https://gallium.inria.fr/~fpottier/menhir/manual.html#sec32). - +https://github.com/ruby/lrama/pull/181 ## Lrama 0.5.7 (2023-10-23) ### Racc parser Replace Lrama's parser from hand written parser to LR parser generated by Racc. -Lrama uses `--embedded` option to generate LR parser because Racc is changed from default gem to bundled gem by Ruby 3.3 (). +Lrama uses `--embedded` option to generate LR parser because Racc is changed from default gem to bundled gem by Ruby 3.3 (https://github.com/ruby/lrama/pull/132). - +https://github.com/ruby/lrama/pull/62 ## Lrama 0.5.4 (2023-08-17) @@ -316,7 +631,7 @@ Make error recovery function configurable on runtime by two new macros. - `YYMAXREPAIR`: Expected to return max length of repair operations. `%parse-param` is passed to this function. - `YYERROR_RECOVERY_ENABLED`: Expected to return bool value to determine error recovery is enabled or not. `%parse-param` is passed to this function. - +https://github.com/ruby/lrama/pull/74 ## Lrama 0.5.3 (2023-08-05) @@ -325,7 +640,7 @@ Make error recovery function configurable on runtime by two new macros. Support token insert base Error Recovery. `-e` option is needed to generate parser with error recovery functions. - +https://github.com/ruby/lrama/pull/44 ## Lrama 0.5.2 (2023-06-14) @@ -334,7 +649,7 @@ Support token insert base Error Recovery. Instead of positional references like `$1` or `$$`, named references allow to access to symbol by name. -``` +```yacc primary: k_class cpath superclass bodystmt k_end { $primary = new_class($cpath, $bodystmt, $superclass); @@ -343,7 +658,7 @@ primary: k_class cpath superclass bodystmt k_end Alias name can be declared. -``` +```yacc expr[result]: expr[ex-left] '+' expr[ex.right] { $result = $[ex-left] + $[ex.right]; @@ -363,9 +678,9 @@ Bison supports this feature from 2.5. - `YY_REDUCE_PRINT` - `yysyntax_error` - +https://github.com/ruby/lrama/pull/40 -See also: +See also: https://github.com/ruby/ruby/pull/7807 ## Lrama 0.5.0 (2023-05-17) @@ -373,7 +688,7 @@ See also: When `-` is given as grammar file name, reads the grammar source from STDIN, and takes the next argument as the input file name. This mode helps pre-process a grammar source. - +https://github.com/ruby/lrama/pull/8 ## Lrama 0.4.0 (2023-05-13) diff --git a/tools/lrama/exe/lrama b/tools/lrama/exe/lrama index ba5fb06c8..1aece5d14 100755 --- a/tools/lrama/exe/lrama +++ b/tools/lrama/exe/lrama @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# frozen_string_literal: true $LOAD_PATH << File.join(__dir__, "../lib") require "lrama" diff --git a/tools/lrama/lib/lrama.rb b/tools/lrama/lib/lrama.rb index 9e517b0d7..fe2e05807 100644 --- a/tools/lrama/lib/lrama.rb +++ b/tools/lrama/lib/lrama.rb @@ -1,17 +1,22 @@ -require "lrama/bitmap" -require "lrama/command" -require "lrama/context" -require "lrama/counterexamples" -require "lrama/digraph" -require "lrama/grammar" -require "lrama/lexer" -require "lrama/option_parser" -require "lrama/options" -require "lrama/output" -require "lrama/parser" -require "lrama/report" -require "lrama/state" -require "lrama/states" -require "lrama/states_reporter" -require "lrama/version" -require "lrama/warning" +# frozen_string_literal: true + +require_relative "lrama/bitmap" +require_relative "lrama/command" +require_relative "lrama/context" +require_relative "lrama/counterexamples" +require_relative "lrama/diagnostics" +require_relative "lrama/digraph" +require_relative "lrama/grammar" +require_relative "lrama/grammar_validator" +require_relative "lrama/lexer" +require_relative "lrama/logger" +require_relative "lrama/option_parser" +require_relative "lrama/options" +require_relative "lrama/output" +require_relative "lrama/parser" +require_relative "lrama/report" +require_relative "lrama/state" +require_relative "lrama/states" +require_relative "lrama/states_reporter" +require_relative "lrama/trace_reporter" +require_relative "lrama/version" diff --git a/tools/lrama/lib/lrama/bitmap.rb b/tools/lrama/lib/lrama/bitmap.rb index 8349a23c3..098c6e0b7 100644 --- a/tools/lrama/lib/lrama/bitmap.rb +++ b/tools/lrama/lib/lrama/bitmap.rb @@ -1,5 +1,9 @@ +# rbs_inline: enabled +# frozen_string_literal: true + module Lrama module Bitmap + # @rbs (Array[Integer] ary) -> Integer def self.from_array(ary) bit = 0 @@ -10,8 +14,9 @@ module Lrama bit end + # @rbs (Integer int) -> Array[Integer] def self.to_array(int) - a = [] + a = [] #: Array[Integer] i = 0 while int > 0 do diff --git a/tools/lrama/lib/lrama/command.rb b/tools/lrama/lib/lrama/command.rb index 12fc4fc7e..3ff39d578 100644 --- a/tools/lrama/lib/lrama/command.rb +++ b/tools/lrama/lib/lrama/command.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Command LRAMA_LIB = File.realpath(File.join(File.dirname(__FILE__))) @@ -14,11 +16,10 @@ module Lrama Report::Duration.enable if options.trace_opts[:time] - warning = Lrama::Warning.new text = options.y.read options.y.close if options.y != STDIN begin - grammar = Lrama::Parser.new(text, options.grammar_file, options.debug).parse + grammar = Lrama::Parser.new(text, options.grammar_file, options.debug, options.define).parse unless grammar.no_stdlib stdlib_grammar = Lrama::Parser.new(File.read(STDLIB_FILE_PATH), STDLIB_FILE_PATH, options.debug).parse grammar.insert_before_parameterizing_rules(stdlib_grammar.parameterizing_rules) @@ -31,8 +32,9 @@ module Lrama message = message.gsub(/.+/, "\e[1m\\&\e[m") if Exception.to_tty? abort message end - states = Lrama::States.new(grammar, warning, trace_state: (options.trace_opts[:automaton] || options.trace_opts[:closure])) + states = Lrama::States.new(grammar, trace_state: (options.trace_opts[:automaton] || options.trace_opts[:closure])) states.compute + states.compute_ielr if grammar.ielr_defined? context = Lrama::Context.new(states) if options.report_file @@ -42,15 +44,8 @@ module Lrama end end - if options.trace_opts && options.trace_opts[:rules] - puts "Grammar rules:" - puts grammar.rules - end - - if options.trace_opts && options.trace_opts[:actions] - puts "Grammar rules with actions:" - grammar.rules.each { |rule| puts rule.with_actions } - end + reporter = Lrama::TraceReporter.new(grammar) + reporter.report(**options.trace_opts) File.open(options.outfile, "w+") do |f| Lrama::Output.new( @@ -65,9 +60,9 @@ module Lrama ).render end - if warning.has_error? - exit false - end + logger = Lrama::Logger.new + exit false unless Lrama::GrammarValidator.new(grammar, states, logger).valid? + Lrama::Diagnostics.new(grammar, states, logger).run(options.diagnostic) end end end diff --git a/tools/lrama/lib/lrama/context.rb b/tools/lrama/lib/lrama/context.rb index 32017e65f..9f406f8de 100644 --- a/tools/lrama/lib/lrama/context.rb +++ b/tools/lrama/lib/lrama/context.rb @@ -1,4 +1,6 @@ -require "lrama/report/duration" +# frozen_string_literal: true + +require_relative "report/duration" module Lrama # This is passed to a template @@ -253,7 +255,7 @@ module Lrama # If no default_reduction_rule, default behavior is an # error then replace ErrorActionNumber with zero. - if !state.default_reduction_rule + unless state.default_reduction_rule actions.map! do |e| if e == ErrorActionNumber 0 @@ -301,10 +303,7 @@ module Lrama end @states.nterms.each do |nterm| - if !(states = nterm_to_next_states[nterm]) - default_goto = 0 - not_default_gotos = [] - else + if (states = nterm_to_next_states[nterm]) default_state = states.map(&:last).group_by {|s| s }.max_by {|_, v| v.count }.first default_goto = default_state.id not_default_gotos = [] @@ -312,6 +311,9 @@ module Lrama next if to_state.id == default_goto not_default_gotos << [from_state.id, to_state.id] end + else + default_goto = 0 + not_default_gotos = [] end k = nterm_number_to_sequence_number(nterm.number) @@ -403,7 +405,7 @@ module Lrama @check = [] # Key is froms_and_tos, value is index position pushed = {} - userd_res = {} + used_res = {} lowzero = 0 high = 0 @@ -428,7 +430,7 @@ module Lrama end end - if ok && userd_res[res] + if ok && used_res[res] ok = false end @@ -456,7 +458,7 @@ module Lrama @base[state_id] = res pushed[froms_and_tos] = res - userd_res[res] = true + used_res[res] = true end @yylast = high diff --git a/tools/lrama/lib/lrama/counterexamples.rb b/tools/lrama/lib/lrama/counterexamples.rb index 046265da5..ee2b5d595 100644 --- a/tools/lrama/lib/lrama/counterexamples.rb +++ b/tools/lrama/lib/lrama/counterexamples.rb @@ -1,13 +1,15 @@ +# frozen_string_literal: true + require "set" -require "lrama/counterexamples/derivation" -require "lrama/counterexamples/example" -require "lrama/counterexamples/path" -require "lrama/counterexamples/production_path" -require "lrama/counterexamples/start_path" -require "lrama/counterexamples/state_item" -require "lrama/counterexamples/transition_path" -require "lrama/counterexamples/triple" +require_relative "counterexamples/derivation" +require_relative "counterexamples/example" +require_relative "counterexamples/path" +require_relative "counterexamples/production_path" +require_relative "counterexamples/start_path" +require_relative "counterexamples/state_item" +require_relative "counterexamples/transition_path" +require_relative "counterexamples/triple" module Lrama # See: https://www.cs.cornell.edu/andru/papers/cupex/cupex.pdf @@ -30,8 +32,10 @@ module Lrama conflict_state.conflicts.flat_map do |conflict| case conflict.type when :shift_reduce + # @type var conflict: State::ShiftReduceConflict shift_reduce_example(conflict_state, conflict) when :reduce_reduce + # @type var conflict: State::ReduceReduceConflict reduce_reduce_examples(conflict_state, conflict) end end.compact @@ -46,7 +50,7 @@ module Lrama @reverse_transitions = {} @states.states.each do |src_state| - trans = {} + trans = {} #: Hash[Grammar::Symbol, State] src_state.transitions.each do |shift, next_state| trans[shift.next_sym] = next_state @@ -64,6 +68,7 @@ module Lrama @transitions[[src_state_item, sym]] = dest_state_item + # @type var key: [StateItem, Grammar::Symbol] key = [dest_state_item, sym] @reverse_transitions[key] ||= Set.new @reverse_transitions[key] << src_state_item @@ -80,7 +85,7 @@ module Lrama @states.states.each do |state| # LHS => Set(Item) - h = {} + h = {} #: Hash[Grammar::Symbol, Set[States::Item]] state.closure.each do |item| sym = item.lhs @@ -95,6 +100,7 @@ module Lrama sym = item.next_sym state_item = StateItem.new(state, item) + # @type var key: [State, Grammar::Symbol] key = [state, sym] @productions[state_item] = h[sym] @@ -107,6 +113,7 @@ module Lrama def shift_reduce_example(conflict_state, conflict) conflict_symbol = conflict.symbols.first + # @type var shift_conflict_item: ::Lrama::States::Item shift_conflict_item = conflict_state.items.find { |item| item.next_sym == conflict_symbol } path2 = shortest_path(conflict_state, conflict.reduce.item, conflict_symbol) path1 = find_shift_conflict_shortest_path(path2, conflict_state, shift_conflict_item) @@ -151,12 +158,14 @@ module Lrama prev_state_item = prev_path&.to if target_state_item == state_item || target_state_item.item.start_item? - result.concat(reversed_reduce_path[_j..-1].map(&:to)) + result.concat( + reversed_reduce_path[_j..-1] #: Array[StartPath|TransitionPath|ProductionPath] + .map(&:to)) break end if target_state_item.item.beginning_of_rule? - queue = [] + queue = [] #: Array[Array[StateItem]] queue << [target_state_item] # Find reverse production @@ -171,10 +180,18 @@ module Lrama break end - if !si.item.beginning_of_rule? + if si.item.beginning_of_rule? + # @type var key: [State, Grammar::Symbol] + key = [si.state, si.item.lhs] + @reverse_productions[key].each do |item| + state_item = StateItem.new(si.state, item) + queue << (sis + [state_item]) + end + else + # @type var key: [StateItem, Grammar::Symbol] key = [si, si.item.previous_sym] @reverse_transitions[key].each do |prev_target_state_item| - next if prev_target_state_item.state != prev_state_item.state + next if prev_target_state_item.state != prev_state_item&.state sis.shift result.concat(sis) result << prev_target_state_item @@ -183,19 +200,14 @@ module Lrama queue.clear break end - else - key = [si.state, si.item.lhs] - @reverse_productions[key].each do |item| - state_item = StateItem.new(si.state, item) - queue << (sis + [state_item]) - end end end else # Find reverse transition + # @type var key: [StateItem, Grammar::Symbol] key = [target_state_item, target_state_item.item.previous_sym] @reverse_transitions[key].each do |prev_target_state_item| - next if prev_target_state_item.state != prev_state_item.state + next if prev_target_state_item.state != prev_state_item&.state result << prev_target_state_item target_state_item = prev_target_state_item i = j @@ -222,9 +234,9 @@ module Lrama def shortest_path(conflict_state, conflict_reduce_item, conflict_term) # queue: is an array of [Triple, [Path]] - queue = [] - visited = {} - start_state = @states.states.first + queue = [] #: Array[[Triple, Array[StartPath|TransitionPath|ProductionPath]]] + visited = {} #: Hash[Triple, true] + start_state = @states.states.first #: Lrama::State raise "BUG: Start state should be just one kernel." if start_state.kernels.count != 1 start = Triple.new(start_state, start_state.kernels.first, Set.new([@states.eof_symbol])) diff --git a/tools/lrama/lib/lrama/counterexamples/derivation.rb b/tools/lrama/lib/lrama/counterexamples/derivation.rb index 691e93535..368d7f103 100644 --- a/tools/lrama/lib/lrama/counterexamples/derivation.rb +++ b/tools/lrama/lib/lrama/counterexamples/derivation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Counterexamples class Derivation @@ -16,7 +18,7 @@ module Lrama alias :inspect :to_s def render_strings_for_report - result = [] + result = [] #: Array[String] _render_for_report(self, 0, result, 0) result.map(&:rstrip) end @@ -42,18 +44,19 @@ module Lrama str << "#{item.next_sym.display_name}" length = _render_for_report(derivation.left, len, strings, index + 1) # I want String#ljust! - str << " " * (length - str.length) + str << " " * (length - str.length) if length > str.length else str << " • #{item.symbols_after_dot.map(&:display_name).join(" ")} " return str.length end if derivation.right&.left - length = _render_for_report(derivation.right.left, str.length, strings, index + 1) - str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} " + left = derivation.right&.left #: Derivation + length = _render_for_report(left, str.length, strings, index + 1) + str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} " # steep:ignore str << " " * (length - str.length) if length > str.length elsif item.next_next_sym - str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} " + str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} " # steep:ignore end return str.length diff --git a/tools/lrama/lib/lrama/counterexamples/example.rb b/tools/lrama/lib/lrama/counterexamples/example.rb index 62244a77e..bb08428fc 100644 --- a/tools/lrama/lib/lrama/counterexamples/example.rb +++ b/tools/lrama/lib/lrama/counterexamples/example.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Counterexamples class Example @@ -36,9 +38,10 @@ module Lrama private def _derivations(paths) - derivation = nil + derivation = nil #: Derivation current = :production - lookahead_sym = paths.last.to.item.end_of_rule? ? @conflict_symbol : nil + last_path = paths.last #: Path + lookahead_sym = last_path.to.item.end_of_rule? ? @conflict_symbol : nil paths.reverse_each do |path| item = path.to.item @@ -55,12 +58,14 @@ module Lrama when ProductionPath derivation = Derivation.new(item, derivation) current = :production + else + raise "Unexpected. #{path}" end if lookahead_sym && item.next_next_sym && item.next_next_sym.first_set.include?(lookahead_sym) state_item = @counterexamples.transitions[[path.to, item.next_sym]] derivation2 = find_derivation_for_symbol(state_item, lookahead_sym) - derivation.right = derivation2 + derivation.right = derivation2 # steep:ignore lookahead_sym = nil end @@ -87,7 +92,7 @@ module Lrama end def find_derivation_for_symbol(state_item, sym) - queue = [] + queue = [] #: Array[Array[StateItem]] queue << [state_item] while (sis = queue.shift) diff --git a/tools/lrama/lib/lrama/counterexamples/path.rb b/tools/lrama/lib/lrama/counterexamples/path.rb index edba67a3b..0a5823dd2 100644 --- a/tools/lrama/lib/lrama/counterexamples/path.rb +++ b/tools/lrama/lib/lrama/counterexamples/path.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Counterexamples class Path @@ -18,6 +20,10 @@ module Lrama "#" end alias :inspect :to_s + + def type + raise NotImplementedError + end end end end diff --git a/tools/lrama/lib/lrama/counterexamples/production_path.rb b/tools/lrama/lib/lrama/counterexamples/production_path.rb index d7db68851..0a230c7fc 100644 --- a/tools/lrama/lib/lrama/counterexamples/production_path.rb +++ b/tools/lrama/lib/lrama/counterexamples/production_path.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Counterexamples class ProductionPath < Path diff --git a/tools/lrama/lib/lrama/counterexamples/start_path.rb b/tools/lrama/lib/lrama/counterexamples/start_path.rb index 4a6821cd0..c0351c824 100644 --- a/tools/lrama/lib/lrama/counterexamples/start_path.rb +++ b/tools/lrama/lib/lrama/counterexamples/start_path.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Counterexamples class StartPath < Path diff --git a/tools/lrama/lib/lrama/counterexamples/state_item.rb b/tools/lrama/lib/lrama/counterexamples/state_item.rb index 930ff4a5f..c91981832 100644 --- a/tools/lrama/lib/lrama/counterexamples/state_item.rb +++ b/tools/lrama/lib/lrama/counterexamples/state_item.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Counterexamples class StateItem < Struct.new(:state, :item) diff --git a/tools/lrama/lib/lrama/counterexamples/transition_path.rb b/tools/lrama/lib/lrama/counterexamples/transition_path.rb index 96e611612..47bfbc4f9 100644 --- a/tools/lrama/lib/lrama/counterexamples/transition_path.rb +++ b/tools/lrama/lib/lrama/counterexamples/transition_path.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Counterexamples class TransitionPath < Path diff --git a/tools/lrama/lib/lrama/counterexamples/triple.rb b/tools/lrama/lib/lrama/counterexamples/triple.rb index e802beccf..64014ee22 100644 --- a/tools/lrama/lib/lrama/counterexamples/triple.rb +++ b/tools/lrama/lib/lrama/counterexamples/triple.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Counterexamples # s: state diff --git a/tools/lrama/lib/lrama/diagnostics.rb b/tools/lrama/lib/lrama/diagnostics.rb new file mode 100644 index 000000000..e9da398c8 --- /dev/null +++ b/tools/lrama/lib/lrama/diagnostics.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Lrama + class Diagnostics + def initialize(grammar, states, logger) + @grammar = grammar + @states = states + @logger = logger + end + + def run(diagnostic) + if diagnostic + diagnose_conflict + diagnose_parameterizing_redefined + end + end + + private + + def diagnose_conflict + if @states.sr_conflicts_count != 0 + @logger.warn("shift/reduce conflicts: #{@states.sr_conflicts_count} found") + end + + if @states.rr_conflicts_count != 0 + @logger.warn("reduce/reduce conflicts: #{@states.rr_conflicts_count} found") + end + end + + def diagnose_parameterizing_redefined + @grammar.parameterizing_rule_resolver.redefined_rules.each do |rule| + @logger.warn("parameterizing rule redefined: #{rule}") + end + end + end +end diff --git a/tools/lrama/lib/lrama/digraph.rb b/tools/lrama/lib/lrama/digraph.rb index bbaa86019..2161f3047 100644 --- a/tools/lrama/lib/lrama/digraph.rb +++ b/tools/lrama/lib/lrama/digraph.rb @@ -1,21 +1,52 @@ +# rbs_inline: enabled +# frozen_string_literal: true + module Lrama # Algorithm Digraph of https://dl.acm.org/doi/pdf/10.1145/69622.357187 (P. 625) + # + # @rbs generic X < Object -- Type of a member of `sets` + # @rbs generic Y < _Or -- Type of sets assigned to a member of `sets` class Digraph + # TODO: rbs-inline 0.10.0 doesn't support instance variables. + # Move these type declarations above instance variable definitions, once it's supported. + # + # @rbs! + # interface _Or + # def |: (self) -> self + # end + # @sets: Array[X] + # @relation: Hash[X, Array[X]] + # @base_function: Hash[X, Y] + # @stack: Array[X] + # @h: Hash[X, (Integer|Float)?] + # @result: Hash[X, Y] + + # @rbs sets: Array[X] + # @rbs relation: Hash[X, Array[X]] + # @rbs base_function: Hash[X, Y] + # @rbs return: void def initialize(sets, relation, base_function) + # X in the paper @sets = sets + # R in the paper @relation = relation + # F' in the paper @base_function = base_function + # S in the paper @stack = [] + # N in the paper @h = Hash.new(0) + # F in the paper @result = {} end + # @rbs () -> Hash[X, Y] def compute @sets.each do |x| next if @h[x] != 0 @@ -27,6 +58,7 @@ module Lrama private + # @rbs (X x) -> void def traverse(x) @stack.push(x) d = @stack.count diff --git a/tools/lrama/lib/lrama/grammar.rb b/tools/lrama/lib/lrama/grammar.rb index a816b8261..214ca1a3f 100644 --- a/tools/lrama/lib/lrama/grammar.rb +++ b/tools/lrama/lib/lrama/grammar.rb @@ -1,44 +1,41 @@ +# frozen_string_literal: true + require "forwardable" -require "lrama/grammar/auxiliary" -require "lrama/grammar/binding" -require "lrama/grammar/code" -require "lrama/grammar/counter" -require "lrama/grammar/destructor" -require "lrama/grammar/error_token" -require "lrama/grammar/parameterizing_rule" -require "lrama/grammar/percent_code" -require "lrama/grammar/precedence" -require "lrama/grammar/printer" -require "lrama/grammar/reference" -require "lrama/grammar/rule" -require "lrama/grammar/rule_builder" -require "lrama/grammar/symbol" -require "lrama/grammar/symbols" -require "lrama/grammar/type" -require "lrama/grammar/union" -require "lrama/lexer" +require_relative "grammar/auxiliary" +require_relative "grammar/binding" +require_relative "grammar/code" +require_relative "grammar/counter" +require_relative "grammar/destructor" +require_relative "grammar/error_token" +require_relative "grammar/parameterizing_rule" +require_relative "grammar/percent_code" +require_relative "grammar/precedence" +require_relative "grammar/printer" +require_relative "grammar/reference" +require_relative "grammar/rule" +require_relative "grammar/rule_builder" +require_relative "grammar/symbol" +require_relative "grammar/symbols" +require_relative "grammar/type" +require_relative "grammar/union" +require_relative "lexer" module Lrama # Grammar is the result of parsing an input grammar file class Grammar extend Forwardable - attr_reader :percent_codes, :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux - attr_accessor :union, :expect, - :printers, :error_tokens, - :lex_param, :parse_param, :initial_action, + attr_reader :percent_codes, :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux, :parameterizing_rule_resolver + attr_accessor :union, :expect, :printers, :error_tokens, :lex_param, :parse_param, :initial_action, :after_shift, :before_reduce, :after_reduce, :after_shift_error_token, :after_pop_stack, - :symbols_resolver, :types, - :rules, :rule_builders, - :sym_to_rules, :no_stdlib + :symbols_resolver, :types, :rules, :rule_builders, :sym_to_rules, :no_stdlib, :locations, :define - def_delegators "@symbols_resolver", :symbols, :nterms, :terms, :add_nterm, :add_term, + def_delegators "@symbols_resolver", :symbols, :nterms, :terms, :add_nterm, :add_term, :find_term_by_s_value, :find_symbol_by_number!, :find_symbol_by_id!, :token_to_symbol, :find_symbol_by_s_value!, :fill_symbol_number, :fill_nterm_type, :fill_printer, :fill_destructor, :fill_error_token, :sort_by_number! - - def initialize(rule_counter) + def initialize(rule_counter, define = {}) @rule_counter = rule_counter # Code defined by "%code" @@ -59,10 +56,16 @@ module Lrama @accept_symbol = nil @aux = Auxiliary.new @no_stdlib = false + @locations = false + @define = define.map {|d| d.split('=') }.to_h append_special_symbols end + def create_rule_builder(rule_counter, midrule_action_counter) + RuleBuilder.new(rule_counter, midrule_action_counter, @parameterizing_rule_resolver) + end + def add_percent_code(id:, code:) @percent_codes << PercentCode.new(id.s_value, code.s_value) end @@ -141,6 +144,7 @@ module Lrama end def prepare + resolve_inline_rules normalize_rules collect_symbols set_lhs_and_rhs @@ -149,6 +153,7 @@ module Lrama fill_sym_to_rules compute_nullable compute_first_set + set_locations end # TODO: More validation methods @@ -167,6 +172,10 @@ module Lrama @sym_to_rules[sym.number] end + def ielr_defined? + @define.key?('lr.type') && @define['lr.type'] == 'ielr' + end + private def compute_nullable @@ -255,7 +264,7 @@ module Lrama def setup_rules @rule_builders.each do |builder| - builder.setup_rules(@parameterizing_rule_resolver) + builder.setup_rules end end @@ -289,10 +298,23 @@ module Lrama @accept_symbol = term end + def resolve_inline_rules + while @rule_builders.any?(&:has_inline_rules?) do + @rule_builders = @rule_builders.flat_map do |builder| + if builder.has_inline_rules? + builder.resolve_inline_rules + else + builder + end + end + end + end + def normalize_rules # Add $accept rule to the top of rules - lineno = @rule_builders.first ? @rule_builders.first.line : 0 - @rules << Rule.new(id: @rule_counter.increment, _lhs: @accept_symbol.id, _rhs: [@rule_builders.first.lhs, @eof_symbol.id], token_code: nil, lineno: lineno) + rule_builder = @rule_builders.first # : RuleBuilder + lineno = rule_builder ? rule_builder.line : 0 + @rules << Rule.new(id: @rule_counter.increment, _lhs: @accept_symbol.id, _rhs: [rule_builder.lhs, @eof_symbol.id], token_code: nil, lineno: lineno) setup_rules @@ -365,17 +387,21 @@ module Lrama end def validate_rule_lhs_is_nterm! - errors = [] + errors = [] #: Array[String] rules.each do |rule| next if rule.lhs.nterm? - errors << "[BUG] LHS of #{rule} (line: #{rule.lineno}) is term. It should be nterm." + errors << "[BUG] LHS of #{rule.display_name} (line: #{rule.lineno}) is term. It should be nterm." end return if errors.empty? raise errors.join("\n") end + + def set_locations + @locations = @locations || @rules.any? {|rule| rule.contains_at_reference? } + end end end diff --git a/tools/lrama/lib/lrama/grammar/auxiliary.rb b/tools/lrama/lib/lrama/grammar/auxiliary.rb index 933574b0f..2bacee6f1 100644 --- a/tools/lrama/lib/lrama/grammar/auxiliary.rb +++ b/tools/lrama/lib/lrama/grammar/auxiliary.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar # Grammar file information not used by States but by Output diff --git a/tools/lrama/lib/lrama/grammar/binding.rb b/tools/lrama/lib/lrama/grammar/binding.rb index e5ea3fb03..2efb918a0 100644 --- a/tools/lrama/lib/lrama/grammar/binding.rb +++ b/tools/lrama/lib/lrama/grammar/binding.rb @@ -1,22 +1,65 @@ +# rbs_inline: enabled +# frozen_string_literal: true + module Lrama class Grammar class Binding - attr_reader :actual_args, :count + # @rbs @actual_args: Array[Lexer::Token] + # @rbs @param_to_arg: Hash[String, Lexer::Token] - def initialize(parameterizing_rule, actual_args) - @parameters = parameterizing_rule.parameters + # @rbs (Array[Lexer::Token] params, Array[Lexer::Token] actual_args) -> void + def initialize(params, actual_args) @actual_args = actual_args - @parameter_to_arg = @parameters.zip(actual_args).map do |param, arg| + @param_to_arg = map_params_to_args(params, @actual_args) + end + + # @rbs (Lexer::Token sym) -> Lexer::Token + def resolve_symbol(sym) + if sym.is_a?(Lexer::Token::InstantiateRule) + Lrama::Lexer::Token::InstantiateRule.new( + s_value: sym.s_value, location: sym.location, args: resolved_args(sym), lhs_tag: sym.lhs_tag + ) + else + param_to_arg(sym) + end + end + + # @rbs (Lexer::Token::InstantiateRule token) -> String + def concatenated_args_str(token) + "#{token.rule_name}_#{token_to_args_s_values(token).join('_')}" + end + + private + + # @rbs (Array[Lexer::Token] params, Array[Lexer::Token] actual_args) -> Hash[String, Lexer::Token] + def map_params_to_args(params, actual_args) + params.zip(actual_args).map do |param, arg| [param.s_value, arg] end.to_h end - def resolve_symbol(symbol) - if symbol.is_a?(Lexer::Token::InstantiateRule) - resolved_args = symbol.args.map { |arg| resolve_symbol(arg) } - Lrama::Lexer::Token::InstantiateRule.new(s_value: symbol.s_value, location: symbol.location, args: resolved_args, lhs_tag: symbol.lhs_tag) - else - @parameter_to_arg[symbol.s_value] || symbol + # @rbs (Lexer::Token::InstantiateRule sym) -> Array[Lexer::Token] + def resolved_args(sym) + sym.args.map { |arg| resolve_symbol(arg) } + end + + # @rbs (Lexer::Token sym) -> Lexer::Token + def param_to_arg(sym) + if (arg = @param_to_arg[sym.s_value].dup) + arg.alias_name = sym.alias_name + end + arg || sym + end + + # @rbs (Lexer::Token::InstantiateRule token) -> Array[String] + def token_to_args_s_values(token) + token.args.flat_map do |arg| + resolved = resolve_symbol(arg) + if resolved.is_a?(Lexer::Token::InstantiateRule) + [resolved.s_value] + resolved.args.map(&:s_value) + else + [resolved.s_value] + end end end end diff --git a/tools/lrama/lib/lrama/grammar/code.rb b/tools/lrama/lib/lrama/grammar/code.rb index 3bad599da..b6c1cc49e 100644 --- a/tools/lrama/lib/lrama/grammar/code.rb +++ b/tools/lrama/lib/lrama/grammar/code.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require "forwardable" -require "lrama/grammar/code/destructor_code" -require "lrama/grammar/code/initial_action_code" -require "lrama/grammar/code/no_reference_code" -require "lrama/grammar/code/printer_code" -require "lrama/grammar/code/rule_action" +require_relative "code/destructor_code" +require_relative "code/initial_action_code" +require_relative "code/no_reference_code" +require_relative "code/printer_code" +require_relative "code/rule_action" module Lrama class Grammar diff --git a/tools/lrama/lib/lrama/grammar/code/destructor_code.rb b/tools/lrama/lib/lrama/grammar/code/destructor_code.rb index 70360eb90..794017257 100644 --- a/tools/lrama/lib/lrama/grammar/code/destructor_code.rb +++ b/tools/lrama/lib/lrama/grammar/code/destructor_code.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class Code diff --git a/tools/lrama/lib/lrama/grammar/code/initial_action_code.rb b/tools/lrama/lib/lrama/grammar/code/initial_action_code.rb index a694f193c..02f2badc9 100644 --- a/tools/lrama/lib/lrama/grammar/code/initial_action_code.rb +++ b/tools/lrama/lib/lrama/grammar/code/initial_action_code.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class Code diff --git a/tools/lrama/lib/lrama/grammar/code/no_reference_code.rb b/tools/lrama/lib/lrama/grammar/code/no_reference_code.rb index 6e614cc64..ab12f32e2 100644 --- a/tools/lrama/lib/lrama/grammar/code/no_reference_code.rb +++ b/tools/lrama/lib/lrama/grammar/code/no_reference_code.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class Code diff --git a/tools/lrama/lib/lrama/grammar/code/printer_code.rb b/tools/lrama/lib/lrama/grammar/code/printer_code.rb index ffccd8939..c0b8d2430 100644 --- a/tools/lrama/lib/lrama/grammar/code/printer_code.rb +++ b/tools/lrama/lib/lrama/grammar/code/printer_code.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class Code diff --git a/tools/lrama/lib/lrama/grammar/code/rule_action.rb b/tools/lrama/lib/lrama/grammar/code/rule_action.rb index d3c0eab64..363ecdf25 100644 --- a/tools/lrama/lib/lrama/grammar/code/rule_action.rb +++ b/tools/lrama/lib/lrama/grammar/code/rule_action.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class Code @@ -41,6 +43,7 @@ module Lrama when ref.type == :dollar && ref.name == "$" # $$ tag = ref.ex_tag || lhs.tag raise_tag_not_found_error(ref) unless tag + # @type var tag: Lexer::Token::Tag "(yyval.#{tag.member})" when ref.type == :at && ref.name == "$" # @$ "(yyloc)" @@ -50,6 +53,7 @@ module Lrama i = -position_in_rhs + ref.index tag = ref.ex_tag || rhs[ref.index - 1].tag raise_tag_not_found_error(ref) unless tag + # @type var tag: Lexer::Token::Tag "(yyvsp[#{i}].#{tag.member})" when ref.type == :at # @n i = -position_in_rhs + ref.index @@ -69,18 +73,18 @@ module Lrama @rule.position_in_original_rule_rhs || @rule.rhs.count end - # If this is midrule action, RHS is a RHS of the original rule. + # If this is midrule action, RHS is an RHS of the original rule. def rhs (@rule.original_rule || @rule).rhs end - # Unlike `rhs`, LHS is always a LHS of the rule. + # Unlike `rhs`, LHS is always an LHS of the rule. def lhs @rule.lhs end def raise_tag_not_found_error(ref) - raise "Tag is not specified for '$#{ref.value}' in '#{@rule}'" + raise "Tag is not specified for '$#{ref.value}' in '#{@rule.display_name}'" end end end diff --git a/tools/lrama/lib/lrama/grammar/counter.rb b/tools/lrama/lib/lrama/grammar/counter.rb index c13f4ec3e..dc91b87b7 100644 --- a/tools/lrama/lib/lrama/grammar/counter.rb +++ b/tools/lrama/lib/lrama/grammar/counter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class Counter diff --git a/tools/lrama/lib/lrama/grammar/destructor.rb b/tools/lrama/lib/lrama/grammar/destructor.rb index 4b7059e92..a2b6fde0e 100644 --- a/tools/lrama/lib/lrama/grammar/destructor.rb +++ b/tools/lrama/lib/lrama/grammar/destructor.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class Destructor < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true) diff --git a/tools/lrama/lib/lrama/grammar/error_token.rb b/tools/lrama/lib/lrama/grammar/error_token.rb index 8efde7df3..50eaafeeb 100644 --- a/tools/lrama/lib/lrama/grammar/error_token.rb +++ b/tools/lrama/lib/lrama/grammar/error_token.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class ErrorToken < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true) diff --git a/tools/lrama/lib/lrama/grammar/parameterizing_rule.rb b/tools/lrama/lib/lrama/grammar/parameterizing_rule.rb index d371805f4..ddc1a467c 100644 --- a/tools/lrama/lib/lrama/grammar/parameterizing_rule.rb +++ b/tools/lrama/lib/lrama/grammar/parameterizing_rule.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative 'parameterizing_rule/resolver' require_relative 'parameterizing_rule/rhs' require_relative 'parameterizing_rule/rule' diff --git a/tools/lrama/lib/lrama/grammar/parameterizing_rule/resolver.rb b/tools/lrama/lib/lrama/grammar/parameterizing_rule/resolver.rb index d8f3ae789..06f2f1cef 100644 --- a/tools/lrama/lib/lrama/grammar/parameterizing_rule/resolver.rb +++ b/tools/lrama/lib/lrama/grammar/parameterizing_rule/resolver.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class ParameterizingRule @@ -18,13 +20,17 @@ module Lrama end def find_inline(token) - @rules.select { |rule| rule.name == token.s_value && rule.is_inline }.last + @rules.reverse.find { |rule| rule.name == token.s_value && rule.is_inline } end def created_lhs(lhs_s_value) @created_lhs_list.reverse.find { |created_lhs| created_lhs.s_value == lhs_s_value } end + def redefined_rules + @rules.select { |rule| @rules.count { |r| r.name == rule.name && r.required_parameters_count == rule.required_parameters_count } > 1 } + end + private def select_rules(rules, token) diff --git a/tools/lrama/lib/lrama/grammar/parameterizing_rule/rhs.rb b/tools/lrama/lib/lrama/grammar/parameterizing_rule/rhs.rb index 3eb92f8ef..f60781c05 100644 --- a/tools/lrama/lib/lrama/grammar/parameterizing_rule/rhs.rb +++ b/tools/lrama/lib/lrama/grammar/parameterizing_rule/rhs.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class ParameterizingRule @@ -13,7 +15,8 @@ module Lrama def resolve_user_code(bindings) return unless user_code - var_to_arg = {} + resolved = Lexer::Token::UserCode.new(s_value: user_code.s_value, location: user_code.location) + var_to_arg = {} #: Hash[String, String] symbols.each do |sym| resolved_sym = bindings.resolve_symbol(sym) if resolved_sym != sym @@ -22,14 +25,14 @@ module Lrama end var_to_arg.each do |var, arg| - user_code.references.each do |ref| + resolved.references.each do |ref| if ref.name == var ref.name = arg end end end - return user_code + return resolved end end end diff --git a/tools/lrama/lib/lrama/grammar/parameterizing_rule/rule.rb b/tools/lrama/lib/lrama/grammar/parameterizing_rule/rule.rb index 38f0fca4e..cc200d2fb 100644 --- a/tools/lrama/lib/lrama/grammar/parameterizing_rule/rule.rb +++ b/tools/lrama/lib/lrama/grammar/parameterizing_rule/rule.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class ParameterizingRule @@ -12,6 +14,10 @@ module Lrama @is_inline = is_inline @required_parameters_count = parameters.count end + + def to_s + "#{@name}(#{@parameters.map(&:s_value).join(', ')})" + end end end end diff --git a/tools/lrama/lib/lrama/grammar/percent_code.rb b/tools/lrama/lib/lrama/grammar/percent_code.rb index 8cbc5aef2..416a2d275 100644 --- a/tools/lrama/lib/lrama/grammar/percent_code.rb +++ b/tools/lrama/lib/lrama/grammar/percent_code.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class PercentCode diff --git a/tools/lrama/lib/lrama/grammar/precedence.rb b/tools/lrama/lib/lrama/grammar/precedence.rb index fed739b3c..13cf960c3 100644 --- a/tools/lrama/lib/lrama/grammar/precedence.rb +++ b/tools/lrama/lib/lrama/grammar/precedence.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class Precedence < Struct.new(:type, :precedence, keyword_init: true) diff --git a/tools/lrama/lib/lrama/grammar/printer.rb b/tools/lrama/lib/lrama/grammar/printer.rb index 8984a96e1..b78459e81 100644 --- a/tools/lrama/lib/lrama/grammar/printer.rb +++ b/tools/lrama/lib/lrama/grammar/printer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class Printer < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true) diff --git a/tools/lrama/lib/lrama/grammar/reference.rb b/tools/lrama/lib/lrama/grammar/reference.rb index c56e7673a..b044516bd 100644 --- a/tools/lrama/lib/lrama/grammar/reference.rb +++ b/tools/lrama/lib/lrama/grammar/reference.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar # type: :dollar or :at diff --git a/tools/lrama/lib/lrama/grammar/rule.rb b/tools/lrama/lib/lrama/grammar/rule.rb index 0e06edc80..445752ae0 100644 --- a/tools/lrama/lib/lrama/grammar/rule.rb +++ b/tools/lrama/lib/lrama/grammar/rule.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar # _rhs holds original RHS element. Use rhs to refer to Symbol. @@ -16,10 +18,17 @@ module Lrama self.lineno == other.lineno end - # TODO: Change this to display_name - def to_s + def display_name l = lhs.id.s_value r = empty_rule? ? "ε" : rhs.map {|r| r.id.s_value }.join(" ") + "#{l} -> #{r}" + end + + def display_name_without_action + l = lhs.id.s_value + r = empty_rule? ? "ε" : rhs.map do |r| + r.id.s_value if r.first_set.any? + end.compact.join(" ") "#{l} -> #{r}" end @@ -33,7 +42,7 @@ module Lrama end def with_actions - "#{to_s} {#{token_code&.s_value}}" + "#{display_name} {#{token_code&.s_value}}" end # opt_nl: ε <-- empty_rule @@ -55,6 +64,12 @@ module Lrama Code::RuleAction.new(type: :rule_action, token_code: token_code, rule: self).translated_code end + + def contains_at_reference? + return false unless token_code + + token_code.references.any? {|r| r.type == :at } + end end end end diff --git a/tools/lrama/lib/lrama/grammar/rule_builder.rb b/tools/lrama/lib/lrama/grammar/rule_builder.rb index ccb41e67f..481a3780f 100644 --- a/tools/lrama/lib/lrama/grammar/rule_builder.rb +++ b/tools/lrama/lib/lrama/grammar/rule_builder.rb @@ -1,12 +1,15 @@ +# frozen_string_literal: true + module Lrama class Grammar class RuleBuilder attr_accessor :lhs, :line attr_reader :lhs_tag, :rhs, :user_code, :precedence_sym - def initialize(rule_counter, midrule_action_counter, position_in_original_rule_rhs = nil, lhs_tag: nil, skip_preprocess_references: false) + def initialize(rule_counter, midrule_action_counter, parameterizing_rule_resolver, position_in_original_rule_rhs = nil, lhs_tag: nil, skip_preprocess_references: false) @rule_counter = rule_counter @midrule_action_counter = midrule_action_counter + @parameterizing_rule_resolver = parameterizing_rule_resolver @position_in_original_rule_rhs = position_in_original_rule_rhs @skip_preprocess_references = skip_preprocess_references @@ -19,16 +22,12 @@ module Lrama @rules = [] @rule_builders_for_parameterizing_rules = [] @rule_builders_for_derived_rules = [] - @rule_builders_for_inline_rules = [] @parameterizing_rules = [] - @inline_rules = [] @midrule_action_rules = [] end def add_rhs(rhs) - if !@line - @line = rhs.line - end + @line ||= rhs.line flush_user_code @@ -36,9 +35,7 @@ module Lrama end def user_code=(user_code) - if !@line - @line = user_code&.line - end + @line ||= user_code&.line flush_user_code @@ -55,18 +52,41 @@ module Lrama freeze_rhs end - def setup_rules(parameterizing_rule_resolver) + def setup_rules preprocess_references unless @skip_preprocess_references - if rhs.any? { |token| parameterizing_rule_resolver.find_inline(token) } - resolve_inline(parameterizing_rule_resolver) - else - process_rhs(parameterizing_rule_resolver) - end + process_rhs build_rules end def rules - @parameterizing_rules + @inline_rules + @midrule_action_rules + @rules + @parameterizing_rules + @midrule_action_rules + @rules + end + + def has_inline_rules? + rhs.any? { |token| @parameterizing_rule_resolver.find_inline(token) } + end + + def resolve_inline_rules + resolved_builders = [] #: Array[RuleBuilder] + rhs.each_with_index do |token, i| + if (inline_rule = @parameterizing_rule_resolver.find_inline(token)) + inline_rule.rhs_list.each do |inline_rhs| + rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, @parameterizing_rule_resolver, lhs_tag: lhs_tag) + if token.is_a?(Lexer::Token::InstantiateRule) + resolve_inline_rhs(rule_builder, inline_rhs, i, Binding.new(inline_rule.parameters, token.args)) + else + resolve_inline_rhs(rule_builder, inline_rhs, i) + end + rule_builder.lhs = lhs + rule_builder.line = line + rule_builder.precedence_sym = precedence_sym + rule_builder.user_code = replace_inline_user_code(inline_rhs, i) + resolved_builders << rule_builder + end + break + end + end + resolved_builders end private @@ -82,31 +102,25 @@ module Lrama def build_rules tokens = @replaced_rhs - if tokens - rule = Rule.new( - id: @rule_counter.increment, _lhs: lhs, _rhs: tokens, lhs_tag: lhs_tag, token_code: user_code, - position_in_original_rule_rhs: @position_in_original_rule_rhs, precedence_sym: precedence_sym, lineno: line - ) - @rules = [rule] - @parameterizing_rules = @rule_builders_for_parameterizing_rules.map do |rule_builder| - rule_builder.rules - end.flatten - @midrule_action_rules = @rule_builders_for_derived_rules.map do |rule_builder| - rule_builder.rules - end.flatten - @midrule_action_rules.each do |r| - r.original_rule = rule - end - else - @inline_rules = @rule_builders_for_inline_rules.map do |rule_builder| - rule_builder.rules - end.flatten + rule = Rule.new( + id: @rule_counter.increment, _lhs: lhs, _rhs: tokens, lhs_tag: lhs_tag, token_code: user_code, + position_in_original_rule_rhs: @position_in_original_rule_rhs, precedence_sym: precedence_sym, lineno: line + ) + @rules = [rule] + @parameterizing_rules = @rule_builders_for_parameterizing_rules.map do |rule_builder| + rule_builder.rules + end.flatten + @midrule_action_rules = @rule_builders_for_derived_rules.map do |rule_builder| + rule_builder.rules + end.flatten + @midrule_action_rules.each do |r| + r.original_rule = rule end end # rhs is a mixture of variety type of tokens like `Ident`, `InstantiateRule`, `UserCode` and so on. # `#process_rhs` replaces some kind of tokens to `Ident` so that all `@replaced_rhs` are `Ident` or `Char`. - def process_rhs(parameterizing_rule_resolver) + def process_rhs return if @replaced_rhs @replaced_rhs = [] @@ -118,26 +132,26 @@ module Lrama when Lrama::Lexer::Token::Ident @replaced_rhs << token when Lrama::Lexer::Token::InstantiateRule - parameterizing_rule = parameterizing_rule_resolver.find_rule(token) + parameterizing_rule = @parameterizing_rule_resolver.find_rule(token) raise "Unexpected token. #{token}" unless parameterizing_rule - bindings = Binding.new(parameterizing_rule, token.args) - lhs_s_value = lhs_s_value(token, bindings) - if (created_lhs = parameterizing_rule_resolver.created_lhs(lhs_s_value)) + bindings = Binding.new(parameterizing_rule.parameters, token.args) + lhs_s_value = bindings.concatenated_args_str(token) + if (created_lhs = @parameterizing_rule_resolver.created_lhs(lhs_s_value)) @replaced_rhs << created_lhs else lhs_token = Lrama::Lexer::Token::Ident.new(s_value: lhs_s_value, location: token.location) @replaced_rhs << lhs_token - parameterizing_rule_resolver.created_lhs_list << lhs_token + @parameterizing_rule_resolver.created_lhs_list << lhs_token parameterizing_rule.rhs_list.each do |r| - rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, lhs_tag: token.lhs_tag || parameterizing_rule.tag) + rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, @parameterizing_rule_resolver, lhs_tag: token.lhs_tag || parameterizing_rule.tag) rule_builder.lhs = lhs_token r.symbols.each { |sym| rule_builder.add_rhs(bindings.resolve_symbol(sym)) } rule_builder.line = line rule_builder.precedence_sym = r.precedence_sym rule_builder.user_code = r.resolve_user_code(bindings) rule_builder.complete_input - rule_builder.setup_rules(parameterizing_rule_resolver) + rule_builder.setup_rules @rule_builders_for_parameterizing_rules << rule_builder end end @@ -147,11 +161,11 @@ module Lrama new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + @midrule_action_counter.increment.to_s) @replaced_rhs << new_token - rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, i, lhs_tag: tag, skip_preprocess_references: true) + rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, @parameterizing_rule_resolver, i, lhs_tag: tag, skip_preprocess_references: true) rule_builder.lhs = new_token rule_builder.user_code = token rule_builder.complete_input - rule_builder.setup_rules(parameterizing_rule_resolver) + rule_builder.setup_rules @rule_builders_for_derived_rules << rule_builder else @@ -160,39 +174,10 @@ module Lrama end end - def lhs_s_value(token, bindings) - s_values = token.args.map do |arg| - resolved = bindings.resolve_symbol(arg) - if resolved.is_a?(Lexer::Token::InstantiateRule) - [resolved.s_value, resolved.args.map(&:s_value)] - else - resolved.s_value - end - end - "#{token.rule_name}_#{s_values.join('_')}" - end - - def resolve_inline(parameterizing_rule_resolver) - rhs.each_with_index do |token, i| - if inline_rule = parameterizing_rule_resolver.find_inline(token) - inline_rule.rhs_list.each_with_index do |inline_rhs| - rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, lhs_tag: lhs_tag, skip_preprocess_references: true) - resolve_inline_rhs(rule_builder, inline_rhs, i) - rule_builder.lhs = lhs - rule_builder.line = line - rule_builder.user_code = replace_inline_user_code(inline_rhs, i) - rule_builder.complete_input - rule_builder.setup_rules(parameterizing_rule_resolver) - @rule_builders_for_inline_rules << rule_builder - end - end - end - end - - def resolve_inline_rhs(rule_builder, inline_rhs, index) + def resolve_inline_rhs(rule_builder, inline_rhs, index, bindings = nil) rhs.each_with_index do |token, i| if index == i - inline_rhs.symbols.each { |sym| rule_builder.add_rhs(sym) } + inline_rhs.symbols.each { |sym| rule_builder.add_rhs(bindings.nil? ? sym : bindings.resolve_symbol(sym)) } else rule_builder.add_rhs(token) end @@ -204,6 +189,11 @@ module Lrama return user_code if user_code.nil? code = user_code.s_value.gsub(/\$#{index + 1}/, inline_rhs.user_code.s_value) + user_code.references.each do |ref| + next if ref.index.nil? || ref.index <= index # nil is a case for `$$` + code = code.gsub(/\$#{ref.index}/, "$#{ref.index + (inline_rhs.symbols.count-1)}") + code = code.gsub(/@#{ref.index}/, "@#{ref.index + (inline_rhs.symbols.count-1)}") + end Lrama::Lexer::Token::UserCode.new(s_value: code, location: user_code.location) end @@ -238,9 +228,6 @@ module Lrama end if ref.number - # TODO: When Inlining is implemented, for example, if `$1` is expanded to multiple RHS tokens, - # `$2` needs to access `$2 + n` to actually access it. So, after the Inlining implementation, - # it needs resolves from number to index. ref.index = ref.number end diff --git a/tools/lrama/lib/lrama/grammar/symbol.rb b/tools/lrama/lib/lrama/grammar/symbol.rb index deb67ad9a..f9dffcad6 100644 --- a/tools/lrama/lib/lrama/grammar/symbol.rb +++ b/tools/lrama/lib/lrama/grammar/symbol.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Symbol is both of nterm and term # `number` is both for nterm and term # `token_id` is tokentype for term, internal sequence number for nterm diff --git a/tools/lrama/lib/lrama/grammar/symbols.rb b/tools/lrama/lib/lrama/grammar/symbols.rb index cc9b4ec55..337241d1b 100644 --- a/tools/lrama/lib/lrama/grammar/symbols.rb +++ b/tools/lrama/lib/lrama/grammar/symbols.rb @@ -1 +1,3 @@ +# frozen_string_literal: true + require_relative "symbols/resolver" diff --git a/tools/lrama/lib/lrama/grammar/symbols/resolver.rb b/tools/lrama/lib/lrama/grammar/symbols/resolver.rb index 1788ed63f..52f4ff90b 100644 --- a/tools/lrama/lib/lrama/grammar/symbols/resolver.rb +++ b/tools/lrama/lib/lrama/grammar/symbols/resolver.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class Symbols @@ -42,7 +44,9 @@ module Lrama end def add_nterm(id:, alias_name: nil, tag: nil) - return if find_symbol_by_id(id) + if (sym = find_symbol_by_id(id)) + return sym + end @symbols = nil nterm = Symbol.new( @@ -53,6 +57,10 @@ module Lrama nterm end + def find_term_by_s_value(s_value) + terms.find { |s| s.id.s_value == s_value } + end + def find_symbol_by_s_value(s_value) symbols.find { |s| s.id.s_value == s_value } end diff --git a/tools/lrama/lib/lrama/grammar/type.rb b/tools/lrama/lib/lrama/grammar/type.rb index 6b4b0961a..65537288b 100644 --- a/tools/lrama/lib/lrama/grammar/type.rb +++ b/tools/lrama/lib/lrama/grammar/type.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class Type diff --git a/tools/lrama/lib/lrama/grammar/union.rb b/tools/lrama/lib/lrama/grammar/union.rb index 854bffb5c..5f1bee006 100644 --- a/tools/lrama/lib/lrama/grammar/union.rb +++ b/tools/lrama/lib/lrama/grammar/union.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Grammar class Union < Struct.new(:code, :lineno, keyword_init: true) diff --git a/tools/lrama/lib/lrama/grammar_validator.rb b/tools/lrama/lib/lrama/grammar_validator.rb new file mode 100644 index 000000000..779049958 --- /dev/null +++ b/tools/lrama/lib/lrama/grammar_validator.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Lrama + class GrammarValidator + def initialize(grammar, states, logger) + @grammar = grammar + @states = states + @logger = logger + end + + def valid? + conflicts_within_threshold? + end + + private + + def conflicts_within_threshold? + return true unless @grammar.expect + + [sr_conflicts_within_threshold(@grammar.expect), rr_conflicts_within_threshold(0)].all? + end + + def sr_conflicts_within_threshold(expected) + return true if expected == @states.sr_conflicts_count + + @logger.error("shift/reduce conflicts: #{@states.sr_conflicts_count} found, #{expected} expected") + false + end + + def rr_conflicts_within_threshold(expected) + return true if expected == @states.rr_conflicts_count + + @logger.error("reduce/reduce conflicts: #{@states.rr_conflicts_count} found, #{expected} expected") + false + end + end +end diff --git a/tools/lrama/lib/lrama/lexer.rb b/tools/lrama/lib/lrama/lexer.rb index 40622a51b..c50af82ae 100644 --- a/tools/lrama/lib/lrama/lexer.rb +++ b/tools/lrama/lib/lrama/lexer.rb @@ -1,19 +1,22 @@ +# frozen_string_literal: true + require "strscan" -require "lrama/lexer/grammar_file" -require "lrama/lexer/location" -require "lrama/lexer/token" +require_relative "lexer/grammar_file" +require_relative "lexer/location" +require_relative "lexer/token" module Lrama class Lexer attr_reader :head_line, :head_column, :line attr_accessor :status, :end_symbol - SYMBOLS = ['%{', '%}', '%%', '{', '}', '\[', '\]', '\(', '\)', '\,', ':', '\|', ';'] + SYMBOLS = ['%{', '%}', '%%', '{', '}', '\[', '\]', '\(', '\)', '\,', ':', '\|', ';'].freeze PERCENT_TOKENS = %w( %union %token %type + %nterm %left %right %nonassoc @@ -38,7 +41,8 @@ module Lrama %rule %no-stdlib %inline - ) + %locations + ).freeze def initialize(grammar_file) @grammar_file = grammar_file @@ -71,7 +75,7 @@ module Lrama end def lex_token - while !@scanner.eos? do + until @scanner.eos? do case when @scanner.scan(/\n/) newline @@ -126,7 +130,7 @@ module Lrama code = '' reset_first_position - while !@scanner.eos? do + until @scanner.eos? do case when @scanner.scan(/{/) code += @scanner.matched @@ -163,14 +167,13 @@ module Lrama private def lex_comment - while !@scanner.eos? do + until @scanner.eos? do case - when @scanner.scan(/\n/) - newline - when @scanner.scan(/\*\//) + when @scanner.scan_until(/[\s\S]*?\*\//) + @scanner.matched.count("\n").times { newline } return - else - @scanner.getch + when @scanner.scan_until(/\n/) + newline end end end diff --git a/tools/lrama/lib/lrama/lexer/grammar_file.rb b/tools/lrama/lib/lrama/lexer/grammar_file.rb index 3d3368625..37e82ff18 100644 --- a/tools/lrama/lib/lrama/lexer/grammar_file.rb +++ b/tools/lrama/lib/lrama/lexer/grammar_file.rb @@ -1,28 +1,37 @@ +# rbs_inline: enabled +# frozen_string_literal: true + module Lrama class Lexer class GrammarFile class Text < String + # @rbs () -> String def inspect length <= 50 ? super : "#{self[0..47]}...".inspect end end - attr_reader :path, :text + attr_reader :path #: String + attr_reader :text #: String + # @rbs (String path, String text) -> void def initialize(path, text) @path = path @text = Text.new(text).freeze end + # @rbs () -> String def inspect "<#{self.class}: @path=#{path}, @text=#{text.inspect}>" end + # @rbs (GrammarFile other) -> bool def ==(other) self.class == other.class && self.path == other.path end + # @rbs () -> Array[String] def lines @lines ||= text.split("\n") end diff --git a/tools/lrama/lib/lrama/lexer/location.rb b/tools/lrama/lib/lrama/lexer/location.rb index aefce3e16..defdbf8a0 100644 --- a/tools/lrama/lib/lrama/lexer/location.rb +++ b/tools/lrama/lib/lrama/lexer/location.rb @@ -1,8 +1,16 @@ +# rbs_inline: enabled +# frozen_string_literal: true + module Lrama class Lexer class Location - attr_reader :grammar_file, :first_line, :first_column, :last_line, :last_column + attr_reader :grammar_file #: GrammarFile + attr_reader :first_line #: Integer + attr_reader :first_column #: Integer + attr_reader :last_line #: Integer + attr_reader :last_column #: Integer + # @rbs (grammar_file: GrammarFile, first_line: Integer, first_column: Integer, last_line: Integer, last_column: Integer) -> void def initialize(grammar_file:, first_line:, first_column:, last_line:, last_column:) @grammar_file = grammar_file @first_line = first_line @@ -11,6 +19,7 @@ module Lrama @last_column = last_column end + # @rbs (Location other) -> bool def ==(other) self.class == other.class && self.grammar_file == other.grammar_file && @@ -20,6 +29,7 @@ module Lrama self.last_column == other.last_column end + # @rbs (Integer left, Integer right) -> Location def partial_location(left, right) offset = -first_column new_first_line = -1 @@ -50,10 +60,12 @@ module Lrama ) end + # @rbs () -> String def to_s "#{path} (#{first_line},#{first_column})-(#{last_line},#{last_column})" end + # @rbs (String error_message) -> String def generate_error_message(error_message) <<~ERROR.chomp #{path}:#{first_line}:#{first_column}: #{error_message} @@ -61,6 +73,7 @@ module Lrama ERROR end + # @rbs () -> String def line_with_carets <<~TEXT #{text} @@ -70,22 +83,27 @@ module Lrama private + # @rbs () -> String def path grammar_file.path end + # @rbs () -> String def blanks (text[0...first_column] or raise "#{first_column} is invalid").gsub(/[^\t]/, ' ') end + # @rbs () -> String def carets blanks + '^' * (last_column - first_column) end + # @rbs () -> String def text @text ||= _text.join("\n") end + # @rbs () -> Array[String] def _text @_text ||=begin range = (first_line - 1)...last_line diff --git a/tools/lrama/lib/lrama/lexer/token.rb b/tools/lrama/lib/lrama/lexer/token.rb index 59b49d5fb..63da8be4a 100644 --- a/tools/lrama/lib/lrama/lexer/token.rb +++ b/tools/lrama/lib/lrama/lexer/token.rb @@ -1,15 +1,21 @@ -require 'lrama/lexer/token/char' -require 'lrama/lexer/token/ident' -require 'lrama/lexer/token/instantiate_rule' -require 'lrama/lexer/token/tag' -require 'lrama/lexer/token/user_code' +# rbs_inline: enabled +# frozen_string_literal: true + +require_relative 'token/char' +require_relative 'token/ident' +require_relative 'token/instantiate_rule' +require_relative 'token/tag' +require_relative 'token/user_code' module Lrama class Lexer class Token - attr_reader :s_value, :location - attr_accessor :alias_name, :referred + attr_reader :s_value #: String + attr_reader :location #: Location + attr_accessor :alias_name #: String + attr_accessor :referred #: bool + # @rbs (s_value: String, ?alias_name: String, ?location: Location) -> void def initialize(s_value:, alias_name: nil, location: nil) s_value.freeze @s_value = s_value @@ -17,36 +23,44 @@ module Lrama @location = location end + # @rbs () -> String def to_s "value: `#{s_value}`, location: #{location}" end + # @rbs (String string) -> bool def referred_by?(string) [self.s_value, self.alias_name].compact.include?(string) end + # @rbs (Token other) -> bool def ==(other) self.class == other.class && self.s_value == other.s_value end + # @rbs () -> Integer def first_line location.first_line end alias :line :first_line + # @rbs () -> Integer def first_column location.first_column end alias :column :first_column + # @rbs () -> Integer def last_line location.last_line end + # @rbs () -> Integer def last_column location.last_column end + # @rbs (Lrama::Grammar::Reference ref, String message) -> bot def invalid_ref(ref, message) location = self.location.partial_location(ref.first_column, ref.last_column) raise location.generate_error_message(message) diff --git a/tools/lrama/lib/lrama/lexer/token/char.rb b/tools/lrama/lib/lrama/lexer/token/char.rb index ec3560ca0..fcab7a588 100644 --- a/tools/lrama/lib/lrama/lexer/token/char.rb +++ b/tools/lrama/lib/lrama/lexer/token/char.rb @@ -1,3 +1,6 @@ +# rbs_inline: enabled +# frozen_string_literal: true + module Lrama class Lexer class Token diff --git a/tools/lrama/lib/lrama/lexer/token/ident.rb b/tools/lrama/lib/lrama/lexer/token/ident.rb index e576eaecc..8b1328a04 100644 --- a/tools/lrama/lib/lrama/lexer/token/ident.rb +++ b/tools/lrama/lib/lrama/lexer/token/ident.rb @@ -1,3 +1,6 @@ +# rbs_inline: enabled +# frozen_string_literal: true + module Lrama class Lexer class Token diff --git a/tools/lrama/lib/lrama/lexer/token/instantiate_rule.rb b/tools/lrama/lib/lrama/lexer/token/instantiate_rule.rb index 1c4d1095c..37d412aa8 100644 --- a/tools/lrama/lib/lrama/lexer/token/instantiate_rule.rb +++ b/tools/lrama/lib/lrama/lexer/token/instantiate_rule.rb @@ -1,19 +1,26 @@ +# rbs_inline: enabled +# frozen_string_literal: true + module Lrama class Lexer class Token class InstantiateRule < Token - attr_reader :args, :lhs_tag + attr_reader :args #: Array[Lexer::Token] + attr_reader :lhs_tag #: Lexer::Token::Tag? + # @rbs (s_value: String, ?alias_name: String, ?location: Location, ?args: Array[Lexer::Token], ?lhs_tag: Lexer::Token::Tag?) -> void def initialize(s_value:, alias_name: nil, location: nil, args: [], lhs_tag: nil) super s_value: s_value, alias_name: alias_name, location: location @args = args @lhs_tag = lhs_tag end + # @rbs () -> String def rule_name s_value end + # @rbs () -> Integer def args_count args.count end diff --git a/tools/lrama/lib/lrama/lexer/token/tag.rb b/tools/lrama/lib/lrama/lexer/token/tag.rb index e54d77391..b346ef7c5 100644 --- a/tools/lrama/lib/lrama/lexer/token/tag.rb +++ b/tools/lrama/lib/lrama/lexer/token/tag.rb @@ -1,9 +1,13 @@ +# rbs_inline: enabled +# frozen_string_literal: true + module Lrama class Lexer class Token class Tag < Token - # Omit "<>" + # @rbs () -> String def member + # Omit "<>" s_value[1..-2] or raise "Unexpected Tag format (#{s_value})" end end diff --git a/tools/lrama/lib/lrama/lexer/token/user_code.rb b/tools/lrama/lib/lrama/lexer/token/user_code.rb index 4d487bf01..4ef40e6dc 100644 --- a/tools/lrama/lib/lrama/lexer/token/user_code.rb +++ b/tools/lrama/lib/lrama/lexer/token/user_code.rb @@ -1,22 +1,27 @@ +# rbs_inline: enabled +# frozen_string_literal: true + require "strscan" module Lrama class Lexer class Token class UserCode < Token - attr_accessor :tag + attr_accessor :tag #: Lexer::Token::Tag + # @rbs () -> Array[Lrama::Grammar::Reference] def references @references ||= _references end private + # @rbs () -> Array[Lrama::Grammar::Reference] def _references scanner = StringScanner.new(s_value) - references = [] + references = [] #: Array[Grammar::Reference] - while !scanner.eos? do + until scanner.eos? do case when reference = scan_reference(scanner) references << reference @@ -30,6 +35,7 @@ module Lrama references end + # @rbs (StringScanner scanner) -> Lrama::Grammar::Reference? def scan_reference(scanner) start = scanner.pos case diff --git a/tools/lrama/lib/lrama/warning.rb b/tools/lrama/lib/lrama/logger.rb similarity index 52% rename from tools/lrama/lib/lrama/warning.rb rename to tools/lrama/lib/lrama/logger.rb index 3c99791eb..88bb92096 100644 --- a/tools/lrama/lib/lrama/warning.rb +++ b/tools/lrama/lib/lrama/logger.rb @@ -1,25 +1,21 @@ -module Lrama - class Warning - attr_reader :errors, :warns +# rbs_inline: enabled +# frozen_string_literal: true +module Lrama + class Logger + # @rbs (IO out) -> void def initialize(out = STDERR) @out = out - @errors = [] - @warns = [] - end - - def error(message) - @out << message << "\n" - @errors << message end + # @rbs (String message) -> void def warn(message) @out << message << "\n" - @warns << message end - def has_error? - !@errors.empty? + # @rbs (String message) -> void + def error(message) + @out << message << "\n" end end end diff --git a/tools/lrama/lib/lrama/option_parser.rb b/tools/lrama/lib/lrama/option_parser.rb index 1e4d448fd..23988a5fb 100644 --- a/tools/lrama/lib/lrama/option_parser.rb +++ b/tools/lrama/lib/lrama/option_parser.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'optparse' module Lrama @@ -16,7 +18,7 @@ module Lrama @options.report_opts = validate_report(@report) @options.grammar_file = argv.shift - if !@options.grammar_file + unless @options.grammar_file abort "File should be specified\n" end @@ -57,26 +59,42 @@ module Lrama o.separator '' o.separator 'Tuning the Parser:' o.on('-S', '--skeleton=FILE', 'specify the skeleton to use') {|v| @options.skeleton = v } - o.on('-t', 'reserved, do nothing') { } - o.on('--debug', 'display debugging outputs of internal parser') {|v| @options.debug = true } + o.on('-t', '--debug', 'display debugging outputs of internal parser') {|v| @options.debug = true } + o.on('-D', '--define=NAME[=VALUE]', Array, "similar to '%define NAME VALUE'") {|v| @options.define = v } o.separator '' o.separator 'Output:' o.on('-H', '--header=[FILE]', 'also produce a header file named FILE') {|v| @options.header = true; @options.header_file = v } o.on('-d', 'also produce a header file') { @options.header = true } - o.on('-r', '--report=THINGS', Array, 'also produce details on the automaton') {|v| @report = v } + o.on('-r', '--report=REPORTS', Array, 'also produce details on the automaton') {|v| @report = v } o.on_tail '' - o.on_tail 'Valid Reports:' - o.on_tail " #{VALID_REPORTS.join(' ')}" - + o.on_tail 'REPORTS is a list of comma-separated words that can include:' + o.on_tail ' states describe the states' + o.on_tail ' itemsets complete the core item sets with their closure' + o.on_tail ' lookaheads explicitly associate lookahead tokens to items' + o.on_tail ' solved describe shift/reduce conflicts solving' + o.on_tail ' counterexamples, cex generate conflict counterexamples' + o.on_tail ' rules list unused rules' + o.on_tail ' terms list unused terminals' + o.on_tail ' verbose report detailed internal state and analysis results' + o.on_tail ' all include all the above reports' + o.on_tail ' none disable all reports' o.on('--report-file=FILE', 'also produce details on the automaton output to a file named FILE') {|v| @options.report_file = v } o.on('-o', '--output=FILE', 'leave output to FILE') {|v| @options.outfile = v } - - o.on('--trace=THINGS', Array, 'also output trace logs at runtime') {|v| @trace = v } + o.on('--trace=TRACES', Array, 'also output trace logs at runtime') {|v| @trace = v } o.on_tail '' - o.on_tail 'Valid Traces:' - o.on_tail " #{VALID_TRACES.join(' ')}" - - o.on('-v', 'reserved, do nothing') { } + o.on_tail 'TRACES is a list of comma-separated words that can include:' + o.on_tail ' automaton display states' + o.on_tail ' closure display states' + o.on_tail ' rules display grammar rules' + o.on_tail ' only-explicit-rules display only explicit grammar rules' + o.on_tail ' actions display grammar rules with actions' + o.on_tail ' time display generation time' + o.on_tail ' all include all the above traces' + o.on_tail ' none disable all traces' + o.on('-v', '--verbose', "same as '--report=state'") {|_v| @report << 'states' } + o.separator '' + o.separator 'Diagnostics:' + o.on('-W', '--warnings', 'report the warnings') {|v| @options.diagnostic = true } o.separator '' o.separator 'Error Recovery:' o.on('-e', 'enable error recovery') {|v| @options.error_recovery = true } @@ -89,48 +107,57 @@ module Lrama end end - BISON_REPORTS = %w[states itemsets lookaheads solved counterexamples cex all none] - OTHER_REPORTS = %w[verbose] - NOT_SUPPORTED_REPORTS = %w[cex none] - VALID_REPORTS = BISON_REPORTS + OTHER_REPORTS - NOT_SUPPORTED_REPORTS + ALIASED_REPORTS = { cex: :counterexamples }.freeze + VALID_REPORTS = %i[states itemsets lookaheads solved counterexamples rules terms verbose].freeze def validate_report(report) - list = VALID_REPORTS h = { grammar: true } + return h if report.empty? + return {} if report == ['none'] + if report == ['all'] + VALID_REPORTS.each { |r| h[r] = true } + return h + end report.each do |r| - if list.include?(r) - h[r.to_sym] = true + aliased = aliased_report_option(r) + if VALID_REPORTS.include?(aliased) + h[aliased] = true else raise "Invalid report option \"#{r}\"." end end - if h[:all] - (BISON_REPORTS - NOT_SUPPORTED_REPORTS).each do |r| - h[r.to_sym] = true - end - - h.delete(:all) - end - return h end + def aliased_report_option(opt) + (ALIASED_REPORTS[opt.to_sym] || opt).to_sym + end + VALID_TRACES = %w[ - none locations scan parse automaton bitsets - closure grammar rules actions resource - sets muscles tools m4-early m4 skeleton time - ielr cex all - ] + locations scan parse automaton bitsets closure + grammar rules only-explicit-rules actions resource + sets muscles tools m4-early m4 skeleton time ielr cex + ].freeze + NOT_SUPPORTED_TRACES = %w[ + locations scan parse bitsets grammar resource + sets muscles tools m4-early m4 skeleton ielr cex + ].freeze + SUPPORTED_TRACES = VALID_TRACES - NOT_SUPPORTED_TRACES def validate_trace(trace) - list = VALID_TRACES h = {} + return h if trace.empty? || trace == ['none'] + all_traces = SUPPORTED_TRACES - %w[only-explicit-rules] + if trace == ['all'] + all_traces.each { |t| h[t.gsub(/-/, '_').to_sym] = true } + return h + end trace.each do |t| - if list.include?(t) - h[t.to_sym] = true + if SUPPORTED_TRACES.include?(t) + h[t.gsub(/-/, '_').to_sym] = true else raise "Invalid trace option \"#{t}\"." end diff --git a/tools/lrama/lib/lrama/options.rb b/tools/lrama/lib/lrama/options.rb index 739ca16f5..08f75a770 100644 --- a/tools/lrama/lib/lrama/options.rb +++ b/tools/lrama/lib/lrama/options.rb @@ -1,14 +1,17 @@ +# frozen_string_literal: true + module Lrama # Command line options. class Options attr_accessor :skeleton, :header, :header_file, :report_file, :outfile, :error_recovery, :grammar_file, - :trace_opts, :report_opts, :y, - :debug + :trace_opts, :report_opts, + :diagnostic, :y, :debug, :define def initialize @skeleton = "bison/yacc.c" + @define = {} @header = false @header_file = nil @report_file = nil @@ -17,6 +20,7 @@ module Lrama @grammar_file = nil @trace_opts = nil @report_opts = nil + @diagnostic = false @y = STDIN @debug = false end diff --git a/tools/lrama/lib/lrama/output.rb b/tools/lrama/lib/lrama/output.rb index 642c8b470..3c7316ac6 100644 --- a/tools/lrama/lib/lrama/output.rb +++ b/tools/lrama/lib/lrama/output.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "erb" require "forwardable" -require "lrama/report/duration" +require_relative "report/duration" module Lrama class Output @@ -63,37 +65,29 @@ module Lrama # A part of b4_token_enums def token_enums - str = "" - - @context.yytokentype.each do |s_value, token_id, display_name| + @context.yytokentype.map do |s_value, token_id, display_name| s = sprintf("%s = %d%s", s_value, token_id, token_id == yymaxutok ? "" : ",") if display_name - str << sprintf(" %-30s /* %s */\n", s, display_name) + sprintf(" %-30s /* %s */\n", s, display_name) else - str << sprintf(" %s\n", s) + sprintf(" %s\n", s) end - end - - str + end.join end # b4_symbol_enum def symbol_enum - str = "" - last_sym_number = @context.yysymbol_kind_t.last[1] - @context.yysymbol_kind_t.each do |s_value, sym_number, display_name| + @context.yysymbol_kind_t.map do |s_value, sym_number, display_name| s = sprintf("%s = %d%s", s_value, sym_number, (sym_number == last_sym_number) ? "" : ",") if display_name - str << sprintf(" %-40s /* %s */\n", s, display_name) + sprintf(" %-40s /* %s */\n", s, display_name) else - str << sprintf(" %s\n", s) + sprintf(" %s\n", s) end - end - - str + end.join end def yytranslate @@ -132,12 +126,10 @@ module Lrama end def symbol_actions_for_printer - str = "" - - @grammar.symbols.each do |sym| + @grammar.symbols.map do |sym| next unless sym.printer - str << <<-STR + <<-STR case #{sym.enum_name}: /* #{sym.comment} */ #line #{sym.printer.lineno} "#{@grammar_file_path}" {#{sym.printer.translated_code(sym.tag)}} @@ -145,18 +137,14 @@ module Lrama break; STR - end - - str + end.join end def symbol_actions_for_destructor - str = "" - - @grammar.symbols.each do |sym| + @grammar.symbols.map do |sym| next unless sym.destructor - str << <<-STR + <<-STR case #{sym.enum_name}: /* #{sym.comment} */ #line #{sym.destructor.lineno} "#{@grammar_file_path}" {#{sym.destructor.translated_code(sym.tag)}} @@ -164,9 +152,7 @@ module Lrama break; STR - end - - str + end.join end # b4_user_initial_action @@ -236,12 +222,10 @@ module Lrama end def symbol_actions_for_error_token - str = "" - - @grammar.symbols.each do |sym| + @grammar.symbols.map do |sym| next unless sym.error_token - str << <<-STR + <<-STR case #{sym.enum_name}: /* #{sym.comment} */ #line #{sym.error_token.lineno} "#{@grammar_file_path}" {#{sym.error_token.translated_code(sym.tag)}} @@ -249,22 +233,18 @@ module Lrama break; STR - end - - str + end.join end # b4_user_actions def user_actions - str = "" - - @context.states.rules.each do |rule| + action = @context.states.rules.map do |rule| next unless rule.token_code code = rule.token_code spaces = " " * (code.column - 1) - str << <<-STR + <<-STR case #{rule.id + 1}: /* #{rule.as_comment} */ #line #{code.line} "#{@grammar_file_path}" #{spaces}{#{rule.translated_code}} @@ -272,14 +252,12 @@ module Lrama break; STR - end + end.join - str << <<-STR + action + <<-STR #line [@oline@] [@ofile@] STR - - str end def omit_blanks(param) @@ -343,7 +321,7 @@ module Lrama # b4_parse_param_use def parse_param_use(val, loc) - str = <<-STR + str = <<-STR.dup YY_USE (#{val}); YY_USE (#{loc}); STR @@ -357,7 +335,8 @@ module Lrama # b4_yylex_formals def yylex_formals - ary = ["&yylval", "&yylloc"] + ary = ["&yylval"] + ary << "&yylloc" if @grammar.locations if @grammar.lex_param ary << lex_param_name @@ -397,17 +376,9 @@ module Lrama def int_array_to_string(ary) last = ary.count - 1 - s = ary.each_with_index.each_slice(10).map do |slice| - str = " " - - slice.each do |e, i| - str << sprintf("%6d%s", e, (i == last) ? "" : ",") - end - - str - end - - s.join("\n") + ary.each_with_index.each_slice(10).map do |slice| + " " + slice.map { |e, i| sprintf("%6d%s", e, (i == last) ? "" : ",") }.join + end.join("\n") end def spec_mapped_header_file @@ -457,26 +428,24 @@ module Lrama end def template_dir - File.expand_path("../../../template", __FILE__) + File.expand_path('../../template', __dir__) end def string_array_to_string(ary) - str = "" + result = "" tmp = " " ary.each do |s| - s = s.gsub('\\', '\\\\\\\\') - s = s.gsub('"', '\\"') - - if (tmp + s + " \"\",").length > 75 - str << tmp << "\n" - tmp = " \"#{s}\"," + replaced = s.gsub('\\', '\\\\\\\\').gsub('"', '\\"') + if (tmp + replaced + " \"\",").length > 75 + result = "#{result}#{tmp}\n" + tmp = " \"#{replaced}\"," else - tmp << " \"#{s}\"," + tmp = "#{tmp} \"#{replaced}\"," end end - str << tmp + result + tmp end def replace_special_variables(str, ofile) diff --git a/tools/lrama/lib/lrama/parser.rb b/tools/lrama/lib/lrama/parser.rb index 04603105b..177e784e5 100644 --- a/tools/lrama/lib/lrama/parser.rb +++ b/tools/lrama/lib/lrama/parser.rb @@ -1,6 +1,6 @@ # # DO NOT MODIFY!!!! -# This file is automatically generated by Racc 1.7.3 +# This file is automatically generated by Racc 1.8.1 # from Racc grammar file "parser.y". # @@ -23,7 +23,7 @@ unless $".find {|p| p.end_with?('/racc/info.rb')} $".push "#{__dir__}/racc/info.rb" module Racc - VERSION = '1.7.3' + VERSION = '1.8.1' Version = VERSION Copyright = 'Copyright (c) 1999-2006 Minero Aoki' end @@ -31,10 +31,6 @@ end end -unless defined?(NotImplementedError) - NotImplementedError = NotImplementError # :nodoc: -end - module Racc class ParseError < StandardError; end end @@ -42,7 +38,7 @@ unless defined?(::ParseError) ParseError = Racc::ParseError # :nodoc: end -# Racc is a LALR(1) parser generator. +# Racc is an LALR(1) parser generator. # It is written in Ruby itself, and generates Ruby programs. # # == Command-line Reference @@ -658,21 +654,22 @@ end module Lrama class Parser < Racc::Parser -module_eval(<<'...end parser.y/module_eval...', 'parser.y', 536) +module_eval(<<'...end parser.y/module_eval...', 'parser.y', 428) include Lrama::Report::Duration -def initialize(text, path, debug = false) +def initialize(text, path, debug = false, define = {}) @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) + @define = define end def parse report_duration(:parse) do @lexer = Lrama::Lexer.new(@grammar_file) - @grammar = Lrama::Grammar.new(@rule_counter) + @grammar = Lrama::Grammar.new(@rule_counter, @define) @precedence_number = 0 reset_precs do_parse @@ -732,322 +729,306 @@ end ##### State transition tables begin ### racc_action_table = [ - 98, 51, 99, 163, 88, 79, 51, 51, 180, 163, - 79, 79, 51, 162, 180, 156, 79, 165, 157, 51, - 3, 50, 181, 165, 70, 51, 8, 50, 181, 79, - 75, 51, 6, 50, 7, 161, 82, 47, 51, 51, - 50, 50, 89, 82, 82, 166, 41, 51, 100, 50, - 182, 166, 82, 51, 48, 50, 182, 23, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 47, 51, 51, 50, 50, 93, 79, 197, - 51, 51, 50, 50, 79, 197, 51, 51, 50, 50, - 79, 197, 23, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 9, 51, 54, - 50, 14, 15, 16, 17, 18, 19, 54, 54, 20, - 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 51, 51, - 50, 50, 79, 197, 51, 51, 50, 50, 79, 197, - 51, 51, 50, 50, 79, 197, 51, 51, 50, 50, - 79, 79, 51, 51, 50, 50, 79, 79, 51, 51, - 50, 50, 79, 79, 51, 51, 50, 207, 79, 79, - 51, 51, 207, 207, 79, 79, 51, 51, 50, 50, - 79, 187, 188, 189, 96, 187, 188, 189, 96, 217, - 221, 229, 218, 218, 218, 51, 51, 50, 50, 187, - 188, 189, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 90, 94, 96, 101, 101, 101, 103, - 109, 113, 114, 117, 117, 117, 117, 120, 47, 124, - 125, 127, 129, 130, 131, 132, 133, 136, 140, 141, - 142, 143, 146, 147, 148, 150, 160, 168, 170, 171, - 172, 173, 174, 176, 177, 178, 146, 184, 192, 193, - 200, 160, 204, 176, 211, 160, 215, 216, 178, 176, - 226, 176, 228, 96, 96, 176 ] + 89, 49, 90, 167, 49, 101, 173, 49, 101, 167, + 49, 101, 173, 6, 101, 80, 49, 49, 48, 48, + 41, 76, 76, 49, 49, 48, 48, 42, 76, 76, + 49, 49, 48, 48, 101, 96, 113, 49, 87, 48, + 150, 101, 96, 151, 45, 171, 169, 170, 151, 176, + 170, 91, 169, 170, 81, 176, 170, 20, 24, 25, + 26, 27, 28, 29, 30, 31, 87, 32, 33, 34, + 35, 36, 37, 38, 39, 49, 4, 48, 5, 101, + 96, 181, 182, 183, 128, 20, 24, 25, 26, 27, + 28, 29, 30, 31, 46, 32, 33, 34, 35, 36, + 37, 38, 39, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 53, 20, 24, 25, 26, 27, 28, 29, + 30, 31, 53, 32, 33, 34, 35, 36, 37, 38, + 39, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 44, 20, 24, 25, 26, 27, 28, 29, 30, 31, + 53, 32, 33, 34, 35, 36, 37, 38, 39, 49, + 4, 48, 5, 101, 96, 49, 49, 48, 48, 101, + 101, 49, 49, 48, 48, 101, 101, 49, 49, 48, + 197, 101, 101, 49, 49, 197, 48, 101, 101, 49, + 49, 197, 48, 101, 181, 182, 183, 128, 204, 210, + 217, 205, 205, 205, 49, 49, 48, 48, 49, 49, + 48, 48, 49, 49, 48, 48, 181, 182, 183, 116, + 117, 56, 53, 53, 53, 53, 53, 62, 63, 64, + 65, 66, 68, 68, 68, 82, 53, 53, 104, 108, + 108, 115, 122, 123, 125, 128, 129, 133, 139, 140, + 141, 142, 144, 145, 101, 154, 139, 157, 154, 161, + 162, 68, 164, 165, 172, 177, 154, 184, 128, 188, + 154, 190, 128, 154, 199, 154, 128, 68, 165, 206, + 165, 68, 68, 215, 128, 68 ] racc_action_check = [ - 49, 145, 49, 145, 39, 145, 159, 183, 159, 183, - 159, 183, 201, 144, 201, 139, 201, 145, 139, 33, - 1, 33, 159, 183, 33, 34, 3, 34, 201, 34, - 34, 35, 2, 35, 2, 144, 35, 9, 36, 37, - 36, 37, 39, 36, 37, 145, 7, 38, 49, 38, - 159, 183, 38, 15, 14, 15, 201, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 42, 69, 172, 69, 172, 42, 172, 172, - 173, 70, 173, 70, 173, 173, 174, 81, 174, 81, - 174, 174, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 4, 82, 16, - 82, 4, 4, 4, 4, 4, 4, 17, 18, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 194, 109, - 194, 109, 194, 194, 198, 111, 198, 111, 198, 198, - 199, 117, 199, 117, 199, 199, 74, 75, 74, 75, - 74, 75, 114, 116, 114, 116, 114, 116, 137, 166, - 137, 166, 137, 166, 182, 184, 182, 184, 182, 184, - 204, 216, 204, 216, 204, 216, 218, 119, 218, 119, - 218, 164, 164, 164, 164, 179, 179, 179, 179, 208, - 214, 223, 208, 214, 223, 134, 138, 134, 138, 209, - 209, 209, 19, 20, 23, 25, 26, 27, 28, 29, - 30, 31, 32, 40, 45, 46, 53, 55, 56, 57, - 68, 72, 73, 80, 85, 86, 87, 88, 89, 95, - 96, 102, 104, 105, 106, 107, 108, 112, 120, 121, - 122, 123, 124, 125, 126, 128, 141, 149, 151, 152, - 153, 154, 155, 156, 157, 158, 161, 163, 167, 169, - 175, 178, 180, 186, 190, 200, 205, 207, 213, 217, - 220, 221, 222, 226, 228, 230 ] + 47, 153, 47, 153, 159, 153, 159, 178, 159, 178, + 189, 178, 189, 1, 189, 39, 35, 36, 35, 36, + 5, 35, 36, 37, 38, 37, 38, 6, 37, 38, + 59, 74, 59, 74, 59, 59, 74, 60, 45, 60, + 138, 60, 60, 138, 9, 156, 153, 153, 156, 159, + 159, 47, 178, 178, 39, 189, 189, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 83, 45, 45, 45, + 45, 45, 45, 45, 45, 61, 0, 61, 0, 61, + 61, 166, 166, 166, 166, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 11, 83, 83, 83, 83, 83, + 83, 83, 83, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 13, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 14, 3, 3, 3, 3, 3, 3, 3, + 3, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 15, 8, 8, 8, 8, 8, 8, 8, 8, 97, + 2, 97, 2, 97, 97, 71, 108, 71, 108, 71, + 108, 109, 169, 109, 169, 109, 169, 176, 184, 176, + 184, 176, 184, 190, 205, 190, 205, 190, 205, 206, + 12, 206, 12, 206, 174, 174, 174, 174, 196, 201, + 214, 196, 201, 214, 69, 76, 69, 76, 104, 105, + 104, 105, 111, 113, 111, 113, 198, 198, 198, 81, + 81, 16, 17, 20, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 40, 51, 56, 67, 70, + 72, 80, 84, 85, 86, 87, 93, 107, 115, 116, + 117, 118, 127, 128, 134, 140, 141, 143, 144, 145, + 146, 150, 151, 152, 158, 163, 165, 167, 168, 171, + 172, 173, 175, 177, 187, 188, 192, 193, 195, 197, + 200, 202, 204, 209, 210, 216 ] racc_action_pointer = [ - nil, 20, 22, 26, 98, nil, nil, 39, nil, 33, - nil, nil, nil, nil, 48, 50, 90, 98, 99, 207, - 194, nil, nil, 195, nil, 196, 197, 198, 213, 214, - 215, 216, 217, 16, 22, 28, 35, 36, 44, -1, - 221, nil, 68, nil, nil, 201, 174, nil, nil, -5, - nil, nil, nil, 207, nil, 208, 209, 210, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, 222, 70, - 78, nil, 225, 224, 153, 154, nil, nil, nil, nil, - 225, 84, 105, nil, nil, 226, 227, 228, 197, 234, - nil, nil, nil, nil, nil, 197, 235, nil, nil, nil, - nil, nil, 239, nil, 240, 241, 242, 243, 244, 136, - nil, 142, 240, nil, 159, nil, 160, 148, nil, 184, - 243, 207, 239, 249, 206, 201, 252, nil, 253, nil, - nil, nil, nil, nil, 202, nil, nil, 165, 203, -26, - nil, 210, nil, nil, -10, -2, nil, nil, nil, 237, - nil, 238, 239, 240, 241, 242, 255, 259, 220, 3, - nil, 220, nil, 227, 143, nil, 166, 248, nil, 249, - nil, nil, 71, 77, 83, 228, nil, nil, 225, 147, - 232, nil, 171, 4, 172, nil, 265, nil, nil, nil, - 272, nil, nil, nil, 135, nil, nil, nil, 141, 147, - 229, 9, nil, nil, 177, 274, nil, 237, 158, 161, - nil, nil, nil, 233, 159, nil, 178, 271, 183, nil, - 260, 273, 262, 160, nil, nil, 232, nil, 233, nil, - 277, nil, nil ] + 66, 13, 150, 90, nil, 13, 27, nil, 118, 35, + nil, 88, 187, 63, 73, 101, 216, 173, nil, nil, + 174, nil, nil, nil, 175, 176, 177, 222, 223, 224, + 225, 226, 224, 225, 226, 13, 14, 20, 21, 10, + 233, nil, nil, nil, nil, 34, nil, -5, nil, nil, + nil, 187, nil, nil, nil, nil, 188, nil, nil, 27, + 34, 72, nil, nil, nil, nil, nil, 230, nil, 201, + 231, 162, 232, nil, 28, nil, 202, nil, nil, nil, + 200, 215, nil, 62, 233, 221, 222, 191, nil, nil, + nil, nil, nil, 244, nil, nil, nil, 156, nil, nil, + nil, nil, nil, nil, 205, 206, nil, 241, 163, 168, + nil, 209, nil, 210, nil, 243, 206, 209, 240, nil, + nil, nil, nil, nil, nil, nil, nil, 209, 248, nil, + nil, nil, nil, nil, 247, nil, nil, nil, -2, nil, + 208, 251, nil, 255, 211, 204, 210, nil, nil, nil, + 253, 257, 217, -2, nil, nil, 3, nil, 218, 1, + nil, nil, nil, 222, nil, 219, 30, 226, 214, 169, + nil, 226, 223, 230, 143, 218, 174, 226, 4, nil, + nil, nil, nil, nil, 175, nil, nil, 272, 228, 7, + 180, nil, 222, 269, nil, 232, 156, 238, 165, nil, + 234, 157, 273, nil, 274, 181, 186, nil, nil, 233, + 230, nil, nil, nil, 158, nil, 277, nil, nil ] racc_action_default = [ - -2, -138, -8, -138, -138, -3, -4, -138, 233, -138, - -9, -10, -11, -12, -138, -138, -138, -138, -138, -138, - -138, -24, -25, -138, -29, -138, -138, -138, -138, -138, - -138, -138, -138, -138, -138, -138, -138, -138, -138, -138, - -138, -7, -123, -96, -98, -138, -120, -122, -13, -127, - -94, -95, -126, -15, -85, -16, -17, -138, -21, -26, - -30, -33, -36, -39, -40, -41, -42, -43, -44, -50, - -138, -53, -71, -45, -75, -138, -78, -80, -81, -135, - -46, -88, -138, -91, -93, -47, -48, -49, -138, -138, - -5, -1, -97, -124, -99, -138, -138, -14, -128, -129, - -130, -82, -138, -18, -138, -138, -138, -138, -138, -138, - -54, -51, -73, -72, -138, -79, -76, -138, -92, -89, - -138, -138, -138, -138, -104, -138, -138, -86, -138, -22, - -27, -31, -34, -37, -52, -55, -74, -77, -90, -138, - -58, -62, -6, -125, -100, -101, -105, -121, -83, -138, - -19, -138, -138, -138, -138, -138, -136, -138, -57, -60, - -63, -104, -103, -94, -120, -109, -138, -138, -87, -138, - -23, -28, -138, -138, -138, -138, -137, -59, -62, -120, - -94, -67, -138, -102, -138, -106, -136, -113, -114, -115, - -138, -112, -84, -20, -32, -131, -133, -134, -35, -38, - -62, -61, -64, -65, -138, -138, -70, -94, -138, -116, - -107, -110, -132, -56, -138, -68, -138, -136, -138, -118, - -138, -136, -138, -138, -108, -117, -120, -66, -120, -119, - -136, -69, -111 ] + -1, -128, -1, -3, -10, -128, -128, -2, -3, -128, + -16, -128, -128, -128, -128, -128, -128, -128, -24, -25, + -128, -32, -33, -34, -128, -128, -128, -128, -128, -128, + -128, -128, -50, -50, -50, -128, -128, -128, -128, -128, + -128, -13, 219, -4, -26, -128, -17, -123, -93, -94, + -122, -14, -19, -85, -20, -21, -128, -23, -31, -128, + -128, -128, -38, -39, -40, -41, -42, -43, -51, -128, + -44, -128, -45, -46, -88, -90, -128, -47, -48, -49, + -128, -128, -11, -5, -7, -95, -128, -68, -18, -124, + -125, -126, -15, -128, -22, -27, -28, -29, -35, -83, + -84, -127, -36, -37, -128, -52, -54, -56, -128, -79, + -81, -88, -89, -128, -91, -128, -128, -128, -128, -6, + -8, -9, -120, -96, -97, -98, -69, -128, -128, -86, + -30, -55, -53, -57, -76, -82, -80, -92, -128, -62, + -66, -128, -12, -128, -66, -128, -128, -58, -77, -78, + -50, -128, -60, -64, -67, -70, -128, -121, -99, -100, + -102, -119, -87, -128, -63, -66, -68, -93, -68, -128, + -116, -128, -66, -93, -68, -68, -128, -66, -65, -71, + -72, -108, -109, -110, -128, -74, -75, -128, -66, -101, + -128, -103, -68, -50, -107, -59, -128, -93, -111, -117, + -61, -128, -50, -106, -50, -128, -128, -112, -113, -128, + -68, -104, -73, -114, -128, -118, -50, -115, -105 ] racc_goto_table = [ - 76, 95, 69, 52, 74, 158, 110, 175, 118, 119, - 145, 208, 1, 212, 186, 2, 43, 212, 212, 4, - 42, 72, 91, 84, 84, 84, 84, 5, 40, 203, - 122, 214, 80, 85, 86, 87, 10, 210, 11, 111, - 115, 76, 12, 223, 138, 116, 118, 183, 110, 92, - 53, 55, 56, 194, 198, 199, 13, 72, 72, 219, - 49, 97, 128, 169, 213, 118, 104, 151, 224, 84, - 84, 110, 227, 105, 152, 106, 153, 107, 134, 154, - 76, 232, 115, 108, 137, 155, 68, 73, 112, 135, - 139, 121, 201, 205, 222, 126, 167, 72, 102, 72, - 149, 144, 190, 115, 220, 84, 123, 84, nil, nil, - nil, 164, nil, nil, nil, nil, nil, nil, nil, 185, - nil, nil, 72, nil, nil, 179, 84, nil, nil, nil, - nil, nil, 191, nil, 202, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, 206, 164, - 209, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, 179, nil, nil, - 209, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, 230, 209, 231, 225 ] + 69, 109, 50, 152, 57, 127, 84, 58, 112, 160, + 114, 59, 60, 61, 86, 52, 54, 55, 98, 102, + 103, 159, 106, 110, 175, 74, 74, 74, 74, 138, + 9, 1, 3, 180, 7, 43, 120, 160, 109, 109, + 195, 192, 121, 94, 119, 112, 40, 137, 118, 189, + 47, 200, 86, 92, 175, 156, 130, 131, 132, 107, + 135, 136, 88, 196, 111, 207, 111, 70, 72, 201, + 73, 77, 78, 79, 67, 147, 134, 178, 148, 149, + 93, 146, 124, 166, 179, 214, 185, 158, 208, 174, + 187, 209, 191, 193, 107, 107, 143, nil, nil, 186, + nil, 111, nil, 111, nil, nil, 194, nil, 166, nil, + 202, nil, nil, nil, 198, nil, nil, nil, 163, 174, + 198, nil, nil, nil, nil, nil, nil, nil, 216, nil, + nil, nil, nil, nil, nil, 213, 198, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, 203, nil, nil, nil, nil, nil, nil, nil, nil, + 211, nil, 212, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 218 ] racc_goto_check = [ - 43, 44, 33, 35, 49, 40, 34, 39, 56, 55, - 60, 46, 1, 64, 45, 2, 57, 64, 64, 3, - 4, 35, 5, 35, 35, 35, 35, 6, 7, 45, - 8, 46, 32, 32, 32, 32, 9, 39, 10, 33, - 43, 43, 11, 46, 55, 49, 56, 60, 34, 57, - 15, 15, 15, 21, 21, 21, 12, 35, 35, 45, - 13, 14, 16, 17, 40, 56, 18, 19, 39, 35, - 35, 34, 39, 22, 23, 24, 25, 26, 33, 27, - 43, 39, 43, 28, 49, 29, 30, 31, 36, 37, - 38, 41, 42, 47, 48, 51, 52, 35, 53, 35, - 54, 59, 61, 43, 62, 35, 63, 35, nil, nil, - nil, 43, nil, nil, nil, nil, nil, nil, nil, 44, - nil, nil, 35, nil, nil, 43, 35, nil, nil, nil, - nil, nil, 43, nil, 44, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, 43, 43, - 43, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, 43, nil, nil, - 43, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, 44, 43, 44, 43 ] + 27, 20, 29, 33, 15, 40, 8, 15, 46, 39, + 46, 15, 15, 15, 12, 16, 16, 16, 22, 22, + 22, 50, 28, 43, 38, 29, 29, 29, 29, 32, + 7, 1, 6, 36, 6, 7, 5, 39, 20, 20, + 33, 36, 9, 15, 8, 46, 10, 46, 11, 50, + 13, 33, 12, 16, 38, 32, 22, 28, 28, 29, + 43, 43, 14, 37, 29, 36, 29, 24, 24, 37, + 25, 25, 25, 25, 23, 30, 31, 34, 41, 42, + 44, 45, 48, 20, 40, 37, 40, 49, 51, 20, + 52, 53, 40, 40, 29, 29, 54, nil, nil, 20, + nil, 29, nil, 29, nil, nil, 20, nil, 20, nil, + 40, nil, nil, nil, 20, nil, nil, nil, 27, 20, + 20, nil, nil, nil, nil, nil, nil, nil, 40, nil, + nil, nil, nil, nil, nil, 20, 20, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, 27, nil, nil, nil, nil, nil, nil, nil, nil, + 27, nil, 27, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 27 ] racc_goto_pointer = [ - nil, 12, 15, 17, 11, -20, 25, 22, -60, 32, - 34, 38, 52, 45, 12, 34, -41, -87, 8, -62, - nil, -119, 14, -56, 15, -55, 16, -53, 21, -48, - 53, 53, -3, -31, -63, -12, 16, -23, -30, -149, - -136, 2, -86, -34, -45, -150, -173, -88, -121, -30, - nil, -6, -52, 44, -27, -73, -73, 7, nil, -23, - -114, -63, -107, 13, -181 ] + nil, 31, nil, nil, nil, -48, 32, 27, -39, -42, + 42, -34, -31, 38, 15, -13, 2, nil, nil, nil, + -70, nil, -41, 42, 34, 35, nil, -32, -47, -10, + -59, -31, -86, -137, -88, nil, -133, -121, -135, -135, + -82, -56, -55, -48, 27, -48, -66, nil, -3, -57, + -123, -110, -80, -108, -26 ] racc_goto_default = [ - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 45, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 24, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, 71, 77, nil, nil, nil, nil, - nil, 46, 159, 196, nil, nil, nil, nil, nil, nil, - 78, nil, nil, nil, nil, 81, 83, nil, 44, nil, - nil, nil, nil, nil, 195 ] + nil, nil, 2, 8, 83, nil, nil, nil, nil, nil, + nil, nil, 10, nil, nil, 51, nil, 21, 22, 23, + 95, 97, nil, nil, nil, nil, 105, 71, nil, 99, + nil, nil, nil, nil, 153, 126, nil, nil, 168, 155, + nil, 100, nil, nil, nil, nil, 75, 85, nil, nil, + nil, nil, nil, nil, nil ] racc_reduce_table = [ 0, 0, :racc_error, - 5, 55, :_reduce_none, - 0, 56, :_reduce_none, - 2, 56, :_reduce_none, - 0, 61, :_reduce_4, - 0, 62, :_reduce_5, - 5, 60, :_reduce_6, + 0, 63, :_reduce_1, + 2, 63, :_reduce_2, + 0, 64, :_reduce_3, + 2, 64, :_reduce_4, + 1, 65, :_reduce_5, + 2, 65, :_reduce_6, + 0, 66, :_reduce_none, + 1, 66, :_reduce_none, + 5, 58, :_reduce_none, + 0, 67, :_reduce_10, + 0, 68, :_reduce_11, + 5, 59, :_reduce_12, + 2, 59, :_reduce_none, + 1, 73, :_reduce_14, + 2, 73, :_reduce_15, + 1, 60, :_reduce_none, + 2, 60, :_reduce_17, + 3, 60, :_reduce_18, 2, 60, :_reduce_none, - 0, 57, :_reduce_8, - 2, 57, :_reduce_none, - 1, 63, :_reduce_none, - 1, 63, :_reduce_none, - 1, 63, :_reduce_none, - 2, 63, :_reduce_13, - 3, 63, :_reduce_none, - 2, 63, :_reduce_none, - 2, 63, :_reduce_16, - 2, 63, :_reduce_17, - 0, 70, :_reduce_18, - 0, 71, :_reduce_19, - 7, 63, :_reduce_20, - 0, 72, :_reduce_21, - 0, 73, :_reduce_22, - 6, 63, :_reduce_23, - 1, 63, :_reduce_24, - 1, 63, :_reduce_none, - 0, 76, :_reduce_26, - 0, 77, :_reduce_27, - 6, 64, :_reduce_28, - 1, 64, :_reduce_none, - 0, 78, :_reduce_30, - 0, 79, :_reduce_31, - 7, 64, :_reduce_32, - 0, 80, :_reduce_33, - 0, 81, :_reduce_34, - 7, 64, :_reduce_35, - 0, 82, :_reduce_36, - 0, 83, :_reduce_37, - 7, 64, :_reduce_38, - 2, 64, :_reduce_39, - 2, 64, :_reduce_40, - 2, 64, :_reduce_41, - 2, 64, :_reduce_42, - 2, 64, :_reduce_43, + 2, 60, :_reduce_20, + 2, 60, :_reduce_21, + 3, 60, :_reduce_22, + 2, 60, :_reduce_23, + 1, 60, :_reduce_24, + 1, 60, :_reduce_25, + 2, 60, :_reduce_none, + 1, 78, :_reduce_27, + 1, 78, :_reduce_28, + 1, 79, :_reduce_29, + 2, 79, :_reduce_30, + 2, 69, :_reduce_31, + 1, 69, :_reduce_none, + 1, 69, :_reduce_none, + 1, 69, :_reduce_none, + 3, 69, :_reduce_35, + 3, 69, :_reduce_36, + 3, 69, :_reduce_37, + 2, 69, :_reduce_38, + 2, 69, :_reduce_39, + 2, 69, :_reduce_40, + 2, 69, :_reduce_41, + 2, 69, :_reduce_42, 2, 74, :_reduce_none, + 2, 74, :_reduce_44, 2, 74, :_reduce_45, 2, 74, :_reduce_46, 2, 74, :_reduce_47, 2, 74, :_reduce_48, 2, 74, :_reduce_49, - 1, 84, :_reduce_50, - 2, 84, :_reduce_51, - 3, 84, :_reduce_52, - 1, 87, :_reduce_53, - 2, 87, :_reduce_54, - 3, 88, :_reduce_55, - 8, 65, :_reduce_56, - 5, 66, :_reduce_57, - 1, 92, :_reduce_58, - 3, 92, :_reduce_59, - 1, 94, :_reduce_60, - 3, 94, :_reduce_61, - 0, 96, :_reduce_62, - 1, 96, :_reduce_63, - 3, 96, :_reduce_64, - 3, 96, :_reduce_65, - 6, 96, :_reduce_66, - 0, 101, :_reduce_67, - 0, 102, :_reduce_68, - 7, 96, :_reduce_69, - 3, 96, :_reduce_70, - 0, 90, :_reduce_none, - 1, 90, :_reduce_none, - 0, 91, :_reduce_none, - 1, 91, :_reduce_none, - 1, 85, :_reduce_75, - 2, 85, :_reduce_76, - 3, 85, :_reduce_77, - 1, 103, :_reduce_78, - 2, 103, :_reduce_79, + 0, 84, :_reduce_none, + 1, 84, :_reduce_none, + 1, 85, :_reduce_52, + 2, 85, :_reduce_53, + 2, 80, :_reduce_54, + 3, 80, :_reduce_55, + 0, 88, :_reduce_none, + 1, 88, :_reduce_none, + 3, 83, :_reduce_58, + 8, 75, :_reduce_59, + 5, 76, :_reduce_60, + 8, 76, :_reduce_61, + 1, 89, :_reduce_62, + 3, 89, :_reduce_63, + 1, 90, :_reduce_64, + 3, 90, :_reduce_65, + 0, 96, :_reduce_none, + 1, 96, :_reduce_none, + 0, 97, :_reduce_none, 1, 97, :_reduce_none, - 1, 97, :_reduce_none, - 0, 105, :_reduce_82, - 0, 106, :_reduce_83, - 6, 69, :_reduce_84, - 0, 107, :_reduce_85, - 0, 108, :_reduce_86, - 5, 69, :_reduce_87, - 1, 86, :_reduce_88, - 2, 86, :_reduce_89, - 3, 86, :_reduce_90, - 1, 109, :_reduce_91, - 2, 109, :_reduce_92, - 1, 110, :_reduce_none, - 1, 89, :_reduce_94, - 1, 89, :_reduce_95, - 1, 58, :_reduce_none, - 2, 58, :_reduce_none, - 1, 111, :_reduce_none, - 2, 111, :_reduce_none, - 4, 112, :_reduce_100, - 1, 113, :_reduce_101, - 3, 113, :_reduce_102, - 2, 113, :_reduce_none, - 0, 114, :_reduce_104, - 1, 114, :_reduce_105, - 3, 114, :_reduce_106, - 4, 114, :_reduce_107, - 6, 114, :_reduce_108, - 0, 115, :_reduce_109, - 0, 116, :_reduce_110, - 8, 114, :_reduce_111, - 3, 114, :_reduce_112, - 1, 99, :_reduce_113, - 1, 99, :_reduce_114, - 1, 99, :_reduce_115, - 1, 100, :_reduce_116, - 3, 100, :_reduce_117, - 2, 100, :_reduce_118, - 4, 100, :_reduce_119, - 0, 98, :_reduce_none, - 3, 98, :_reduce_121, - 1, 95, :_reduce_none, - 0, 59, :_reduce_none, - 0, 117, :_reduce_124, - 3, 59, :_reduce_125, - 1, 67, :_reduce_none, - 0, 68, :_reduce_none, - 1, 68, :_reduce_none, - 1, 68, :_reduce_none, - 1, 68, :_reduce_none, - 1, 75, :_reduce_131, - 2, 75, :_reduce_132, - 1, 118, :_reduce_none, - 1, 118, :_reduce_none, - 1, 104, :_reduce_135, - 0, 93, :_reduce_none, - 1, 93, :_reduce_none ] + 1, 91, :_reduce_70, + 3, 91, :_reduce_71, + 3, 91, :_reduce_72, + 6, 91, :_reduce_73, + 3, 91, :_reduce_74, + 3, 91, :_reduce_75, + 0, 99, :_reduce_none, + 1, 99, :_reduce_none, + 1, 87, :_reduce_78, + 1, 100, :_reduce_79, + 2, 100, :_reduce_80, + 2, 81, :_reduce_81, + 3, 81, :_reduce_82, + 1, 77, :_reduce_none, + 1, 77, :_reduce_none, + 0, 101, :_reduce_85, + 0, 102, :_reduce_86, + 5, 72, :_reduce_87, + 1, 103, :_reduce_88, + 2, 103, :_reduce_89, + 1, 82, :_reduce_90, + 2, 82, :_reduce_91, + 3, 82, :_reduce_92, + 1, 86, :_reduce_93, + 1, 86, :_reduce_94, + 0, 105, :_reduce_none, + 1, 105, :_reduce_none, + 2, 61, :_reduce_none, + 2, 61, :_reduce_none, + 4, 104, :_reduce_99, + 1, 106, :_reduce_100, + 3, 106, :_reduce_101, + 1, 107, :_reduce_102, + 3, 107, :_reduce_103, + 5, 107, :_reduce_104, + 7, 107, :_reduce_105, + 4, 107, :_reduce_106, + 3, 107, :_reduce_107, + 1, 93, :_reduce_108, + 1, 93, :_reduce_109, + 1, 93, :_reduce_110, + 0, 108, :_reduce_none, + 1, 108, :_reduce_none, + 2, 94, :_reduce_113, + 3, 94, :_reduce_114, + 4, 94, :_reduce_115, + 0, 109, :_reduce_116, + 0, 110, :_reduce_117, + 5, 95, :_reduce_118, + 3, 92, :_reduce_119, + 0, 111, :_reduce_120, + 3, 62, :_reduce_121, + 1, 70, :_reduce_none, + 0, 71, :_reduce_none, + 1, 71, :_reduce_none, + 1, 71, :_reduce_none, + 1, 71, :_reduce_none, + 1, 98, :_reduce_127 ] -racc_reduce_n = 138 +racc_reduce_n = 128 -racc_shift_n = 233 +racc_shift_n = 219 racc_token_table = { false => 0, @@ -1069,43 +1050,46 @@ racc_token_table = { "%lex-param" => 16, "%parse-param" => 17, "%code" => 18, - "{" => 19, - "}" => 20, - "%initial-action" => 21, - "%no-stdlib" => 22, - ";" => 23, - "%union" => 24, - "%destructor" => 25, - "%printer" => 26, - "%error-token" => 27, - "%after-shift" => 28, - "%before-reduce" => 29, - "%after-reduce" => 30, - "%after-shift-error-token" => 31, - "%after-pop-stack" => 32, + "%initial-action" => 19, + "%no-stdlib" => 20, + "%locations" => 21, + ";" => 22, + "%union" => 23, + "%destructor" => 24, + "%printer" => 25, + "%error-token" => 26, + "%after-shift" => 27, + "%before-reduce" => 28, + "%after-reduce" => 29, + "%after-shift-error-token" => 30, + "%after-pop-stack" => 31, + "-temp-group" => 32, "%token" => 33, "%type" => 34, - "%left" => 35, - "%right" => 36, - "%precedence" => 37, - "%nonassoc" => 38, - "%rule" => 39, - "(" => 40, - ")" => 41, - ":" => 42, - "%inline" => 43, - "," => 44, - "|" => 45, - "%empty" => 46, - "%prec" => 47, - "?" => 48, - "+" => 49, - "*" => 50, - "[" => 51, - "]" => 52, - "{...}" => 53 } + "%nterm" => 35, + "%left" => 36, + "%right" => 37, + "%precedence" => 38, + "%nonassoc" => 39, + "%rule" => 40, + "(" => 41, + ")" => 42, + ":" => 43, + "%inline" => 44, + "," => 45, + "|" => 46, + "%empty" => 47, + "%prec" => 48, + "{" => 49, + "}" => 50, + "?" => 51, + "+" => 52, + "*" => 53, + "[" => 54, + "]" => 55, + "{...}" => 56 } -racc_nt_base = 54 +racc_nt_base = 57 racc_use_result_var = true @@ -1146,10 +1130,9 @@ Racc_token_to_s_table = [ "\"%lex-param\"", "\"%parse-param\"", "\"%code\"", - "\"{\"", - "\"}\"", "\"%initial-action\"", "\"%no-stdlib\"", + "\"%locations\"", "\";\"", "\"%union\"", "\"%destructor\"", @@ -1160,8 +1143,10 @@ Racc_token_to_s_table = [ "\"%after-reduce\"", "\"%after-shift-error-token\"", "\"%after-pop-stack\"", + "\"-temp-group\"", "\"%token\"", "\"%type\"", + "\"%nterm\"", "\"%left\"", "\"%right\"", "\"%precedence\"", @@ -1175,6 +1160,8 @@ Racc_token_to_s_table = [ "\"|\"", "\"%empty\"", "\"%prec\"", + "\"{\"", + "\"}\"", "\"?\"", "\"+\"", "\"*\"", @@ -1183,69 +1170,59 @@ Racc_token_to_s_table = [ "\"{...}\"", "$start", "input", - "prologue_declarations", - "bison_declarations", - "grammar", - "epilogue_opt", "prologue_declaration", + "bison_declaration", + "rules_or_grammar_declaration", + "epilogue_declaration", + "\"-many@prologue_declaration\"", + "\"-many@bison_declaration\"", + "\"-many1@rules_or_grammar_declaration\"", + "\"-option@epilogue_declaration\"", "@1", "@2", - "bison_declaration", "grammar_declaration", - "rule_declaration", - "inline_declaration", "variable", "value", - "params", - "@3", - "@4", - "@5", - "@6", + "param", + "\"-many1@param\"", "symbol_declaration", - "generic_symlist", - "@7", - "@8", - "@9", - "@10", - "@11", - "@12", - "@13", - "@14", + "rule_declaration", + "inline_declaration", + "symbol", + "\"-group@symbol|TAG\"", + "\"-many1@-group@symbol|TAG\"", "token_declarations", "symbol_declarations", "token_declarations_for_precedence", - "token_declaration_list", "token_declaration", + "\"-option@TAG\"", + "\"-many1@token_declaration\"", "id", - "int_opt", "alias", + "\"-option@INTEGER\"", "rule_args", - "tag_opt", "rule_rhs_list", - "id_colon", "rule_rhs", - "symbol", - "named_ref_opt", + "named_ref", "parameterizing_suffix", "parameterizing_args", - "@15", - "@16", - "symbol_declaration_list", + "midrule_action", + "\"-option@%empty\"", + "\"-option@named_ref\"", "string_as_id", - "@17", - "@18", - "@19", - "@20", - "token_declaration_list_for_precedence", - "token_declaration_for_precedence", - "rules_or_grammar_declaration", + "\"-option@string_as_id\"", + "\"-many1@symbol\"", + "@3", + "@4", + "\"-many1@id\"", "rules", + "\"-option@;\"", "rhs_list", "rhs", - "@21", - "@22", - "@23", - "generic_symlist_item" ] + "\"-option@parameterizing_suffix\"", + "@5", + "@6", + "@7" ] Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor) Racc_debug_parser = true @@ -1254,14 +1231,56 @@ Racc_debug_parser = true # reduce 0 omitted -# reduce 1 omitted +module_eval(<<'.,.,', 'parser.y', 11) + def _reduce_1(val, _values, result) + result = val[1] ? val[1].unshift(val[0]) : val + result + end +.,., -# reduce 2 omitted +module_eval(<<'.,.,', 'parser.y', 11) + def _reduce_2(val, _values, result) + result = val[1] ? val[1].unshift(val[0]) : val + result + end +.,., -# reduce 3 omitted +module_eval(<<'.,.,', 'parser.y', 11) + def _reduce_3(val, _values, result) + result = val[1] ? val[1].unshift(val[0]) : val + result + end +.,., -module_eval(<<'.,.,', 'parser.y', 14) +module_eval(<<'.,.,', 'parser.y', 11) def _reduce_4(val, _values, result) + result = val[1] ? val[1].unshift(val[0]) : val + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 11) + def _reduce_5(val, _values, result) + result = val[1] ? val[1].unshift(val[0]) : val + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 11) + def _reduce_6(val, _values, result) + result = val[1] ? val[1].unshift(val[0]) : val + result + end +.,., + +# reduce 7 omitted + +# reduce 8 omitted + +# reduce 9 omitted + +module_eval(<<'.,.,', 'parser.y', 12) + def _reduce_10(val, _values, result) begin_c_declaration("%}") @grammar.prologue_first_lineno = @lexer.line @@ -1269,52 +1288,58 @@ module_eval(<<'.,.,', 'parser.y', 14) end .,., -module_eval(<<'.,.,', 'parser.y', 19) - def _reduce_5(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 17) + def _reduce_11(val, _values, result) end_c_declaration result end .,., -module_eval(<<'.,.,', 'parser.y', 23) - def _reduce_6(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 21) + def _reduce_12(val, _values, result) @grammar.prologue = val[2].s_value result end .,., -# reduce 7 omitted +# reduce 13 omitted -module_eval(<<'.,.,', 'parser.y', 27) - def _reduce_8(val, _values, result) - result = "" +module_eval(<<'.,.,', 'parser.y', 54) + def _reduce_14(val, _values, result) + result = val[1] ? val[1].unshift(val[0]) : val result end .,., -# reduce 9 omitted +module_eval(<<'.,.,', 'parser.y', 54) + def _reduce_15(val, _values, result) + result = val[1] ? val[1].unshift(val[0]) : val + result + end +.,., -# reduce 10 omitted +# reduce 16 omitted -# reduce 11 omitted - -# reduce 12 omitted - -module_eval(<<'.,.,', 'parser.y', 33) - def _reduce_13(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 26) + def _reduce_17(val, _values, result) @grammar.expect = val[1] result end .,., -# reduce 14 omitted +module_eval(<<'.,.,', 'parser.y', 27) + def _reduce_18(val, _values, result) + @grammar.define[val[1].s_value] = val[2]&.s_value + result + end +.,., -# reduce 15 omitted +# reduce 19 omitted -module_eval(<<'.,.,', 'parser.y', 38) - def _reduce_16(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 31) + def _reduce_20(val, _values, result) val[1].each {|token| @grammar.lex_param = Grammar::Code::NoReferenceCode.new(type: :lex_param, token_code: token).token_code.s_value } @@ -1323,8 +1348,8 @@ module_eval(<<'.,.,', 'parser.y', 38) end .,., -module_eval(<<'.,.,', 'parser.y', 44) - def _reduce_17(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 37) + def _reduce_21(val, _values, result) val[1].each {|token| @grammar.parse_param = Grammar::Code::NoReferenceCode.new(type: :parse_param, token_code: token).token_code.s_value } @@ -1333,220 +1358,163 @@ module_eval(<<'.,.,', 'parser.y', 44) end .,., -module_eval(<<'.,.,', 'parser.y', 50) - def _reduce_18(val, _values, result) - begin_c_declaration("}") - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 54) - def _reduce_19(val, _values, result) - end_c_declaration - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 58) - def _reduce_20(val, _values, result) - @grammar.add_percent_code(id: val[1], code: val[4]) - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 62) - def _reduce_21(val, _values, result) - begin_c_declaration("}") - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 66) +module_eval(<<'.,.,', 'parser.y', 43) def _reduce_22(val, _values, result) - end_c_declaration + @grammar.add_percent_code(id: val[1], code: val[2]) result end .,., -module_eval(<<'.,.,', 'parser.y', 70) +module_eval(<<'.,.,', 'parser.y', 47) def _reduce_23(val, _values, result) - @grammar.initial_action = Grammar::Code::InitialActionCode.new(type: :initial_action, token_code: val[3]) + @grammar.initial_action = Grammar::Code::InitialActionCode.new(type: :initial_action, token_code: val[1]) result end .,., -module_eval(<<'.,.,', 'parser.y', 72) +module_eval(<<'.,.,', 'parser.y', 49) def _reduce_24(val, _values, result) @grammar.no_stdlib = true result end .,., -# reduce 25 omitted +module_eval(<<'.,.,', 'parser.y', 50) + def _reduce_25(val, _values, result) + @grammar.locations = true + result + end +.,., -module_eval(<<'.,.,', 'parser.y', 77) - def _reduce_26(val, _values, result) - begin_c_declaration("}") +# reduce 26 omitted + +module_eval(<<'.,.,', 'parser.y', 109) + def _reduce_27(val, _values, result) + result = val + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 109) + def _reduce_28(val, _values, result) + result = val + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 109) + def _reduce_29(val, _values, result) + result = val[1] ? val[1].unshift(val[0]) : val + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 109) + def _reduce_30(val, _values, result) + result = val[1] ? val[1].unshift(val[0]) : val + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 55) + def _reduce_31(val, _values, result) + @grammar.set_union( + Grammar::Code::NoReferenceCode.new(type: :union, token_code: val[1]), + val[1].line + ) + + result + end +.,., + +# reduce 32 omitted + +# reduce 33 omitted + +# reduce 34 omitted + +module_eval(<<'.,.,', 'parser.y', 65) + def _reduce_35(val, _values, result) + @grammar.add_destructor( + ident_or_tags: val[2].flatten, + token_code: val[1], + lineno: val[1].line + ) + + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 73) + def _reduce_36(val, _values, result) + @grammar.add_printer( + ident_or_tags: val[2].flatten, + token_code: val[1], + lineno: val[1].line + ) result end .,., module_eval(<<'.,.,', 'parser.y', 81) - def _reduce_27(val, _values, result) - end_c_declaration - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 85) - def _reduce_28(val, _values, result) - @grammar.set_union( - Grammar::Code::NoReferenceCode.new(type: :union, token_code: val[3]), - val[3].line - ) - - result - end -.,., - -# reduce 29 omitted - -module_eval(<<'.,.,', 'parser.y', 93) - def _reduce_30(val, _values, result) - begin_c_declaration("}") - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 97) - def _reduce_31(val, _values, result) - end_c_declaration - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 101) - def _reduce_32(val, _values, result) - @grammar.add_destructor( - ident_or_tags: val[6], - token_code: val[3], - lineno: val[3].line - ) - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 109) - def _reduce_33(val, _values, result) - begin_c_declaration("}") - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 113) - def _reduce_34(val, _values, result) - end_c_declaration - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 117) - def _reduce_35(val, _values, result) - @grammar.add_printer( - ident_or_tags: val[6], - token_code: val[3], - lineno: val[3].line - ) - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 125) - def _reduce_36(val, _values, result) - begin_c_declaration("}") - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 129) def _reduce_37(val, _values, result) - end_c_declaration - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 133) - def _reduce_38(val, _values, result) @grammar.add_error_token( - ident_or_tags: val[6], - token_code: val[3], - lineno: val[3].line + ident_or_tags: val[2].flatten, + token_code: val[1], + lineno: val[1].line ) result end .,., -module_eval(<<'.,.,', 'parser.y', 141) - def _reduce_39(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 89) + def _reduce_38(val, _values, result) @grammar.after_shift = val[1] result end .,., -module_eval(<<'.,.,', 'parser.y', 145) - def _reduce_40(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 93) + def _reduce_39(val, _values, result) @grammar.before_reduce = val[1] result end .,., -module_eval(<<'.,.,', 'parser.y', 149) - def _reduce_41(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 97) + def _reduce_40(val, _values, result) @grammar.after_reduce = val[1] result end .,., -module_eval(<<'.,.,', 'parser.y', 153) - def _reduce_42(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 101) + def _reduce_41(val, _values, result) @grammar.after_shift_error_token = val[1] result end .,., -module_eval(<<'.,.,', 'parser.y', 157) - def _reduce_43(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 105) + def _reduce_42(val, _values, result) @grammar.after_pop_stack = val[1] result end .,., -# reduce 44 omitted +# reduce 43 omitted -module_eval(<<'.,.,', 'parser.y', 163) - def _reduce_45(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 111) + def _reduce_44(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| @grammar.add_type(id: id, tag: hash[:tag]) @@ -1557,7 +1525,23 @@ module_eval(<<'.,.,', 'parser.y', 163) end .,., -module_eval(<<'.,.,', 'parser.y', 171) +module_eval(<<'.,.,', 'parser.y', 119) + def _reduce_45(val, _values, result) + val[1].each {|hash| + hash[:tokens].each {|id| + if @grammar.find_term_by_s_value(id.s_value) + on_action_error("symbol #{id.s_value} redeclared as a nonterminal", id) + else + @grammar.add_type(id: id, tag: hash[:tag]) + end + } + } + + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 131) def _reduce_46(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| @@ -1571,7 +1555,7 @@ module_eval(<<'.,.,', 'parser.y', 171) end .,., -module_eval(<<'.,.,', 'parser.y', 181) +module_eval(<<'.,.,', 'parser.y', 141) def _reduce_47(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| @@ -1585,7 +1569,7 @@ module_eval(<<'.,.,', 'parser.y', 181) end .,., -module_eval(<<'.,.,', 'parser.y', 191) +module_eval(<<'.,.,', 'parser.y', 151) def _reduce_48(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| @@ -1599,7 +1583,7 @@ module_eval(<<'.,.,', 'parser.y', 191) end .,., -module_eval(<<'.,.,', 'parser.y', 201) +module_eval(<<'.,.,', 'parser.y', 161) def _reduce_49(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| @@ -1613,18 +1597,26 @@ module_eval(<<'.,.,', 'parser.y', 201) end .,., -module_eval(<<'.,.,', 'parser.y', 212) - def _reduce_50(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) - } +# reduce 50 omitted +# reduce 51 omitted + +module_eval(<<'.,.,', 'parser.y', 184) + def _reduce_52(val, _values, result) + result = val[1] ? val[1].unshift(val[0]) : val result end .,., -module_eval(<<'.,.,', 'parser.y', 218) - def _reduce_51(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 184) + def _reduce_53(val, _values, result) + result = val[1] ? val[1].unshift(val[0]) : val + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 172) + def _reduce_54(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) } @@ -1633,8 +1625,8 @@ module_eval(<<'.,.,', 'parser.y', 218) end .,., -module_eval(<<'.,.,', 'parser.y', 224) - def _reduce_52(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 178) + def _reduce_55(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) } @@ -1643,29 +1635,19 @@ module_eval(<<'.,.,', 'parser.y', 224) end .,., -module_eval(<<'.,.,', 'parser.y', 229) - def _reduce_53(val, _values, result) - result = [val[0]] - result - end -.,., +# reduce 56 omitted -module_eval(<<'.,.,', 'parser.y', 230) - def _reduce_54(val, _values, result) - result = val[0].append(val[1]) - result - end -.,., +# reduce 57 omitted -module_eval(<<'.,.,', 'parser.y', 232) - def _reduce_55(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 183) + def _reduce_58(val, _values, result) result = val result end .,., -module_eval(<<'.,.,', 'parser.y', 236) - def _reduce_56(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 187) + def _reduce_59(val, _values, result) rule = Grammar::ParameterizingRule::Rule.new(val[1].s_value, val[3], val[7], tag: val[5]) @grammar.add_parameterizing_rule(rule) @@ -1673,8 +1655,8 @@ module_eval(<<'.,.,', 'parser.y', 236) end .,., -module_eval(<<'.,.,', 'parser.y', 242) - def _reduce_57(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 193) + def _reduce_60(val, _values, result) rule = Grammar::ParameterizingRule::Rule.new(val[2].s_value, [], val[4], is_inline: true) @grammar.add_parameterizing_rule(rule) @@ -1682,22 +1664,31 @@ module_eval(<<'.,.,', 'parser.y', 242) end .,., -module_eval(<<'.,.,', 'parser.y', 246) - def _reduce_58(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 198) + def _reduce_61(val, _values, result) + rule = Grammar::ParameterizingRule::Rule.new(val[2].s_value, val[4], val[7], is_inline: true) + @grammar.add_parameterizing_rule(rule) + + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 202) + def _reduce_62(val, _values, result) result = [val[0]] result end .,., -module_eval(<<'.,.,', 'parser.y', 247) - def _reduce_59(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 203) + def _reduce_63(val, _values, result) result = val[0].append(val[2]) result end .,., -module_eval(<<'.,.,', 'parser.y', 251) - def _reduce_60(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 207) + def _reduce_64(val, _values, result) builder = val[0] result = [builder] @@ -1705,8 +1696,8 @@ module_eval(<<'.,.,', 'parser.y', 251) end .,., -module_eval(<<'.,.,', 'parser.y', 256) - def _reduce_61(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 212) + def _reduce_65(val, _values, result) builder = val[2] result = val[0].append(builder) @@ -1714,8 +1705,16 @@ module_eval(<<'.,.,', 'parser.y', 256) end .,., -module_eval(<<'.,.,', 'parser.y', 262) - def _reduce_62(val, _values, result) +# reduce 66 omitted + +# reduce 67 omitted + +# reduce 68 omitted + +# reduce 69 omitted + +module_eval(<<'.,.,', 'parser.y', 218) + def _reduce_70(val, _values, result) reset_precs result = Grammar::ParameterizingRule::Rhs.new @@ -1723,17 +1722,8 @@ module_eval(<<'.,.,', 'parser.y', 262) end .,., -module_eval(<<'.,.,', 'parser.y', 267) - def _reduce_63(val, _values, result) - reset_precs - result = Grammar::ParameterizingRule::Rhs.new - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 272) - def _reduce_64(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 223) + def _reduce_71(val, _values, result) token = val[1] token.alias_name = val[2] builder = val[0] @@ -1744,8 +1734,8 @@ module_eval(<<'.,.,', 'parser.y', 272) end .,., -module_eval(<<'.,.,', 'parser.y', 280) - def _reduce_65(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 231) + def _reduce_72(val, _values, result) builder = val[0] builder.symbols << Lrama::Lexer::Token::InstantiateRule.new(s_value: val[2], location: @lexer.location, args: [val[1]]) result = builder @@ -1754,8 +1744,8 @@ module_eval(<<'.,.,', 'parser.y', 280) end .,., -module_eval(<<'.,.,', 'parser.y', 286) - def _reduce_66(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 237) + def _reduce_73(val, _values, result) builder = val[0] builder.symbols << Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, location: @lexer.location, args: val[3], lhs_tag: val[5]) result = builder @@ -1764,30 +1754,10 @@ module_eval(<<'.,.,', 'parser.y', 286) end .,., -module_eval(<<'.,.,', 'parser.y', 292) - def _reduce_67(val, _values, result) - 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("}") - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 300) - def _reduce_68(val, _values, result) - end_c_declaration - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 304) - def _reduce_69(val, _values, result) - user_code = val[3] - user_code.alias_name = val[6] +module_eval(<<'.,.,', 'parser.y', 243) + def _reduce_74(val, _values, result) + user_code = val[1] + user_code.alias_name = val[2] builder = val[0] builder.user_code = user_code result = builder @@ -1796,8 +1766,8 @@ module_eval(<<'.,.,', 'parser.y', 304) end .,., -module_eval(<<'.,.,', 'parser.y', 312) - def _reduce_70(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 251) + def _reduce_75(val, _values, result) sym = @grammar.find_symbol_by_id!(val[2]) @prec_seen = true builder = val[0] @@ -1808,168 +1778,137 @@ module_eval(<<'.,.,', 'parser.y', 312) end .,., -# reduce 71 omitted +# reduce 76 omitted -# reduce 72 omitted +# reduce 77 omitted -# reduce 73 omitted - -# reduce 74 omitted - -module_eval(<<'.,.,', 'parser.y', 327) - def _reduce_75(val, _values, result) - result = [{tag: nil, tokens: val[0]}] - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 331) - def _reduce_76(val, _values, result) - result = [{tag: val[0], tokens: val[1]}] - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 335) - def _reduce_77(val, _values, result) - result = val[0].append({tag: val[1], tokens: val[2]}) - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 338) +module_eval(<<'.,.,', 'parser.y', 258) def _reduce_78(val, _values, result) - result = [val[0]] + result = val[0].s_value if val[0] result end .,., -module_eval(<<'.,.,', 'parser.y', 339) +module_eval(<<'.,.,', 'parser.y', 271) def _reduce_79(val, _values, result) - result = val[0].append(val[1]) + result = val[1] ? val[1].unshift(val[0]) : val result end .,., -# reduce 80 omitted +module_eval(<<'.,.,', 'parser.y', 271) + def _reduce_80(val, _values, result) + result = val[1] ? val[1].unshift(val[0]) : val + result + end +.,., -# reduce 81 omitted +module_eval(<<'.,.,', 'parser.y', 262) + def _reduce_81(val, _values, result) + result = if val[0] + [{tag: val[0], tokens: val[1]}] + else + [{tag: nil, tokens: val[1]}] + end -module_eval(<<'.,.,', 'parser.y', 346) + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 268) def _reduce_82(val, _values, result) - begin_c_declaration("}") - + result = val[0].append({tag: val[1], tokens: val[2]}) result end .,., -module_eval(<<'.,.,', 'parser.y', 350) - def _reduce_83(val, _values, result) - end_c_declaration +# reduce 83 omitted - result - end -.,., +# reduce 84 omitted -module_eval(<<'.,.,', 'parser.y', 354) - def _reduce_84(val, _values, result) - result = val[0].append(val[3]) - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 358) +module_eval(<<'.,.,', 'parser.y', 274) def _reduce_85(val, _values, result) - begin_c_declaration("}") + begin_c_declaration("}") result end .,., -module_eval(<<'.,.,', 'parser.y', 362) +module_eval(<<'.,.,', 'parser.y', 278) def _reduce_86(val, _values, result) - end_c_declaration + end_c_declaration result end .,., -module_eval(<<'.,.,', 'parser.y', 366) +module_eval(<<'.,.,', 'parser.y', 282) def _reduce_87(val, _values, result) - result = [val[2]] + result = val[2] result end .,., -module_eval(<<'.,.,', 'parser.y', 371) +module_eval(<<'.,.,', 'parser.y', 290) def _reduce_88(val, _values, result) - result = [{tag: nil, tokens: val[0]}] - + result = val[1] ? val[1].unshift(val[0]) : val result end .,., -module_eval(<<'.,.,', 'parser.y', 375) +module_eval(<<'.,.,', 'parser.y', 290) def _reduce_89(val, _values, result) - result = [{tag: val[0], tokens: val[1]}] - + result = val[1] ? val[1].unshift(val[0]) : val result end .,., -module_eval(<<'.,.,', 'parser.y', 379) +module_eval(<<'.,.,', 'parser.y', 285) def _reduce_90(val, _values, result) - result = val[0].append({tag: val[1], tokens: val[2]}) - + result = [{tag: nil, tokens: val[0]}] result end .,., -module_eval(<<'.,.,', 'parser.y', 382) +module_eval(<<'.,.,', 'parser.y', 286) def _reduce_91(val, _values, result) - result = [val[0]] + result = [{tag: val[0], tokens: val[1]}] result end .,., -module_eval(<<'.,.,', 'parser.y', 383) +module_eval(<<'.,.,', 'parser.y', 287) def _reduce_92(val, _values, result) - result = val[0].append(val[1]) + result = val[0].append({tag: val[1], tokens: val[2]}) result end .,., -# reduce 93 omitted - -module_eval(<<'.,.,', 'parser.y', 387) - def _reduce_94(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 289) + def _reduce_93(val, _values, result) on_action_error("ident after %prec", val[0]) if @prec_seen result end .,., -module_eval(<<'.,.,', 'parser.y', 388) - def _reduce_95(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 290) + def _reduce_94(val, _values, result) on_action_error("char after %prec", val[0]) if @prec_seen result end .,., +# reduce 95 omitted + # reduce 96 omitted # reduce 97 omitted # reduce 98 omitted -# reduce 99 omitted - -module_eval(<<'.,.,', 'parser.y', 398) - def _reduce_100(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 298) + def _reduce_99(val, _values, result) lhs = val[0] lhs.alias_name = val[1] val[3].each do |builder| @@ -1982,8 +1921,8 @@ module_eval(<<'.,.,', 'parser.y', 398) end .,., -module_eval(<<'.,.,', 'parser.y', 409) - def _reduce_101(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 309) + def _reduce_100(val, _values, result) builder = val[0] if !builder.line builder.line = @lexer.line - 1 @@ -1994,8 +1933,8 @@ module_eval(<<'.,.,', 'parser.y', 409) end .,., -module_eval(<<'.,.,', 'parser.y', 417) - def _reduce_102(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 317) + def _reduce_101(val, _values, result) builder = val[2] if !builder.line builder.line = @lexer.line - 1 @@ -2006,28 +1945,17 @@ module_eval(<<'.,.,', 'parser.y', 417) end .,., -# reduce 103 omitted - -module_eval(<<'.,.,', 'parser.y', 427) - def _reduce_104(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 326) + def _reduce_102(val, _values, result) reset_precs - result = Grammar::RuleBuilder.new(@rule_counter, @midrule_action_counter) + result = @grammar.create_rule_builder(@rule_counter, @midrule_action_counter) result end .,., -module_eval(<<'.,.,', 'parser.y', 432) - def _reduce_105(val, _values, result) - reset_precs - result = Grammar::RuleBuilder.new(@rule_counter, @midrule_action_counter) - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 437) - def _reduce_106(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 331) + def _reduce_103(val, _values, result) token = val[1] token.alias_name = val[2] builder = val[0] @@ -2038,9 +1966,9 @@ module_eval(<<'.,.,', 'parser.y', 437) end .,., -module_eval(<<'.,.,', 'parser.y', 445) - def _reduce_107(val, _values, result) - token = Lrama::Lexer::Token::InstantiateRule.new(s_value: val[2], location: @lexer.location, args: [val[1]], lhs_tag: val[3]) +module_eval(<<'.,.,', 'parser.y', 339) + def _reduce_104(val, _values, result) + token = Lrama::Lexer::Token::InstantiateRule.new(s_value: val[2], alias_name: val[3], location: @lexer.location, args: [val[1]], lhs_tag: val[4]) builder = val[0] builder.add_rhs(token) builder.line = val[1].first_line @@ -2050,9 +1978,9 @@ module_eval(<<'.,.,', 'parser.y', 445) end .,., -module_eval(<<'.,.,', 'parser.y', 453) - def _reduce_108(val, _values, result) - token = Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, location: @lexer.location, args: val[3], lhs_tag: val[5]) +module_eval(<<'.,.,', 'parser.y', 347) + def _reduce_105(val, _values, result) + token = Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, alias_name: val[5], location: @lexer.location, args: val[3], lhs_tag: val[6]) builder = val[0] builder.add_rhs(token) builder.line = val[1].first_line @@ -2062,31 +1990,11 @@ module_eval(<<'.,.,', 'parser.y', 453) end .,., -module_eval(<<'.,.,', 'parser.y', 461) - def _reduce_109(val, _values, result) - 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("}") - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 469) - def _reduce_110(val, _values, result) - end_c_declaration - - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 473) - def _reduce_111(val, _values, result) - user_code = val[3] - user_code.alias_name = val[6] - user_code.tag = val[7] +module_eval(<<'.,.,', 'parser.y', 355) + def _reduce_106(val, _values, result) + user_code = val[1] + user_code.alias_name = val[2] + user_code.tag = val[3] builder = val[0] builder.user_code = user_code result = builder @@ -2095,8 +2003,8 @@ module_eval(<<'.,.,', 'parser.y', 473) end .,., -module_eval(<<'.,.,', 'parser.y', 482) - def _reduce_112(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 364) + def _reduce_107(val, _values, result) sym = @grammar.find_symbol_by_id!(val[2]) @prec_seen = true builder = val[0] @@ -2107,125 +2015,127 @@ module_eval(<<'.,.,', 'parser.y', 482) end .,., -module_eval(<<'.,.,', 'parser.y', 489) - def _reduce_113(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 371) + def _reduce_108(val, _values, result) result = "option" result end .,., -module_eval(<<'.,.,', 'parser.y', 490) - def _reduce_114(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 372) + def _reduce_109(val, _values, result) result = "nonempty_list" result end .,., -module_eval(<<'.,.,', 'parser.y', 491) - def _reduce_115(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 373) + def _reduce_110(val, _values, result) result = "list" result end .,., -module_eval(<<'.,.,', 'parser.y', 493) - def _reduce_116(val, _values, result) - result = [val[0]] +# reduce 111 omitted + +# reduce 112 omitted + +module_eval(<<'.,.,', 'parser.y', 377) + def _reduce_113(val, _values, result) + result = if val[1] + [Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, location: @lexer.location, args: val[0])] + else + [val[0]] + end + result end .,., -module_eval(<<'.,.,', 'parser.y', 494) - def _reduce_117(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 383) + def _reduce_114(val, _values, result) result = val[0].append(val[2]) result end .,., -module_eval(<<'.,.,', 'parser.y', 495) - def _reduce_118(val, _values, result) - result = [Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, location: @lexer.location, args: val[0])] - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 496) - def _reduce_119(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 384) + def _reduce_115(val, _values, result) result = [Lrama::Lexer::Token::InstantiateRule.new(s_value: val[0].s_value, location: @lexer.location, args: val[2])] result end .,., -# reduce 120 omitted +module_eval(<<'.,.,', 'parser.y', 388) + def _reduce_116(val, _values, result) + 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("}") -module_eval(<<'.,.,', 'parser.y', 499) - def _reduce_121(val, _values, result) + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 396) + def _reduce_117(val, _values, result) + end_c_declaration + + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 400) + def _reduce_118(val, _values, result) + result = val[2] + + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 403) + def _reduce_119(val, _values, result) result = val[1].s_value result end .,., +module_eval(<<'.,.,', 'parser.y', 407) + def _reduce_120(val, _values, result) + begin_c_declaration('\Z') + @grammar.epilogue_first_lineno = @lexer.line + 1 + + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 412) + def _reduce_121(val, _values, result) + end_c_declaration + @grammar.epilogue = val[2].s_value + + result + end +.,., + # reduce 122 omitted # reduce 123 omitted -module_eval(<<'.,.,', 'parser.y', 506) - def _reduce_124(val, _values, result) - begin_c_declaration('\Z') - @grammar.epilogue_first_lineno = @lexer.line + 1 +# reduce 124 omitted - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 511) - def _reduce_125(val, _values, result) - end_c_declaration - @grammar.epilogue = val[2].s_value - - result - end -.,., +# reduce 125 omitted # reduce 126 omitted -# reduce 127 omitted - -# reduce 128 omitted - -# reduce 129 omitted - -# reduce 130 omitted - -module_eval(<<'.,.,', 'parser.y', 522) - def _reduce_131(val, _values, result) - result = [val[0]] - result - end -.,., - -module_eval(<<'.,.,', 'parser.y', 523) - def _reduce_132(val, _values, result) - result = val[0].append(val[1]) - result - end -.,., - -# reduce 133 omitted - -# reduce 134 omitted - -module_eval(<<'.,.,', 'parser.y', 528) - def _reduce_135(val, _values, result) +module_eval(<<'.,.,', 'parser.y', 423) + def _reduce_127(val, _values, result) result = Lrama::Lexer::Token::Ident.new(s_value: val[0]) result end .,., -# reduce 136 omitted - -# reduce 137 omitted - def _reduce_none(val, _values, result) val[0] end diff --git a/tools/lrama/lib/lrama/report.rb b/tools/lrama/lib/lrama/report.rb index 650ac09d5..890e5f1e8 100644 --- a/tools/lrama/lib/lrama/report.rb +++ b/tools/lrama/lib/lrama/report.rb @@ -1,2 +1,4 @@ -require 'lrama/report/duration' -require 'lrama/report/profile' +# frozen_string_literal: true + +require_relative 'report/duration' +require_relative 'report/profile' diff --git a/tools/lrama/lib/lrama/report/duration.rb b/tools/lrama/lib/lrama/report/duration.rb index 7afe284f1..fe09a0d02 100644 --- a/tools/lrama/lib/lrama/report/duration.rb +++ b/tools/lrama/lib/lrama/report/duration.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Report module Duration diff --git a/tools/lrama/lib/lrama/report/profile.rb b/tools/lrama/lib/lrama/report/profile.rb index 36156800a..10488cf91 100644 --- a/tools/lrama/lib/lrama/report/profile.rb +++ b/tools/lrama/lib/lrama/report/profile.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class Report module Profile diff --git a/tools/lrama/lib/lrama/state.rb b/tools/lrama/lib/lrama/state.rb index ceb74d856..3008786ce 100644 --- a/tools/lrama/lib/lrama/state.rb +++ b/tools/lrama/lib/lrama/state.rb @@ -1,14 +1,16 @@ -require "lrama/state/reduce" -require "lrama/state/reduce_reduce_conflict" -require "lrama/state/resolved_conflict" -require "lrama/state/shift" -require "lrama/state/shift_reduce_conflict" +# frozen_string_literal: true + +require_relative "state/reduce" +require_relative "state/reduce_reduce_conflict" +require_relative "state/resolved_conflict" +require_relative "state/shift" +require_relative "state/shift_reduce_conflict" module Lrama class State attr_reader :id, :accessing_symbol, :kernels, :conflicts, :resolved_conflicts, :default_reduction_rule, :closure, :items - attr_accessor :shifts, :reduces + attr_accessor :shifts, :reduces, :ielr_isocores, :lalr_isocore def initialize(id, accessing_symbol, kernels) @id = id @@ -21,6 +23,12 @@ module Lrama @conflicts = [] @resolved_conflicts = [] @default_reduction_rule = nil + @predecessors = [] + @lalr_isocore = self + @ielr_isocores = [self] + @internal_dependencies = {} + @successor_dependencies = {} + @always_follows = {} end def closure=(closure) @@ -82,6 +90,18 @@ module Lrama @transitions ||= shifts.map {|shift| [shift, @items_to_state[shift.next_items]] } end + def update_transition(shift, next_state) + set_items_to_state(shift.next_items, next_state) + next_state.append_predecessor(self) + clear_transitions_cache + end + + def clear_transitions_cache + @nterm_transitions = nil + @term_transitions = nil + @transitions = nil + end + def selected_term_transitions term_transitions.reject do |shift, next_state| shift.not_selected @@ -140,5 +160,274 @@ module Lrama conflict.type == :reduce_reduce end end + + def propagate_lookaheads(next_state) + next_state.kernels.map {|item| + lookahead_sets = + if item.position == 1 + goto_follow_set(item.lhs) + else + kernel = kernels.find {|k| k.predecessor_item_of?(item) } + item_lookahead_set[kernel] + end + + [item, lookahead_sets & next_state.lookahead_set_filters[item]] + }.to_h + end + + def lookaheads_recomputed + !@item_lookahead_set.nil? + end + + def compatible_lookahead?(filtered_lookahead) + !lookaheads_recomputed || + @lalr_isocore.annotation_list.all? {|token, actions| + a = dominant_contribution(token, actions, item_lookahead_set) + b = dominant_contribution(token, actions, filtered_lookahead) + a.nil? || b.nil? || a == b + } + end + + def lookahead_set_filters + kernels.map {|kernel| + [kernel, + @lalr_isocore.annotation_list.select {|token, actions| + token.term? && actions.any? {|action, contributions| + !contributions.nil? && contributions.key?(kernel) && contributions[kernel] + } + }.map {|token, _| token } + ] + }.to_h + end + + def dominant_contribution(token, actions, lookaheads) + a = actions.select {|action, contributions| + contributions.nil? || contributions.any? {|item, contributed| contributed && lookaheads[item].include?(token) } + }.map {|action, _| action } + return nil if a.empty? + a.reject {|action| + if action.is_a?(State::Shift) + action.not_selected + elsif action.is_a?(State::Reduce) + action.not_selected_symbols.include?(token) + end + } + end + + def inadequacy_list + return @inadequacy_list if @inadequacy_list + + shift_contributions = shifts.map {|shift| + [shift.next_sym, [shift]] + }.to_h + reduce_contributions = reduces.map {|reduce| + (reduce.look_ahead || []).map {|sym| + [sym, [reduce]] + }.to_h + }.reduce(Hash.new([])) {|hash, cont| + hash.merge(cont) {|_, a, b| a | b } + } + + list = shift_contributions.merge(reduce_contributions) {|_, a, b| a | b } + @inadequacy_list = list.select {|token, actions| token.term? && actions.size > 1 } + end + + def annotation_list + return @annotation_list if @annotation_list + + @annotation_list = annotate_manifestation + @annotation_list = @items_to_state.values.map {|next_state| next_state.annotate_predecessor(self) } + .reduce(@annotation_list) {|result, annotations| + result.merge(annotations) {|_, actions_a, actions_b| + if actions_a.nil? || actions_b.nil? + actions_a || actions_b + else + actions_a.merge(actions_b) {|_, contributions_a, contributions_b| + if contributions_a.nil? || contributions_b.nil? + next contributions_a || contributions_b + end + + contributions_a.merge(contributions_b) {|_, contributed_a, contributed_b| + contributed_a || contributed_b + } + } + end + } + } + end + + def annotate_manifestation + inadequacy_list.transform_values {|actions| + actions.map {|action| + if action.is_a?(Shift) + [action, nil] + elsif action.is_a?(Reduce) + if action.rule.empty_rule? + [action, lhs_contributions(action.rule.lhs, inadequacy_list.key(actions))] + else + contributions = kernels.map {|kernel| [kernel, kernel.rule == action.rule && kernel.end_of_rule?] }.to_h + [action, contributions] + end + end + }.to_h + } + end + + def annotate_predecessor(predecessor) + annotation_list.transform_values {|actions| + token = annotation_list.key(actions) + actions.transform_values {|inadequacy| + next nil if inadequacy.nil? + lhs_adequacy = kernels.any? {|kernel| + inadequacy[kernel] && kernel.position == 1 && predecessor.lhs_contributions(kernel.lhs, token).nil? + } + if lhs_adequacy + next nil + else + predecessor.kernels.map {|pred_k| + [pred_k, kernels.any? {|k| + inadequacy[k] && ( + pred_k.predecessor_item_of?(k) && predecessor.item_lookahead_set[pred_k].include?(token) || + k.position == 1 && predecessor.lhs_contributions(k.lhs, token)[pred_k] + ) + }] + }.to_h + end + } + } + end + + def lhs_contributions(sym, token) + shift, next_state = nterm_transitions.find {|sh, _| sh.next_sym == sym } + if always_follows(shift, next_state).include?(token) + nil + else + kernels.map {|kernel| [kernel, follow_kernel_items(shift, next_state, kernel) && item_lookahead_set[kernel].include?(token)] }.to_h + end + end + + def follow_kernel_items(shift, next_state, kernel) + queue = [[self, shift, next_state]] + until queue.empty? + st, sh, next_st = queue.pop + return true if kernel.next_sym == sh.next_sym && kernel.symbols_after_transition.all?(&:nullable) + st.internal_dependencies(sh, next_st).each {|v| queue << v } + end + false + end + + def item_lookahead_set + return @item_lookahead_set if @item_lookahead_set + + kernels.map {|item| + value = + if item.lhs.accept_symbol? + [] + elsif item.position > 1 + prev_items = predecessors_with_item(item) + prev_items.map {|st, i| st.item_lookahead_set[i] }.reduce([]) {|acc, syms| acc |= syms } + elsif item.position == 1 + prev_state = @predecessors.find {|p| p.shifts.any? {|shift| shift.next_sym == item.lhs } } + shift, next_state = prev_state.nterm_transitions.find {|shift, _| shift.next_sym == item.lhs } + prev_state.goto_follows(shift, next_state) + end + [item, value] + }.to_h + end + + def item_lookahead_set=(k) + @item_lookahead_set = k + end + + def predecessors_with_item(item) + result = [] + @predecessors.each do |pre| + pre.items.each do |i| + result << [pre, i] if i.predecessor_item_of?(item) + end + end + result + end + + def append_predecessor(prev_state) + @predecessors << prev_state + @predecessors.uniq! + end + + def goto_follow_set(nterm_token) + return [] if nterm_token.accept_symbol? + shift, next_state = @lalr_isocore.nterm_transitions.find {|sh, _| sh.next_sym == nterm_token } + + @kernels + .select {|kernel| follow_kernel_items(shift, next_state, kernel) } + .map {|kernel| item_lookahead_set[kernel] } + .reduce(always_follows(shift, next_state)) {|result, terms| result |= terms } + end + + def goto_follows(shift, next_state) + queue = internal_dependencies(shift, next_state) + predecessor_dependencies(shift, next_state) + terms = always_follows(shift, next_state) + until queue.empty? + st, sh, next_st = queue.pop + terms |= st.always_follows(sh, next_st) + st.internal_dependencies(sh, next_st).each {|v| queue << v } + st.predecessor_dependencies(sh, next_st).each {|v| queue << v } + end + terms + end + + def always_follows(shift, next_state) + return @always_follows[[shift, next_state]] if @always_follows[[shift, next_state]] + + queue = internal_dependencies(shift, next_state) + successor_dependencies(shift, next_state) + terms = [] + until queue.empty? + st, sh, next_st = queue.pop + terms |= next_st.term_transitions.map {|sh, _| sh.next_sym } + st.internal_dependencies(sh, next_st).each {|v| queue << v } + st.successor_dependencies(sh, next_st).each {|v| queue << v } + end + @always_follows[[shift, next_state]] = terms + end + + def internal_dependencies(shift, next_state) + return @internal_dependencies[[shift, next_state]] if @internal_dependencies[[shift, next_state]] + + syms = @items.select {|i| + i.next_sym == shift.next_sym && i.symbols_after_transition.all?(&:nullable) && i.position == 0 + }.map(&:lhs).uniq + @internal_dependencies[[shift, next_state]] = nterm_transitions.select {|sh, _| syms.include?(sh.next_sym) }.map {|goto| [self, *goto] } + end + + def successor_dependencies(shift, next_state) + return @successor_dependencies[[shift, next_state]] if @successor_dependencies[[shift, next_state]] + + @successor_dependencies[[shift, next_state]] = + next_state.nterm_transitions + .select {|next_shift, _| next_shift.next_sym.nullable } + .map {|transition| [next_state, *transition] } + end + + def predecessor_dependencies(shift, next_state) + state_items = [] + @kernels.select {|kernel| + kernel.next_sym == shift.next_sym && kernel.symbols_after_transition.all?(&:nullable) + }.each do |item| + queue = predecessors_with_item(item) + until queue.empty? + st, i = queue.pop + if i.position == 0 + state_items << [st, i] + else + st.predecessors_with_item(i).each {|v| queue << v } + end + end + end + + state_items.map {|state, item| + sh, next_st = state.nterm_transitions.find {|shi, _| shi.next_sym == item.lhs } + [state, sh, next_st] + } + end end end diff --git a/tools/lrama/lib/lrama/state/reduce.rb b/tools/lrama/lib/lrama/state/reduce.rb index 8ba51f45f..54ab87b46 100644 --- a/tools/lrama/lib/lrama/state/reduce.rb +++ b/tools/lrama/lib/lrama/state/reduce.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class State class Reduce @@ -24,8 +26,8 @@ module Lrama end def selected_look_ahead - if @look_ahead - @look_ahead - @not_selected_symbols + if look_ahead + look_ahead - @not_selected_symbols else [] end diff --git a/tools/lrama/lib/lrama/state/reduce_reduce_conflict.rb b/tools/lrama/lib/lrama/state/reduce_reduce_conflict.rb index 0a0e4dc20..736d08376 100644 --- a/tools/lrama/lib/lrama/state/reduce_reduce_conflict.rb +++ b/tools/lrama/lib/lrama/state/reduce_reduce_conflict.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class State class ReduceReduceConflict < Struct.new(:symbols, :reduce1, :reduce2, keyword_init: true) diff --git a/tools/lrama/lib/lrama/state/resolved_conflict.rb b/tools/lrama/lib/lrama/state/resolved_conflict.rb index 02ea89214..3bb3d1446 100644 --- a/tools/lrama/lib/lrama/state/resolved_conflict.rb +++ b/tools/lrama/lib/lrama/state/resolved_conflict.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class State # * symbol: A symbol under discussion @@ -6,7 +8,7 @@ module Lrama class ResolvedConflict < Struct.new(:symbol, :reduce, :which, :same_prec, keyword_init: true) def report_message s = symbol.display_name - r = reduce.rule.precedence_sym.display_name + r = reduce.rule.precedence_sym&.display_name case when which == :shift && same_prec msg = "resolved as #{which} (%right #{s})" diff --git a/tools/lrama/lib/lrama/state/shift.rb b/tools/lrama/lib/lrama/state/shift.rb index 2021eb61f..81ef013a1 100644 --- a/tools/lrama/lib/lrama/state/shift.rb +++ b/tools/lrama/lib/lrama/state/shift.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class State class Shift diff --git a/tools/lrama/lib/lrama/state/shift_reduce_conflict.rb b/tools/lrama/lib/lrama/state/shift_reduce_conflict.rb index f80bd5f35..fd6683453 100644 --- a/tools/lrama/lib/lrama/state/shift_reduce_conflict.rb +++ b/tools/lrama/lib/lrama/state/shift_reduce_conflict.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class State class ShiftReduceConflict < Struct.new(:symbols, :shift, :reduce, keyword_init: true) diff --git a/tools/lrama/lib/lrama/states.rb b/tools/lrama/lib/lrama/states.rb index 290e996b8..fd8ded905 100644 --- a/tools/lrama/lib/lrama/states.rb +++ b/tools/lrama/lib/lrama/states.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "forwardable" -require "lrama/report/duration" -require "lrama/states/item" +require_relative "report/duration" +require_relative "states/item" module Lrama # States is passed to a template file @@ -16,9 +18,8 @@ module Lrama attr_reader :states, :reads_relation, :includes_relation, :lookback_relation - def initialize(grammar, warning, trace_state: false) + def initialize(grammar, trace_state: false) @grammar = grammar - @warning = warning @trace_state = trace_state @states = [] @@ -40,6 +41,8 @@ module Lrama # value is array of [state.id, nterm.token_id]. @reads_relation = {} + # `Read(p, A) =s DR(p, A) ∪ ∪{Read(r, C) | (p, A) reads (r, C)}` + # # `@read_sets` is a hash whose # key is [state.id, nterm.token_id], # value is bitmap of term. @@ -61,6 +64,8 @@ module Lrama # value is array of [state.id, nterm.token_id]. @lookback_relation = {} + # `Follow(p, A) =s Read(p, A) ∪ ∪{Follow(p', B) | (p, A) includes (p', B)}` + # # `@follow_sets` is a hash whose # key is [state.id, rule.id], # value is bitmap of term. @@ -89,8 +94,20 @@ module Lrama report_duration(:compute_conflicts) { compute_conflicts } report_duration(:compute_default_reduction) { compute_default_reduction } + end - check_conflicts + def compute_ielr + report_duration(:split_states) { split_states } + report_duration(:compute_direct_read_sets) { compute_direct_read_sets } + report_duration(:compute_reads_relation) { compute_reads_relation } + report_duration(:compute_read_sets) { compute_read_sets } + report_duration(:compute_includes_relation) { compute_includes_relation } + report_duration(:compute_lookback_relation) { compute_lookback_relation } + report_duration(:compute_follow_sets) { compute_follow_sets } + report_duration(:compute_look_ahead_sets) { compute_look_ahead_sets } + report_duration(:compute_conflicts) { compute_conflicts } + + report_duration(:compute_default_reduction) { compute_default_reduction } end def reporter @@ -125,16 +142,16 @@ module Lrama end end + def sr_conflicts_count + @sr_conflicts_count ||= @states.flat_map(&:sr_conflicts).count + end + + def rr_conflicts_count + @rr_conflicts_count ||= @states.flat_map(&:rr_conflicts).count + end + private - def sr_conflicts - @states.flat_map(&:sr_conflicts) - end - - def rr_conflicts - @states.flat_map(&:rr_conflicts) - end - def trace_state if @trace_state yield STDERR @@ -236,7 +253,7 @@ module Lrama # Trace previous = state.kernels.first.previous_sym trace_state do |out| - out << sprintf("state_list_append (state = %d, symbol = %d (%s))", + out << sprintf("state_list_append (state = %d, symbol = %d (%s))\n", @states.count, previous.number, previous.display_name) end @@ -266,7 +283,10 @@ module Lrama state.shifts.each do |shift| new_state, created = create_state(shift.next_sym, shift.next_items, states_created) state.set_items_to_state(shift.next_items, new_state) - enqueue_state(states, new_state) if created + if created + enqueue_state(states, new_state) + new_state.append_predecessor(state) + end end end end @@ -350,7 +370,7 @@ module Lrama # TODO: need to omit if state == state2 ? @includes_relation[key] ||= [] @includes_relation[key] << [state.id, nterm.token_id] - break if !sym.nullable + break unless sym.nullable i -= 1 end end @@ -385,7 +405,7 @@ module Lrama @states.each do |state| rules.each do |rule| ary = @lookback_relation[[state.id, rule.id]] - next if !ary + next unless ary ary.each do |state2_id, nterm_token_id| # q = state, A -> ω = rule, p = state2, A = nterm @@ -428,7 +448,7 @@ module Lrama sym = shift.next_sym next unless reduce.look_ahead - next if !reduce.look_ahead.include?(sym) + next unless reduce.look_ahead.include?(sym) # Shift/Reduce conflict shift_prec = sym.precedence @@ -492,17 +512,17 @@ module Lrama states.each do |state| count = state.reduces.count - for i in 0...count do + (0...count).each do |i| reduce1 = state.reduces[i] next if reduce1.look_ahead.nil? - for j in (i+1)...count do + ((i+1)...count).each do |j| reduce2 = state.reduces[j] next if reduce2.look_ahead.nil? intersection = reduce1.look_ahead & reduce2.look_ahead - if !intersection.empty? + unless intersection.empty? state.conflicts << State::ReduceReduceConflict.new(symbols: intersection, reduce1: reduce1, reduce2: reduce2) end end @@ -514,7 +534,7 @@ module Lrama states.each do |state| next if state.reduces.empty? # Do not set, if conflict exist - next if !state.conflicts.empty? + next unless state.conflicts.empty? # Do not set, if shift with `error` exists. next if state.shifts.map(&:next_sym).include?(@grammar.error_symbol) @@ -526,30 +546,49 @@ module Lrama end end - def check_conflicts - sr_count = sr_conflicts.count - rr_count = rr_conflicts.count - - if @grammar.expect - - expected_sr_conflicts = @grammar.expect - expected_rr_conflicts = 0 - - if expected_sr_conflicts != sr_count - @warning.error("shift/reduce conflicts: #{sr_count} found, #{expected_sr_conflicts} expected") + def split_states + @states.each do |state| + state.transitions.each do |shift, next_state| + compute_state(state, shift, next_state) end + end + end - if expected_rr_conflicts != rr_count - @warning.error("reduce/reduce conflicts: #{rr_count} found, #{expected_rr_conflicts} expected") + def merge_lookaheads(state, filtered_lookaheads) + return if state.kernels.all? {|item| (filtered_lookaheads[item] - state.item_lookahead_set[item]).empty? } + + state.item_lookahead_set = state.item_lookahead_set.merge {|_, v1, v2| v1 | v2 } + state.transitions.each do |shift, next_state| + next if next_state.lookaheads_recomputed + compute_state(state, shift, next_state) + end + end + + def compute_state(state, shift, next_state) + filtered_lookaheads = state.propagate_lookaheads(next_state) + s = next_state.ielr_isocores.find {|st| st.compatible_lookahead?(filtered_lookaheads) } + + if s.nil? + s = next_state.ielr_isocores.last + new_state = State.new(@states.count, s.accessing_symbol, s.kernels) + new_state.closure = s.closure + new_state.compute_shifts_reduces + s.transitions.each do |sh, next_state| + new_state.set_items_to_state(sh.next_items, next_state) end + @states << new_state + new_state.lalr_isocore = s + s.ielr_isocores << new_state + s.ielr_isocores.each do |st| + st.ielr_isocores = s.ielr_isocores + end + new_state.item_lookahead_set = filtered_lookaheads + state.update_transition(shift, new_state) + elsif(!s.lookaheads_recomputed) + s.item_lookahead_set = filtered_lookaheads else - if sr_count != 0 - @warning.warn("shift/reduce conflicts: #{sr_count} found") - end - - if rr_count != 0 - @warning.warn("reduce/reduce conflicts: #{rr_count} found") - end + state.update_transition(shift, s) + merge_lookaheads(s, filtered_lookaheads) end end end diff --git a/tools/lrama/lib/lrama/states/item.rb b/tools/lrama/lib/lrama/states/item.rb index 31b74b9d3..e89cb9695 100644 --- a/tools/lrama/lib/lrama/states/item.rb +++ b/tools/lrama/lib/lrama/states/item.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # TODO: Validate position is not over rule rhs require "forwardable" @@ -54,14 +56,18 @@ module Lrama Item.new(rule: rule, position: position + 1) end - def symbols_before_dot + def symbols_before_dot # steep:ignore rhs[0...position] end - def symbols_after_dot + def symbols_after_dot # steep:ignore rhs[position..-1] end + def symbols_after_transition + rhs[position+1..-1] + end + def to_s "#{lhs.id.s_value}: #{display_name}" end @@ -73,9 +79,13 @@ module Lrama # Right after position def display_rest - r = rhs[position..-1].map(&:display_name).join(" ") + r = symbols_after_dot.map(&:display_name).join(" ") ". #{r} (rule #{rule_id})" end + + def predecessor_item_of?(other_item) + rule == other_item.rule && position == other_item.position - 1 + end end end end diff --git a/tools/lrama/lib/lrama/states_reporter.rb b/tools/lrama/lib/lrama/states_reporter.rb index 6f96cc6f6..64ff4de10 100644 --- a/tools/lrama/lib/lrama/states_reporter.rb +++ b/tools/lrama/lib/lrama/states_reporter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama class StatesReporter include Lrama::Report::Duration @@ -14,15 +16,54 @@ module Lrama private - def _report(io, grammar: false, states: false, itemsets: false, lookaheads: false, solved: false, counterexamples: false, verbose: false) - # TODO: Unused terms - # TODO: Unused rules - + def _report(io, grammar: false, rules: false, terms: false, states: false, itemsets: false, lookaheads: false, solved: false, counterexamples: false, verbose: false) + report_unused_rules(io) if rules + report_unused_terms(io) if terms report_conflicts(io) report_grammar(io) if grammar report_states(io, itemsets, lookaheads, solved, counterexamples, verbose) end + def report_unused_terms(io) + look_aheads = @states.states.each do |state| + state.reduces.flat_map do |reduce| + reduce.look_ahead unless reduce.look_ahead.nil? + end + end + + next_terms = @states.states.flat_map do |state| + state.shifts.map(&:next_sym).select(&:term?) + end + + unused_symbols = @states.terms.select do |term| + !(look_aheads + next_terms).include?(term) + end + + unless unused_symbols.empty? + io << "#{unused_symbols.count} Unused Terms\n\n" + unused_symbols.each_with_index do |term, index| + io << sprintf("%5d %s\n", index, term.id.s_value) + end + io << "\n\n" + end + end + + def report_unused_rules(io) + used_rules = @states.rules.flat_map(&:rhs) + + unused_rules = @states.rules.map(&:lhs).select do |rule| + !used_rules.include?(rule) && rule.token_id != 0 + end + + unless unused_rules.empty? + io << "#{unused_rules.count} Unused Rules\n\n" + unused_rules.each_with_index do |rule, index| + io << sprintf("%5d %s\n", index, rule.display_name) + end + io << "\n\n" + end + end + def report_conflicts(io) has_conflict = false @@ -37,7 +78,7 @@ module Lrama messages << "#{cs[:reduce_reduce].count} reduce/reduce" end - if !messages.empty? + unless messages.empty? has_conflict = true io << "State #{state.id} conflicts: #{messages.join(', ')}\n" end @@ -98,7 +139,7 @@ module Lrama if lookaheads && item.end_of_rule? reduce = state.find_reduce_by_item!(item) look_ahead = reduce.selected_look_ahead - if !look_ahead.empty? + unless look_ahead.empty? la = " [#{look_ahead.map(&:display_name).join(", ")}]" end end @@ -118,7 +159,7 @@ module Lrama tmp.each do |term, state_id| io << " #{term.display_name.ljust(max_len)} shift, and go to state #{state_id}\n" end - io << "\n" if !tmp.empty? + io << "\n" unless tmp.empty? # Report error caused by %nonassoc nl = false @@ -132,7 +173,7 @@ module Lrama nl = true io << " #{name.ljust(max_len)} error (nonassociative)\n" end - io << "\n" if !tmp.empty? + io << "\n" unless tmp.empty? # Report reduces nl = false @@ -181,14 +222,14 @@ module Lrama tmp.each do |nterm, state_id| io << " #{nterm.id.s_value.ljust(max_len)} go to state #{state_id}\n" end - io << "\n" if !tmp.empty? + io << "\n" unless tmp.empty? if solved # Report conflict resolutions state.resolved_conflicts.each do |resolved| io << " #{resolved.report_message}\n" end - io << "\n" if !state.resolved_conflicts.empty? + io << "\n" unless state.resolved_conflicts.empty? end if counterexamples && state.has_conflicts? @@ -219,7 +260,7 @@ module Lrama direct_read_sets = @states.direct_read_sets @states.nterms.each do |nterm| terms = direct_read_sets[[state.id, nterm.token_id]] - next if !terms + next unless terms next if terms.empty? str = terms.map {|sym| sym.id.s_value }.join(", ") @@ -231,7 +272,7 @@ module Lrama io << " [Reads Relation]\n" @states.nterms.each do |nterm| a = @states.reads_relation[[state.id, nterm.token_id]] - next if !a + next unless a a.each do |state_id2, nterm_id2| n = @states.nterms.find {|n| n.token_id == nterm_id2 } @@ -245,7 +286,7 @@ module Lrama read_sets = @states.read_sets @states.nterms.each do |nterm| terms = read_sets[[state.id, nterm.token_id]] - next if !terms + next unless terms next if terms.empty? terms.each do |sym| @@ -258,7 +299,7 @@ module Lrama io << " [Includes Relation]\n" @states.nterms.each do |nterm| a = @states.includes_relation[[state.id, nterm.token_id]] - next if !a + next unless a a.each do |state_id2, nterm_id2| n = @states.nterms.find {|n| n.token_id == nterm_id2 } @@ -271,11 +312,11 @@ module Lrama io << " [Lookback Relation]\n" @states.rules.each do |rule| a = @states.lookback_relation[[state.id, rule.id]] - next if !a + next unless a a.each do |state_id2, nterm_id2| n = @states.nterms.find {|n| n.token_id == nterm_id2 } - io << " (Rule: #{rule}) -> (State #{state_id2}, #{n.id.s_value})\n" + io << " (Rule: #{rule.display_name}) -> (State #{state_id2}, #{n.id.s_value})\n" end end io << "\n" @@ -286,7 +327,7 @@ module Lrama @states.nterms.each do |nterm| terms = follow_sets[[state.id, nterm.token_id]] - next if !terms + next unless terms terms.each do |sym| io << " #{nterm.id.s_value} -> #{sym.id.s_value}\n" @@ -300,7 +341,7 @@ module Lrama max_len = 0 @states.rules.each do |rule| syms = @states.la[[state.id, rule.id]] - next if !syms + next unless syms tmp << [rule, syms] max_len = ([max_len] + syms.map {|s| s.id.s_value.length }).max @@ -310,7 +351,7 @@ module Lrama io << " #{sym.id.s_value.ljust(max_len)} reduce using rule #{rule.id} (#{rule.lhs.id.s_value})\n" end end - io << "\n" if !tmp.empty? + io << "\n" unless tmp.empty? end # End of Report State diff --git a/tools/lrama/lib/lrama/trace_reporter.rb b/tools/lrama/lib/lrama/trace_reporter.rb new file mode 100644 index 000000000..bcf1ef1e5 --- /dev/null +++ b/tools/lrama/lib/lrama/trace_reporter.rb @@ -0,0 +1,45 @@ +# rbs_inline: enabled +# frozen_string_literal: true + +module Lrama + class TraceReporter + # @rbs (Lrama::Grammar grammar) -> void + def initialize(grammar) + @grammar = grammar + end + + # @rbs (**Hash[Symbol, bool] options) -> void + def report(**options) + _report(**options) + end + + private + + # @rbs rules: (bool rules, bool actions, bool only_explicit_rules, **untyped _) -> void + def _report(rules: false, actions: false, only_explicit_rules: false, **_) + report_rules if rules && !only_explicit_rules + report_only_explicit_rules if only_explicit_rules + report_actions if actions + end + + # @rbs () -> void + def report_rules + puts "Grammar rules:" + @grammar.rules.each { |rule| puts rule.display_name } + end + + # @rbs () -> void + def report_only_explicit_rules + puts "Grammar rules:" + @grammar.rules.each do |rule| + puts rule.display_name_without_action if rule.lhs.first_set.any? + end + end + + # @rbs () -> void + def report_actions + puts "Grammar rules with actions:" + @grammar.rules.each { |rule| puts rule.with_actions } + end + end +end diff --git a/tools/lrama/lib/lrama/version.rb b/tools/lrama/lib/lrama/version.rb index ef840ce43..12ece5a8f 100644 --- a/tools/lrama/lib/lrama/version.rb +++ b/tools/lrama/lib/lrama/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lrama - VERSION = "0.6.9".freeze + VERSION = "0.7.0".freeze end diff --git a/tools/lrama/template/bison/yacc.c b/tools/lrama/template/bison/yacc.c index 42d875605..5577c5f07 100644 --- a/tools/lrama/template/bison/yacc.c +++ b/tools/lrama/template/bison/yacc.c @@ -1166,9 +1166,9 @@ yydestruct (const char *yymsg, #endif enum yy_repair_type { - insert, - delete, - shift, + inserting, + deleting, + shifting, }; struct yy_repair { @@ -1401,27 +1401,27 @@ yyrecover(yy_state_t *yyss, yy_state_t *yyssp, int yychar<%= output.user_formals if (current->repair_length + 1 > YYMAXREPAIR(<%= output.parse_param_name %>)) continue; - yy_repairs *new = (yy_repairs *) YYMALLOC (sizeof (yy_repairs)); - new->id = count; - new->next = 0; - new->stack_length = stack_length; - new->states = (yy_state_t *) YYMALLOC (sizeof (yy_state_t) * (stack_length)); - new->state = new->states + (current->state - current->states); - YYCOPY (new->states, current->states, current->state - current->states + 1); - new->repair_length = current->repair_length + 1; - new->prev_repair = current; - new->repair.type = insert; - new->repair.term = (yysymbol_kind_t) yyx; + yy_repairs *reps = (yy_repairs *) YYMALLOC (sizeof (yy_repairs)); + reps->id = count; + reps->next = 0; + reps->stack_length = stack_length; + reps->states = (yy_state_t *) YYMALLOC (sizeof (yy_state_t) * (stack_length)); + reps->state = reps->states + (current->state - current->states); + YYCOPY (reps->states, current->states, current->state - current->states + 1); + reps->repair_length = current->repair_length + 1; + reps->prev_repair = current; + reps->repair.type = inserting; + reps->repair.term = (yysymbol_kind_t) yyx; /* Process PDA assuming next token is yyx */ - if (! yy_process_repairs (new, yyx)) + if (! yy_process_repairs (reps, (yysymbol_kind_t)yyx)) { - YYFREE (new); + YYFREE (reps); continue; } - tail->next = new; - tail = new; + tail->next = reps; + tail = reps; count++; if (yyx == yytoken) @@ -1437,7 +1437,7 @@ yyrecover(yy_state_t *yyss, yy_state_t *yyssp, int yychar<%= output.user_formals YYDPRINTF ((stderr, "New repairs is enqueued. count: %d, yystate: %d, yyx: %d\n", count, yystate, yyx)); - yy_print_repairs (new<%= output.user_args %>); + yy_print_repairs (reps<%= output.user_args %>); } } } @@ -1475,7 +1475,12 @@ int yychar; /* The semantic value of the lookahead symbol. */ /* Default value used for initialization, for pacifying older GCCs or non-GCC compilers. */ -YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +#ifdef __cplusplus +static const YYSTYPE yyval_default = {}; +(void) yyval_default; +#else +YY_INITIAL_VALUE (static const YYSTYPE yyval_default;) +#endif YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); /* Location data for the lookahead symbol. */