Skip to content

fix(parser): preserve the original text of COND equations - #12

Open
ThVerg wants to merge 1 commit into
FPGA-Research:masterfrom
ThVerg:fix/cond-equation-text
Open

fix(parser): preserve the original text of COND equations#12
ThVerg wants to merge 1 commit into
FPGA-Research:masterfrom
ThVerg:fix/cond-equation-text

Conversation

@ThVerg

@ThVerg ThVerg commented Aug 13, 2026

Copy link
Copy Markdown

Conditional expressions are rewritten into something no other tool accepts

Condition text is currently passed through Python's float(), and Verilog scalar constants
are split in half by the lexer:

condition in the source before after this PR
B==1'b0 B == 1.0 'b0 B == 1'b0
TE == 0 TE == 0.0 TE == 0
A == -1 A == -1.0 A == -1
A==+2 A == + 2.0 A == +2
B==1'b0&&C==1'b1 B == 1.0 'b0 && C == 1.0 'b1 B == 1'b0 && C == 1'b1
A==1.5 A == 1.5 A == 1.5 (unchanged)
~EN ~ EN ~ EN (unchanged)

Cause

Two independent mechanisms.

Scalar constants split. FLOAT and SCALARCONSTANT overlap: the constant's leading
digit is optional ([01]?), so for 1'b0 the lexer matches FLOAT on the 1 first and
SCALARCONSTANT on the remaining 'b0. equation() then rejoins the pieces with a space.

Numbers lose their text. equation shares the FLOAT terminal with delay values, and
the transformer's FLOAT() callback converts every FLOAT token to a Python float —
correct for a delay, destructive for condition text, where 0 and 0.0 are different
tokens to a Verilog consumer.

Fix

Grammar only; no Python changes.

-equation: (operator | STRING | FLOAT | SCALARCONSTANT)+
+equation: (operator | STRING | EQNUMBER | SCALARCONSTANT)+

-SCALARCONSTANT: /[01]?'[bB][01]/
+SCALARCONSTANT.3: /[01]?'[bB][01]/
+// Numbers inside a condition keep their original text (see equation)
+EQNUMBER.2: /[-+]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/

Conditions get their own number terminal, so equation never touches FLOAT and no
conversion callback fires. This works because LALR mode uses a contextual lexer: EQNUMBER
is only reachable inside equation, so delay positions still lex as FLOAT exactly as
before.

Three details that matter if this is edited later:

  • SCALARCONSTANT must outrank EQNUMBER (.3 vs .2). Reversed, the number terminal
    takes the leading 1 and 1'b0 splits again.
  • EQNUMBER must cover decimals, or A==1.5 splits into 1 and .5.
  • EQNUMBER needs [-+]?, or A == -1 fails to parse — FLOAT's -? had been carrying
    that case. This also makes +2 work, which FLOAT never allowed.

Golden files

Two goldens are regenerated. The diff is the corruption being undone:

-  (COND (B == 1.0 'b0 && C == 1.0 'b0 && D == 1.0 'b0)
+  (COND (B == 1'b0 && C == 1'b0 && D == 1'b0)
-  (COND (TE == 0.0 && RB == 1.0 && SB == 1.0)
+  (COND (TE == 0 && RB == 1 && SB == 1)

8 lines in golden/fixpoint.sdf, 8 in golden/spec-example2.sdf. No other golden changes.

Verification

  • 346 passed after regenerating the two goldens.
  • The unsized form A=='b1 was already correct and is unchanged.
  • No file changes accept/reject status: this fixes the text a condition round-trips to,
    not what parses.

Conditional expressions were rewritten on parse and written back in a form no
other tool accepts. Two independent mechanisms were responsible.

FLOAT and SCALARCONSTANT overlap: the constant's leading digit is optional, so
for 1'b0 the lexer matched FLOAT on the 1 and SCALARCONSTANT on the remaining
'b0, and equation() rejoined the pieces with a space, giving B == 1.0 'b0.

Separately, equation shared the FLOAT terminal with delay values, and the
FLOAT() callback converts every such token to a Python float. That is correct
for a delay and destructive for condition text, where 0 and 0.0 are different
tokens, so TE == 0 became TE == 0.0 with no scalar constant involved.

Conditions now use their own EQNUMBER terminal, so equation never touches FLOAT
and no conversion callback fires. LALR mode uses a contextual lexer, so delay
positions still lex as FLOAT. SCALARCONSTANT must outrank EQNUMBER or 1'b0
splits again; EQNUMBER covers decimals so 1.5 does not split, and carries an
optional sign because FLOAT's -? had been handling negative literals.

golden/fixpoint.sdf and golden/spec-example2.sdf are regenerated; the diff is
the corruption being undone.
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