By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,847 Members | 1,274 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,847 IT Pros & Developers. It's quick & easy.

Beautification Script - Regular Expressions

P: 6
Hi all,

I am working on a VHDL code beautifier with Perl. I've come to this part of the beautification process and I got really stuck. Assume for example the following piece of VHDl code:

CODE
Expand|Select|Wrap|Line Numbers
  1. entity JK_FF is
  2.   port( clock : in std_logic;
  3.          J, K : in std_logic;
  4.         reset : in std_logic;
  5.         Q, Qbar : out std_logic);
  6. end JK_FF;
  7.  
Well I'm trying to figure out the regular expressions to transform it to that:

Expand|Select|Wrap|Line Numbers
  1. entity JK_FF is
  2.   port( clock : in  std_logic;
  3.         J     : in  std_logic;
  4.         K     : in  std_logic;
  5.         reset : in  std_logic;
  6.         Q     : out std_logic;
  7.         Qbar  : out std_logic);
  8. end JK_FF;
  9.  
Hence, briefly,
i. Place all words between 'port(' and ');' in columns.
ii. Separate
<signal_name_1>, <signal_name_2>,...,<signal_name_n> : <direction> <type>;

to

<signal_name_1> : <direction> <type>;
<signal_name_2> : <direction> <type>;
...
<signal_name_n> : <direction> <type>;

Any help, suggestion is more than welcomed

Thanks in advance!
Mar 24 '08 #1
Share this Question
Share on Google+
11 Replies


nithinpes
Expert 100+
P: 410
Hi all,

I am working on a VHDL code beautifier with Perl. I've come to this part of the beautification process and I got really stuck. Assume for example the following piece of VHDl code:

CODE
Expand|Select|Wrap|Line Numbers
  1. entity JK_FF is
  2.   port( clock : in std_logic;
  3.          J, K : in std_logic;
  4.         reset : in std_logic;
  5.         Q, Qbar : out std_logic);
  6. end JK_FF;
  7.  
Well I'm trying to figure out the regular expressions to transform it to that:

Expand|Select|Wrap|Line Numbers
  1. entity JK_FF is
  2.   port( clock : in  std_logic;
  3.         J     : in  std_logic;
  4.         K     : in  std_logic;
  5.         reset : in  std_logic;
  6.         Q     : out std_logic;
  7.         Qbar  : out std_logic);
  8. end JK_FF;
  9.  
Hence, briefly,
i. Place all words between 'port(' and ');' in columns.
ii. Separate
<signal_name_1>, <signal_name_2>,...,<signal_name_n> : <direction> <type>;

to

<signal_name_1> : <direction> <type>;
<signal_name_2> : <direction> <type>;
...
<signal_name_n> : <direction> <type>;

Any help, suggestion is more than welcomed

Thanks in advance!
This can be done using a split() function to split on commas for each line in the file, then splitting the last element of the resulting array on colon to get the last two fields.
It would be good to know what you have tried so far!
Mar 24 '08 #2

P: 6
This can be done using a split() function to split on commas for each line in the file, then splitting the last element of the resulting array on colon to get the last two fields.
It would be good to know what you have tried so far!
Yes you're right! Sorry I forgot to mention, but I've tried this lot already:

Expand|Select|Wrap|Line Numbers
  1. use strict;
  2. #use warnings;
  3.  
  4. my @data;
  5. #push @data, [split (/\s+/, $_)] for <DATA>;
  6. push @data, [split (' ', $_)] for <DATA>;
  7.  
  8. foreach my $row(0..8) {
  9. foreach my $col(0..(@data-1)) {
  10. printf("%-15s", $data[$row][$col]);
  11. }
  12. print "\n";
  13. }
  14.  
  15. __DATA__
  16. clk         : in std_logic;
  17. areset        : in std_logic;
  18. busy : out std_logic;
  19. writeEnable : in std_logic;
  20. readEnable : in std_logic;
  21. write    : in std_logic_vector(wordSize-1 downto 0);
  22. read    : out std_logic_vector(wordSize-1 downto 0);
  23. addr : in std_logic_vector(maxAddrBit downto minAddrBit));
  24.  
eventhough <wordSize-1 downto> has a space separator, for some reason I get this:

write : in std_logic_vector(wordSize-1downto 0);

Any ideas?
Mar 24 '08 #3

