Formality 语法解析报错:括号分号、关键字冲突与方言开关速查
更新时间:2026-10-23。FAQ 速查页,属于 EDA 工具排错系列。Formality(fm_shell)读入参考设计与实现设计时,
read_verilog/read_vhdl/read_sverilog各自带一套词法语法前端,报 syntax error 的方式出奇一致:行号指向一个 token,而真正的错往往在它前面——上面某个括号没闭合、某个宏没定义、某个文件根本不是你以为的方言。特征是报错行本身看着完全正常,往下改那一行永远是徒劳。同系列对照见 Formality 编码乱码报错;如果报错是「符号/模块对不上」而非语法层面,转 Formality 未定义符号 或 Formality 模块未找到。
本文要回答的问题
read_verilog报 syntax error,指向的行是一条普通的 assign?- RTL 里明明有 SystemVerilog 的
logic/always_ff,Formality 却把它当错误? - VHDL 用了 2008 的特性,fm_shell 一解析就拒收?
source run_fm.tcl报 extra characters after close-brace,脚本看着没问题?- 报错行号和编辑器里看到的行号对不上,差了几行甚至几十行?
一、报错原文与现象
Error: ./rtl/ctrl_ref.v:137: syntax error at or near token 'assign' (VER-936)
Error: ./rtl/dsp.sv:58: syntax error at or near 'always_ff' (VER-936)
Error: ./rtl/top.vhd:22: syntax error near 'process(all)' (VHDL-2283)
Error: extra characters after close-brace while executing (run_fm.tcl line 45)
Warning: Ignoring undefined macro 'SIM_DEBUG' (VER-941)
Error: ./rtl/top.v:3: unknown compiler directive '`protect' (VER-955)第一条报错的第 137 行通常只是一条无辜的 assign out = a & b;——真正的缺括号在上方某个 module 端口列表里,解析器一路吞到 137 行才「咽不下去」。第二条是方言乌龙:文件里是 SystemVerilog,却用 read_verilog 读,always_ff 对 Verilog-2005 前端来说就是非法 token。第五条宏未定义更要命:undefined macro 只是 Warning,但缺了宏展开的代码片段会让后面的语法树整个错位,报出一连串指向无关行的 syntax error。解析报错的第一戒律:从报错行往上找,而不是盯着报错行改。
还有一个高迷惑性现象:同一份 RTL 在仿真器(VCS/Xcelium)里编译完全通过,Formality 却报语法错。这不奇怪——仿真器默认开了 SystemVerilog 宽松方言和各种扩展,Formality 的 read_verilog 是严格 Verilog-2005 前端,SV 特性必须显式走 read_sverilog 或加 -sverilog;VHDL 同理,2008 特性要靠 set hdlin_vhdl_2008 true 先开开关再 read_vhdl。两边前端不同,「仿真能过」从来不是「FM 能读」的证据。
二、可能原因总览
| 现象特征 | 可能原因 | 处置 |
|---|---|---|
| syntax error 指向普通 assign/always,报错行无错 | 上方括号/端口列表未闭合 | 从报错行往上找第一个 module,逐层配对 |
| 报文含 always_ff/logic/interface 等 SV 关键字 | 用 read_verilog 读了 SV 文件 | 改 read_sverilog 或加 -sverilog |
| 报文含 process(all)、generic map 新写法 | VHDL-2008 特性未开开关 | set hdlin_vhdl_2008 true 后再 read_vhdl |
| source 脚本报 close-brace / close-quote | Tcl 花括号/双引号没配对 | 定位脚本行号,检查字符串内嵌套括号 |
| 先报 undefined macro 然后一串 syntax error | 宏未定义导致代码片段塌陷 | 用 -define 或 `define 补齐宏再读 |
unknown compiler directive protect/pragma | 加密 IP 的编译指令不识别 | 用 Synopsys 加密流程或删掉非标准指令 |
| syntax error 指向含中文注释的段落 | 隐藏字节吃掉注释边界 | 按编码篇流程验字节,见下方内链 |
| 报错行号比编辑器行号小几行 | include 展开/`line 指令导致偏移 | 按展开后视图定位,别按物理行号 |
三、排查决策图
解析类报错的排查顺序有一条铁律:先定方言、再查宏与指令、最后才怀疑配对——方言和宏这两类「环境性」根因占解析报错的大头,且排查成本最低,先把它们排除掉,剩下的真括号问题才值得逐层配对。下面这张图把主线串起来:红色是入口现象与命中的根因,蓝色是排查动作,绿色是方言/环境确认通过,橙色是修复动作,紫色是收尾防复发。
读这张图抓住一条主线:三个蓝色判别节点按「方言 → 宏 → 字节」的顺序过滤,任何一个命中就直接跳对应橙色修复,不用走完;只有三个都排除后才进入最费工的括号逐层配对。绿色「重读验证通过」是所有支线的汇合点——任何修复后必须立刻 read 一遍验证,而不是攒着改多处一起验,否则报错行号一变就失去定位锚点。
四、逐条排查展开
先认方言:SV 走 SV 的门,VHDL-2008 开 2008 的开关。 报错 token 是 always_ff、logic、interface、typedef enum 这类 SystemVerilog 关键字时,根因几乎必然是读入命令用错:
# 错误:SV 文件用 Verilog-2005 前端读
read_verilog ./rtl/dsp.sv
# 正确:显式走 SV 前端
read_sverilog ./rtl/dsp.sv
# 或保持 read_verilog 但加方言开关
read_verilog -sverilog ./rtl/dsp.svfilelist 混编时按扩展名分流:*.v 走 read_verilog、*.sv 走 read_sverilog,别图省事一把 read_verilog 全读。VHDL 侧对应的坑是 process(all)、context 引用等 2008 特性,需要先 set hdlin_vhdl_2008 true 再 read_vhdl;团队里常见的翻车场景是仿真工程默认开 2008、FM 脚本忘了同步开关。
宏未定义:一个 Warning 引发的一串 Error。 报错序列里只要先有 Ignoring undefined macro,后面的 syntax error 就全是次生灾害:
# 读入时把仿真侧依赖的宏补齐
read_sverilog -define {SIM_DEBUG SYNTHESIS} ./rtl/top.sv判别技巧:把报错序列里第一个 Error 找出来,它之前的最后一个 Warning 是 undefined macro 的话,优先补宏而不是改语法。宏的值不一致也会导致两版设计读出来的代码不同、后续 compare 莫名 mismatch——补宏时顺手核对仿真侧的宏清单。
Tcl 脚本配对:close-brace 报错的行号可信。 与 RTL 不同,Tcl 的 extra characters after close-brace 行号基本准确。高频根因有两个:一是字符串里嵌套的花括号没配对(if { $a == {x} } { 这类手写时漏一个);二是双引号里写了 $ 变量但变量未定义、展开后留下残缺 token。用编辑器的括号匹配功能跳到脚本报错行,逐段选中看配对,三十秒能定位。注释里含未配对引号也会咬掉后面的行——Tcl 的注释不是纯粹的文本忽略,引号配对在词法阶段就生效。
compiler directive 与加密 IP:不认识的反引号指令。 `protect / `pragma 这类指令是 Synopsys 加密流程或特定厂商 IP 的标志,FM 前端遇到不认识的 directive 会报 VER-955。处置方向两个:加密 IP 走 Synopsys 认可的加密格式交付;非标准指令(仿真器私有 pragma)在交付 FM 的版本里删掉或用 ifdef 包起来。
隐藏字符:报错指向注释段时立刻换赛道。 如果报错行附近有大段中文注释,或者文件刚从 Windows 编辑器另存过,按本篇流程继续改代码是浪费——先按 Formality 编码乱码报错 的 od -c / file 三件套验字节,GBK 尾字节吃掉注释边界、BOM 咬第一行,表现都是「无辜行 syntax error」。
行号偏移:include 展开的视图差。 文件里用 `include 包含头文件时,报错行号是展开后视图的行号,和编辑器里的物理行号差几行到几十行。定位方法:从头往下数 include 展开引入的行数,修正偏移后再看;或者干脆把头文件内联后再读一遍,让行号回归物理视图。若展开后有未解析引用(模块、package 名对不上),那是读入成功之后的符号问题,转 Formality 未解析引用。
五、预防与纪律
- 读入命令按扩展名分流:
*.v/*.sv/*.vhd各走各的前端,filelist 生成脚本里写死,不靠人肉记。 - VHDL 开关与仿真工程同步:
hdlin_vhdl_2008写进 FM 模板脚本,仿真工程改方言时联动改。 - 宏清单一处维护:
-define列表从公共配置文件生成,仿真与 FM 同源,避免两边漂移。 - Tcl 脚本过 tclsh 静态检查:
tclsh只解析不执行地 source 一遍(或用 nagelfar),CI 里挡住配对类错误再进 FM 流程。 - 入库前过编译器 lint:能过仿真器 lint 的 RTL 未必能过 FM 前端,但至少能挡掉真配对问题;SV 语法检查用 verilator --lint-only 成本最低。
- 加密 IP 只收标准格式:交付清单里写明 FM 可读性要求,非标 directive 的 IP 退回供应商。
这一篇在知识体系里的位置
本篇是 EDA 排错速查簇中「读入解析」节点的 Formality 篇,覆盖语法层面的 syntax error;报错指向注释段/隐藏字节时转 Formality 编码乱码报错;读入成功后的符号问题分两条支线——宏/信号层面见 Formality 未定义符号,模块/引用层面见 Formality 模块未找到 与 Formality 未解析引用。
一句话总结
Formality 语法解析报错按「方言 → 宏 → 字节 → 配对」四层排查:报错 token 是 SV/VHDL-2008 关键字就换 read_sverilog 或开 hdlin_vhdl_2008,报错序列先见 undefined macro 就补 -define,报错指向注释段就转编码流程验字节,三者都排除后才从报错行往上逐层配括号;Tcl 脚本的 close-brace 行号可信、直接查配对;根治靠读入命令按扩展名分流、宏清单与仿真同源、脚本 lint 进 CI,让解析报错从「盯着无辜行干瞪眼」变成十分钟可定位的机械活。