我正在尝试解析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,它将拒绝:
IDENT MODULE IDENT LPAREN IDENT IDENT LPAREN
REJECT
...当然,在这些defs之前,实际的verilog文件中会有标识符。
我试图不必完全指定一个Verilog语法,而是我想慢慢地逐步构建语法,最终解析越来越多的语言。
如果我将IDENT添加到垃圾规则中,那就解决了上面的问题,但是模块实例化规则不起作用,因为现在垃圾规则正在捕获IDENT。
是否有可能创建一个非常宽松的规则来绕过我不想匹配的东西,或者通常要求你必须创建一个完整的语法才能真正做到这样的事情?
是否可以创建一个让我匹配的规则:
MODULE IDENT LPAREN stuff* RPAREN ENDMODULE
其中“stuff *”最初匹配除RPAREN之外的所有内容?
类似的东西:
stuff:
| !RPAREN { } ;
我过去曾使用PEG解析器,这样可以使用类似的结构。
答案 0 :(得分: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中生成一个解析器应该非常快。