nithinpes
Expert 100+
P: 410
I feel the problem lies in this line:
Expand|Select|Wrap|Line Numbers
  1. foreach my $col(0..(@data-1))
  2.  
In your script, @data is changing dynamically(also the number of elements). But the range cannot be varying inside foreach() loop. Hence, the range will take number of elements in first @data(first line) as upperlimit of the range.
Therefore, the column count would end after "std_logic_vector(wordSize-1".
Also, you are unconditionally splitting on spaces,though you require exactly 4 fields to be aligned/ formatted. For this purpose, you can make use of third argument in split() function. This number would tell the exact number of splits to be made. The string after these many delimiter characters would become the last element of the array.
Use:
Expand|Select|Wrap|Line Numbers
  1. push @data, [split (/\s+/, $_,4)] for <DATA>;
  2.  
Mar 24 '08 #4

P: 6
Bingo! That worked exactly the way I want it! Thanks a lot!

Now the tricky part (for me it is!), is how to:

Separate
<signal_name_1>, <signal_name_2>,...,<signal_name_n> : <direction> <type>;

to

<signal_name_1> : <direction> <type>;
<signal_name_2> : <direction> <type>;
...
<signal_name_n> : <direction> <type>;

Well, the above special case, may or may not exist, so some sort of detection is required...I can roughly think a way of using split() (switch rows to col etc.), concat the end ;, and multiple if's, but looks quite dodgy. I'd rather prefer a better more neat way of doing it. Could you suggest anything? Especially for the detection part!
Mar 24 '08 #5

KevinADC
Expert 2.5K+
P: 4,059
Bingo! That worked exactly the way I want it! Thanks a lot!

Now the tricky part (for me it is!), is how to:

Separate
<signal_name_1>, <signal_name_2>,...,<signal_name_n> : <direction> <type>;

to

<signal_name_1> : <direction> <type>;
<signal_name_2> : <direction> <type>;
...
<signal_name_n> : <direction> <type>;

Well, the above special case, may or may not exist, so some sort of detection is required...I can roughly think a way of using split() (switch rows to col etc.), concat the end ;, and multiple if's, but looks quite dodgy. I'd rather prefer a better more neat way of doing it. Could you suggest anything? Especially for the detection part!
And it will be fairly tricky. You could use a hash of arrays.

<direction> will be (it appears) one of two values (boolean) "in" or "out". <type> looks like it could be just about anything but i assume its everything after the <direction> indicator. You would use those two pieces of information as hash keys. Then you would push the <signal_name> indicator into the approrpiate array. One possible draw back is the loss of order of the data, but if the original order is not important then that is not a problem.
Mar 24 '08 #6

P: 6
And it will be fairly tricky. You could use a hash of arrays.

<direction> will be (it appears) one of two values (boolean) "in" or "out". <type> looks like it could be just about anything but i assume its everything after the <direction> indicator. You would use those two pieces of information as hash keys. Then you would push the <signal_name> indicator into the approrpiate array. One possible draw back is the loss of order of the data, but if the original order is not important then that is not a problem.
Could you spare me an example? Little something to start feedling with! Hope am not asking too much.
Mar 24 '08 #7

nithinpes
Expert 100+
P: 410
Could you spare me an example? Little something to start feedling with! Hope am not asking too much.
Using hash of arrays is a good approach. But, from your initial description, I assume you need to retain the order.This can be done using array of arrays itself, though bit lengthy.
The following code would do the job:
Expand|Select|Wrap|Line Numbers
  1. use strict;
  2.  
  3. my @data;
  4. for (<DATA>) {
  5. ###checking for commas. Otherwise even these signals can be split
  6. ##into separate elements if there is space before/after comma
  7. unless(/,/) {           
  8. push @data, [split (/\s+/, $_,4)];
  9. } else {
  10.   $_=~s/\s*,\s*/,/;
  11.   push @data, [split (/\s+/, $_,4)]; 
  12. }
  13. }
  14.  
  15. foreach my $row(0..8) {
  16. my @signals;my @other;
  17. my $multi;
  18. foreach my $col(0..(@data-1)) {
  19. if($data[$row][$col]=~/,/) {
  20.   $multi=1;
  21.   @signals=split(/,/,$data[$row][$col]); ##separate out signals
  22.   until($col==(@data-1)) {
  23.       $col++;
  24.       ##take out corresponding type and direction
  25.        push @other,$data[$row][$col]; 
  26.        }
  27. foreach(@signals) {
  28. print "\n";
  29. printf("%-15s",$_); 
  30. printf("%-15s", $_) foreach(@other);
  31. }
  32. last;
  33. else {
  34. printf("%-15s", $data[$row][$col]);
  35. }
  36. }
  37. print "\n";
  38. }
  39.  
  40. __DATA__
  41. clk         : in std_logic;
  42. areset,reset        : in std_logic;
  43. busy : out std_logic;
  44. writeEnable : in std_logic;
  45. readEnable, modifyEnable : in std_logic;
  46. write, copy    : in std_logic_vector(wordSize-1 downto 0);
  47. read  ,clock    : out std_logic_vector(wordSize-1 downto 0);
  48. addr : in std_logic_vector(maxAddrBit downto minAddrBit));
  49.  
  50.  
