Skip to content

odb: add LEFDEF grammar railroad diagram documentation#9866

Merged
maliberty merged 15 commits into
The-OpenROAD-Project:masterfrom
sparsh-karna:odb/grammar-railroad-diagrams
Mar 30, 2026
Merged

odb: add LEFDEF grammar railroad diagram documentation#9866
maliberty merged 15 commits into
The-OpenROAD-Project:masterfrom
sparsh-karna:odb/grammar-railroad-diagrams

Conversation

@sparsh-karna

Copy link
Copy Markdown
Contributor

Summary

Closes #2488.

Adds auto-generated SVG railroad diagrams for all LEF and DEF grammar rules
in OpenROAD's ODB parser, alongside Markdown documentation pages that embed
them. Railroad diagrams visually show every valid syntax path through the
LEF/DEF grammars, making them significantly easier to read than raw Bison
grammar files.

This is a documentation-only change. No production source code is modified.

What's Included

  • src/odb/doc/generate_railroad_diagrams.py: Python script that
    converts lef.y / def.y (Bison grammars) → W3C EBNF → SVG railroad
    diagrams via two vendored Java tools.
  • src/odb/doc/tools/ebnf-convert.war: Vendored
    Gunther Rademacher's ebnf-convert
    tool (Bison → EBNF conversion). Vendored directly to avoid requiring
    contributors to build or download it separately.
  • src/odb/doc/tools/rr.war: Vendored
    Railroad Diagram Generator rr lib
    (de.bottlecaps.rr:rr-lib:2.6 from Maven Central). Vendored for the
    same reason.
  • src/odb/doc/images/lef/*.svg: 246 SVG railroad diagrams covering
    every LEF grammar rule.
  • src/odb/doc/images/def/*.svg: 276 SVG railroad diagrams covering
    every DEF grammar rule.
  • src/odb/doc/LEFGrammar.md: Markdown doc embedding all LEF diagrams,
    grouped by category.
  • src/odb/doc/DEFGrammar.md: Markdown doc embedding all DEF diagrams,
    grouped by category.
  • .github/workflows/github-actions-update-grammar-railroad-diagrams.yml:
    CI workflow that auto-regenerates diagrams and opens a PR whenever
    lef.y or def.y changes on master.
  • docs/toc.yml: Adds LEFGrammar and DEFGrammar entries to the
    OpenROAD documentation navigation.
  • src/odb/doc/.gitignore: Ignores intermediate .ebnf and .zip
    artifacts produced during generation.

How to Regenerate Diagrams

Requires Java 11+ on PATH.

# Both grammars
python3 src/odb/doc/generate_railroad_diagrams.py all

# LEF only
python3 src/odb/doc/generate_railroad_diagrams.py lef

# DEF only
python3 src/odb/doc/generate_railroad_diagrams.py def

Example Diagram:

class_type

@sparsh-karna sparsh-karna force-pushed the odb/grammar-railroad-diagrams branch from 54ed0c5 to aeac43c Compare March 21, 2026 10:20

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces auto-generated SVG railroad diagrams for LEF and DEF grammar rules in OpenROAD's ODB parser, along with Markdown documentation pages embedding these diagrams. The changes are documentation-only, with no modifications to production source code. The pull request includes a Python script for diagram generation, vendored Java tools, SVG diagrams for LEF and DEF grammars, Markdown documentation, and a CI workflow for automatic regeneration. No specific style guides were provided, so the review focuses on general code quality and best practices.

Comment thread src/odb/doc/generate_railroad_diagrams.py Outdated
Comment thread src/odb/doc/generate_railroad_diagrams.py
Comment thread src/odb/doc/LEF_Grammar.md
Comment thread src/odb/doc/DEF_Grammar.md
@sparsh-karna sparsh-karna force-pushed the odb/grammar-railroad-diagrams branch from aeac43c to 20aaaf4 Compare March 21, 2026 10:44
Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
Add SVG railroad diagrams generated directly from lef.y and def.y,
a Python script to regenerate them, Markdown documentation that
embeds the diagrams, and a GitHub Actions workflow that opens a PR
whenever a grammar file changes.

Files added:
- src/odb/doc/generate_railroad_diagrams.py  — converts .y → EBNF →
  individual SVG files using ebnf-convert and rr (downloaded from
  Maven Central on first use; not committed).
- src/odb/doc/images/lef/  — 246 SVGs generated from lef.y
- src/odb/doc/images/def/  — 276 SVGs generated from def.y
- src/odb/doc/LEF_Grammar.md  — documentation with embedded diagrams
- src/odb/doc/DEF_Grammar.md  — documentation with embedded diagrams
- src/odb/doc/.gitignore  — excludes tools/ and intermediate files
- .github/workflows/github-actions-update-grammar-railroad-diagrams.yml
  — auto-regenerates and opens a PR on grammar changes

Resolves The-OpenROAD-Project#2488

Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
Place ebnf-convert.war (v0.73) and rr.war (v2.6) in src/odb/doc/tools/
so the script works offline without a Maven Central fetch.

Update ensure_tools() to fail with actionable instructions rather than
silently downloading, and remove tools/ from .gitignore now that the
files are committed.

Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
LEF_Grammar.md now covers 243 rules across 18 sections:
File structure, Units, Layers, Vias, Via Rules, Spacing, Sites,
Macros, Macro Pins, Non-default Rules, Properties, IRDrop,
Noise & Correction Tables, Timing, Arrays (Floorplan),
Antenna Rules, Dielectric & Minfeature, Primitives.

DEF_Grammar.md now covers 274 rules across 28 sections:
File structure, Design Attributes, Properties, Components,
Nets, Net Routing, Net Subnets, Special Nets, Pins, Virtual Pins,
Pin Properties, Blockages, Regions, Groups, Via Definitions,
Non-default Rules, Fills, Slots, Styles, IO Timing, Scan Chains,
Timing Disables, Partitions, Constraints, Assertions,
Floorplan Constraints, Extension, Primitives.

Each section has a linked TOC at the top of the page.

Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
Inject a CSS custom property and inline style into each generated SVG
so the diagrams render with a solid warm-white background (#FFFCF0)
instead of being transparent.  This keeps them legible in both light
and dark documentation themes.

Also clean up generate_railroad_diagrams.py: remove dead Maven Central
download code (WARs are now vendored), update the module docstring, and
wire in the new fix_svg_background() helper that is called after each
SVG is extracted from the rr output ZIP.

Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
@sparsh-karna sparsh-karna force-pushed the odb/grammar-railroad-diagrams branch from 20aaaf4 to e73ad78 Compare March 21, 2026 10:47
@sparsh-karna

sparsh-karna commented Mar 21, 2026

Copy link
Copy Markdown
Contributor Author

@maliberty both CI failures are unrelated to the C++ changes.

clang-tidy: the clang-tidy-review action uses the GitHub API to fetch changed files, which hard-caps at 300. this PR has ~500 new SVGs so it hits a 406 before it even looks at any C++ code. no actual tidy warnings.

scan-code: flagging src/odb/doc/tools/ebnf-convert.war as a binary with blocked content. the WAR itself is a standard open-source Java tool (GuntherRademacher/ebnf-convert)

the routing code itself is clean.

@luarss luarss left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice first cut. Just some feedback to make it more future-proof

Comment thread .github/workflows/github-actions-update-grammar-railroad-diagrams.yml Outdated
Comment thread .github/workflows/github-actions-update-grammar-railroad-diagrams.yml Outdated
Comment thread src/odb/doc/tools/ebnf-convert.war Outdated
Comment thread src/odb/doc/generate_railroad_diagrams.py Outdated
Comment thread src/odb/doc/generate_railroad_diagrams.py
- Use **/*.y glob in CI workflow trigger instead of hardcoded lef.y/def.y
  paths so any future grammar additions are covered automatically
