如何使用 Perl 解析 Verilog 代码来识别正在分配的寄存器?
How to use Perl to parse Verilog code to identify registers being assigned?
======== 2016 年 2 月 1 日编辑 ========
最终在匿名小伙伴的帮助下解决了问题:
while ($verilog_code =~ /\/\/.*?\n|(\w+)\s*<=\s*.*?;/smgx) {
if(defined ) {
push (@regs, );
}
}
foreach (0..$#regs) {
print "\@regs[$_]= @regs[$_]\n";
}
使用两个匹配项:一个用于评论,"jumps over" 不需要的评论;赋值语法的另一个匹配项,它捕获了我想要的东西。结果如下,是我所期望的:
@regs[0]= ak47
@regs[1]= ak48
@regs[2]= ak49
@regs[3]= ak50
@regs[4]= ak53
@regs[5]= ak54
再次感谢大家:)
======== 以下为原文post ========
我在 Whosebug 上的第一个 post,感谢任何可能提供帮助的人。
我正在使用 Perl 解析 Verilog 源代码并识别块中分配的所有寄存器。 Verilog 赋值语法类似于“reg_data <= din ;”,意思是 "reg_data is assigned the value of din".
随着Verilog代码越来越复杂,Perl解析也越来越困难。例如(在 Perl 变量 $verilog_code 中定义):
my $verilog_code = "
if (s1) ak47 <= din; ak48
<= d48; // my comment
else if (s2) begin
// comments
ak49 <= d49; ak50 <= d50; // ak51 <= d51 ; ak52 <= d52; // comments
ak53 <=
d5+d3;
end
else ak54 <= ((d<=e) ? (d540) : d541) ;
// comment: ak55 <= d55 ;
";
其中涵盖了一些具体案例:
- 一行代码可能包含许多赋值,例如。 ak47和ak48共线,ak49和ak50共线等
- 一个作业可能跨越多行,例如。 ak48和ak53都占两行
- 以“//”开头的行注释可能出现在行首或行中;评论中的任何内容都应被忽略。
因此,对于 $verilog_code,ak47、ak48、ak49、ak50、ak53 和 ak54 的分配应该被识别,而 ak51、ak52 和 ak55 应该被忽略。我做了很多尝试,使用 Perl 正则表达式 (regex) 来解析文本,但到目前为止 none 成功了:
@reg_assignments = $verilog_code =~ m/(?<!\/\/\s*)(\w+\s*<=.*?;)/sg;
====> 这个报错 "Variable length lookbehind not implemented in regex".
@reg_assignments = $verilog_code =~ m/(?<!\/\/ )(\b\w+\b\s*<=.*?;)/sg;
====> 这个得到了以下结果:
@reg_assignments[0]= ak47 <= din;
@reg_assignments[1]= ak48
<= d48;
@reg_assignments[2]= ak49 <= d49;
@reg_assignments[3]= ak50 <= d50;
@reg_assignments[4]= ak52 <= d52;
@reg_assignments[5]= ak53 <=
d5+d3;
@reg_assignments[6]= ak54 <= ((d<=e) ? (d540) : d541) ;
@reg_assignments[7]= ak55 <= d55 ;
----> 这里成功忽略了ak51的赋值,但是错误捕获了ak52和ak55。
@reg_assignments = $verilog_code =~ m/(?<!\/\/)(?:[^\n]*?(\b\w+\s*<=.*?;))/sg ;
====> 这一个得到以下结果:
@reg_assignments[0]= ak47 <= din;
@reg_assignments[1]= ak48
<= d48;
@reg_assignments[2]= ak49 <= d49;
@reg_assignments[3]= ak50 <= d50;
@reg_assignments[4]= ak51 <= d51 ;
@reg_assignments[5]= ak52 <= d52;
@reg_assignments[6]= ak53 <=
d5+d3;
@reg_assignments[7]= ak54 <= ((d<=e) ? (d540) : d541) ;
@reg_assignments[8]= ak55 <= d55 ;
我只想提取Verilog文本中所有有效的赋值,不包括注释中的东西。解决方案一直困扰着我好几天了。谁能给我任何关于如何实现这个的提示?谢谢~
如果您的 verilog 代码真的那么简单并且您不想安装某些模块并且性能并不重要,那么我建议两三个步骤:
删除任何评论:
$verilog_code =~ s:^(.*?)//.*$::mg;
可选:去掉换行符:
$verilog_code =~ s/\n//g;
获取作业:
my @assignments = ($verilog_code =~ /\S+\s*<=[^;]+;/g);
这都是非空白,接着是<=
直到下一个;
。
这给出了
@assignments = (
'ak47 <= din;',
'ak48 <= d48;',
'ak49 <= d49;',
'ak50 <= d50;',
'ak53 <= d5+d3;',
'ak54 <= ((d<=e) ? (d540) : d541) ;'
);
根据@Greg 的建议,我只是将解决方案发布在这里,以防其他人可能需要它。非常感谢花时间帮助我的 Perl Dog :-)
======== 2016 年 2 月 1 日编辑 ========
最终在匿名小伙伴的帮助下解决了问题:
while ($verilog_code =~ /\/\/.*?\n|(\w+)\s*<=\s*.*?;/smgx) {
if(defined ) {
push (@regs, );
}
}
foreach (0..$#regs) {
print "\@regs[$_]= @regs[$_]\n";
}
使用两个匹配项:一个用于评论,"jumps over" 不需要的评论;赋值语法的另一个匹配项,它捕获了我想要的东西。结果如下,符合我的预期:
@regs[0]= ak47
@regs[1]= ak48
@regs[2]= ak49
@regs[3]= ak50
@regs[4]= ak53
@regs[5]= ak54
再次感谢大家:)
======== 2016 年 2 月 1 日编辑 ========
最终在匿名小伙伴的帮助下解决了问题:
while ($verilog_code =~ /\/\/.*?\n|(\w+)\s*<=\s*.*?;/smgx) {
if(defined ) {
push (@regs, );
}
}
foreach (0..$#regs) {
print "\@regs[$_]= @regs[$_]\n";
}
使用两个匹配项:一个用于评论,"jumps over" 不需要的评论;赋值语法的另一个匹配项,它捕获了我想要的东西。结果如下,是我所期望的:
@regs[0]= ak47
@regs[1]= ak48
@regs[2]= ak49
@regs[3]= ak50
@regs[4]= ak53
@regs[5]= ak54
再次感谢大家:)
======== 以下为原文post ========
我在 Whosebug 上的第一个 post,感谢任何可能提供帮助的人。
我正在使用 Perl 解析 Verilog 源代码并识别块中分配的所有寄存器。 Verilog 赋值语法类似于“reg_data <= din ;”,意思是 "reg_data is assigned the value of din".
随着Verilog代码越来越复杂,Perl解析也越来越困难。例如(在 Perl 变量 $verilog_code 中定义):
my $verilog_code = "
if (s1) ak47 <= din; ak48
<= d48; // my comment
else if (s2) begin
// comments
ak49 <= d49; ak50 <= d50; // ak51 <= d51 ; ak52 <= d52; // comments
ak53 <=
d5+d3;
end
else ak54 <= ((d<=e) ? (d540) : d541) ;
// comment: ak55 <= d55 ;
";
其中涵盖了一些具体案例:
- 一行代码可能包含许多赋值,例如。 ak47和ak48共线,ak49和ak50共线等
- 一个作业可能跨越多行,例如。 ak48和ak53都占两行
- 以“//”开头的行注释可能出现在行首或行中;评论中的任何内容都应被忽略。
因此,对于 $verilog_code,ak47、ak48、ak49、ak50、ak53 和 ak54 的分配应该被识别,而 ak51、ak52 和 ak55 应该被忽略。我做了很多尝试,使用 Perl 正则表达式 (regex) 来解析文本,但到目前为止 none 成功了:
@reg_assignments = $verilog_code =~ m/(?<!\/\/\s*)(\w+\s*<=.*?;)/sg;
====> 这个报错 "Variable length lookbehind not implemented in regex".
@reg_assignments = $verilog_code =~ m/(?<!\/\/ )(\b\w+\b\s*<=.*?;)/sg;
====> 这个得到了以下结果:
@reg_assignments[0]= ak47 <= din;
@reg_assignments[1]= ak48
<= d48;
@reg_assignments[2]= ak49 <= d49;
@reg_assignments[3]= ak50 <= d50;
@reg_assignments[4]= ak52 <= d52;
@reg_assignments[5]= ak53 <=
d5+d3;
@reg_assignments[6]= ak54 <= ((d<=e) ? (d540) : d541) ;
@reg_assignments[7]= ak55 <= d55 ;
----> 这里成功忽略了ak51的赋值,但是错误捕获了ak52和ak55。
@reg_assignments = $verilog_code =~ m/(?<!\/\/)(?:[^\n]*?(\b\w+\s*<=.*?;))/sg ;
====> 这一个得到以下结果:
@reg_assignments[0]= ak47 <= din;
@reg_assignments[1]= ak48
<= d48;
@reg_assignments[2]= ak49 <= d49;
@reg_assignments[3]= ak50 <= d50;
@reg_assignments[4]= ak51 <= d51 ;
@reg_assignments[5]= ak52 <= d52;
@reg_assignments[6]= ak53 <=
d5+d3;
@reg_assignments[7]= ak54 <= ((d<=e) ? (d540) : d541) ;
@reg_assignments[8]= ak55 <= d55 ;
我只想提取Verilog文本中所有有效的赋值,不包括注释中的东西。解决方案一直困扰着我好几天了。谁能给我任何关于如何实现这个的提示?谢谢~
如果您的 verilog 代码真的那么简单并且您不想安装某些模块并且性能并不重要,那么我建议两三个步骤:
删除任何评论:
$verilog_code =~ s:^(.*?)//.*$::mg;
可选:去掉换行符:
$verilog_code =~ s/\n//g;
获取作业:
my @assignments = ($verilog_code =~ /\S+\s*<=[^;]+;/g);
这都是非空白,接着是
<=
直到下一个;
。
这给出了
@assignments = (
'ak47 <= din;',
'ak48 <= d48;',
'ak49 <= d49;',
'ak50 <= d50;',
'ak53 <= d5+d3;',
'ak54 <= ((d<=e) ? (d540) : d541) ;'
);
根据@Greg 的建议,我只是将解决方案发布在这里,以防其他人可能需要它。非常感谢花时间帮助我的 Perl Dog :-)
======== 2016 年 2 月 1 日编辑 ========
最终在匿名小伙伴的帮助下解决了问题:
while ($verilog_code =~ /\/\/.*?\n|(\w+)\s*<=\s*.*?;/smgx) {
if(defined ) {
push (@regs, );
}
}
foreach (0..$#regs) {
print "\@regs[$_]= @regs[$_]\n";
}
使用两个匹配项:一个用于评论,"jumps over" 不需要的评论;赋值语法的另一个匹配项,它捕获了我想要的东西。结果如下,符合我的预期:
@regs[0]= ak47
@regs[1]= ak48
@regs[2]= ak49
@regs[3]= ak50
@regs[4]= ak53
@regs[5]= ak54
再次感谢大家:)