1

我正在尝试解析 Verilog 的一些点点滴滴——我主要对提取模块定义和实例感兴趣。

在verilog中,模块定义如下:

module foo ( ... ) endmodule;

并且模块以两种不同的可能方式之一实例化:

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

此时我只对查找已定义或实例化模块的名称感兴趣;'foo' 在上述两种情况下。

鉴于此 menhir 语法 (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 出现在其中任何一个之前,它将 REJECT:

IDENT MODULE IDENT LPAREN IDENT IDENT LPAREN
REJECT

...当然,在这些defs之前的实际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 回答