Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Beautification Script - Regular Expressions 2

Status
Not open for further replies.

DrFuzzy

Programmer
Mar 23, 2008
16
GR
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:
entity JK_FF is
  port( clock : in std_logic;
        J, K : in std_logic;
        reset : in std_logic;
        Q, Qbar : out std_logic);
end JK_FF;

Well I'm trying to figure out the regular expressions to transform it to that:

Code:
entity JK_FF is
  port( clock : in  std_logic;
        J     : in  std_logic;
        K     : in  std_logic;
        reset : in  std_logic;
        Q     : out std_logic;
        Qbar  : out std_logic);
end JK_FF;

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!


 
Miserably all I get is an empty FILE_OUT...

An example FILE_IN is the following:

Code:
library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

use std.textio.all;

library work;
use work.zpu_config.all;
use work.zpupkg.all;
use work.txt_util.all;
 
entity  zpu_io is
  port( clk         : in std_logic;
       	areset        : in std_logic;
		busy : out std_logic;
		writeEnable : in std_logic;
		readEnable : in std_logic;
		write	: in std_logic_vector(wordSize-1 downto 0);
		read	: out std_logic_vector(wordSize-1 downto 0);
		addr : in std_logic_vector(maxAddrBit downto minAddrBit));
end zpu_io;
   
   
architecture behave of zpu_io is

signal timer_read : std_logic_vector(7 downto 0);
--signal timer_write : std_logic_vector(7 downto 0);
signal timer_we : std_logic;

signal serving : std_logic;

file 		l_file		: TEXT open write_mode is log_file;

