1

Verilog の一部を解析しようとしています。主に、モジュールの定義とインスタンス化を抽出することに関心があります。

Verilog では、モジュールは次のように定義されます。

module foo ( ... ) endmodule;

モジュールは、次の 2 つの異なる方法のいずれかでインスタンス化されます。

foo fooinst ( ... );
foo #( ...list of params... ) fooinst ( .... );

この時点では、定義済みまたはインスタンス化されたモジュールの名前を見つけることにのみ関心があります。上記の両方の場合で「foo」。

このメンヒル文法 (verParser.mly) を考えると:

%{ 

  type expr =   Module of expr 
           | ModInst of expr
           | Ident of string 
           | Int of int
           | Lparen 
           | Rparen  
           | Junk 
           | ExprList of expr list

%}

%token <string> INT
%token <string> IDENT
%token  LPAREN RPAREN MODULE TICK OTHER HASH EOF



%start expr2
%type <expr> mod_expr
%type <expr> expr1
%type <expr list> expr2

%%


mod_expr:
  | MODULE IDENT LPAREN    { Module ( Ident $2) }
  | IDENT IDENT LPAREN     { ModInst ( Ident $1) }
  | IDENT HASH  LPAREN     { ModInst ( Ident $1) };

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

expr1:
  | junk* mod_expr junk* { $2 } ;

expr2: 
  | expr1* EOF { $1 };

menhir インタープリターでこれを試してみると、モジュール インスタンスをうまく抽出できます。

MODULE IDENT LPAREN
ACCEPT
[expr2:
  [list(expr1):
    [expr1:
      [list(junk):]
      [mod_expr: MODULE IDENT LPAREN]
      [list(junk):]
    ]
    [list(expr1):]
  ]
  EOF
]

単一モジュールのインスタンス化では問題なく機能します。

IDENT IDENT LPAREN
ACCEPT
[expr2:
  [list(expr1):
    [expr1:
      [list(junk):]
      [mod_expr: IDENT IDENT LPAREN]
      [list(junk):]
    ]
    [list(expr1):]
  ]
  EOF
]

しかしもちろん、これらのいずれかの前に現れる IDENT がある場合、拒否されます。

IDENT MODULE IDENT LPAREN IDENT IDENT LPAREN
REJECT

...そしてもちろん、これらの定義の前に実際の Verilog ファイルに識別子があります。

Verilog 文法を完全に指定する必要はないようにしています。代わりに、文法をゆっくりと段階的に構築して、最終的にはより多くの言語を解析したいと考えています。

IDENT をジャンク ルールに追加すると、上記の問題は修正されますが、ジャンク ルールが IDENT をキャプチャしているため、モジュールのインスタンス化ルールは機能しません。

一致させたくないものをバイパスする非常に寛容なルールを作成することは可能ですか、それとも実際にこのようなことを行うには完全な文法を作成する必要がありますか?

一致させるルールを作成することは可能ですか:

MODULE IDENT LPAREN stuff* RPAREN ENDMODULE

「stuff*」は、最初は RPAREN 以外のすべてに一致しますか?

何かのようなもの :

stuff: 
  | !RPAREN { } ;

私は過去に、そのような構造を可能にする PEG パーサーを使用しました。

4

1 に答える 1

1

私は、寛大で網羅的でない文法には PEG の方が適していると判断しました。peg/legを見て、必要なことを行う脚の文法を非常に迅速にまとめることができました。

start   = ( comment | mod_match | char)

line    = < (( '\n' '\r'* ) | ( '\r' '\n'* )) > { lines++;  chars += yyleng; }
module_decl =    module  modnm:ident lparen ( !rparen . )* rparen   {  chars += yyleng; printf("Module    decl: <%s>\n",yytext);}
module_inst = modinstname:ident ident lparen { chars += yyleng; printf("Module Inst: <%s>\n",yytext);}
         |modinstname:ident hash lparen { chars += yyleng; printf("Module Inst: <%s>\n",yytext);} 

mod_match = ( module_decl | module_inst ) 
module     =  'module' ws                { modules++;    chars +=yyleng; printf("Module: <%s>\n", yytext);  } 
endmodule  = 'endmodule' ws              { endmodules++; chars +=yyleng; printf("EndModule: <%s>\n", yytext); } 

kwd = (module|endmodule)
ident   = !kwd<[a-zA-z][a-zA-Z0-9_]+>-    { words++;  chars += yyleng;  printf("Ident: <%s>\n", yytext);  }

char    = .                 { chars++; }
lparen  =  '(' - 
rparen  =  ')' - 
hash    =  '#' 

- =  ( space | comment )*
ws = space+
space = ' ' | '\t' | EOL
comment = '//' ( !EOL .)* EOL
          | '/*' ( !'*/' .)* '*/' 
EOF = !.
EOL = '\r\n' | '\n' | '\r' 

Aurochsもオプションの可能性がありますが、Aurochs で生成されたパーサーの速度とメモリ使用量について懸念があります。peg/leg は C でパーサーを生成します。これは非常に高速なはずです。

于 2012-08-27T17:12:53.420 に答える