私は正規表現を使用して、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ファイルに「modulefoo(」ステートメントが含まれていることを確認する方法はありますか?はい、正規表現はこれには問題なく機能しますが、前述のように、この文法をゆっくりと成長させ、さらに要素を追加することを計画しています。正規表現が機能しなくなります。
編集:lexルールにmatch any charを追加しました:
| _ { lex lexbuf }
これまで一致しなかった文字をスキップすることを考えていますが、それは機能していないようです:
# expr1 lex (Lexing.from_string "fof\n module foo (\n" ) ;;
Exception: Parsing.Parse_error.