我一直在使用正则表达式来检查一堆 Verilog 文件并提取某些语句。目前,正则表达式对此很好,但是,我开始意识到需要一个真正的解析器来处理嵌套结构,所以我正在研究 ocamllex/ocamlyacc。我想首先复制我在正则表达式实现中得到的内容,然后慢慢地在语法中添加更多内容。
现在我主要对提取模块声明和实例感兴趣。为了让这个问题更简短,让我们只看一下模块声明。
在 Verilog 中,模块声明如下所示:
module modmame ( ...other statements ) endmodule;
我当前的正则表达式实现只是检查是否有一个使用特定名称声明的模块(检查我感兴趣的名称列表 - 我不需要找到所有模块声明,只是具有特定名称的模块声明)。所以基本上,我得到了我想要解析的 Verilog 文件的每一行并进行这样的匹配(带有 Pythonish 和 Rubyish 元素的伪 OCaml):
foreach file in list_of_files:
let found_mods = Hashtbl.create 17;
open file
foreach line in file:
foreach modname in modlist
let mod_patt= Str.regexp ("module"^space^"+"^modname^"\\("^space^"+\\|(\\)") in
try
Str.search_forward (mod_patt) line 0
found_mods[file] = modname; (* map filename to modname *)
with Not_found -> ()
这很好用。模块声明可以出现在 Verilog 文件中的任何位置;我只是想知道该文件是否包含该特定声明,我不在乎该文件中可能还有什么。
我第一次尝试将其转换为 ocamllex/ocamlyacc:
verLexer.mll:
rule lex = parse
| [' ' '\n' '\t'] { lex lexbuf }
| ['0'-'9']+ as s { INT(int_of_string s) }
| '(' { LPAREN }
| ')' { RPAREN }
| "module" { MODULE }
| ['A'-'Z''a'-'z''0'-'9''_']+ as s { IDENT(s) }
| _ { lex lexbuf }
| eof
verParser.mly:
%{ type expr = Module of expr | Ident of string | Int of int %}
%token <int> INT
%token <string> IDENT
%token LPAREN RPAREN MODULE EOF
%start expr1
%type <expr> expr1
%%
expr:
| MODULE IDENT LPAREN { Module( Ident $2) };
expr1:
| expr EOF { $1 };
然后在 REPL 中尝试一下:
# #use "verLexer.ml" ;;
# #use "verParser.ml" ;;
# expr1 lex (Lexing.from_string "module foo (" ) ;;
- : expr = Module (Ident "foo")
太好了,它有效!
然而,一个真正的 Verilog 文件将不止包含一个模块声明:
# expr1 lex (Lexing.from_string "//comment\nmodule foo ( \nstuff" ) ;;
Exception: Failure "lexing: empty token".
我并不真正关心该模块定义之前或之后出现的内容,有没有办法只提取语法的那部分以确定Verilog文件包含'module foo('语句?是的,我意识到正则表达式是工作正常,但是,如上所述,我计划慢慢地发展这个语法并添加更多元素,正则表达式将开始分解。
编辑:我在 lex 规则中添加了一个 match any char:
| _ { lex lexbuf }
认为它会跳过迄今为止不匹配的任何字符,但这似乎不起作用:
# expr1 lex (Lexing.from_string "fof\n module foo (\n" ) ;;
Exception: Parsing.Parse_error.