- Refactor argument parsing in generate_railroad_diagrams.py to use
  argparse instead of manual sys.argv handling

Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
@sparsh-karna sparsh-karna requested a review from luarss March 21, 2026 13:52
@sparsh-karna

Copy link
Copy Markdown
Contributor Author

hey @luarss could you check the changes that i made

Comment thread src/odb/doc/generate_railroad_diagrams.py Outdated
Comment thread src/odb/doc/generate_railroad_diagrams.py Outdated
Comment thread src/odb/doc/generate_railroad_diagrams.py Outdated
Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
@sparsh-karna

Copy link
Copy Markdown
Contributor Author

hey @luarss, i have updated the ci for this could you check and give feedback

@sparsh-karna sparsh-karna requested a review from luarss March 21, 2026 19:38
- name: Regenerate railroad diagram SVGs
run: python3 src/odb/doc/generate_railroad_diagrams.py

- name: Open PR if diagrams changed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens in the case of successive updates? Is there a flag in this action that you can use for pruning old branches/rebasing?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

peter-evans/create-pull-request@v7 uses a fixed branch name (auto/grammar-railroad-diagrams), so on successive runs it force-pushes to that same branch and updates the existing open PR instead of creating a new one. delete-branch: true is set so the branch is automatically pruned after merge. I also verified that update-branch is not a valid input in v7's action.yml, the fixed-branch behavior handles successive updates natively.

id: cache-tools
with:
path: src/odb/doc/tools
key: railroad-tools-ebnf-v0.73-rr-2.6

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible that this cache might cache invalid tools? Can you validate the cache before using/storing it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a Validate cached railroad tools step that runs after cache restore. It checks both WARs are non-empty and uses jar tf to verify internal contents, WEB-INF/lib/Saxon-HE-12.9.jar in ebnf-convert and de/bottlecaps/railroad/Railroad.class in rr.war. If either fails, the files are deleted and the build step is forced to run regardless of cache hit status.

