Skip to content

fix(parser): accept single-value rvalues and C-style block comments - #11

Open
ThVerg wants to merge 1 commit into
FPGA-Research:masterfrom
ThVerg:fix/rvalue-and-comments
Open

fix(parser): accept single-value rvalues and C-style block comments#11
ThVerg wants to merge 1 commit into
FPGA-Research:masterfrom
ThVerg:fix/rvalue-and-comments

Conversation

@ThVerg

@ThVerg ThVerg commented Aug 13, 2026

Copy link
Copy Markdown

Single-value rvalue is unparseable, rejecting most real-world SDF

parse_sdf('(DELAYFILE (SDFVERSION "3.0") (CELL (CELLTYPE "C") (INSTANCE u1) (DELAY (ABSOLUTE (IOPATH a y (5))))))')
LarkError: SDF parsing failed at 1:97 - Unexpected token Token('RPAR', ')') at line 1, column 97.
Expected one of:
	* COLON
Previous tokens: [Token('FLOAT', '5')]

Replacing (5) with (5:5:5) parses fine, confirming the rvalue rule is the cause.

IEEE 1497 defines rvalue ::= "(" [signed_real_number] ")" | "(" [rtriple] ")", so a
parenthesised single number is legal everywhere a delay or check value appears. The
grammar currently admits only an empty () or a full two-colon triple, so any file using
the scalar form fails to parse outright.

rvalue is the shared value rule for every delay and every timing check (IOPATH,
INTERCONNECT, PORT, DEVICE via delval_list, plus SETUP, HOLD, SETUPHOLD,
RECOVERY, REMOVAL, WIDTH, PERIOD, PATHCONSTRAINT), so the single missing
alternative rejects the whole file with no partial recovery.

Changes

1. sdf.lark — the missing rvalue alternative

 rvalue: FLOAT
       | "(" [real_triple] ")"
+      | "(" FLOAT ")"

Added at the rvalue level rather than as an alternative to real_triple. The latter
looks more natural but does not build — the parser is LALR, and
real_triple: ... | FLOAT gives:

GrammarError: Reduce/Reduce collision in Terminal('RPAR') between the following rules:
  - <real_triple : FLOAT>
  - <rvalue : FLOAT>

The existing bare-FLOAT alternative is kept: it is what makes the unparenthesised header
forms (VOLTAGE 1.8) / (TEMPERATURE 25) parse.

2. transformers.py — a single number applies to all three corners

-                return Values(min=None, avg=arg, max=None)
+                return Values(min=arg, avg=arg, max=arg)

The grammar change alone is not sufficient. Without this, (5) parses but stores
min=None, avg=5.0, max=None, so get_scalar("nominal", "max") returns None — delays
disappear from critical-path, stats and slack — and a round-trip rewrites (5) as
(:5:), which tells downstream tools the min and max are unknown.

3. sdf.lark — C-style block comments

Same class of problem, separate cause. Only // line comments were ignored, so a file
carrying a /* ... */ banner — a normal thing for an EDA tool to emit — fails to parse at
the very first character:

/* Generated by SomeTool v3.2 */
(DELAYFILE
  (SDFVERSION "3.0")
  ...
LarkError: Unexpected token Token('SLASH', '/') at line 1, column 1
 COMMENT: /\/\/[^\n]*/
 %ignore COMMENT
+BLOCK_COMMENT: /\/\*[\s\S]*?\*\//
+%ignore BLOCK_COMMENT

The terminal matches /*, then any characters, then */; %ignore discards those tokens
before the grammar sees them, mirroring the existing COMMENT / %ignore COMMENT pair
directly above.

Two details in the pattern:

  • [\s\S] rather than ., because . does not match a newline and block comments are
    usually multi-line.
  • non-greedy *? rather than *, because a greedy match would run from the first /* to
    the last */ in the file and swallow all the SDF in between.

IEEE 1497 defines rvalue as "(" [signed_real_number] ")" | "(" [rtriple] ")",
but the grammar admitted only an empty () or a full two-colon triple, so any
SDF file using the scalar form failed to parse outright. rvalue is the shared
value rule for every delay and timing check, so the missing alternative
rejected the whole file.

The alternative is added at the rvalue level rather than to real_triple; the
latter does not build under LALR (reduce/reduce collision on RPAR between
real_triple: FLOAT and rvalue: FLOAT).

A lone number also applies to all three of min:typ:max, not to typ alone, so
rvalue() now fills every field. Without this, (5) parsed but reported no min
or max, dropping the delay from critical-path and stats and round-tripping as
(:5:).

Separately, only // line comments were ignored, so a file carrying a /* */
banner failed at its first character. BLOCK_COMMENT matches a multi-line,
non-greedy /* ... */ and is ignored alongside COMMENT.
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.

1 participant