Mar 25 '08 #8

P: 6
Thanks a lot, yes thats the idea more or less. Now, probably should have justified that from start, but I dont really want to print the formatted text, but collect it into a buffer in order to replace the original part with the formatted one. Any ideas how to achieve that in your existing code?
Mar 25 '08 #9

nithinpes
Expert 100+
P: 410
Thanks a lot, yes thats the idea more or less. Now, probably should have justified that from start, but I dont really want to print the formatted text, but collect it into a buffer in order to replace the original part with the formatted one. Any ideas how to achieve that in your existing code?
If you want to modify the file containing data according to format, all you need to do is to read from that file, write into a temporary file and later change the temporary file to data file.You can use this example:
Expand|Select|Wrap|Line Numbers
  1. use strict;
  2.  
  3. my @data;
  4. open(DATA,"data.txt") or die "read failed:$!";
  5. open(TEMP,">temp.txt") or die "write failed:$!";  ##open temporary file
  6. for (<DATA>) {
  7. s/^\s*//;       ## trim out spaces from beginning of line
  8. ###checking for commas. Otherwise even these signals can be split
  9. ##into separate elements if there is space before/after comma
  10. unless(/,/) {           
  11. push @data, [split (/\s+/, $_,4)];
  12. } else {
  13.   $_=~s/\s*,\s*/,/;
  14.   push @data, [split (/\s+/, $_,4)]; 
  15. }
  16. }
  17.  
  18. foreach my $row(0..(@data-1)) {   ### upto last row
  19. my @signals;my @other;
  20. my $multi;
  21. foreach my $col(0..(@{$data[$row]}-1)) {   ### upto last element in the row
  22. if($data[$row][$col]=~/,/) {
  23.   $multi=1;
  24.   @signals=split(/,/,$data[$row][$col]); ##separate out signals
  25.   until($col==(@data-1)) {
  26.       $col++;
  27.       ##take out corresponding type and direction
  28.        push @other,$data[$row][$col]; 
  29.        }
  30. foreach(@signals) {
  31. print TEMP "\n";
  32. printf TEMP ("%-15s",$_); 
  33. printf TEMP ("%-15s", $_) foreach(@other);
  34. }
  35. last;
  36. else {
  37. printf TEMP ("%-15s", $data[$row][$col]);
  38. }
  39. }
  40. print TEMP "\n";
  41. }
  42. close(DATA); 
  43. close(TEMP);
  44. ##change temp.txt to data.txt
  45. rename("temp.txt","data.txt") or die "rename failed:$!";  
  46.  
Also, note the change in range used for $row and $column. This should be the range you need to ideally use to parse through all rows and all columns in each row.
Mar 26 '08 #10

KevinADC
Expert 2.5K+
P: 4,059
"rharsh" on Tek-Tips has already written you a 99% working solution. "nithinpes " code is largely a duplication of that code. You seem a bit disengenuous to me by not informing either forum you are also getting help from another forum.
Mar 26 '08 #11

P: 6
"rharsh" on Tek-Tips has already written you a 99% working solution. "nithinpes " code is largely a duplication of that code. You seem a bit disengenuous to me by not informing either forum you are also getting help from another forum.
You probably mean 'disingenuous'...Well it never crossed my mind that querying multiple sources possesses a form of disingenuousness! Based on that, I should be reading one and only one, say Perl book, but not two or more even worse, cause this would make me disingenuous to the author of the first book! Nevertheless, I truly apologize if that insulted you in any way!
Mar 26 '08 #12

Post your reply

Sign in to post your reply or Sign up for a free account.