3

私は正規表現を使用して、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.
4

2 に答える 2

4

最初の広告の議事録:代わりに、ocamlyaccフランソワ・ポティエのメンヒルを使用することを検討する必要があります。これは、「yacc、アップグレード」のようなもので、すべての面で優れています(より読みやすい文法、より強力な構成、デバッグが容易です...)。もちろん、と組み合わせて使用​​することもできocamllexます。

ルールexpr1では、ルールの開始と終了のみが許可されますexpr。前後に「もの」が入るように拡大する必要がありますexpr。何かのようなもの:

junk:
| junk LPAREN
| junk RPAREN
| junk INT
| junk IDENT

expr1:
| junk expr junk EOF

moduleこの文法では、トークンをセクションに表示できないことに注意してくださいjunk。これを行うと、文法があいまいになるため、少し問題があります(探している構造は、exprまたはに埋め込むことができますjunk)。module探しているフォームの外部でトークンが発生する可能性がある場合はmodule ident (、文法からアトミックに一致できるように、対象の構造全体を1つのトークンにキャプチャするようにレクサーを変更することを検討する必要があります。ただし、長期的には、よりきめの細かいトークンを使用する方がおそらく良いでしょう。

于 2012-08-22T05:35:48.700 に答える
3

@gascheが示唆しているように、私はmenhirを試しましたが、すでにはるかに良い結果が得られています。verLexer.mlを次のように変更しました。

{
  open VerParser
}
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) }
  | _  as c                       { lex lexbuf }
  | eof                           { EOF }

そして、verParser.mlyを次のように変更しました。

%{ type expr =  Module of expr | Ident of string | Int of int
           |Lparen | Rparen  | Junk %}

%token <int> INT
%token <string> IDENT
%token  LPAREN RPAREN MODULE EOF

%start expr1
%type <expr> expr1


%%

expr:
  | MODULE IDENT LPAREN    { Module( Ident $2) };

junk: 
  |  LPAREN {  }
  |  RPAREN {  }
  |  INT {  }
  |  IDENT {  } ;

expr1:
| junk* expr junk* EOF { $2 };

ここで重要なのは、menhirでは、上記の行のように、ルールを「*」でパラメーター化できることです。ルールには、ジャンクを0回以上一致させることを意味する「ジャンク*」があります。ocamlyaccはそれを許可していないようです。

今、REPLで試してみると、次のようになります。

# #use "verParser.ml" ;;
# #use "verLexer.ml" ;;
# expr1 lex (Lexing.from_string "module foo ( " ) ;;
- : expr = Module (Ident "foo")
# expr1 lex (Lexing.from_string "some module foo ( " ) ;;
- : expr = Module (Ident "foo")
# expr1 lex (Lexing.from_string "some module foo (\nbar " ) ;;
- : expr = Module (Ident "foo")
# expr1 lex (Lexing.from_string "some module foo (\n//comment " ) ;;
- : expr = Module (Ident "foo")
# expr1 lex (Lexing.from_string "some module fot foo (\n//comment " ) ;;
Exception: Error.
# expr1 lex (Lexing.from_string "some module foo (\n//comment " ) ;;

これは私が望むとおりに機能しているようです。

于 2012-08-22T21:02:28.873 に答える