Lrama v0.6.10
This commit is contained in:
parent
2a1962fc4a
commit
885cf350de
Notes:
git
2024-09-12 12:06:34 +00:00
@ -1,5 +1,225 @@
|
|||||||
# NEWS for Lrama
|
# NEWS for Lrama
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
```
|
||||||
|
%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.
|
||||||
|
|
||||||
|
```
|
||||||
|
opt_nl: '\n'?[nl] <str> { $$ = $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.
|
||||||
|
|
||||||
|
```
|
||||||
|
%rule defined_option(X): /* empty */
|
||||||
|
| X
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
program : defined_option(number) <i>
|
||||||
|
| defined_list(number) <i>
|
||||||
|
;
|
||||||
|
|
||||||
|
%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.
|
||||||
|
|
||||||
|
```
|
||||||
|
❯ 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.
|
||||||
|
|
||||||
|
```
|
||||||
|
❯ 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.
|
||||||
|
|
||||||
|
```
|
||||||
|
❯ 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.
|
||||||
|
|
||||||
|
```
|
||||||
|
%union {
|
||||||
|
int i;
|
||||||
|
}
|
||||||
|
|
||||||
|
%rule with_tag(X) <i>: X { $$ = $1; }
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Named References for actions of RHS in parameterizing rules
|
||||||
|
|
||||||
|
Allow to use named references for actions of RHS in parameterizing rules.
|
||||||
|
|
||||||
|
```
|
||||||
|
%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.
|
||||||
|
|
||||||
|
```
|
||||||
|
%union {
|
||||||
|
int i;
|
||||||
|
}
|
||||||
|
|
||||||
|
%rule nested_nested_option(X): /* empty */
|
||||||
|
| X
|
||||||
|
;
|
||||||
|
|
||||||
|
%rule nested_option(X): /* empty */
|
||||||
|
| nested_nested_option(X) <i>
|
||||||
|
;
|
||||||
|
|
||||||
|
%rule option(Y): /* empty */
|
||||||
|
| nested_option(Y) <i>
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
```
|
||||||
|
❯ 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.
|
||||||
|
|
||||||
|
```
|
||||||
|
%rule %inline op: PLUS { + }
|
||||||
|
| TIMES { * }
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
expr : number { $$ = $1; }
|
||||||
|
| expr op expr { $$ = $1 $2 $3; }
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
as same as
|
||||||
|
|
||||||
|
```
|
||||||
|
expr : number { $$ = $1; }
|
||||||
|
| expr '+' expr { $$ = $1 + $3; }
|
||||||
|
| expr '*' expr { $$ = $1 * $3; }
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
## Lrama 0.6.5 (2024-03-25)
|
## Lrama 0.6.5 (2024-03-25)
|
||||||
|
|
||||||
### Typed Midrule Actions
|
### Typed Midrule Actions
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
$LOAD_PATH << File.join(__dir__, "../lib")
|
$LOAD_PATH << File.join(__dir__, "../lib")
|
||||||
require "lrama"
|
require "lrama"
|
||||||
|
@ -1,17 +1,22 @@
|
|||||||
require "lrama/bitmap"
|
# frozen_string_literal: true
|
||||||
require "lrama/command"
|
|
||||||
require "lrama/context"
|
require_relative "lrama/bitmap"
|
||||||
require "lrama/counterexamples"
|
require_relative "lrama/command"
|
||||||
require "lrama/digraph"
|
require_relative "lrama/context"
|
||||||
require "lrama/grammar"
|
require_relative "lrama/counterexamples"
|
||||||
require "lrama/lexer"
|
require_relative "lrama/diagnostics"
|
||||||
require "lrama/option_parser"
|
require_relative "lrama/digraph"
|
||||||
require "lrama/options"
|
require_relative "lrama/grammar"
|
||||||
require "lrama/output"
|
require_relative "lrama/grammar_validator"
|
||||||
require "lrama/parser"
|
require_relative "lrama/lexer"
|
||||||
require "lrama/report"
|
require_relative "lrama/logger"
|
||||||
require "lrama/state"
|
require_relative "lrama/option_parser"
|
||||||
require "lrama/states"
|
require_relative "lrama/options"
|
||||||
require "lrama/states_reporter"
|
require_relative "lrama/output"
|
||||||
require "lrama/version"
|
require_relative "lrama/parser"
|
||||||
require "lrama/warning"
|
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"
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
module Bitmap
|
module Bitmap
|
||||||
def self.from_array(ary)
|
def self.from_array(ary)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Command
|
class Command
|
||||||
LRAMA_LIB = File.realpath(File.join(File.dirname(__FILE__)))
|
LRAMA_LIB = File.realpath(File.join(File.dirname(__FILE__)))
|
||||||
@ -14,7 +16,6 @@ module Lrama
|
|||||||
|
|
||||||
Report::Duration.enable if options.trace_opts[:time]
|
Report::Duration.enable if options.trace_opts[:time]
|
||||||
|
|
||||||
warning = Lrama::Warning.new
|
|
||||||
text = options.y.read
|
text = options.y.read
|
||||||
options.y.close if options.y != STDIN
|
options.y.close if options.y != STDIN
|
||||||
begin
|
begin
|
||||||
@ -31,7 +32,7 @@ module Lrama
|
|||||||
message = message.gsub(/.+/, "\e[1m\\&\e[m") if Exception.to_tty?
|
message = message.gsub(/.+/, "\e[1m\\&\e[m") if Exception.to_tty?
|
||||||
abort message
|
abort message
|
||||||
end
|
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
|
||||||
context = Lrama::Context.new(states)
|
context = Lrama::Context.new(states)
|
||||||
|
|
||||||
@ -42,15 +43,8 @@ module Lrama
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if options.trace_opts && options.trace_opts[:rules]
|
reporter = Lrama::TraceReporter.new(grammar)
|
||||||
puts "Grammar rules:"
|
reporter.report(**options.trace_opts)
|
||||||
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
|
|
||||||
|
|
||||||
File.open(options.outfile, "w+") do |f|
|
File.open(options.outfile, "w+") do |f|
|
||||||
Lrama::Output.new(
|
Lrama::Output.new(
|
||||||
@ -65,9 +59,9 @@ module Lrama
|
|||||||
).render
|
).render
|
||||||
end
|
end
|
||||||
|
|
||||||
if warning.has_error?
|
logger = Lrama::Logger.new
|
||||||
exit false
|
exit false unless Lrama::GrammarValidator.new(grammar, states, logger).valid?
|
||||||
end
|
Lrama::Diagnostics.new(grammar, states, logger).run(options.diagnostic)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
require "lrama/report/duration"
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative "report/duration"
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
# This is passed to a template
|
# This is passed to a template
|
||||||
@ -253,7 +255,7 @@ module Lrama
|
|||||||
|
|
||||||
# If no default_reduction_rule, default behavior is an
|
# If no default_reduction_rule, default behavior is an
|
||||||
# error then replace ErrorActionNumber with zero.
|
# error then replace ErrorActionNumber with zero.
|
||||||
if !state.default_reduction_rule
|
unless state.default_reduction_rule
|
||||||
actions.map! do |e|
|
actions.map! do |e|
|
||||||
if e == ErrorActionNumber
|
if e == ErrorActionNumber
|
||||||
0
|
0
|
||||||
@ -301,10 +303,7 @@ module Lrama
|
|||||||
end
|
end
|
||||||
|
|
||||||
@states.nterms.each do |nterm|
|
@states.nterms.each do |nterm|
|
||||||
if !(states = nterm_to_next_states[nterm])
|
if (states = nterm_to_next_states[nterm])
|
||||||
default_goto = 0
|
|
||||||
not_default_gotos = []
|
|
||||||
else
|
|
||||||
default_state = states.map(&:last).group_by {|s| s }.max_by {|_, v| v.count }.first
|
default_state = states.map(&:last).group_by {|s| s }.max_by {|_, v| v.count }.first
|
||||||
default_goto = default_state.id
|
default_goto = default_state.id
|
||||||
not_default_gotos = []
|
not_default_gotos = []
|
||||||
@ -312,6 +311,9 @@ module Lrama
|
|||||||
next if to_state.id == default_goto
|
next if to_state.id == default_goto
|
||||||
not_default_gotos << [from_state.id, to_state.id]
|
not_default_gotos << [from_state.id, to_state.id]
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
default_goto = 0
|
||||||
|
not_default_gotos = []
|
||||||
end
|
end
|
||||||
|
|
||||||
k = nterm_number_to_sequence_number(nterm.number)
|
k = nterm_number_to_sequence_number(nterm.number)
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "set"
|
require "set"
|
||||||
|
|
||||||
require "lrama/counterexamples/derivation"
|
require_relative "counterexamples/derivation"
|
||||||
require "lrama/counterexamples/example"
|
require_relative "counterexamples/example"
|
||||||
require "lrama/counterexamples/path"
|
require_relative "counterexamples/path"
|
||||||
require "lrama/counterexamples/production_path"
|
require_relative "counterexamples/production_path"
|
||||||
require "lrama/counterexamples/start_path"
|
require_relative "counterexamples/start_path"
|
||||||
require "lrama/counterexamples/state_item"
|
require_relative "counterexamples/state_item"
|
||||||
require "lrama/counterexamples/transition_path"
|
require_relative "counterexamples/transition_path"
|
||||||
require "lrama/counterexamples/triple"
|
require_relative "counterexamples/triple"
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
# See: https://www.cs.cornell.edu/andru/papers/cupex/cupex.pdf
|
# See: https://www.cs.cornell.edu/andru/papers/cupex/cupex.pdf
|
||||||
@ -171,7 +173,13 @@ module Lrama
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
|
||||||
if !si.item.beginning_of_rule?
|
if si.item.beginning_of_rule?
|
||||||
|
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
|
||||||
key = [si, si.item.previous_sym]
|
key = [si, si.item.previous_sym]
|
||||||
@reverse_transitions[key].each do |prev_target_state_item|
|
@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
|
||||||
@ -183,12 +191,6 @@ module Lrama
|
|||||||
queue.clear
|
queue.clear
|
||||||
break
|
break
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Counterexamples
|
class Counterexamples
|
||||||
class Derivation
|
class Derivation
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Counterexamples
|
class Counterexamples
|
||||||
class Example
|
class Example
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Counterexamples
|
class Counterexamples
|
||||||
class Path
|
class Path
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Counterexamples
|
class Counterexamples
|
||||||
class ProductionPath < Path
|
class ProductionPath < Path
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Counterexamples
|
class Counterexamples
|
||||||
class StartPath < Path
|
class StartPath < Path
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Counterexamples
|
class Counterexamples
|
||||||
class StateItem < Struct.new(:state, :item)
|
class StateItem < Struct.new(:state, :item)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Counterexamples
|
class Counterexamples
|
||||||
class TransitionPath < Path
|
class TransitionPath < Path
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Counterexamples
|
class Counterexamples
|
||||||
# s: state
|
# s: state
|
||||||
|
36
tool/lrama/lib/lrama/diagnostics.rb
Normal file
36
tool/lrama/lib/lrama/diagnostics.rb
Normal file
@ -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
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
# Algorithm Digraph of https://dl.acm.org/doi/pdf/10.1145/69622.357187 (P. 625)
|
# Algorithm Digraph of https://dl.acm.org/doi/pdf/10.1145/69622.357187 (P. 625)
|
||||||
class Digraph
|
class Digraph
|
||||||
|
@ -1,43 +1,40 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "forwardable"
|
require "forwardable"
|
||||||
require "lrama/grammar/auxiliary"
|
require_relative "grammar/auxiliary"
|
||||||
require "lrama/grammar/binding"
|
require_relative "grammar/binding"
|
||||||
require "lrama/grammar/code"
|
require_relative "grammar/code"
|
||||||
require "lrama/grammar/counter"
|
require_relative "grammar/counter"
|
||||||
require "lrama/grammar/destructor"
|
require_relative "grammar/destructor"
|
||||||
require "lrama/grammar/error_token"
|
require_relative "grammar/error_token"
|
||||||
require "lrama/grammar/parameterizing_rule"
|
require_relative "grammar/parameterizing_rule"
|
||||||
require "lrama/grammar/percent_code"
|
require_relative "grammar/percent_code"
|
||||||
require "lrama/grammar/precedence"
|
require_relative "grammar/precedence"
|
||||||
require "lrama/grammar/printer"
|
require_relative "grammar/printer"
|
||||||
require "lrama/grammar/reference"
|
require_relative "grammar/reference"
|
||||||
require "lrama/grammar/rule"
|
require_relative "grammar/rule"
|
||||||
require "lrama/grammar/rule_builder"
|
require_relative "grammar/rule_builder"
|
||||||
require "lrama/grammar/symbol"
|
require_relative "grammar/symbol"
|
||||||
require "lrama/grammar/symbols"
|
require_relative "grammar/symbols"
|
||||||
require "lrama/grammar/type"
|
require_relative "grammar/type"
|
||||||
require "lrama/grammar/union"
|
require_relative "grammar/union"
|
||||||
require "lrama/lexer"
|
require_relative "lexer"
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
# Grammar is the result of parsing an input grammar file
|
# Grammar is the result of parsing an input grammar file
|
||||||
class Grammar
|
class Grammar
|
||||||
extend Forwardable
|
extend Forwardable
|
||||||
|
|
||||||
attr_reader :percent_codes, :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux
|
attr_reader :percent_codes, :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux, :parameterizing_rule_resolver
|
||||||
attr_accessor :union, :expect,
|
attr_accessor :union, :expect, :printers, :error_tokens, :lex_param, :parse_param, :initial_action,
|
||||||
:printers, :error_tokens,
|
|
||||||
:lex_param, :parse_param, :initial_action,
|
|
||||||
:after_shift, :before_reduce, :after_reduce, :after_shift_error_token, :after_pop_stack,
|
:after_shift, :before_reduce, :after_reduce, :after_shift_error_token, :after_pop_stack,
|
||||||
:symbols_resolver, :types,
|
:symbols_resolver, :types, :rules, :rule_builders, :sym_to_rules, :no_stdlib, :locations
|
||||||
:rules, :rule_builders,
|
|
||||||
:sym_to_rules, :no_stdlib
|
|
||||||
|
|
||||||
def_delegators "@symbols_resolver", :symbols, :nterms, :terms, :add_nterm, :add_term,
|
def_delegators "@symbols_resolver", :symbols, :nterms, :terms, :add_nterm, :add_term,
|
||||||
:find_symbol_by_number!, :find_symbol_by_id!, :token_to_symbol,
|
:find_symbol_by_number!, :find_symbol_by_id!, :token_to_symbol,
|
||||||
:find_symbol_by_s_value!, :fill_symbol_number, :fill_nterm_type,
|
:find_symbol_by_s_value!, :fill_symbol_number, :fill_nterm_type,
|
||||||
:fill_printer, :fill_destructor, :fill_error_token, :sort_by_number!
|
:fill_printer, :fill_destructor, :fill_error_token, :sort_by_number!
|
||||||
|
|
||||||
|
|
||||||
def initialize(rule_counter)
|
def initialize(rule_counter)
|
||||||
@rule_counter = rule_counter
|
@rule_counter = rule_counter
|
||||||
|
|
||||||
@ -59,10 +56,15 @@ module Lrama
|
|||||||
@accept_symbol = nil
|
@accept_symbol = nil
|
||||||
@aux = Auxiliary.new
|
@aux = Auxiliary.new
|
||||||
@no_stdlib = false
|
@no_stdlib = false
|
||||||
|
@locations = false
|
||||||
|
|
||||||
append_special_symbols
|
append_special_symbols
|
||||||
end
|
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:)
|
def add_percent_code(id:, code:)
|
||||||
@percent_codes << PercentCode.new(id.s_value, code.s_value)
|
@percent_codes << PercentCode.new(id.s_value, code.s_value)
|
||||||
end
|
end
|
||||||
@ -141,6 +143,7 @@ module Lrama
|
|||||||
end
|
end
|
||||||
|
|
||||||
def prepare
|
def prepare
|
||||||
|
resolve_inline_rules
|
||||||
normalize_rules
|
normalize_rules
|
||||||
collect_symbols
|
collect_symbols
|
||||||
set_lhs_and_rhs
|
set_lhs_and_rhs
|
||||||
@ -149,6 +152,7 @@ module Lrama
|
|||||||
fill_sym_to_rules
|
fill_sym_to_rules
|
||||||
compute_nullable
|
compute_nullable
|
||||||
compute_first_set
|
compute_first_set
|
||||||
|
set_locations
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: More validation methods
|
# TODO: More validation methods
|
||||||
@ -255,7 +259,7 @@ module Lrama
|
|||||||
|
|
||||||
def setup_rules
|
def setup_rules
|
||||||
@rule_builders.each do |builder|
|
@rule_builders.each do |builder|
|
||||||
builder.setup_rules(@parameterizing_rule_resolver)
|
builder.setup_rules
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -289,10 +293,23 @@ module Lrama
|
|||||||
@accept_symbol = term
|
@accept_symbol = term
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def resolve_inline_rules
|
||||||
|
while @rule_builders.any? {|r| r.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
|
def normalize_rules
|
||||||
# Add $accept rule to the top of rules
|
# Add $accept rule to the top of rules
|
||||||
lineno = @rule_builders.first ? @rule_builders.first.line : 0
|
rule_builder = @rule_builders.first # : RuleBuilder
|
||||||
@rules << Rule.new(id: @rule_counter.increment, _lhs: @accept_symbol.id, _rhs: [@rule_builders.first.lhs, @eof_symbol.id], token_code: nil, lineno: lineno)
|
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
|
setup_rules
|
||||||
|
|
||||||
@ -370,12 +387,16 @@ module Lrama
|
|||||||
rules.each do |rule|
|
rules.each do |rule|
|
||||||
next if rule.lhs.nterm?
|
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
|
end
|
||||||
|
|
||||||
return if errors.empty?
|
return if errors.empty?
|
||||||
|
|
||||||
raise errors.join("\n")
|
raise errors.join("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_locations
|
||||||
|
@locations = @locations || @rules.any? {|rule| rule.contains_at_reference? }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
# Grammar file information not used by States but by Output
|
# Grammar file information not used by States but by Output
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class Binding
|
class Binding
|
||||||
@ -16,9 +18,18 @@ module Lrama
|
|||||||
resolved_args = symbol.args.map { |arg| resolve_symbol(arg) }
|
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)
|
Lrama::Lexer::Token::InstantiateRule.new(s_value: symbol.s_value, location: symbol.location, args: resolved_args, lhs_tag: symbol.lhs_tag)
|
||||||
else
|
else
|
||||||
@parameter_to_arg[symbol.s_value] || symbol
|
parameter_to_arg(symbol) || symbol
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def parameter_to_arg(symbol)
|
||||||
|
if (arg = @parameter_to_arg[symbol.s_value].dup)
|
||||||
|
arg.alias_name = symbol.alias_name
|
||||||
|
end
|
||||||
|
arg
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "forwardable"
|
require "forwardable"
|
||||||
require "lrama/grammar/code/destructor_code"
|
require_relative "code/destructor_code"
|
||||||
require "lrama/grammar/code/initial_action_code"
|
require_relative "code/initial_action_code"
|
||||||
require "lrama/grammar/code/no_reference_code"
|
require_relative "code/no_reference_code"
|
||||||
require "lrama/grammar/code/printer_code"
|
require_relative "code/printer_code"
|
||||||
require "lrama/grammar/code/rule_action"
|
require_relative "code/rule_action"
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class Code
|
class Code
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class Code
|
class Code
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class Code
|
class Code
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class Code
|
class Code
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class Code
|
class Code
|
||||||
@ -41,6 +43,7 @@ module Lrama
|
|||||||
when ref.type == :dollar && ref.name == "$" # $$
|
when ref.type == :dollar && ref.name == "$" # $$
|
||||||
tag = ref.ex_tag || lhs.tag
|
tag = ref.ex_tag || lhs.tag
|
||||||
raise_tag_not_found_error(ref) unless tag
|
raise_tag_not_found_error(ref) unless tag
|
||||||
|
# @type var tag: Lexer::Token::Tag
|
||||||
"(yyval.#{tag.member})"
|
"(yyval.#{tag.member})"
|
||||||
when ref.type == :at && ref.name == "$" # @$
|
when ref.type == :at && ref.name == "$" # @$
|
||||||
"(yyloc)"
|
"(yyloc)"
|
||||||
@ -50,6 +53,7 @@ module Lrama
|
|||||||
i = -position_in_rhs + ref.index
|
i = -position_in_rhs + ref.index
|
||||||
tag = ref.ex_tag || rhs[ref.index - 1].tag
|
tag = ref.ex_tag || rhs[ref.index - 1].tag
|
||||||
raise_tag_not_found_error(ref) unless tag
|
raise_tag_not_found_error(ref) unless tag
|
||||||
|
# @type var tag: Lexer::Token::Tag
|
||||||
"(yyvsp[#{i}].#{tag.member})"
|
"(yyvsp[#{i}].#{tag.member})"
|
||||||
when ref.type == :at # @n
|
when ref.type == :at # @n
|
||||||
i = -position_in_rhs + ref.index
|
i = -position_in_rhs + ref.index
|
||||||
@ -69,18 +73,18 @@ module Lrama
|
|||||||
@rule.position_in_original_rule_rhs || @rule.rhs.count
|
@rule.position_in_original_rule_rhs || @rule.rhs.count
|
||||||
end
|
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
|
def rhs
|
||||||
(@rule.original_rule || @rule).rhs
|
(@rule.original_rule || @rule).rhs
|
||||||
end
|
end
|
||||||
|
|
||||||
# Unlike `rhs`, LHS is always a LHS of the rule.
|
# Unlike `rhs`, LHS is always an LHS of the rule.
|
||||||
def lhs
|
def lhs
|
||||||
@rule.lhs
|
@rule.lhs
|
||||||
end
|
end
|
||||||
|
|
||||||
def raise_tag_not_found_error(ref)
|
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
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class Counter
|
class Counter
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class Destructor < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true)
|
class Destructor < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class ErrorToken < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true)
|
class ErrorToken < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require_relative 'parameterizing_rule/resolver'
|
require_relative 'parameterizing_rule/resolver'
|
||||||
require_relative 'parameterizing_rule/rhs'
|
require_relative 'parameterizing_rule/rhs'
|
||||||
require_relative 'parameterizing_rule/rule'
|
require_relative 'parameterizing_rule/rule'
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class ParameterizingRule
|
class ParameterizingRule
|
||||||
@ -18,13 +20,17 @@ module Lrama
|
|||||||
end
|
end
|
||||||
|
|
||||||
def find_inline(token)
|
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
|
end
|
||||||
|
|
||||||
def created_lhs(lhs_s_value)
|
def created_lhs(lhs_s_value)
|
||||||
@created_lhs_list.reverse.find { |created_lhs| created_lhs.s_value == lhs_s_value }
|
@created_lhs_list.reverse.find { |created_lhs| created_lhs.s_value == lhs_s_value }
|
||||||
end
|
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
|
private
|
||||||
|
|
||||||
def select_rules(rules, token)
|
def select_rules(rules, token)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class ParameterizingRule
|
class ParameterizingRule
|
||||||
@ -13,6 +15,7 @@ module Lrama
|
|||||||
def resolve_user_code(bindings)
|
def resolve_user_code(bindings)
|
||||||
return unless user_code
|
return unless user_code
|
||||||
|
|
||||||
|
resolved = Lexer::Token::UserCode.new(s_value: user_code.s_value, location: user_code.location)
|
||||||
var_to_arg = {}
|
var_to_arg = {}
|
||||||
symbols.each do |sym|
|
symbols.each do |sym|
|
||||||
resolved_sym = bindings.resolve_symbol(sym)
|
resolved_sym = bindings.resolve_symbol(sym)
|
||||||
@ -22,14 +25,14 @@ module Lrama
|
|||||||
end
|
end
|
||||||
|
|
||||||
var_to_arg.each do |var, arg|
|
var_to_arg.each do |var, arg|
|
||||||
user_code.references.each do |ref|
|
resolved.references.each do |ref|
|
||||||
if ref.name == var
|
if ref.name == var
|
||||||
ref.name = arg
|
ref.name = arg
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return user_code
|
return resolved
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class ParameterizingRule
|
class ParameterizingRule
|
||||||
@ -12,6 +14,10 @@ module Lrama
|
|||||||
@is_inline = is_inline
|
@is_inline = is_inline
|
||||||
@required_parameters_count = parameters.count
|
@required_parameters_count = parameters.count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"#{@name}(#{@parameters.map(&:s_value).join(', ')})"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class PercentCode
|
class PercentCode
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class Precedence < Struct.new(:type, :precedence, keyword_init: true)
|
class Precedence < Struct.new(:type, :precedence, keyword_init: true)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class Printer < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true)
|
class Printer < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
# type: :dollar or :at
|
# type: :dollar or :at
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
# _rhs holds original RHS element. Use rhs to refer to Symbol.
|
# _rhs holds original RHS element. Use rhs to refer to Symbol.
|
||||||
@ -16,8 +18,7 @@ module Lrama
|
|||||||
self.lineno == other.lineno
|
self.lineno == other.lineno
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: Change this to display_name
|
def display_name
|
||||||
def to_s
|
|
||||||
l = lhs.id.s_value
|
l = lhs.id.s_value
|
||||||
r = empty_rule? ? "ε" : rhs.map {|r| r.id.s_value }.join(" ")
|
r = empty_rule? ? "ε" : rhs.map {|r| r.id.s_value }.join(" ")
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ module Lrama
|
|||||||
end
|
end
|
||||||
|
|
||||||
def with_actions
|
def with_actions
|
||||||
"#{to_s} {#{token_code&.s_value}}"
|
"#{display_name} {#{token_code&.s_value}}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# opt_nl: ε <-- empty_rule
|
# opt_nl: ε <-- empty_rule
|
||||||
@ -55,6 +56,12 @@ module Lrama
|
|||||||
|
|
||||||
Code::RuleAction.new(type: :rule_action, token_code: token_code, rule: self).translated_code
|
Code::RuleAction.new(type: :rule_action, token_code: token_code, rule: self).translated_code
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def contains_at_reference?
|
||||||
|
return false unless token_code
|
||||||
|
|
||||||
|
token_code.references.any? {|r| r.type == :at }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class RuleBuilder
|
class RuleBuilder
|
||||||
attr_accessor :lhs, :line
|
attr_accessor :lhs, :line
|
||||||
attr_reader :lhs_tag, :rhs, :user_code, :precedence_sym
|
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
|
@rule_counter = rule_counter
|
||||||
@midrule_action_counter = midrule_action_counter
|
@midrule_action_counter = midrule_action_counter
|
||||||
|
@parameterizing_rule_resolver = parameterizing_rule_resolver
|
||||||
@position_in_original_rule_rhs = position_in_original_rule_rhs
|
@position_in_original_rule_rhs = position_in_original_rule_rhs
|
||||||
@skip_preprocess_references = skip_preprocess_references
|
@skip_preprocess_references = skip_preprocess_references
|
||||||
|
|
||||||
@ -19,16 +22,12 @@ module Lrama
|
|||||||
@rules = []
|
@rules = []
|
||||||
@rule_builders_for_parameterizing_rules = []
|
@rule_builders_for_parameterizing_rules = []
|
||||||
@rule_builders_for_derived_rules = []
|
@rule_builders_for_derived_rules = []
|
||||||
@rule_builders_for_inline_rules = []
|
|
||||||
@parameterizing_rules = []
|
@parameterizing_rules = []
|
||||||
@inline_rules = []
|
|
||||||
@midrule_action_rules = []
|
@midrule_action_rules = []
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_rhs(rhs)
|
def add_rhs(rhs)
|
||||||
if !@line
|
@line ||= rhs.line
|
||||||
@line = rhs.line
|
|
||||||
end
|
|
||||||
|
|
||||||
flush_user_code
|
flush_user_code
|
||||||
|
|
||||||
@ -36,9 +35,7 @@ module Lrama
|
|||||||
end
|
end
|
||||||
|
|
||||||
def user_code=(user_code)
|
def user_code=(user_code)
|
||||||
if !@line
|
@line ||= user_code&.line
|
||||||
@line = user_code&.line
|
|
||||||
end
|
|
||||||
|
|
||||||
flush_user_code
|
flush_user_code
|
||||||
|
|
||||||
@ -55,18 +52,41 @@ module Lrama
|
|||||||
freeze_rhs
|
freeze_rhs
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup_rules(parameterizing_rule_resolver)
|
def setup_rules
|
||||||
preprocess_references unless @skip_preprocess_references
|
preprocess_references unless @skip_preprocess_references
|
||||||
if rhs.any? { |token| parameterizing_rule_resolver.find_inline(token) }
|
process_rhs
|
||||||
resolve_inline(parameterizing_rule_resolver)
|
|
||||||
else
|
|
||||||
process_rhs(parameterizing_rule_resolver)
|
|
||||||
end
|
|
||||||
build_rules
|
build_rules
|
||||||
end
|
end
|
||||||
|
|
||||||
def rules
|
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 = []
|
||||||
|
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, 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
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@ -82,31 +102,25 @@ module Lrama
|
|||||||
def build_rules
|
def build_rules
|
||||||
tokens = @replaced_rhs
|
tokens = @replaced_rhs
|
||||||
|
|
||||||
if tokens
|
rule = Rule.new(
|
||||||
rule = Rule.new(
|
id: @rule_counter.increment, _lhs: lhs, _rhs: tokens, lhs_tag: lhs_tag, token_code: user_code,
|
||||||
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
|
||||||
position_in_original_rule_rhs: @position_in_original_rule_rhs, precedence_sym: precedence_sym, lineno: line
|
)
|
||||||
)
|
@rules = [rule]
|
||||||
@rules = [rule]
|
@parameterizing_rules = @rule_builders_for_parameterizing_rules.map do |rule_builder|
|
||||||
@parameterizing_rules = @rule_builders_for_parameterizing_rules.map do |rule_builder|
|
rule_builder.rules
|
||||||
rule_builder.rules
|
end.flatten
|
||||||
end.flatten
|
@midrule_action_rules = @rule_builders_for_derived_rules.map do |rule_builder|
|
||||||
@midrule_action_rules = @rule_builders_for_derived_rules.map do |rule_builder|
|
rule_builder.rules
|
||||||
rule_builder.rules
|
end.flatten
|
||||||
end.flatten
|
@midrule_action_rules.each do |r|
|
||||||
@midrule_action_rules.each do |r|
|
r.original_rule = rule
|
||||||
r.original_rule = rule
|
|
||||||
end
|
|
||||||
else
|
|
||||||
@inline_rules = @rule_builders_for_inline_rules.map do |rule_builder|
|
|
||||||
rule_builder.rules
|
|
||||||
end.flatten
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# rhs is a mixture of variety type of tokens like `Ident`, `InstantiateRule`, `UserCode` and so on.
|
# 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`.
|
# `#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
|
return if @replaced_rhs
|
||||||
|
|
||||||
@replaced_rhs = []
|
@replaced_rhs = []
|
||||||
@ -118,26 +132,26 @@ module Lrama
|
|||||||
when Lrama::Lexer::Token::Ident
|
when Lrama::Lexer::Token::Ident
|
||||||
@replaced_rhs << token
|
@replaced_rhs << token
|
||||||
when Lrama::Lexer::Token::InstantiateRule
|
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
|
raise "Unexpected token. #{token}" unless parameterizing_rule
|
||||||
|
|
||||||
bindings = Binding.new(parameterizing_rule, token.args)
|
bindings = Binding.new(parameterizing_rule, token.args)
|
||||||
lhs_s_value = lhs_s_value(token, bindings)
|
lhs_s_value = lhs_s_value(token, bindings)
|
||||||
if (created_lhs = parameterizing_rule_resolver.created_lhs(lhs_s_value))
|
if (created_lhs = @parameterizing_rule_resolver.created_lhs(lhs_s_value))
|
||||||
@replaced_rhs << created_lhs
|
@replaced_rhs << created_lhs
|
||||||
else
|
else
|
||||||
lhs_token = Lrama::Lexer::Token::Ident.new(s_value: lhs_s_value, location: token.location)
|
lhs_token = Lrama::Lexer::Token::Ident.new(s_value: lhs_s_value, location: token.location)
|
||||||
@replaced_rhs << lhs_token
|
@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|
|
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
|
rule_builder.lhs = lhs_token
|
||||||
r.symbols.each { |sym| rule_builder.add_rhs(bindings.resolve_symbol(sym)) }
|
r.symbols.each { |sym| rule_builder.add_rhs(bindings.resolve_symbol(sym)) }
|
||||||
rule_builder.line = line
|
rule_builder.line = line
|
||||||
rule_builder.precedence_sym = r.precedence_sym
|
rule_builder.precedence_sym = r.precedence_sym
|
||||||
rule_builder.user_code = r.resolve_user_code(bindings)
|
rule_builder.user_code = r.resolve_user_code(bindings)
|
||||||
rule_builder.complete_input
|
rule_builder.complete_input
|
||||||
rule_builder.setup_rules(parameterizing_rule_resolver)
|
rule_builder.setup_rules
|
||||||
@rule_builders_for_parameterizing_rules << rule_builder
|
@rule_builders_for_parameterizing_rules << rule_builder
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -147,11 +161,11 @@ module Lrama
|
|||||||
new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + @midrule_action_counter.increment.to_s)
|
new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + @midrule_action_counter.increment.to_s)
|
||||||
@replaced_rhs << new_token
|
@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.lhs = new_token
|
||||||
rule_builder.user_code = token
|
rule_builder.user_code = token
|
||||||
rule_builder.complete_input
|
rule_builder.complete_input
|
||||||
rule_builder.setup_rules(parameterizing_rule_resolver)
|
rule_builder.setup_rules
|
||||||
|
|
||||||
@rule_builders_for_derived_rules << rule_builder
|
@rule_builders_for_derived_rules << rule_builder
|
||||||
else
|
else
|
||||||
@ -172,27 +186,10 @@ module Lrama
|
|||||||
"#{token.rule_name}_#{s_values.join('_')}"
|
"#{token.rule_name}_#{s_values.join('_')}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def resolve_inline(parameterizing_rule_resolver)
|
def resolve_inline_rhs(rule_builder, inline_rhs, index, bindings = nil)
|
||||||
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)
|
|
||||||
rhs.each_with_index do |token, i|
|
rhs.each_with_index do |token, i|
|
||||||
if index == 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
|
else
|
||||||
rule_builder.add_rhs(token)
|
rule_builder.add_rhs(token)
|
||||||
end
|
end
|
||||||
@ -204,6 +201,11 @@ module Lrama
|
|||||||
return user_code if user_code.nil?
|
return user_code if user_code.nil?
|
||||||
|
|
||||||
code = user_code.s_value.gsub(/\$#{index + 1}/, inline_rhs.user_code.s_value)
|
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)
|
Lrama::Lexer::Token::UserCode.new(s_value: code, location: user_code.location)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -238,9 +240,6 @@ module Lrama
|
|||||||
end
|
end
|
||||||
|
|
||||||
if ref.number
|
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
|
ref.index = ref.number
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Symbol is both of nterm and term
|
# Symbol is both of nterm and term
|
||||||
# `number` is both for nterm and term
|
# `number` is both for nterm and term
|
||||||
# `token_id` is tokentype for term, internal sequence number for nterm
|
# `token_id` is tokentype for term, internal sequence number for nterm
|
||||||
|
@ -1 +1,3 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require_relative "symbols/resolver"
|
require_relative "symbols/resolver"
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class Symbols
|
class Symbols
|
||||||
@ -42,7 +44,9 @@ module Lrama
|
|||||||
end
|
end
|
||||||
|
|
||||||
def add_nterm(id:, alias_name: nil, tag: nil)
|
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
|
@symbols = nil
|
||||||
nterm = Symbol.new(
|
nterm = Symbol.new(
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class Type
|
class Type
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Grammar
|
class Grammar
|
||||||
class Union < Struct.new(:code, :lineno, keyword_init: true)
|
class Union < Struct.new(:code, :lineno, keyword_init: true)
|
||||||
|
37
tool/lrama/lib/lrama/grammar_validator.rb
Normal file
37
tool/lrama/lib/lrama/grammar_validator.rb
Normal file
@ -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
|
@ -1,15 +1,17 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "strscan"
|
require "strscan"
|
||||||
|
|
||||||
require "lrama/lexer/grammar_file"
|
require_relative "lexer/grammar_file"
|
||||||
require "lrama/lexer/location"
|
require_relative "lexer/location"
|
||||||
require "lrama/lexer/token"
|
require_relative "lexer/token"
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Lexer
|
class Lexer
|
||||||
attr_reader :head_line, :head_column, :line
|
attr_reader :head_line, :head_column, :line
|
||||||
attr_accessor :status, :end_symbol
|
attr_accessor :status, :end_symbol
|
||||||
|
|
||||||
SYMBOLS = ['%{', '%}', '%%', '{', '}', '\[', '\]', '\(', '\)', '\,', ':', '\|', ';']
|
SYMBOLS = ['%{', '%}', '%%', '{', '}', '\[', '\]', '\(', '\)', '\,', ':', '\|', ';'].freeze
|
||||||
PERCENT_TOKENS = %w(
|
PERCENT_TOKENS = %w(
|
||||||
%union
|
%union
|
||||||
%token
|
%token
|
||||||
@ -38,7 +40,8 @@ module Lrama
|
|||||||
%rule
|
%rule
|
||||||
%no-stdlib
|
%no-stdlib
|
||||||
%inline
|
%inline
|
||||||
)
|
%locations
|
||||||
|
).freeze
|
||||||
|
|
||||||
def initialize(grammar_file)
|
def initialize(grammar_file)
|
||||||
@grammar_file = grammar_file
|
@grammar_file = grammar_file
|
||||||
@ -71,7 +74,7 @@ module Lrama
|
|||||||
end
|
end
|
||||||
|
|
||||||
def lex_token
|
def lex_token
|
||||||
while !@scanner.eos? do
|
until @scanner.eos? do
|
||||||
case
|
case
|
||||||
when @scanner.scan(/\n/)
|
when @scanner.scan(/\n/)
|
||||||
newline
|
newline
|
||||||
@ -126,7 +129,7 @@ module Lrama
|
|||||||
code = ''
|
code = ''
|
||||||
reset_first_position
|
reset_first_position
|
||||||
|
|
||||||
while !@scanner.eos? do
|
until @scanner.eos? do
|
||||||
case
|
case
|
||||||
when @scanner.scan(/{/)
|
when @scanner.scan(/{/)
|
||||||
code += @scanner.matched
|
code += @scanner.matched
|
||||||
@ -163,7 +166,7 @@ module Lrama
|
|||||||
private
|
private
|
||||||
|
|
||||||
def lex_comment
|
def lex_comment
|
||||||
while !@scanner.eos? do
|
until @scanner.eos? do
|
||||||
case
|
case
|
||||||
when @scanner.scan(/\n/)
|
when @scanner.scan(/\n/)
|
||||||
newline
|
newline
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Lexer
|
class Lexer
|
||||||
class GrammarFile
|
class GrammarFile
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Lexer
|
class Lexer
|
||||||
class Location
|
class Location
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
require 'lrama/lexer/token/char'
|
# frozen_string_literal: true
|
||||||
require 'lrama/lexer/token/ident'
|
|
||||||
require 'lrama/lexer/token/instantiate_rule'
|
require_relative 'token/char'
|
||||||
require 'lrama/lexer/token/tag'
|
require_relative 'token/ident'
|
||||||
require 'lrama/lexer/token/user_code'
|
require_relative 'token/instantiate_rule'
|
||||||
|
require_relative 'token/tag'
|
||||||
|
require_relative 'token/user_code'
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Lexer
|
class Lexer
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Lexer
|
class Lexer
|
||||||
class Token
|
class Token
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Lexer
|
class Lexer
|
||||||
class Token
|
class Token
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Lexer
|
class Lexer
|
||||||
class Token
|
class Token
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Lexer
|
class Lexer
|
||||||
class Token
|
class Token
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "strscan"
|
require "strscan"
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
@ -16,7 +18,7 @@ module Lrama
|
|||||||
scanner = StringScanner.new(s_value)
|
scanner = StringScanner.new(s_value)
|
||||||
references = []
|
references = []
|
||||||
|
|
||||||
while !scanner.eos? do
|
until scanner.eos? do
|
||||||
case
|
case
|
||||||
when reference = scan_reference(scanner)
|
when reference = scan_reference(scanner)
|
||||||
references << reference
|
references << reference
|
||||||
|
17
tool/lrama/lib/lrama/logger.rb
Normal file
17
tool/lrama/lib/lrama/logger.rb
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Lrama
|
||||||
|
class Logger
|
||||||
|
def initialize(out = STDERR)
|
||||||
|
@out = out
|
||||||
|
end
|
||||||
|
|
||||||
|
def warn(message)
|
||||||
|
@out << message << "\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
def error(message)
|
||||||
|
@out << message << "\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'optparse'
|
require 'optparse'
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
@ -16,7 +18,7 @@ module Lrama
|
|||||||
@options.report_opts = validate_report(@report)
|
@options.report_opts = validate_report(@report)
|
||||||
@options.grammar_file = argv.shift
|
@options.grammar_file = argv.shift
|
||||||
|
|
||||||
if !@options.grammar_file
|
unless @options.grammar_file
|
||||||
abort "File should be specified\n"
|
abort "File should be specified\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -63,20 +65,35 @@ module Lrama
|
|||||||
o.separator 'Output:'
|
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('-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('-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 ''
|
||||||
o.on_tail 'Valid Reports:'
|
o.on_tail 'REPORTS is a list of comma-separated words that can include:'
|
||||||
o.on_tail " #{VALID_REPORTS.join(' ')}"
|
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('--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('-o', '--output=FILE', 'leave output to FILE') {|v| @options.outfile = v }
|
||||||
|
o.on('--trace=TRACES', Array, 'also output trace logs at runtime') {|v| @trace = v }
|
||||||
o.on('--trace=THINGS', Array, 'also output trace logs at runtime') {|v| @trace = v }
|
|
||||||
o.on_tail ''
|
o.on_tail ''
|
||||||
o.on_tail 'Valid Traces:'
|
o.on_tail 'TRACES is a list of comma-separated words that can include:'
|
||||||
o.on_tail " #{VALID_TRACES.join(' ')}"
|
o.on_tail ' automaton display states'
|
||||||
|
o.on_tail ' closure display states'
|
||||||
o.on('-v', 'reserved, do nothing') { }
|
o.on_tail ' rules display 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 ''
|
||||||
o.separator 'Error Recovery:'
|
o.separator 'Error Recovery:'
|
||||||
o.on('-e', 'enable error recovery') {|v| @options.error_recovery = true }
|
o.on('-e', 'enable error recovery') {|v| @options.error_recovery = true }
|
||||||
@ -89,47 +106,55 @@ module Lrama
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
BISON_REPORTS = %w[states itemsets lookaheads solved counterexamples cex all none]
|
ALIASED_REPORTS = { cex: :counterexamples }.freeze
|
||||||
OTHER_REPORTS = %w[verbose]
|
VALID_REPORTS = %i[states itemsets lookaheads solved counterexamples rules terms verbose].freeze
|
||||||
NOT_SUPPORTED_REPORTS = %w[cex none]
|
|
||||||
VALID_REPORTS = BISON_REPORTS + OTHER_REPORTS - NOT_SUPPORTED_REPORTS
|
|
||||||
|
|
||||||
def validate_report(report)
|
def validate_report(report)
|
||||||
list = VALID_REPORTS
|
|
||||||
h = { grammar: true }
|
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|
|
report.each do |r|
|
||||||
if list.include?(r)
|
aliased = aliased_report_option(r)
|
||||||
h[r.to_sym] = true
|
if VALID_REPORTS.include?(aliased)
|
||||||
|
h[aliased] = true
|
||||||
else
|
else
|
||||||
raise "Invalid report option \"#{r}\"."
|
raise "Invalid report option \"#{r}\"."
|
||||||
end
|
end
|
||||||
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
|
return h
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def aliased_report_option(opt)
|
||||||
|
(ALIASED_REPORTS[opt.to_sym] || opt).to_sym
|
||||||
|
end
|
||||||
|
|
||||||
VALID_TRACES = %w[
|
VALID_TRACES = %w[
|
||||||
none locations scan parse automaton bitsets
|
locations scan parse automaton bitsets closure
|
||||||
closure grammar rules actions resource
|
grammar rules actions resource sets muscles
|
||||||
sets muscles tools m4-early m4 skeleton time
|
tools m4-early m4 skeleton time ielr cex
|
||||||
ielr cex all
|
].freeze
|
||||||
]
|
NOT_SUPPORTED_TRACES = %w[
|
||||||
|
locations scan parse bitsets grammar resource
|
||||||
|
sets muscles tools m4-early m4 skeleton ielr cex
|
||||||
|
].freeze
|
||||||
|
|
||||||
def validate_trace(trace)
|
def validate_trace(trace)
|
||||||
list = VALID_TRACES
|
|
||||||
h = {}
|
h = {}
|
||||||
|
return h if trace.empty? || trace == ['none']
|
||||||
|
supported = VALID_TRACES - NOT_SUPPORTED_TRACES
|
||||||
|
if trace == ['all']
|
||||||
|
supported.each { |t| h[t.to_sym] = true }
|
||||||
|
return h
|
||||||
|
end
|
||||||
|
|
||||||
trace.each do |t|
|
trace.each do |t|
|
||||||
if list.include?(t)
|
if supported.include?(t)
|
||||||
h[t.to_sym] = true
|
h[t.to_sym] = true
|
||||||
else
|
else
|
||||||
raise "Invalid trace option \"#{t}\"."
|
raise "Invalid trace option \"#{t}\"."
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
# Command line options.
|
# Command line options.
|
||||||
class Options
|
class Options
|
||||||
attr_accessor :skeleton, :header, :header_file,
|
attr_accessor :skeleton, :header, :header_file,
|
||||||
:report_file, :outfile,
|
:report_file, :outfile,
|
||||||
:error_recovery, :grammar_file,
|
:error_recovery, :grammar_file,
|
||||||
:trace_opts, :report_opts, :y,
|
:trace_opts, :report_opts,
|
||||||
:debug
|
:diagnostic, :y, :debug
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@skeleton = "bison/yacc.c"
|
@skeleton = "bison/yacc.c"
|
||||||
@ -17,6 +19,7 @@ module Lrama
|
|||||||
@grammar_file = nil
|
@grammar_file = nil
|
||||||
@trace_opts = nil
|
@trace_opts = nil
|
||||||
@report_opts = nil
|
@report_opts = nil
|
||||||
|
@diagnostic = false
|
||||||
@y = STDIN
|
@y = STDIN
|
||||||
@debug = false
|
@debug = false
|
||||||
end
|
end
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "erb"
|
require "erb"
|
||||||
require "forwardable"
|
require "forwardable"
|
||||||
require "lrama/report/duration"
|
require_relative "report/duration"
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Output
|
class Output
|
||||||
@ -63,37 +65,29 @@ module Lrama
|
|||||||
|
|
||||||
# A part of b4_token_enums
|
# A part of b4_token_enums
|
||||||
def token_enums
|
def token_enums
|
||||||
str = ""
|
@context.yytokentype.map do |s_value, token_id, display_name|
|
||||||
|
|
||||||
@context.yytokentype.each do |s_value, token_id, display_name|
|
|
||||||
s = sprintf("%s = %d%s", s_value, token_id, token_id == yymaxutok ? "" : ",")
|
s = sprintf("%s = %d%s", s_value, token_id, token_id == yymaxutok ? "" : ",")
|
||||||
|
|
||||||
if display_name
|
if display_name
|
||||||
str << sprintf(" %-30s /* %s */\n", s, display_name)
|
sprintf(" %-30s /* %s */\n", s, display_name)
|
||||||
else
|
else
|
||||||
str << sprintf(" %s\n", s)
|
sprintf(" %s\n", s)
|
||||||
end
|
end
|
||||||
end
|
end.join
|
||||||
|
|
||||||
str
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# b4_symbol_enum
|
# b4_symbol_enum
|
||||||
def symbol_enum
|
def symbol_enum
|
||||||
str = ""
|
|
||||||
|
|
||||||
last_sym_number = @context.yysymbol_kind_t.last[1]
|
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) ? "" : ",")
|
s = sprintf("%s = %d%s", s_value, sym_number, (sym_number == last_sym_number) ? "" : ",")
|
||||||
|
|
||||||
if display_name
|
if display_name
|
||||||
str << sprintf(" %-40s /* %s */\n", s, display_name)
|
sprintf(" %-40s /* %s */\n", s, display_name)
|
||||||
else
|
else
|
||||||
str << sprintf(" %s\n", s)
|
sprintf(" %s\n", s)
|
||||||
end
|
end
|
||||||
end
|
end.join
|
||||||
|
|
||||||
str
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def yytranslate
|
def yytranslate
|
||||||
@ -132,12 +126,10 @@ module Lrama
|
|||||||
end
|
end
|
||||||
|
|
||||||
def symbol_actions_for_printer
|
def symbol_actions_for_printer
|
||||||
str = ""
|
@grammar.symbols.map do |sym|
|
||||||
|
|
||||||
@grammar.symbols.each do |sym|
|
|
||||||
next unless sym.printer
|
next unless sym.printer
|
||||||
|
|
||||||
str << <<-STR
|
<<-STR
|
||||||
case #{sym.enum_name}: /* #{sym.comment} */
|
case #{sym.enum_name}: /* #{sym.comment} */
|
||||||
#line #{sym.printer.lineno} "#{@grammar_file_path}"
|
#line #{sym.printer.lineno} "#{@grammar_file_path}"
|
||||||
{#{sym.printer.translated_code(sym.tag)}}
|
{#{sym.printer.translated_code(sym.tag)}}
|
||||||
@ -145,18 +137,14 @@ module Lrama
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
STR
|
STR
|
||||||
end
|
end.join
|
||||||
|
|
||||||
str
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def symbol_actions_for_destructor
|
def symbol_actions_for_destructor
|
||||||
str = ""
|
@grammar.symbols.map do |sym|
|
||||||
|
|
||||||
@grammar.symbols.each do |sym|
|
|
||||||
next unless sym.destructor
|
next unless sym.destructor
|
||||||
|
|
||||||
str << <<-STR
|
<<-STR
|
||||||
case #{sym.enum_name}: /* #{sym.comment} */
|
case #{sym.enum_name}: /* #{sym.comment} */
|
||||||
#line #{sym.destructor.lineno} "#{@grammar_file_path}"
|
#line #{sym.destructor.lineno} "#{@grammar_file_path}"
|
||||||
{#{sym.destructor.translated_code(sym.tag)}}
|
{#{sym.destructor.translated_code(sym.tag)}}
|
||||||
@ -164,9 +152,7 @@ module Lrama
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
STR
|
STR
|
||||||
end
|
end.join
|
||||||
|
|
||||||
str
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# b4_user_initial_action
|
# b4_user_initial_action
|
||||||
@ -236,12 +222,10 @@ module Lrama
|
|||||||
end
|
end
|
||||||
|
|
||||||
def symbol_actions_for_error_token
|
def symbol_actions_for_error_token
|
||||||
str = ""
|
@grammar.symbols.map do |sym|
|
||||||
|
|
||||||
@grammar.symbols.each do |sym|
|
|
||||||
next unless sym.error_token
|
next unless sym.error_token
|
||||||
|
|
||||||
str << <<-STR
|
<<-STR
|
||||||
case #{sym.enum_name}: /* #{sym.comment} */
|
case #{sym.enum_name}: /* #{sym.comment} */
|
||||||
#line #{sym.error_token.lineno} "#{@grammar_file_path}"
|
#line #{sym.error_token.lineno} "#{@grammar_file_path}"
|
||||||
{#{sym.error_token.translated_code(sym.tag)}}
|
{#{sym.error_token.translated_code(sym.tag)}}
|
||||||
@ -249,22 +233,18 @@ module Lrama
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
STR
|
STR
|
||||||
end
|
end.join
|
||||||
|
|
||||||
str
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# b4_user_actions
|
# b4_user_actions
|
||||||
def user_actions
|
def user_actions
|
||||||
str = ""
|
action = @context.states.rules.map do |rule|
|
||||||
|
|
||||||
@context.states.rules.each do |rule|
|
|
||||||
next unless rule.token_code
|
next unless rule.token_code
|
||||||
|
|
||||||
code = rule.token_code
|
code = rule.token_code
|
||||||
spaces = " " * (code.column - 1)
|
spaces = " " * (code.column - 1)
|
||||||
|
|
||||||
str << <<-STR
|
<<-STR
|
||||||
case #{rule.id + 1}: /* #{rule.as_comment} */
|
case #{rule.id + 1}: /* #{rule.as_comment} */
|
||||||
#line #{code.line} "#{@grammar_file_path}"
|
#line #{code.line} "#{@grammar_file_path}"
|
||||||
#{spaces}{#{rule.translated_code}}
|
#{spaces}{#{rule.translated_code}}
|
||||||
@ -272,14 +252,12 @@ module Lrama
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
STR
|
STR
|
||||||
end
|
end.join
|
||||||
|
|
||||||
str << <<-STR
|
action + <<-STR
|
||||||
|
|
||||||
#line [@oline@] [@ofile@]
|
#line [@oline@] [@ofile@]
|
||||||
STR
|
STR
|
||||||
|
|
||||||
str
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def omit_blanks(param)
|
def omit_blanks(param)
|
||||||
@ -343,7 +321,7 @@ module Lrama
|
|||||||
|
|
||||||
# b4_parse_param_use
|
# b4_parse_param_use
|
||||||
def parse_param_use(val, loc)
|
def parse_param_use(val, loc)
|
||||||
str = <<-STR
|
str = <<-STR.dup
|
||||||
YY_USE (#{val});
|
YY_USE (#{val});
|
||||||
YY_USE (#{loc});
|
YY_USE (#{loc});
|
||||||
STR
|
STR
|
||||||
@ -357,7 +335,8 @@ module Lrama
|
|||||||
|
|
||||||
# b4_yylex_formals
|
# b4_yylex_formals
|
||||||
def yylex_formals
|
def yylex_formals
|
||||||
ary = ["&yylval", "&yylloc"]
|
ary = ["&yylval"]
|
||||||
|
ary << "&yylloc" if @grammar.locations
|
||||||
|
|
||||||
if @grammar.lex_param
|
if @grammar.lex_param
|
||||||
ary << lex_param_name
|
ary << lex_param_name
|
||||||
@ -397,17 +376,9 @@ module Lrama
|
|||||||
def int_array_to_string(ary)
|
def int_array_to_string(ary)
|
||||||
last = ary.count - 1
|
last = ary.count - 1
|
||||||
|
|
||||||
s = ary.each_with_index.each_slice(10).map do |slice|
|
ary.each_with_index.each_slice(10).map do |slice|
|
||||||
str = " "
|
" " + slice.map { |e, i| sprintf("%6d%s", e, (i == last) ? "" : ",") }.join
|
||||||
|
end.join("\n")
|
||||||
slice.each do |e, i|
|
|
||||||
str << sprintf("%6d%s", e, (i == last) ? "" : ",")
|
|
||||||
end
|
|
||||||
|
|
||||||
str
|
|
||||||
end
|
|
||||||
|
|
||||||
s.join("\n")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def spec_mapped_header_file
|
def spec_mapped_header_file
|
||||||
@ -457,26 +428,24 @@ module Lrama
|
|||||||
end
|
end
|
||||||
|
|
||||||
def template_dir
|
def template_dir
|
||||||
File.expand_path("../../../template", __FILE__)
|
File.expand_path('../../template', __dir__)
|
||||||
end
|
end
|
||||||
|
|
||||||
def string_array_to_string(ary)
|
def string_array_to_string(ary)
|
||||||
str = ""
|
result = ""
|
||||||
tmp = " "
|
tmp = " "
|
||||||
|
|
||||||
ary.each do |s|
|
ary.each do |s|
|
||||||
s = s.gsub('\\', '\\\\\\\\')
|
replaced = s.gsub('\\', '\\\\\\\\').gsub('"', '\\"')
|
||||||
s = s.gsub('"', '\\"')
|
if (tmp + replaced + " \"\",").length > 75
|
||||||
|
result = "#{result}#{tmp}\n"
|
||||||
if (tmp + s + " \"\",").length > 75
|
tmp = " \"#{replaced}\","
|
||||||
str << tmp << "\n"
|
|
||||||
tmp = " \"#{s}\","
|
|
||||||
else
|
else
|
||||||
tmp << " \"#{s}\","
|
tmp = "#{tmp} \"#{replaced}\","
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
str << tmp
|
result + tmp
|
||||||
end
|
end
|
||||||
|
|
||||||
def replace_special_variables(str, ofile)
|
def replace_special_variables(str, ofile)
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,2 +1,4 @@
|
|||||||
require 'lrama/report/duration'
|
# frozen_string_literal: true
|
||||||
require 'lrama/report/profile'
|
|
||||||
|
require_relative 'report/duration'
|
||||||
|
require_relative 'report/profile'
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Report
|
class Report
|
||||||
module Duration
|
module Duration
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class Report
|
class Report
|
||||||
module Profile
|
module Profile
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
require "lrama/state/reduce"
|
# frozen_string_literal: true
|
||||||
require "lrama/state/reduce_reduce_conflict"
|
|
||||||
require "lrama/state/resolved_conflict"
|
require_relative "state/reduce"
|
||||||
require "lrama/state/shift"
|
require_relative "state/reduce_reduce_conflict"
|
||||||
require "lrama/state/shift_reduce_conflict"
|
require_relative "state/resolved_conflict"
|
||||||
|
require_relative "state/shift"
|
||||||
|
require_relative "state/shift_reduce_conflict"
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class State
|
class State
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class State
|
class State
|
||||||
class Reduce
|
class Reduce
|
||||||
@ -25,6 +27,7 @@ module Lrama
|
|||||||
|
|
||||||
def selected_look_ahead
|
def selected_look_ahead
|
||||||
if @look_ahead
|
if @look_ahead
|
||||||
|
# @type ivar @look_ahead: Array<Grammar::Symbol>
|
||||||
@look_ahead - @not_selected_symbols
|
@look_ahead - @not_selected_symbols
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class State
|
class State
|
||||||
class ReduceReduceConflict < Struct.new(:symbols, :reduce1, :reduce2, keyword_init: true)
|
class ReduceReduceConflict < Struct.new(:symbols, :reduce1, :reduce2, keyword_init: true)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class State
|
class State
|
||||||
# * symbol: A symbol under discussion
|
# * symbol: A symbol under discussion
|
||||||
@ -6,7 +8,7 @@ module Lrama
|
|||||||
class ResolvedConflict < Struct.new(:symbol, :reduce, :which, :same_prec, keyword_init: true)
|
class ResolvedConflict < Struct.new(:symbol, :reduce, :which, :same_prec, keyword_init: true)
|
||||||
def report_message
|
def report_message
|
||||||
s = symbol.display_name
|
s = symbol.display_name
|
||||||
r = reduce.rule.precedence_sym.display_name
|
r = reduce.rule.precedence_sym&.display_name
|
||||||
case
|
case
|
||||||
when which == :shift && same_prec
|
when which == :shift && same_prec
|
||||||
msg = "resolved as #{which} (%right #{s})"
|
msg = "resolved as #{which} (%right #{s})"
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class State
|
class State
|
||||||
class Shift
|
class Shift
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class State
|
class State
|
||||||
class ShiftReduceConflict < Struct.new(:symbols, :shift, :reduce, keyword_init: true)
|
class ShiftReduceConflict < Struct.new(:symbols, :shift, :reduce, keyword_init: true)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "forwardable"
|
require "forwardable"
|
||||||
require "lrama/report/duration"
|
require_relative "report/duration"
|
||||||
require "lrama/states/item"
|
require_relative "states/item"
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
# States is passed to a template file
|
# States is passed to a template file
|
||||||
@ -16,9 +18,8 @@ module Lrama
|
|||||||
|
|
||||||
attr_reader :states, :reads_relation, :includes_relation, :lookback_relation
|
attr_reader :states, :reads_relation, :includes_relation, :lookback_relation
|
||||||
|
|
||||||
def initialize(grammar, warning, trace_state: false)
|
def initialize(grammar, trace_state: false)
|
||||||
@grammar = grammar
|
@grammar = grammar
|
||||||
@warning = warning
|
|
||||||
@trace_state = trace_state
|
@trace_state = trace_state
|
||||||
|
|
||||||
@states = []
|
@states = []
|
||||||
@ -89,8 +90,6 @@ module Lrama
|
|||||||
report_duration(:compute_conflicts) { compute_conflicts }
|
report_duration(:compute_conflicts) { compute_conflicts }
|
||||||
|
|
||||||
report_duration(:compute_default_reduction) { compute_default_reduction }
|
report_duration(:compute_default_reduction) { compute_default_reduction }
|
||||||
|
|
||||||
check_conflicts
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def reporter
|
def reporter
|
||||||
@ -125,16 +124,16 @@ module Lrama
|
|||||||
end
|
end
|
||||||
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
|
private
|
||||||
|
|
||||||
def sr_conflicts
|
|
||||||
@states.flat_map(&:sr_conflicts)
|
|
||||||
end
|
|
||||||
|
|
||||||
def rr_conflicts
|
|
||||||
@states.flat_map(&:rr_conflicts)
|
|
||||||
end
|
|
||||||
|
|
||||||
def trace_state
|
def trace_state
|
||||||
if @trace_state
|
if @trace_state
|
||||||
yield STDERR
|
yield STDERR
|
||||||
@ -350,7 +349,7 @@ module Lrama
|
|||||||
# TODO: need to omit if state == state2 ?
|
# TODO: need to omit if state == state2 ?
|
||||||
@includes_relation[key] ||= []
|
@includes_relation[key] ||= []
|
||||||
@includes_relation[key] << [state.id, nterm.token_id]
|
@includes_relation[key] << [state.id, nterm.token_id]
|
||||||
break if !sym.nullable
|
break unless sym.nullable
|
||||||
i -= 1
|
i -= 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -385,7 +384,7 @@ module Lrama
|
|||||||
@states.each do |state|
|
@states.each do |state|
|
||||||
rules.each do |rule|
|
rules.each do |rule|
|
||||||
ary = @lookback_relation[[state.id, rule.id]]
|
ary = @lookback_relation[[state.id, rule.id]]
|
||||||
next if !ary
|
next unless ary
|
||||||
|
|
||||||
ary.each do |state2_id, nterm_token_id|
|
ary.each do |state2_id, nterm_token_id|
|
||||||
# q = state, A -> ω = rule, p = state2, A = nterm
|
# q = state, A -> ω = rule, p = state2, A = nterm
|
||||||
@ -428,7 +427,7 @@ module Lrama
|
|||||||
sym = shift.next_sym
|
sym = shift.next_sym
|
||||||
|
|
||||||
next unless reduce.look_ahead
|
next unless reduce.look_ahead
|
||||||
next if !reduce.look_ahead.include?(sym)
|
next unless reduce.look_ahead.include?(sym)
|
||||||
|
|
||||||
# Shift/Reduce conflict
|
# Shift/Reduce conflict
|
||||||
shift_prec = sym.precedence
|
shift_prec = sym.precedence
|
||||||
@ -492,17 +491,17 @@ module Lrama
|
|||||||
states.each do |state|
|
states.each do |state|
|
||||||
count = state.reduces.count
|
count = state.reduces.count
|
||||||
|
|
||||||
for i in 0...count do
|
(0...count).each do |i|
|
||||||
reduce1 = state.reduces[i]
|
reduce1 = state.reduces[i]
|
||||||
next if reduce1.look_ahead.nil?
|
next if reduce1.look_ahead.nil?
|
||||||
|
|
||||||
for j in (i+1)...count do
|
((i+1)...count).each do |j|
|
||||||
reduce2 = state.reduces[j]
|
reduce2 = state.reduces[j]
|
||||||
next if reduce2.look_ahead.nil?
|
next if reduce2.look_ahead.nil?
|
||||||
|
|
||||||
intersection = reduce1.look_ahead & reduce2.look_ahead
|
intersection = reduce1.look_ahead & reduce2.look_ahead
|
||||||
|
|
||||||
if !intersection.empty?
|
unless intersection.empty?
|
||||||
state.conflicts << State::ReduceReduceConflict.new(symbols: intersection, reduce1: reduce1, reduce2: reduce2)
|
state.conflicts << State::ReduceReduceConflict.new(symbols: intersection, reduce1: reduce1, reduce2: reduce2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -514,7 +513,7 @@ module Lrama
|
|||||||
states.each do |state|
|
states.each do |state|
|
||||||
next if state.reduces.empty?
|
next if state.reduces.empty?
|
||||||
# Do not set, if conflict exist
|
# Do not set, if conflict exist
|
||||||
next if !state.conflicts.empty?
|
next unless state.conflicts.empty?
|
||||||
# Do not set, if shift with `error` exists.
|
# Do not set, if shift with `error` exists.
|
||||||
next if state.shifts.map(&:next_sym).include?(@grammar.error_symbol)
|
next if state.shifts.map(&:next_sym).include?(@grammar.error_symbol)
|
||||||
|
|
||||||
@ -525,32 +524,5 @@ module Lrama
|
|||||||
end.first
|
end.first
|
||||||
end
|
end
|
||||||
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")
|
|
||||||
end
|
|
||||||
|
|
||||||
if expected_rr_conflicts != rr_count
|
|
||||||
@warning.error("reduce/reduce conflicts: #{rr_count} found, #{expected_rr_conflicts} expected")
|
|
||||||
end
|
|
||||||
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
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# TODO: Validate position is not over rule rhs
|
# TODO: Validate position is not over rule rhs
|
||||||
|
|
||||||
require "forwardable"
|
require "forwardable"
|
||||||
@ -54,11 +56,11 @@ module Lrama
|
|||||||
Item.new(rule: rule, position: position + 1)
|
Item.new(rule: rule, position: position + 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
def symbols_before_dot
|
def symbols_before_dot # steep:ignore
|
||||||
rhs[0...position]
|
rhs[0...position]
|
||||||
end
|
end
|
||||||
|
|
||||||
def symbols_after_dot
|
def symbols_after_dot # steep:ignore
|
||||||
rhs[position..-1]
|
rhs[position..-1]
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -73,7 +75,7 @@ module Lrama
|
|||||||
|
|
||||||
# Right after position
|
# Right after position
|
||||||
def display_rest
|
def display_rest
|
||||||
r = rhs[position..-1].map(&:display_name).join(" ")
|
r = symbols_after_dot.map(&:display_name).join(" ")
|
||||||
". #{r} (rule #{rule_id})"
|
". #{r} (rule #{rule_id})"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
class StatesReporter
|
class StatesReporter
|
||||||
include Lrama::Report::Duration
|
include Lrama::Report::Duration
|
||||||
@ -14,15 +16,54 @@ module Lrama
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def _report(io, grammar: false, states: false, itemsets: false, lookaheads: false, solved: false, counterexamples: false, verbose: false)
|
def _report(io, grammar: false, rules: false, terms: false, states: false, itemsets: false, lookaheads: false, solved: false, counterexamples: false, verbose: false)
|
||||||
# TODO: Unused terms
|
report_unused_rules(io) if rules
|
||||||
# TODO: Unused rules
|
report_unused_terms(io) if terms
|
||||||
|
|
||||||
report_conflicts(io)
|
report_conflicts(io)
|
||||||
report_grammar(io) if grammar
|
report_grammar(io) if grammar
|
||||||
report_states(io, itemsets, lookaheads, solved, counterexamples, verbose)
|
report_states(io, itemsets, lookaheads, solved, counterexamples, verbose)
|
||||||
end
|
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)
|
def report_conflicts(io)
|
||||||
has_conflict = false
|
has_conflict = false
|
||||||
|
|
||||||
@ -37,7 +78,7 @@ module Lrama
|
|||||||
messages << "#{cs[:reduce_reduce].count} reduce/reduce"
|
messages << "#{cs[:reduce_reduce].count} reduce/reduce"
|
||||||
end
|
end
|
||||||
|
|
||||||
if !messages.empty?
|
unless messages.empty?
|
||||||
has_conflict = true
|
has_conflict = true
|
||||||
io << "State #{state.id} conflicts: #{messages.join(', ')}\n"
|
io << "State #{state.id} conflicts: #{messages.join(', ')}\n"
|
||||||
end
|
end
|
||||||
@ -98,7 +139,7 @@ module Lrama
|
|||||||
if lookaheads && item.end_of_rule?
|
if lookaheads && item.end_of_rule?
|
||||||
reduce = state.find_reduce_by_item!(item)
|
reduce = state.find_reduce_by_item!(item)
|
||||||
look_ahead = reduce.selected_look_ahead
|
look_ahead = reduce.selected_look_ahead
|
||||||
if !look_ahead.empty?
|
unless look_ahead.empty?
|
||||||
la = " [#{look_ahead.map(&:display_name).join(", ")}]"
|
la = " [#{look_ahead.map(&:display_name).join(", ")}]"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -118,7 +159,7 @@ module Lrama
|
|||||||
tmp.each do |term, state_id|
|
tmp.each do |term, state_id|
|
||||||
io << " #{term.display_name.ljust(max_len)} shift, and go to state #{state_id}\n"
|
io << " #{term.display_name.ljust(max_len)} shift, and go to state #{state_id}\n"
|
||||||
end
|
end
|
||||||
io << "\n" if !tmp.empty?
|
io << "\n" unless tmp.empty?
|
||||||
|
|
||||||
# Report error caused by %nonassoc
|
# Report error caused by %nonassoc
|
||||||
nl = false
|
nl = false
|
||||||
@ -132,7 +173,7 @@ module Lrama
|
|||||||
nl = true
|
nl = true
|
||||||
io << " #{name.ljust(max_len)} error (nonassociative)\n"
|
io << " #{name.ljust(max_len)} error (nonassociative)\n"
|
||||||
end
|
end
|
||||||
io << "\n" if !tmp.empty?
|
io << "\n" unless tmp.empty?
|
||||||
|
|
||||||
# Report reduces
|
# Report reduces
|
||||||
nl = false
|
nl = false
|
||||||
@ -181,14 +222,14 @@ module Lrama
|
|||||||
tmp.each do |nterm, state_id|
|
tmp.each do |nterm, state_id|
|
||||||
io << " #{nterm.id.s_value.ljust(max_len)} go to state #{state_id}\n"
|
io << " #{nterm.id.s_value.ljust(max_len)} go to state #{state_id}\n"
|
||||||
end
|
end
|
||||||
io << "\n" if !tmp.empty?
|
io << "\n" unless tmp.empty?
|
||||||
|
|
||||||
if solved
|
if solved
|
||||||
# Report conflict resolutions
|
# Report conflict resolutions
|
||||||
state.resolved_conflicts.each do |resolved|
|
state.resolved_conflicts.each do |resolved|
|
||||||
io << " #{resolved.report_message}\n"
|
io << " #{resolved.report_message}\n"
|
||||||
end
|
end
|
||||||
io << "\n" if !state.resolved_conflicts.empty?
|
io << "\n" unless state.resolved_conflicts.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
if counterexamples && state.has_conflicts?
|
if counterexamples && state.has_conflicts?
|
||||||
@ -219,7 +260,7 @@ module Lrama
|
|||||||
direct_read_sets = @states.direct_read_sets
|
direct_read_sets = @states.direct_read_sets
|
||||||
@states.nterms.each do |nterm|
|
@states.nterms.each do |nterm|
|
||||||
terms = direct_read_sets[[state.id, nterm.token_id]]
|
terms = direct_read_sets[[state.id, nterm.token_id]]
|
||||||
next if !terms
|
next unless terms
|
||||||
next if terms.empty?
|
next if terms.empty?
|
||||||
|
|
||||||
str = terms.map {|sym| sym.id.s_value }.join(", ")
|
str = terms.map {|sym| sym.id.s_value }.join(", ")
|
||||||
@ -231,7 +272,7 @@ module Lrama
|
|||||||
io << " [Reads Relation]\n"
|
io << " [Reads Relation]\n"
|
||||||
@states.nterms.each do |nterm|
|
@states.nterms.each do |nterm|
|
||||||
a = @states.reads_relation[[state.id, nterm.token_id]]
|
a = @states.reads_relation[[state.id, nterm.token_id]]
|
||||||
next if !a
|
next unless a
|
||||||
|
|
||||||
a.each do |state_id2, nterm_id2|
|
a.each do |state_id2, nterm_id2|
|
||||||
n = @states.nterms.find {|n| n.token_id == nterm_id2 }
|
n = @states.nterms.find {|n| n.token_id == nterm_id2 }
|
||||||
@ -245,7 +286,7 @@ module Lrama
|
|||||||
read_sets = @states.read_sets
|
read_sets = @states.read_sets
|
||||||
@states.nterms.each do |nterm|
|
@states.nterms.each do |nterm|
|
||||||
terms = read_sets[[state.id, nterm.token_id]]
|
terms = read_sets[[state.id, nterm.token_id]]
|
||||||
next if !terms
|
next unless terms
|
||||||
next if terms.empty?
|
next if terms.empty?
|
||||||
|
|
||||||
terms.each do |sym|
|
terms.each do |sym|
|
||||||
@ -258,7 +299,7 @@ module Lrama
|
|||||||
io << " [Includes Relation]\n"
|
io << " [Includes Relation]\n"
|
||||||
@states.nterms.each do |nterm|
|
@states.nterms.each do |nterm|
|
||||||
a = @states.includes_relation[[state.id, nterm.token_id]]
|
a = @states.includes_relation[[state.id, nterm.token_id]]
|
||||||
next if !a
|
next unless a
|
||||||
|
|
||||||
a.each do |state_id2, nterm_id2|
|
a.each do |state_id2, nterm_id2|
|
||||||
n = @states.nterms.find {|n| n.token_id == nterm_id2 }
|
n = @states.nterms.find {|n| n.token_id == nterm_id2 }
|
||||||
@ -271,11 +312,11 @@ module Lrama
|
|||||||
io << " [Lookback Relation]\n"
|
io << " [Lookback Relation]\n"
|
||||||
@states.rules.each do |rule|
|
@states.rules.each do |rule|
|
||||||
a = @states.lookback_relation[[state.id, rule.id]]
|
a = @states.lookback_relation[[state.id, rule.id]]
|
||||||
next if !a
|
next unless a
|
||||||
|
|
||||||
a.each do |state_id2, nterm_id2|
|
a.each do |state_id2, nterm_id2|
|
||||||
n = @states.nterms.find {|n| n.token_id == 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
|
||||||
end
|
end
|
||||||
io << "\n"
|
io << "\n"
|
||||||
@ -286,7 +327,7 @@ module Lrama
|
|||||||
@states.nterms.each do |nterm|
|
@states.nterms.each do |nterm|
|
||||||
terms = follow_sets[[state.id, nterm.token_id]]
|
terms = follow_sets[[state.id, nterm.token_id]]
|
||||||
|
|
||||||
next if !terms
|
next unless terms
|
||||||
|
|
||||||
terms.each do |sym|
|
terms.each do |sym|
|
||||||
io << " #{nterm.id.s_value} -> #{sym.id.s_value}\n"
|
io << " #{nterm.id.s_value} -> #{sym.id.s_value}\n"
|
||||||
@ -300,7 +341,7 @@ module Lrama
|
|||||||
max_len = 0
|
max_len = 0
|
||||||
@states.rules.each do |rule|
|
@states.rules.each do |rule|
|
||||||
syms = @states.la[[state.id, rule.id]]
|
syms = @states.la[[state.id, rule.id]]
|
||||||
next if !syms
|
next unless syms
|
||||||
|
|
||||||
tmp << [rule, syms]
|
tmp << [rule, syms]
|
||||||
max_len = ([max_len] + syms.map {|s| s.id.s_value.length }).max
|
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"
|
io << " #{sym.id.s_value.ljust(max_len)} reduce using rule #{rule.id} (#{rule.lhs.id.s_value})\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
io << "\n" if !tmp.empty?
|
io << "\n" unless tmp.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
# End of Report State
|
# End of Report State
|
||||||
|
30
tool/lrama/lib/lrama/trace_reporter.rb
Normal file
30
tool/lrama/lib/lrama/trace_reporter.rb
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Lrama
|
||||||
|
class TraceReporter
|
||||||
|
def initialize(grammar)
|
||||||
|
@grammar = grammar
|
||||||
|
end
|
||||||
|
|
||||||
|
def report(**options)
|
||||||
|
_report(**options)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def _report(rules: false, actions: false, **_)
|
||||||
|
report_rules if rules
|
||||||
|
report_actions if actions
|
||||||
|
end
|
||||||
|
|
||||||
|
def report_rules
|
||||||
|
puts "Grammar rules:"
|
||||||
|
@grammar.rules.each { |rule| puts rule.display_name }
|
||||||
|
end
|
||||||
|
|
||||||
|
def report_actions
|
||||||
|
puts "Grammar rules with actions:"
|
||||||
|
@grammar.rules.each { |rule| puts rule.with_actions }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Lrama
|
module Lrama
|
||||||
VERSION = "0.6.9".freeze
|
VERSION = "0.6.10".freeze
|
||||||
end
|
end
|
||||||
|
@ -1166,9 +1166,9 @@ yydestruct (const char *yymsg,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum yy_repair_type {
|
enum yy_repair_type {
|
||||||
insert,
|
inserting,
|
||||||
delete,
|
deleting,
|
||||||
shift,
|
shifting,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct yy_repair {
|
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 %>))
|
if (current->repair_length + 1 > YYMAXREPAIR(<%= output.parse_param_name %>))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
yy_repairs *new = (yy_repairs *) YYMALLOC (sizeof (yy_repairs));
|
yy_repairs *reps = (yy_repairs *) YYMALLOC (sizeof (yy_repairs));
|
||||||
new->id = count;
|
reps->id = count;
|
||||||
new->next = 0;
|
reps->next = 0;
|
||||||
new->stack_length = stack_length;
|
reps->stack_length = stack_length;
|
||||||
new->states = (yy_state_t *) YYMALLOC (sizeof (yy_state_t) * (stack_length));
|
reps->states = (yy_state_t *) YYMALLOC (sizeof (yy_state_t) * (stack_length));
|
||||||
new->state = new->states + (current->state - current->states);
|
reps->state = reps->states + (current->state - current->states);
|
||||||
YYCOPY (new->states, current->states, current->state - current->states + 1);
|
YYCOPY (reps->states, current->states, current->state - current->states + 1);
|
||||||
new->repair_length = current->repair_length + 1;
|
reps->repair_length = current->repair_length + 1;
|
||||||
new->prev_repair = current;
|
reps->prev_repair = current;
|
||||||
new->repair.type = insert;
|
reps->repair.type = inserting;
|
||||||
new->repair.term = (yysymbol_kind_t) yyx;
|
reps->repair.term = (yysymbol_kind_t) yyx;
|
||||||
|
|
||||||
/* Process PDA assuming next token is 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
tail->next = new;
|
tail->next = reps;
|
||||||
tail = new;
|
tail = reps;
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
if (yyx == yytoken)
|
if (yyx == yytoken)
|
||||||
@ -1437,7 +1437,7 @@ yyrecover(yy_state_t *yyss, yy_state_t *yyssp, int yychar<%= output.user_formals
|
|||||||
YYDPRINTF ((stderr,
|
YYDPRINTF ((stderr,
|
||||||
"New repairs is enqueued. count: %d, yystate: %d, yyx: %d\n",
|
"New repairs is enqueued. count: %d, yystate: %d, yyx: %d\n",
|
||||||
count, yystate, yyx));
|
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. */
|
/* The semantic value of the lookahead symbol. */
|
||||||
/* Default value used for initialization, for pacifying older GCCs
|
/* Default value used for initialization, for pacifying older GCCs
|
||||||
or non-GCC compilers. */
|
or non-GCC compilers. */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
static const YYSTYPE yyval_default = {};
|
||||||
|
(void) yyval_default;
|
||||||
|
#else
|
||||||
YY_INITIAL_VALUE (static const YYSTYPE yyval_default;)
|
YY_INITIAL_VALUE (static const YYSTYPE yyval_default;)
|
||||||
|
#endif
|
||||||
YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
|
YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
|
||||||
|
|
||||||
/* Location data for the lookahead symbol. */
|
/* Location data for the lookahead symbol. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user