begin
	
	process(areset, clk)
	begin
		if (areset = '1') then
		elsif (clk'event and clk = '1') then
			if writeEnable = '1' then
				-- external interface
				if addr=x"2028003" then
					-- Write to UART
					-- report "" & character'image(conv_integer(memBint)) severity note;
				    print(l_file, character'val(conv_integer(write)));
				elsif addr(12)='1' then
				else
					print(l_file, character'val(conv_integer(write)));
					report "Illegal IO write" severity warning;
				end if;
				
			end if;
			read <= (others => '0');
			if (readEnable = '1') then
				if addr=x"1001" then
					read <= (0=>'1', others => '0'); -- recieve empty
 				elsif addr(12)='1' then
 					read(7 downto 0) <= timer_read;
 				elsif addr(11)='1' then
 					read(7 downto 0) <= ZPU_Frequency;
 				elsif addr=x"2028003" then
					read <= (others => '0');
				else
					read <= (others => '0');
					read(8) <= '1';
					report "Illegal IO read" severity warning;
				end if;
			end if;
		end if;
	end process;


end behave;


PS. Sorry for the double post, but I could not find how to modify the first one.
 
Can't really follow you, you are mixing up different logics (how to parse a file, regexps, how to modify a parsed file, what and how to print the result...): it would be better if you raise separate questions for separate problems, posting a piece of code that only treats that specific logic.
In your last two posts, joining together the two pieces of code, you are reading three times the same file, but the first while loop will get to the eof, so the slurp and the second while won't have anything to read, so what?
Please read carefully what rharsh said in their last post: you don't need to mess up with arrays and slurps, unless your logic requires replacements on single lines that depend on the content of the following lines.

Franco
: Online engineering calculations
: Magnetic brakes for fun rides
: Air bearing pads
 
Sadly, I see what you mean, but I don't know how to cope with it...

My logic is mainly based on replacements on single lines that depend on the content of previous or following lines, so definitely need arrays.

The idea was pretty much what rharsh said, except I missed out one thing, you luckily spotted, this "but the first while loop will get to the eof, so the slurp and the second while won't have anything to read". So how should I deal with this case, I mean for something like:

Code:
open( FILE_IN, $vhdl_filename );
open( FILE_OUT, ">$report_filename" );
.
.
my (@buffer, $line);
.
while ( $line = <FILE_IN> ) {
.
# Performs -> Formatting 1
.
}

# ! EOF ! ?How do I restart, so next loop can do something?  

while ( $line = <FILE_IN> ) {
.
# Performs -> Formatting 2
.
}

print FILE_OUT @buffer;

Sorry but I am totally utterly confused!
 
Looking at your code, you probably want use strict; and use warnings; at the top of your script. You'll have to declare all your variables, but it will save you some headaches in the long run.

About the logic of the script, I'm not sure there's a need to read the file more than once. Once all the lines from the text file are stored in the array, the formatting can be done on the stored data rather than going through the text file again. Maybe approaching it like this will work for you?
Code:
open( FILE_IN, $vhdl_filename ) or die "$!";
open( FILE_OUT, ">$report_filename" ) or die "$!";
my (@buffer, $line);

while ($line = <FILE IN>) {
  # Formatting Pass 1

  # This should probably include any formatting that splits
  # one line into multiple lines.
  # The 'entity' formatting could be done here.
  
  # Add all lines to @buffer after formatting them.
}

foreach $line (@buffer) {
  # Formatting Pass 2

  # All the items in @buffer are aliased to $line.
  # Make the required changes to $line and they will be
  # Changed in @buffer.
}

# Print
foreach (@buffer) {
  print FILE_OUT "$_";
}
 
Ok I need a little help here!

Code so far...

Code:
use strict;
use warnings;

## Prepare IN/OUT Files ##
my $vhdl_filename = $ARGV[0];
my $report_filename = $ARGV[1];
open( FILE_IN, $vhdl_filename ) or die "$!";;
open( FILE_OUT, ">$report_filename" ) or die "$!";;

my $short_record = '  %6s %-12s : %-3s %15s';
my $long_record =  '  %6s %-12s : %-3s %-15s(%10s %6s %10s)';
my $line;

## Our work buffer ##
my $buffer = ();

## Number of indent spaces ##
my $indent = "  ";
my $nesting_level = 0; # init. nesting level
my $cnt = 0; # init. counter
my (@buffer, $line);

# Formatting Pass 1
# Beautify Entity->End
while ( $line = <FILE_IN> ) {
  if($line =~ /\s*port\(\s*(.+)\s*$/) {
    my @temp = $1;
    my %print;
    while ( $line = <FILE_IN> ) {
      last if $line =~ /^end \w+;\s*$/;
      push @temp, $line;
    } 
    foreach my $i (@temp) {
      my ($key, $value) = trim(split /\s*:\s*/, $i);
      $value =~ s/;//;
      $print{$_} = $value for trim(split(/\s*,\s*/, $key));
    }
    my @keys = sort keys %print;
    for (my $i = 0; $i <= $#keys; $i++) {
      if ($print{$keys[$i]} =~ m/([^\(]+)\s*\(([^)]+)\s*\)/) {
        my $str = sprintf $long_record, ($i == 0 ? 'port (' : ""), $keys[$i],
                       split(/\s+/, $1), split(/\s+/, $2);
      } 
      else {
        my $str = sprintf $short_record, ($i == 0 ? 'port (' : ""), $keys[$i],
                       split(/\s+/, $print{$keys[$i]});
      }   
      my $str .= $i == $#keys ? " );\n" : ";\n";
      push @buffer, $str;
    }
      push @buffer, $line;    # print 'end' message
    } 
    else {
      push @buffer, $line;    
    }
}    

# Formatting Pass 2
# Indent inner body of ARCHITECTURE->BEGIN
foreach my $line (@buffer) {
  if ($line =~ m/^architecture/) {
    if ($cnt == 0) {
      $nesting_level++;
      $cnt++;
    }
  }
  if ($line =~ m/^begin/g) {
    $nesting_level--;
  }
  if ( $line =~ m/^architecture/) { # Don't indent ARCHITECTURE!
  }
  else {
    
#########################################################
# THIS IS SUPPOSED TO REMOVE LEADING & TRAILING WHITE SPACES, BUT IT DOESN'T! ???
# SOME HELP HERE!!!
# PROBABLY  MAY HAVE DONE THIS AT BEGINNING. PROBABLY THE WAY I TREAT MY BUFFER,...I DON'T KNOW!
#########################################################

    $line =~ s/[ \t]*\n[ \t]*/\n/g;
    

    $line .= $indent x $nesting_level;
  }
}    

#########################################################
# MY NESTING DOESN'T WORK TOO, THOUGH IT SHOULD...
# SOME HELP HERE!!!
#########################################################

# Formatting Pass 3
$nesting_level = 0; # init. nesting level
foreach my $line (@buffer) {
  if ($line =~ m/^elsif/) {
    $nesting_level--;
  }
  if ($line =~ m/^(end if)/) {
    $nesting_level--;
  }
  $line .= $indent x $nesting_level;# + $nesting_offset; ## Insert the indent string $nesting_level times at the beginning of the line
  if ($line =~ m/then$/) {
    $nesting_level++;
  }
}
if ($nesting_level != 0) {
  warn "Uh-oh, i messed up with the ENDIFs. \$missingENDIFs = $nesting_level.\n";
}

# Print
foreach (@buffer) {
  print FILE_OUT "$_";
}

# Perl trim function to remove whitespace from the start and end of the string
sub trim {
  my @out = @_;
  for (@out) {
    s/^\s+//;
    s/\s+$//;
  }
  return wantarray ? @out : $out[0];
}

## Write Formatted Buffer and Close Files ##
close (FILE_IN);
close (FILE_OUT);

I think by now, you all understand what I am trying to do.
If this approach is wrong, please do let me know! Any suggestions, changes worth a million! Thank you all!
 
I didn't include any of the filehandle / user input portions of your code. But this should be fairly easy to modify to your needs. I think it does most of what you're looking for.
Code:
my $short_record = '  %6s %-12s : %-3s %15s';
my $long_record =  '  %6s %-12s : %-3s %-15s(%10s %6s %10s)';
my ($line, @buffer);
my $indent = "  ";		# Number of indent spaces
my $level = 0;			# init. nesting level
my $fh = *DATA;			# Replace DATA with your the name of your filehandle (FILE_IN?)

# Read until ENTITY
while ($line = <$fh>) {
	push @buffer, trim($line);
	last if $line =~ /entity/i;
}

# Format ENTITY
while ($line = <$fh>) {
	if($line =~ /\s*port\(\s*(.+)\s*$/) {
	    my @temp = $1;
	    my %print;
	    while ( $line = <$fh> ) {
			last if $line =~ /^end \w+;\s*$/;
			push @temp, $line;
	    }
	    foreach my $i (@temp) {
		    my ($key, $value) = trim(split /\s*:\s*/, $i);
			$value =~ s/;//;
			$print{$_} = $value for trim(split(/\s*,\s*/, $key));
	    }
	    my @keys = sort keys %print;
		
		for (my $i = 0; $i <= $#keys; $i++) {
			my $str;
			if ($print{$keys[$i]} =~ m/([^\(]+)\s*\(([^)]+)\s*\)/) {
				$str = sprintf $long_record, ($i == 0 ? 'port (' : ""),
						$keys[$i], split(/\s+/, $1), split(/\s+/, $2);
			} else {
				$str = sprintf $short_record, ($i == 0 ? 'port (' : ""),
						$keys[$i], split(/\s+/, $print{$keys[$i]});
			}   
			$str .= $i == $#keys ? ' );' : ';';
			push @buffer, $str;
	    }
		push @buffer, trim($line);    # print 'end' message
		last;
    } else {
		push @buffer, trim($line);
    }
}

# Format Architecture
while ($line = <$fh>) {
	if ($line =~ /^\s*architecture/i) {
		push @buffer, trim($line);
		$level++;
		while ($line = <$fh>) {
			if ($line =~ /begin/) {
				$level--;
				push @buffer, trim($line);
				$level++;
				last;
			} else {
				push @buffer, $indent x $level . trim($line);
			}
		}
		last;
	} else {
		push @buffer, trim($line);
	}
}

# Format Logic
while ($line = <$fh>) {
	if ($line =~ m/\s*(\w+)/) {
		if ($1 eq 'begin') {
			push @buffer, $indent x $level . trim($line);
			$level++;
		} elsif ($1 eq 'if') {
			push @buffer, $indent x $level . trim($line);
			$level++;
		} elsif ($1 eq 'elsif' || $1 eq 'else') {
			$level--;
			push @buffer, $indent x $level . trim($line);
			$level++;
		} elsif ($1 eq 'end') {
			$level--;
			push @buffer, $indent x $level . trim($line);
		} else {
			push @buffer, $indent x $level . trim($line);
		}
	} else {
		push @buffer, $indent x $level . trim($line);
	}
}

# Grab anything that's left
while ($line = <$fh>) {
	push @buffer, trim($line);
}

# PRINT!
foreach (@buffer) {
	print "$_\n";
}

sub trim {
  my @out = @_;
  for (@out) {
    s/^\s+//;
    s/\s+$//;
  }
  return wantarray ? @out : $out[0];
}

__DATA__
library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

use std.textio.all;

library work;
use work.zpu_config.all;
use work.zpupkg.all;
use work.txt_util.all;
 
entity  zpu_io is
  port( clk         : in std_logic;
           areset        : in std_logic;
        busy : out std_logic;
        writeEnable : in std_logic;
        readEnable : in std_logic;
        write    : in std_logic_vector(wordSize-1 downto 0);
        read    : out std_logic_vector(wordSize-1 downto 0);
        addr : in std_logic_vector(maxAddrBit downto minAddrBit);
end zpu_io;
   
   
architecture behave of zpu_io is

signal timer_read : std_logic_vector(7 downto 0);
--signal timer_write : std_logic_vector(7 downto 0);
signal timer_we : std_logic;

signal serving : std_logic;

file         l_file        : TEXT open write_mode is log_file;

begin
    
    process(areset, clk)
    begin
        if (areset = '1') then
        elsif (clk'event and clk = '1') then
            if writeEnable = '1' then
                -- external interface
                if addr=x"2028003" then
                    -- Write to UART
                    -- report "" & character'image(conv_integer(memBint)) severity note;
                    print(l_file, character'val(conv_integer(write)));
                elsif addr(12)='1' then
                else
                    print(l_file, character'val(conv_integer(write)));
                    report "Illegal IO write" severity warning;
                end if;
                
            end if;
            read <= (others => '0');
            if (readEnable = '1') then
                if addr=x"1001" then
                    read <= (0=>'1', others => '0'); -- recieve empty
                 elsif addr(12)='1' then
                     read(7 downto 0) <= timer_read;
                 elsif addr(11)='1' then
                     read(7 downto 0) <= ZPU_Frequency;
                 elsif addr=x"2028003" then
                    read <= (others => '0');
                else
                    read <= (others => '0');
                    read(8) <= '1';
                    report "Illegal IO read" severity warning;
                end if;
            end if;
        end if;
    end process;


end behave;
 
This is truly a beautiful piece of code. While->up to first stop...then While->from last stop->up to next stop....Multiple whiles segmented in regions. Yep this is probably what I was missing all this time! Thanx a million!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top