diff --git a/Gemfile b/Gemfile
index b50b3b3be..f59ec2123 100644
--- a/Gemfile
+++ b/Gemfile
@@ -7,9 +7,10 @@ gemspec
gem "memory_profiler"
gem "pry"
gem "racc", "1.8.1"
-gem "railroad_diagrams", "0.3.0"
+gem "railroad_diagrams", ">= 1.0.0"
gem "rake"
gem "rdoc"
+gem "rexml", require: false
gem "rspec"
gem "simplecov", require: false
gem "stackprof", platforms: [:ruby] # stackprof doesn't support Windows
diff --git a/doc/Index.md b/doc/Index.md
index 22bf0fdc0..3b36ff052 100644
--- a/doc/Index.md
+++ b/doc/Index.md
@@ -47,6 +47,20 @@ Enter the formula:
=> 9
```
+### Syntax diagrams
+
+Install `railroad_diagrams` 1.0.0 or later to generate SVG diagrams with links to
+referenced rules and links back to referencing rules:
+
+```shell
+$ lrama --diagram=diagram.html -o calc.c sample/calc.y
+```
+
+Open `diagram.html` in a browser. Click a nonterminal symbol to visit its rule
+or follow the referencing-rule links to navigate back.
+
+Midrule action symbols are omitted from diagrams. User-defined empty rules remain visible.
+
## Supported Ruby version
Lrama is executed with BASERUBY when building ruby from source code. Therefore Lrama needs to support BASERUBY, currently 3.1, or later version.
diff --git a/lib/lrama/diagram.rb b/lib/lrama/diagram.rb
index 985808933..f2c518bda 100644
--- a/lib/lrama/diagram.rb
+++ b/lib/lrama/diagram.rb
@@ -29,7 +29,6 @@ def initialize(out:, grammar:, template_name: 'diagram/diagram.html')
# @rbs () -> void
def render
- RailroadDiagrams::TextDiagram.set_formatting(RailroadDiagrams::TextDiagram::PARTS_UNICODE)
@out << ERB.render(template_file, output: self)
end
@@ -38,21 +37,19 @@ def default_style
RailroadDiagrams::Style::default_style
end
- # @rbs () -> string
- def diagrams
- result = +''
- @grammar.unique_rule_s_values.each do |s_value|
- diagrams =
- @grammar.select_rules_by_s_value(s_value).map { |r| r.to_diagrams }
- add_diagram(
- s_value,
- RailroadDiagrams::Diagram.new(
- RailroadDiagrams::Choice.new(0, *diagrams),
- ),
- result
- )
+ # @rbs () -> Array[Hash[Symbol, (String | Array[String])]]
+ def linked_sections
+ document = RailroadDiagrams::Document.new(title: "Lrama syntax diagrams", theme: :default)
+ action_symbols = @grammar.rules.select(&:original_rule).map(&:lhs)
+ @grammar.rules.reject(&:original_rule).group_by { |rule| rule.lhs.id.s_value }.each do |name, rules|
+ alternatives = rules.map do |rule|
+ diagram_rule = rule.dup
+ diagram_rule.rhs = rule.rhs - action_symbols
+ diagram_rule.to_diagrams
+ end
+ document.add_rule(name, RailroadDiagrams::Choice.new(0, *alternatives))
end
- result
+ document.rule_sections
end
private
@@ -67,11 +64,5 @@ def template_file
File.join(template_dir, @template_name)
end
- # @rbs (String name, RailroadDiagrams::Diagram diagram, String result) -> void
- def add_diagram(name, diagram, result)
- result << "\n
"
- diagram.write_svg(result.method(:<<))
- result << "\n"
- end
end
end
diff --git a/sample/diagram.html b/sample/diagram.html
index 0eac74493..e50f1716e 100644
--- a/sample/diagram.html
+++ b/sample/diagram.html
@@ -1,8 +1,9 @@
-
+
+