"""Inject a solid background colour into an SVG file."""
content = svg_path.read_text(encoding="utf-8")
style_block = "<style>\n" f" :root {{ --diagram-bg: {DIAGRAM_BG}; }}\n" "</style>"
content = re.sub(r"(<svg[^>]*>)", r"\1" + style_block, content, count=1)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems fragile. Is there a python library we can use, maybe xmltree?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced the regex approach with xml.etree.ElementTree. The implementation pre-registers all namespace prefixes via ET.iterparse (so xlink is preserved), inserts <style> as the first child of , and writes back with xml_declaration=True. This is in the next commit, being pushed shortly.

classpath = sep.join([str(RR_WAR)] + dep_jars)
subprocess.run(
[
"java",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add java shutil checks in ensure_tools()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in the next commit, ensure_tools() now calls shutil.which("java") and additionally checks the version is ≥ 11, reporting a clear error message if Java is missing or too old.

Comment on lines +49 to +50
- name: Open PR if diagrams changed
uses: peter-evans/create-pull-request@v7

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not add a commit to the current PR rather than make a new one?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow triggers on pushes to master after a grammar PR is already merged, so there is no open PR to commit back to at that point. Opening a dedicated PR for the SVG updates keeps diagram regeneration separate from grammar changes and gives maintainers a focused diff to review.

- name: Regenerate railroad diagram SVGs
run: python3 src/odb/doc/generate_railroad_diagrams.py

- name: Open PR if diagrams changed

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What makes this conditional on changes? Is that somehow within peter-evans/create-pull-request?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added an explicit Detect diagram changes step that runs git diff --quiet -- src/odb/doc/images/ and sets a changed output. The Open PR step is gated with if: steps.diagram-changes.outputs.changed == 'true', so no PR is opened if the diagrams are unchanged. This is explicit rather than relying on action internals.

Comment thread src/odb/doc/generate_railroad_diagrams.py Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a unfortunate that this has no semantic information (i.e., number, string, string). Is there a way to add annotations?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diagram reflects the grammar tokens as defined in def.y. The terminal names (NUMBER, STRING) come directly from the bison grammar, rr.war has no mechanism to inject external annotations into an already-generated SVG. To add semantic labels, the grammar itself would need named sub-rules (e.g., halo_dist, layer_name). That would be a change to def.y which is out of scope for this PR, but could be a follow-up. Happy to open an issue for it.

… check

Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
valid=true
if [[ ! -s "$ebnf_war" ]] || [[ ! -s "$rr_war" ]]; then
valid=false
elif ! jar tf "$ebnf_war" | grep -q "WEB-INF/lib/Saxon-HE-12.9.jar"; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is named a war but the file extension is really a jar?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ebnf-convert.war is a proper WAR, the .jar in the grep is Saxon-HE-12.9.jar, a dependency bundled inside WEB-INF/lib/ per standard WAR layout. rr.war is actually rr-lib-2.6.jar from Maven Central renamed to .war (verified by MD5), so it has no WEB-INF structure, its check looks for a class at the root level instead.

- name: Detect diagram changes
id: diagram-changes
run: |
if git diff --quiet -- src/odb/doc/images/; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this catch untracked files?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git diff misses untracked files (new SVGs being generated for the first time). Switching to git status --porcelain src/odb/doc/images/ which reports both modified and untracked files in one check.

Signed-off-by: Sparsh Karna <78959094+sparsh-karna@users.noreply.github.com>
@sparsh-karna sparsh-karna requested a review from luarss March 23, 2026 09:57
@sparsh-karna sparsh-karna marked this pull request as ready for review March 23, 2026 19:17
@sparsh-karna

Copy link
Copy Markdown
Contributor Author

@maliberty @luarss I’ve updated the PR based on your suggestions. Let me know if anything still needs work, happy to iterate further if needed.


echo "valid=$valid" >> "$GITHUB_OUTPUT"

- name: Build ebnf-convert and fetch rr.war

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really have to build from source on every PR?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the Gradle build is gated behind if: steps.cache-tools.outputs.cache-hit != 'true' || steps.validate-tools.outputs.valid != 'true'. The cache key railroad-tools-ebnf-v0.73-rr-2.6 is pinned to exact tool versions, so normal PRs skip the build entirely and just restore from cache.

@sparsh-karna sparsh-karna requested a review from maliberty March 25, 2026 10:23
@maliberty

Copy link
Copy Markdown
Member

@luarss are your concerns satisfied?

@sparsh-karna

Copy link
Copy Markdown
Contributor Author

Hey @maliberty @luarss, I am sorry I wasn't available over the weekend. Is there any feedback or changes I have to do? I am happy to mend it according to your instructions.

@luarss luarss left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@maliberty maliberty merged commit 08138fb into The-OpenROAD-Project:master Mar 30, 2026
14 of 15 checks passed
@sparsh-karna sparsh-karna deleted the odb/grammar-railroad-diagrams branch March 30, 2026 22:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Grammar railroad diagram

3 participants