OpenCores
URL https://opencores.org/ocsvn/an-fpga-implementation-of-low-latency-noc-based-mpsoc/an-fpga-implementation-of-low-latency-noc-based-mpsoc/trunk

Subversion Repositories an-fpga-implementation-of-low-latency-noc-based-mpsoc

[/] [an-fpga-implementation-of-low-latency-noc-based-mpsoc/] [trunk/] [mpsoc/] [perl_gui/] [lib/] [perl/] [rvp.pm] - Diff between revs 25 and 48

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 25 Rev 48
###############################################################################
###############################################################################
#
#
# File:         rvp.pm
# File:         rvp.pm
# RCS:          $Header: /home/cc/v2html/build/../RCS/rvp.pm,v 7.61 2006/03/25 22:24:57 cc Exp $
# RCS:          $Header: /home/cc/v2html/build/../RCS/rvp.pm,v 7.61 2006/03/25 22:24:57 cc Exp $
# Description:  The Rough Verilog Parser Perl Module
# Description:  The Rough Verilog Parser Perl Module
# Author:       Costas Calamvokis
# Author:       Costas Calamvokis
# Created:      Fri Apr 10 16:59:30 1998
# Created:      Fri Apr 10 16:59:30 1998
# Modified:     Thu Jan 12 10:45:27 2006
# Modified:     Thu Jan 12 10:45:27 2006
# Language:     Perl
# Language:     Perl
#
#
# Copyright 1998-2006 Costas Calamvokis
# Copyright 1998-2006 Costas Calamvokis
#
#
#  This file nay be copied, modified and distributed only in accordance
#  This file nay be copied, modified and distributed only in accordance
#  with the terms of the limited licence contained in the accompanying
#  with the terms of the limited licence contained in the accompanying
#  file LICENCE.TXT.
#  file LICENCE.TXT.
#
#
###############################################################################
###############################################################################
#
#
 
 
=head1 rvp - Rough Verilog Parser Perl Module
=head1 rvp - Rough Verilog Parser Perl Module
 
 
The basic idea is that first you call read_verilog will a list of all of your
The basic idea is that first you call read_verilog will a list of all of your
files. The files are parsed and information stored away. You are then
files. The files are parsed and information stored away. You are then
handed back a pointer to the information which you can use in calls
handed back a pointer to the information which you can use in calls
to the various get_ function to get information about the verilog design.
to the various get_ function to get information about the verilog design.
 
 
For Example:
For Example:
 
 
 #!/usr/bin/perl -w
 #!/usr/bin/perl -w
 use rvp;   # use the rough verilog parser
 use rvp;   # use the rough verilog parser
 
 
 # Read in all the files specified on the command line
 # Read in all the files specified on the command line
 $vdata = rvp->read_verilog(\@ARGV,[],{},1,[],[],'');
 $vdata = rvp->read_verilog(\@ARGV,[],{},1,[],[],'');
 
 
 # Print out all the modules found
 # Print out all the modules found
 foreach $module ($vdata->get_modules()) { print "$module\n"; }
 foreach $module ($vdata->get_modules()) { print "$module\n"; }
 
 
Unless you are doing something very strange, you can probably ignore all
Unless you are doing something very strange, you can probably ignore all
of the functions that have the words 'context' or 'anchors' in them!
of the functions that have the words 'context' or 'anchors' in them!
 
 
=cut
=cut
 
 
package rvp;
package rvp;
 
 
#use strict;
#use strict;
#use Tie::IxHash;
#use Tie::IxHash;
 
 
use File::Basename;
use File::Basename;
 
 
use vars qw(@verilog_gatetype_keywords $verilog_gatetype_regexp
use vars qw(@verilog_gatetype_keywords $verilog_gatetype_regexp
            @verilog_compiler_keywords
            @verilog_compiler_keywords
            @verilog_signal_keywords @verilog_sigs $verilog_sigs_regexp
            @verilog_signal_keywords @verilog_sigs $verilog_sigs_regexp
            $quiet $debug $VID $HVID $VNUM
            $quiet $debug $VID $HVID $VNUM
            $takenArcs
            $takenArcs
            $baseEval $rvpEval $debugEval $languageDef $vid_vnum_or_string
            $baseEval $rvpEval $debugEval $languageDef $vid_vnum_or_string
            $version $VERSION);
            $version $VERSION);
 
 
BEGIN {
BEGIN {
    # $VERSION is used by 'use', but keep $version for backwards compatibility
    # $VERSION is used by 'use', but keep $version for backwards compatibility
    $version = '$Header: /home/cc/v2html/build/../RCS/rvp.pm,v 7.61 2006/03/25 22:24:57 cc Exp $'; #'
    $version = '$Header: /home/cc/v2html/build/../RCS/rvp.pm,v 7.61 2006/03/25 22:24:57 cc Exp $'; #'
    $version =~ s/^\S+ \S+ (\S+) .*$/$1/;
    $version =~ s/^\S+ \S+ (\S+) .*$/$1/;
    $VERSION = $version;
    $VERSION = $version;
 
 
    @verilog_signal_keywords = qw(input    output  inout
    @verilog_signal_keywords = qw(input    output  inout
                       wire     tri     tri1   supply0 wand  triand tri0
                       wire     tri     tri1   supply0 wand  triand tri0
                       supply1  wor     time   trireg  trior
                       supply1  wor     time   trireg  trior
                       reg      integer real   realtime
                       reg      integer real   realtime
 
 
                       genvar
                       genvar
                       );
                       );
    @verilog_sigs = @verilog_signal_keywords; # for backwards compatiblity
    @verilog_sigs = @verilog_signal_keywords; # for backwards compatiblity
 
 
    #V2001
    #V2001
 
 
    $verilog_sigs_regexp = "\\b(?:" .
    $verilog_sigs_regexp = "\\b(?:" .
        join("|",@verilog_signal_keywords) .
        join("|",@verilog_signal_keywords) .
            ")\\b";
            ")\\b";
 
 
    @verilog_gatetype_keywords = qw(and  nand  or  nor xor xnor  buf  bufif0 bufif1
    @verilog_gatetype_keywords = qw(and  nand  or  nor xor xnor  buf  bufif0 bufif1
                                    not  notif0 notif1  pulldown  pullup
                                    not  notif0 notif1  pulldown  pullup
                                    nmos  rnmos pmos rpmos cmos rcmos   tran rtran
                                    nmos  rnmos pmos rpmos cmos rcmos   tran rtran
                                    tranif0  rtranif0  tranif1 rtranif1
                                    tranif0  rtranif0  tranif1 rtranif1
                                    );
                                    );
 
 
    $verilog_gatetype_regexp = "\\b(?:" .
    $verilog_gatetype_regexp = "\\b(?:" .
        join("|",@verilog_gatetype_keywords) .
        join("|",@verilog_gatetype_keywords) .
            ")\\b";
            ")\\b";
 
 
    # Note: optimisation code in _search() assumes all of
    # Note: optimisation code in _search() assumes all of
    #  these compiler keywords contain a ` 
    #  these compiler keywords contain a ` 
    @verilog_compiler_keywords = qw(
    @verilog_compiler_keywords = qw(
     `celldefine            `define
     `celldefine            `define
     `delay_mode_path       `disable_portfaults
     `delay_mode_path       `disable_portfaults
     `else                  `enable_portfaults
     `else                  `enable_portfaults
     `endcelldefine         `endif
     `endcelldefine         `endif
     `ifdef                 `include
     `ifdef                 `include
     `nosuppress_faults     `suppress_faults
     `nosuppress_faults     `suppress_faults
     `timescale             `undef
     `timescale             `undef
     `resetall              `delay_mode_distributed
     `resetall              `delay_mode_distributed
 
 
     `default_nettype  `file `line `ifndef `elsif
     `default_nettype  `file `line `ifndef `elsif
    );    #`
    );    #`
 
 
    # a verilog identifier is this reg exp 
    # a verilog identifier is this reg exp 
    #  a non-escaped identifier is A-Z a-z _ 0-9 or $ 
    #  a non-escaped identifier is A-Z a-z _ 0-9 or $ 
    #  an escaped identifier is \ followed by non-whitespace
    #  an escaped identifier is \ followed by non-whitespace
    #   why \\\\\S+ ? This gets \\\S+ in to the string then when it
    #   why \\\\\S+ ? This gets \\\S+ in to the string then when it
    #   it used we get it searching for \ followed by non-whitespace (\S+)
    #   it used we get it searching for \ followed by non-whitespace (\S+)
    $VID = '(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+)';
    $VID = '(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+)';
 
 
    # hierarchical VID - just $VID(.$VID)+ but can't write it like this
    # hierarchical VID - just $VID(.$VID)+ but can't write it like this
    #  because of \ escaping (and must include whitespace after esc.ids.)
    #  because of \ escaping (and must include whitespace after esc.ids.)
    $HVID = '(?:(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+\s+)'.
    $HVID = '(?:(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+\s+)'.
           '(?:\.(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+\s+))+)';
           '(?:\.(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+\s+))+)';
  # V2001: added [sS] - is this correct
  # V2001: added [sS] - is this correct
    $VNUM= '(?:(?:[0-9]*\'[sS]?[bBhHdDoO]\s*[0-9A-Fa-f_zZxX?]+)|(?:[-0-9Ee._]+))';
    $VNUM= '(?:(?:[0-9]*\'[sS]?[bBhHdDoO]\s*[0-9A-Fa-f_zZxX?]+)|(?:[-0-9Ee._]+))';
 
 
 
 
    $quiet=0;
    $quiet=0;
    $debug=0;
    $debug=0;
 
 
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 read_verilog
=head1 read_verilog
 
 
reads in verilog files, parses them and stores results in an internal
reads in verilog files, parses them and stores results in an internal
data structure (which I call a RVP database).
data structure (which I call a RVP database).
 
 
  Arguments:  - reference to array of files to read (can have paths)
  Arguments:  - reference to array of files to read (can have paths)
              - reference to hash of defines with names as keys
              - reference to hash of defines with names as keys
              - reference to array of global includes - not used anymore,
              - reference to array of global includes - not used anymore,
                 just kept for backwards compatibility
                 just kept for backwards compatibility
              - quite flag. 1=be quiet, 0=be chatty.
              - quite flag. 1=be quiet, 0=be chatty.
              - reference to array of include directories
              - reference to array of include directories
              - reference to array of library directories
              - reference to array of library directories
              - library extension string (eg '.v') or reference to array of strings
              - library extension string (eg '.v') or reference to array of strings
 
 
  Returns:    - a pointer to the internal data structure.
  Returns:    - a pointer to the internal data structure.
 
 
  Example:
  Example:
    $defines{'TRUE'}=1;  # same as +define+TRUE=1 on verilog cmd line
    $defines{'TRUE'}=1;  # same as +define+TRUE=1 on verilog cmd line
    $vdata = rvp->read_verilog(\@files,[],\%defines,1,
    $vdata = rvp->read_verilog(\@files,[],\%defines,1,
                                     \@inc_dirs,\@lib_dirs,\@lib_exts);
                                     \@inc_dirs,\@lib_dirs,\@lib_exts);
 
 
=cut
=cut
sub read_verilog {
sub read_verilog {
    # be backwards compatible with non-OO call
    # be backwards compatible with non-OO call
    my $class = ("ARRAY" eq ref $_[0]) ? "rvp" : shift;
    my $class = ("ARRAY" eq ref $_[0]) ? "rvp" : shift;
    my ($files,$global_includes,$cmd_line_defines,$local_quiet,$inc_dirs,
    my ($files,$global_includes,$cmd_line_defines,$local_quiet,$inc_dirs,
        $lib_dirs,$lib_ext_arg,$exp)
        $lib_dirs,$lib_ext_arg,$exp)
        = @_;
        = @_;
    my ($file,$fb,$old_quiet,@search_files,@new_search_files,$lib_exts);
    my ($file,$fb,$old_quiet,@search_files,@new_search_files,$lib_exts);
 
 
    my $self;
    my $self;
 
 
    die "read_verilog needs an array ref as arg 1" unless "ARRAY" eq ref $files;
    die "read_verilog needs an array ref as arg 1" unless "ARRAY" eq ref $files;
    die "read_verilog needs an hash ref as arg 2" unless "HASH" eq ref $cmd_line_defines;
    die "read_verilog needs an hash ref as arg 2" unless "HASH" eq ref $cmd_line_defines;
    die "read_verilog needs 0 or 1 as arg 3" unless $local_quiet==0 || $local_quiet==1;
    die "read_verilog needs 0 or 1 as arg 3" unless $local_quiet==0 || $local_quiet==1;
 
 
    # be backwards compatible
    # be backwards compatible
    if (!defined($inc_dirs)) { $inc_dirs=[]; }
    if (!defined($inc_dirs)) { $inc_dirs=[]; }
    if (!defined($lib_dirs)) { $lib_dirs=[]; }
    if (!defined($lib_dirs)) { $lib_dirs=[]; }
 
 
    if (!defined($lib_ext_arg)) {  # no libexts given
    if (!defined($lib_ext_arg)) {  # no libexts given
        $lib_exts=[''];
        $lib_exts=[''];
    }
    }
    elsif (!ref($lib_ext_arg))  {  # a string given
    elsif (!ref($lib_ext_arg))  {  # a string given
        $lib_exts=[$lib_ext_arg];
        $lib_exts=[$lib_ext_arg];
    }
    }
    else {                         # an array ref given
    else {                         # an array ref given
        $lib_exts=$lib_ext_arg;
        $lib_exts=$lib_ext_arg;
    }
    }
 
 
 
 
    # make the parser
    # make the parser
    if (! defined &parse_line) {
    if (! defined &parse_line) {
 
 
        my $perlCode=_make_parser( $debug ? [ $baseEval,$debugEval,$rvpEval ]:
        my $perlCode=_make_parser( $debug ? [ $baseEval,$debugEval,$rvpEval ]:
                                          [ $baseEval,$rvpEval ] ,
                                          [ $baseEval,$rvpEval ] ,
                                 $debug );
                                 $debug );
        if ($debug) {
        if ($debug) {
            open(PC,">v2html-parser.pl");
            open(PC,">v2html-parser.pl");
            print PC $perlCode;
            print PC $perlCode;
        }
        }
        eval($perlCode);
        eval($perlCode);
        print STDERR $@ if ($@);
        print STDERR $@ if ($@);
    }
    }
 
 
    if (! defined &_parse_line) { die "Parse code generation failed";}
    if (! defined &_parse_line) { die "Parse code generation failed";}
 
 
    $old_quiet=$quiet;
    $old_quiet=$quiet;
    $quiet=$local_quiet;
    $quiet=$local_quiet;
    # set up top of main data structure
    # set up top of main data structure
    $self = {};
    $self = {};
    $self->{files}               = {}; # information on each file
    $self->{files}               = {}; # information on each file
    $self->{modules}             = {}; # pointers to module info in {files}
    $self->{modules}             = {}; # pointers to module info in {files}
    $self->{defines}             = {};
    $self->{defines}             = {};
    $self->{ignored_modules}     = {}; # list of modules were duplicates were found
    $self->{ignored_modules}     = {}; # list of modules were duplicates were found
    $self->{unresolved_modules}  = {}; # modules we have not found yet
    $self->{unresolved_modules}  = {}; # modules we have not found yet
    $self->{problems}            = []; # warning/confused messages
    $self->{problems}            = []; # warning/confused messages
 
 
    bless($self,$class);
    bless($self,$class);
 
 
    foreach my $d (keys(%$cmd_line_defines)) {
    foreach my $d (keys(%$cmd_line_defines)) {
        _add_define($self->{defines}, $d , $cmd_line_defines->{$d}, '', 0 );
        _add_define($self->{defines}, $d , $cmd_line_defines->{$d}, '', 0 );
    }
    }
 
 
    # go through all the files and find information
    # go through all the files and find information
    @new_search_files = @{$files};
    @new_search_files = @{$files};
    while (@new_search_files) {
    while (@new_search_files) {
        @search_files = @new_search_files;
        @search_files = @new_search_files;
        @new_search_files = ();
        @new_search_files = ();
        foreach $file (@search_files) {
        foreach $file (@search_files) {
            $self->_search($file,$inc_dirs);
            $self->_search($file,$inc_dirs);
        }
        }
        push( @new_search_files , _resolve_modules( $self, $lib_dirs, $lib_exts ) );
        push( @new_search_files , _resolve_modules( $self, $lib_dirs, $lib_exts ) );
    }
    }
 
 
 
 
    if ($debug) {
    if ($debug) {
        _check_coverage();
        _check_coverage();
    }
    }
 
 
    # cross reference files' information
    # cross reference files' information
    print "Cross referencing\n" unless $quiet;
    print "Cross referencing\n" unless $quiet;
    $self->_cross_reference();
    $self->_cross_reference();
 
 
    $quiet=$old_quiet;
    $quiet=$old_quiet;
 
 
    foreach my $m ( sort (keys %{$self->{unresolved_modules}} )) {
    foreach my $m ( sort (keys %{$self->{unresolved_modules}} )) {
        # find somewhere it is instantiated for warning message
        # find somewhere it is instantiated for warning message
        my $file="";
        my $file="";
        my $line="";
        my $line="";
        foreach my $m2 (sort (keys %{$self->{modules}})) {
        foreach my $m2 (sort (keys %{$self->{modules}})) {
            foreach my $inst (@{$self->{modules}{$m2}{instances}}) {
            foreach my $inst (@{$self->{modules}{$m2}{instances}}) {
                if ($inst->{module} eq $m) {
                if ($inst->{module} eq $m) {
                    $file = $inst->{file};
                    $file = $inst->{file};
                    $line = $inst->{line};
                    $line = $inst->{line};
                    last;
                    last;
                }
                }
            }
            }
        }
        }
        #$self->_add_warning("$file:$line: Could not find module $m");
        #$self->_add_warning("$file:$line: Could not find module $m");
    }
    }
    return $self;
    return $self;
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_problems
=head1 get_problems
 
 
Return any problems that happened during parsing
Return any problems that happened during parsing
 
 
  Returns:    - array of strings of problems. Each one is:
  Returns:    - array of strings of problems. Each one is:
                    "TYPE:FILE:LINE: description"
                    "TYPE:FILE:LINE: description"
 
 
=cut
=cut
sub get_problems {
sub get_problems {
    my ($self) = @_;
    my ($self) = @_;
 
 
    return (@{$self->{problems}});
    return (@{$self->{problems}});
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 set_debug
=head1 set_debug
 
 
Turns on debug printing in the parser.
Turns on debug printing in the parser.
 
 
  Returns:    - nothing
  Returns:    - nothing
 
 
=cut
=cut
sub set_debug {
sub set_debug {
    $debug=1;
    $debug=1;
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 unset_debug
=head1 unset_debug
 
 
Turns off debug printing in the parser.
Turns off debug printing in the parser.
 
 
  Returns:    - nothing
  Returns:    - nothing
 
 
=cut
=cut
sub unset_debug {
sub unset_debug {
    $debug=0;
    $debug=0;
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_files
=head1 get_files
 
 
Get a list of all the files in the database.
Get a list of all the files in the database.
 
 
  Returns:    - list of all the files
  Returns:    - list of all the files
 
 
  Example:   @all_files = $vdata->get_files();
  Example:   @all_files = $vdata->get_files();
 
 
=cut
=cut
sub get_files{
sub get_files{
    my ($self) = @_;
    my ($self) = @_;
 
 
    if (wantarray) {
    if (wantarray) {
        return sort (keys %{$self->{files}});
        return sort (keys %{$self->{files}});
    }
    }
    else { # in a scalar context keys returns the number of elements - sort doesn't
    else { # in a scalar context keys returns the number of elements - sort doesn't
        return keys %{$self->{files}};
        return keys %{$self->{files}};
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_files_modules
=head1 get_files_modules
 
 
Get a list of all the modules in a particular file.
Get a list of all the modules in a particular file.
 
 
  Arguments:  - name of file
  Arguments:  - name of file
 
 
  Returns:    - list of module names
  Returns:    - list of module names
 
 
  Example:   @modules = $vdata->get_files_modules($file);
  Example:   @modules = $vdata->get_files_modules($file);
 
 
=cut
=cut
sub get_files_modules{
sub get_files_modules{
    my ($self,$file) = @_;
    my ($self,$file) = @_;
    my (@modules,$m);
    my (@modules,$m);
 
 
    foreach $m (sort (keys %{$self->{files}{$file}{modules}})) {
    foreach $m (sort (keys %{$self->{files}{$file}{modules}})) {
        push(@modules,$m)
        push(@modules,$m)
    }
    }
 
 
    return @modules;
    return @modules;
}
}
 
 
 
 
###########################################################################
###########################################################################
 
 
=head1 get_files_full_name
=head1 get_files_full_name
 
 
Get the full name (including path) of a file.
Get the full name (including path) of a file.
 
 
  Arguments:  - name of file
  Arguments:  - name of file
 
 
  Returns:    - full path name
  Returns:    - full path name
 
 
  Example  $full_name = $vdata->get_files_full_name($file);
  Example  $full_name = $vdata->get_files_full_name($file);
 
 
=cut
=cut
sub get_files_full_name{
sub get_files_full_name{
    my ($self,$file) = @_;
    my ($self,$file) = @_;
 
 
    return $self->{files}{$file}{full_name};
    return $self->{files}{$file}{full_name};
 
 
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_files_stats
=head1 get_files_stats
 
 
Get statistics about a file
Get statistics about a file
 
 
  Arguments:  - name of file
  Arguments:  - name of file
 
 
  Returns:    - number of lines in the file (more later...)
  Returns:    - number of lines in the file (more later...)
 
 
  Example  $full_name = $vdata->get_files_stats($file);
  Example  $full_name = $vdata->get_files_stats($file);
 
 
=cut
=cut
sub get_files_stats{
sub get_files_stats{
    my ($self,$file) = @_;
    my ($self,$file) = @_;
 
 
    return $self->{files}{$file}{lines};
    return $self->{files}{$file}{lines};
 
 
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 file_exists
=head1 file_exists
 
 
Test if a particular module file  in the database.
Test if a particular module file  in the database.
 
 
  Arguments:  - file name to test.
  Arguments:  - file name to test.
 
 
  Returns:    - 1 if exists otherwise 0
  Returns:    - 1 if exists otherwise 0
 
 
  Example:   if ($vdata->file_exists($file))....
  Example:   if ($vdata->file_exists($file))....
 
 
=cut
=cut
sub file_exists{
sub file_exists{
    my ($self,$file) = @_;
    my ($self,$file) = @_;
    return exists($self->{files}{_ffile($file)});
    return exists($self->{files}{_ffile($file)});
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_modules
=head1 get_modules
 
 
Get a list of all the modules in the database.
Get a list of all the modules in the database.
 
 
 
 
  Returns:   - list of all the modules
  Returns:   - list of all the modules
 
 
  Example:   @all_modules = $vdata->get_modules();
  Example:   @all_modules = $vdata->get_modules();
 
 
=cut
=cut
sub get_modules{
sub get_modules{
    my ($self) = @_;
    my ($self) = @_;
 
 
    if (wantarray) {
    if (wantarray) {
        return sort (keys %{$self->{modules}});
        return sort (keys %{$self->{modules}});
    }
    }
    else { # in a scalar context keys returns the number of elements - sort doesn't
    else { # in a scalar context keys returns the number of elements - sort doesn't
        return keys %{$self->{modules}};
        return keys %{$self->{modules}};
    }
    }
 
 
}
}
 
 
 
 
###########################################################################
###########################################################################
 
 
=head1 get_modules_t_and_f
=head1 get_modules_t_and_f
 
 
Get a list of all the tasks and functions in a particular module.
Get a list of all the tasks and functions in a particular module.
 
 
  Arguments:  - name of module
  Arguments:  - name of module
 
 
  Returns:    - list of tasks and function names
  Returns:    - list of tasks and function names
 
 
  Example:    if ( @t_and_f = $vdata->get_modules_t_and_f($m))...
  Example:    if ( @t_and_f = $vdata->get_modules_t_and_f($m))...
 
 
=cut
=cut
# return a list of all the tasks and functions in a module
# return a list of all the tasks and functions in a module
sub get_modules_t_and_f{
sub get_modules_t_and_f{
    my ($self,$module) = @_;
    my ($self,$module) = @_;
 
 
    if (wantarray) {
    if (wantarray) {
        return sort (keys %{$self->{modules}{$module}{t_and_f}});
        return sort (keys %{$self->{modules}{$module}{t_and_f}});
    }
    }
    else { # in a scalar context keys returns the number of elements - sort doesn't
    else { # in a scalar context keys returns the number of elements - sort doesn't
        return keys %{$self->{modules}{$module}{t_and_f}};
        return keys %{$self->{modules}{$module}{t_and_f}};
    }
    }
 
 
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_modules_t_or_f
=head1 get_modules_t_or_f
 
 
Get information on a task or function in a module.
Get information on a task or function in a module.
 
 
  Arguments:  - module name
  Arguments:  - module name
              - task or function name
              - task or function name
 
 
  Returns:    - A 4 element list: type (task or function), definition line,
  Returns:    - A 4 element list: type (task or function), definition line,
                  file, anchor
                  file, anchor
 
 
  Example:    ($t_type,$t_line ,$t_file,$t_anchor)=
  Example:    ($t_type,$t_line ,$t_file,$t_anchor)=
                $vdata->get_modules_t_or_f($m,$tf);
                $vdata->get_modules_t_or_f($m,$tf);
 
 
=cut
=cut
sub get_modules_t_or_f{
sub get_modules_t_or_f{
    my ($self,$mod,$t_or_f) = @_;
    my ($self,$mod,$t_or_f) = @_;
 
 
    if (exists($self->{modules}{$mod}{t_and_f}{$t_or_f})) {
    if (exists($self->{modules}{$mod}{t_and_f}{$t_or_f})) {
        return($self->{modules}{$mod}{t_and_f}{$t_or_f}{type},
        return($self->{modules}{$mod}{t_and_f}{$t_or_f}{type},
               $self->{modules}{$mod}{t_and_f}{$t_or_f}{line},
               $self->{modules}{$mod}{t_and_f}{$t_or_f}{line},
               $self->{modules}{$mod}{t_and_f}{$t_or_f}{file},
               $self->{modules}{$mod}{t_and_f}{$t_or_f}{file},
               $self->{modules}{$mod}{t_and_f}{$t_or_f}{anchor});
               $self->{modules}{$mod}{t_and_f}{$t_or_f}{anchor});
    }
    }
    else {
    else {
        return ();
        return ();
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_modules_signals
=head1 get_modules_signals
 
 
Get a list of all the signals in a particular module.
Get a list of all the signals in a particular module.
 
 
  Arguments:  - name of module
  Arguments:  - name of module
 
 
  Returns:    - list of signal names
  Returns:    - list of signal names
 
 
  Example:    if ( @signs = $vdata->get_modules_signals($m))...
  Example:    if ( @signs = $vdata->get_modules_signals($m))...
 
 
=cut
=cut
# return a list of all the tasks and functions in a module
# return a list of all the tasks and functions in a module
sub get_modules_signals{
sub get_modules_signals{
    my ($self,$module) = @_;
    my ($self,$module) = @_;
 
 
    if (wantarray) {
    if (wantarray) {
        return sort (keys %{$self->{modules}{$module}{signals}});
        return sort (keys %{$self->{modules}{$module}{signals}});
    }
    }
    else { # in a scalar context keys returns the number of elements - sort doesn't
    else { # in a scalar context keys returns the number of elements - sort doesn't
        return keys %{$self->{modules}{$module}{signals}};
        return keys %{$self->{modules}{$module}{signals}};
    }
    }
 
 
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_modules_file
=head1 get_modules_file
 
 
Get the file name (no path) that a module is defined in.
Get the file name (no path) that a module is defined in.
 
 
  Arguments:  - module name
  Arguments:  - module name
 
 
  Returns:    - file name without path, and the line number module starts on
  Returns:    - file name without path, and the line number module starts on
 
 
  Example:    ($f) = $vdata->get_modules_file($m);
  Example:    ($f) = $vdata->get_modules_file($m);
 
 
=cut
=cut
# get the file name that contains a module
# get the file name that contains a module
sub get_modules_file{
sub get_modules_file{
    my ($self,$module) = @_;
    my ($self,$module) = @_;
 
 
    return ($self->{modules}{$module}{file},$self->{modules}{$module}{line});
    return ($self->{modules}{$module}{file},$self->{modules}{$module}{line});
}
}
 
 
 
 
###########################################################################
###########################################################################
 
 
=head1 get_modules_type
=head1 get_modules_type
 
 
Get the type of the module - It is one of: module, macromodule or primitive
Get the type of the module - It is one of: module, macromodule or primitive
(rvp treats these all as modules).
(rvp treats these all as modules).
 
 
  Arguments:  - module name
  Arguments:  - module name
 
 
  Returns:    - type
  Returns:    - type
 
 
  Example:    $t = $vdata->get_modules_type($m);
  Example:    $t = $vdata->get_modules_type($m);
 
 
=cut
=cut
# get the file name that contains a module
# get the file name that contains a module
sub get_modules_type{
sub get_modules_type{
    my ($self,$module) = @_;
    my ($self,$module) = @_;
 
 
    return ($self->{modules}{$module}{type});
    return ($self->{modules}{$module}{type});
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_files_includes
=head1 get_files_includes
 
 
Get the file names (no path) of files included in a file.
Get the file names (no path) of files included in a file.
 
 
  Arguments:  - file name
  Arguments:  - file name
 
 
  Returns:    - list of file names without paths
  Returns:    - list of file names without paths
 
 
  Example:    @f = $vdata->get_files_includes($file);
  Example:    @f = $vdata->get_files_includes($file);
 
 
=cut
=cut
sub get_files_includes {
sub get_files_includes {
    my ($self,$f) = @_;
    my ($self,$f) = @_;
    my @includes_found = ();
    my @includes_found = ();
 
 
    if (exists($self->{files}{$f})) {
    if (exists($self->{files}{$f})) {
        foreach my $inc ( sort ( keys %{$self->{files}{$f}{includes}} )) {
        foreach my $inc ( sort ( keys %{$self->{files}{$f}{includes}} )) {
            push(@includes_found,$inc);
            push(@includes_found,$inc);
            # do the includes for the included file
            # do the includes for the included file
            push(@includes_found, $self->get_files_includes($inc));
            push(@includes_found, $self->get_files_includes($inc));
        }
        }
    }
    }
 
 
    return @includes_found;
    return @includes_found;
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_files_included_by
=head1 get_files_included_by
 
 
Get the file names (no path) of files that included this file.
Get the file names (no path) of files that included this file.
 
 
  Arguments:  - file name
  Arguments:  - file name
 
 
  Returns:    - list of file names without paths
  Returns:    - list of file names without paths
 
 
  Example:    @f = $vdata->get_files_included_by($file);
  Example:    @f = $vdata->get_files_included_by($file);
 
 
=cut
=cut
sub get_files_included_by {
sub get_files_included_by {
    my ($self,$f) = @_;
    my ($self,$f) = @_;
 
 
    return @{$self->{files}{$f}{included_by}};
    return @{$self->{files}{$f}{included_by}};
 
 
}
}
 
 
 
 
###########################################################################
###########################################################################
 
 
=head1 module_ignored
=head1 module_ignored
 
 
Test if a particular module has been ignored because of duplicates found
Test if a particular module has been ignored because of duplicates found
 
 
  Arguments:  - module name to test
  Arguments:  - module name to test
 
 
  Returns:    - 1 if ignored otherwise 0
  Returns:    - 1 if ignored otherwise 0
 
 
  Example:   if ($vdata->module_ignored($module))....
  Example:   if ($vdata->module_ignored($module))....
 
 
=cut
=cut
sub module_ignored {
sub module_ignored {
    my ($self,$module) = @_;
    my ($self,$module) = @_;
    return (exists($self->{modules}{$module}) &&
    return (exists($self->{modules}{$module}) &&
            $self->{modules}{$module}{duplicate});
            $self->{modules}{$module}{duplicate});
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 module_exists
=head1 module_exists
 
 
Test if a particular module exists in the database.
Test if a particular module exists in the database.
 
 
  Arguments:  - module name to test
  Arguments:  - module name to test
 
 
  Returns:    - 1 if exists otherwise 0
  Returns:    - 1 if exists otherwise 0
 
 
  Example:   if ($vdata->module_exists($module))....
  Example:   if ($vdata->module_exists($module))....
 
 
=cut
=cut
sub module_exists{
sub module_exists{
    my ($self,$module) = @_;
    my ($self,$module) = @_;
    return exists($self->{modules}{$module});
    return exists($self->{modules}{$module});
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_ignored_modules
=head1 get_ignored_modules
 
 
Return a list of the ignored modules. These are modules where duplicates
Return a list of the ignored modules. These are modules where duplicates
have been found.
have been found.
 
 
  Returns:    - List of ignored modules
  Returns:    - List of ignored modules
 
 
  Example:    - foreach $module ($vdata->get_ignored_modules())....
  Example:    - foreach $module ($vdata->get_ignored_modules())....
 
 
=cut
=cut
sub get_ignored_modules {
sub get_ignored_modules {
    my ($self) = @_;
    my ($self) = @_;
    my @ig =();
    my @ig =();
    foreach my $m (sort (keys %{$self->{modules}})) {
    foreach my $m (sort (keys %{$self->{modules}})) {
        push(@ig, $m) if ($self->{modules}{$m}{duplicate});
        push(@ig, $m) if ($self->{modules}{$m}{duplicate});
    }
    }
    return @ig;
    return @ig;
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_module_signal
=head1 get_module_signal
 
 
Get information about a particular signal in a particular module.
Get information about a particular signal in a particular module.
 
 
  Arguments:  - name of module
  Arguments:  - name of module
              - name of signal
              - name of signal
 
 
  Returns:    - A list containing:
  Returns:    - A list containing:
                 - the line signal is defined
                 - the line signal is defined
                 - the line signal is assigned first (or -1)
                 - the line signal is assigned first (or -1)
                 - line in instantiating module where an input
                 - line in instantiating module where an input
                       is driven from (or -1)
                       is driven from (or -1)
                 - the type of the signal (input,output,reg etc)
                 - the type of the signal (input,output,reg etc)
                 - the file the signal is in
                 - the file the signal is in
                 - posedge flag (1 if signal ever seen with posedge)
                 - posedge flag (1 if signal ever seen with posedge)
                 - negedge flag (1 if signal ever seen with negedge)
                 - negedge flag (1 if signal ever seen with negedge)
                 - second type (eg reg for a registered output)
                 - second type (eg reg for a registered output)
                 - signal real source file
                 - signal real source file
                 - signal real source line
                 - signal real source line
                 - range string if any ( not including [ and ] )
                 - range string if any ( not including [ and ] )
                 - the file signal is assigned first (or '')
                 - the file signal is assigned first (or '')
                 - file for the instantiating module where an input
                 - file for the instantiating module where an input
                       is driven from (or "")
                       is driven from (or "")
                 - a pointer to an array of dimensions for memories
                 - a pointer to an array of dimensions for memories
                       each element of the array is a dimension, array
                       each element of the array is a dimension, array
                       is empty for non-memories
                       is empty for non-memories
 
 
  Note posedge and negedge information is propagated up the hierarchy to
  Note posedge and negedge information is propagated up the hierarchy to
  attached signals. It is not propagated down the hierarchy.
  attached signals. It is not propagated down the hierarchy.
 
 
  Example:    ($s_line,$s_a_line,$s_i_line,$s_type,$s_file,$s_p,$s_n,
  Example:    ($s_line,$s_a_line,$s_i_line,$s_type,$s_file,$s_p,$s_n,
               $s_type2,$s_r_file,$s_r_line,$range,$s_a_file,$s_i_file) =
               $s_type2,$s_r_file,$s_r_line,$range,$s_a_file,$s_i_file) =
                      $vdata->get_module_signal($m,$sig);
                      $vdata->get_module_signal($m,$sig);
 
 
=cut
=cut
sub get_module_signal{
sub get_module_signal{
    my ($self,$module,$sig) = @_;
    my ($self,$module,$sig) = @_;
 
 
    if (exists( $self->{modules}{$module}{signals}{$sig} )) {
    if (exists( $self->{modules}{$module}{signals}{$sig} )) {
        return ($self->{modules}{$module}{signals}{$sig}{line},
        return ($self->{modules}{$module}{signals}{$sig}{line},
                $self->{modules}{$module}{signals}{$sig}{a_line},
                $self->{modules}{$module}{signals}{$sig}{a_line},
                $self->{modules}{$module}{signals}{$sig}{i_line},
                $self->{modules}{$module}{signals}{$sig}{i_line},
                $self->{modules}{$module}{signals}{$sig}{type},
                $self->{modules}{$module}{signals}{$sig}{type},
                $self->{modules}{$module}{signals}{$sig}{file},
                $self->{modules}{$module}{signals}{$sig}{file},
                $self->{modules}{$module}{signals}{$sig}{posedge},
                $self->{modules}{$module}{signals}{$sig}{posedge},
                $self->{modules}{$module}{signals}{$sig}{negedge},
                $self->{modules}{$module}{signals}{$sig}{negedge},
                $self->{modules}{$module}{signals}{$sig}{type2},
                $self->{modules}{$module}{signals}{$sig}{type2},
                $self->{modules}{$module}{signals}{$sig}{source}{file},
                $self->{modules}{$module}{signals}{$sig}{source}{file},
                $self->{modules}{$module}{signals}{$sig}{source}{line},
                $self->{modules}{$module}{signals}{$sig}{source}{line},
                $self->{modules}{$module}{signals}{$sig}{range},
                $self->{modules}{$module}{signals}{$sig}{range},
                $self->{modules}{$module}{signals}{$sig}{a_file},
                $self->{modules}{$module}{signals}{$sig}{a_file},
                $self->{modules}{$module}{signals}{$sig}{i_file},
                $self->{modules}{$module}{signals}{$sig}{i_file},
                $self->{modules}{$module}{signals}{$sig}{dimensions});
                $self->{modules}{$module}{signals}{$sig}{dimensions});
    }
    }
    else {
    else {
        return ();
        return ();
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_first_signal_port_con
=head1 get_first_signal_port_con
 
 
Get the first port that this signal in this module is connected to.
Get the first port that this signal in this module is connected to.
 
 
  Arguments:  - module name
  Arguments:  - module name
              - signal name
              - signal name
 
 
  Returns:    - a 5 element list: instantiated module name, instance name
  Returns:    - a 5 element list: instantiated module name, instance name
                  port name, line number and file
                  port name, line number and file
 
 
  Example:    ($im,$in,$p,$l,$f)=$vdata->get_first_signal_port_con($m,$s);
  Example:    ($im,$in,$p,$l,$f)=$vdata->get_first_signal_port_con($m,$s);
 
 
=cut
=cut
sub get_first_signal_port_con{
sub get_first_signal_port_con{
    my ($self,$module,$signal) = @_;
    my ($self,$module,$signal) = @_;
 
 
    $self->{current_signal_port_con}       =0;
    $self->{current_signal_port_con}       =0;
    $self->{current_signal_port_con_module}=$module;
    $self->{current_signal_port_con_module}=$module;
    $self->{current_signal_port_con_module_signal}=$signal;
    $self->{current_signal_port_con_module_signal}=$signal;
 
 
    return $self->get_next_signal_port_con();
    return $self->get_next_signal_port_con();
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_next_signal_port_con
=head1 get_next_signal_port_con
 
 
Get the next port that this signal in this module is connected to.
Get the next port that this signal in this module is connected to.
 
 
  Returns:    - a 5 element list: instantiated module name, instance name
  Returns:    - a 5 element list: instantiated module name, instance name
                  port name, line number and file
                  port name, line number and file
 
 
  Example:    ($im,$in,$p,$l,$f)=$vdata->get_next_signal_port_con();
  Example:    ($im,$in,$p,$l,$f)=$vdata->get_next_signal_port_con();
 
 
=cut
=cut
sub get_next_signal_port_con{
sub get_next_signal_port_con{
    my ($self) = @_;
    my ($self) = @_;
    my ($module,$signal,$i,$pcref);
    my ($module,$signal,$i,$pcref);
 
 
    $module = $self->{current_signal_port_con_module};
    $module = $self->{current_signal_port_con_module};
    $signal = $self->{current_signal_port_con_module_signal};
    $signal = $self->{current_signal_port_con_module_signal};
    $i      = $self->{current_signal_port_con};
    $i      = $self->{current_signal_port_con};
 
 
    $pcref = $self->{modules}{$module}{signals}{$signal}{port_con};
    $pcref = $self->{modules}{$module}{signals}{$signal}{port_con};
    if (@{$pcref} > $i ) {
    if (@{$pcref} > $i ) {
        $self->{current_signal_port_con}++;
        $self->{current_signal_port_con}++;
        return ( $pcref->[$i]{module},$pcref->[$i]{inst},$pcref->[$i]{port},
        return ( $pcref->[$i]{module},$pcref->[$i]{inst},$pcref->[$i]{port},
                $pcref->[$i]{line},$pcref->[$i]{file});
                $pcref->[$i]{line},$pcref->[$i]{file});
    }
    }
    else {
    else {
        return ();
        return ();
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_first_signal_con_to
=head1 get_first_signal_con_to
 
 
Get the first signal that is connected to this port in an
Get the first signal that is connected to this port in an
instantiation of this module. This only works for instances that use
instantiation of this module. This only works for instances that use
the .port(sig) notation.
the .port(sig) notation.
 
 
  Arguments:  - module name
  Arguments:  - module name
              - signal name
              - signal name
 
 
  Returns:    - a 4 element list: signal connected to this port
  Returns:    - a 4 element list: signal connected to this port
                                  module signal is in
                                  module signal is in
                                  instance (of this module) where the connection
                                  instance (of this module) where the connection
                                    occurs
                                    occurs
 
 
  Example:    ($cts,$ctm,$cti)=$vdata->get_first_signal_con_to($m,$s);
  Example:    ($cts,$ctm,$cti)=$vdata->get_first_signal_con_to($m,$s);
 
 
=cut
=cut
sub get_first_signal_con_to{
sub get_first_signal_con_to{
    my ($self,$module,$signal) = @_;
    my ($self,$module,$signal) = @_;
 
 
    $self->{current_signal_con_to}       =0;
    $self->{current_signal_con_to}       =0;
    $self->{current_signal_con_to_module}=$module;
    $self->{current_signal_con_to_module}=$module;
    $self->{current_signal_con_to_module_signal}=$signal;
    $self->{current_signal_con_to_module_signal}=$signal;
 
 
    return $self->get_next_signal_con_to();
    return $self->get_next_signal_con_to();
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_next_signal_con_to
=head1 get_next_signal_con_to
 
 
Get the next signal that is connected to this port in an
Get the next signal that is connected to this port in an
instantiation of this module. This only works for instances that use
instantiation of this module. This only works for instances that use
the .port(sig) notation.
the .port(sig) notation.
 
 
  Arguments:  - module name
  Arguments:  - module name
              - signal name
              - signal name
 
 
  Returns:    - a 4 element list: signal connected to this port
  Returns:    - a 4 element list: signal connected to this port
                                  module signal is in
                                  module signal is in
                                  instance (of this module) where the connection
                                  instance (of this module) where the connection
                                    occurs
                                    occurs
 
 
  Example:    ($cts,$ctm,$cti)=$vdata->get_next_signal_con_to();
  Example:    ($cts,$ctm,$cti)=$vdata->get_next_signal_con_to();
 
 
=cut
=cut
sub get_next_signal_con_to{
sub get_next_signal_con_to{
    my ($self) = @_;
    my ($self) = @_;
    my ($module,$signal,$i,$ctref);
    my ($module,$signal,$i,$ctref);
 
 
    $module = $self->{current_signal_con_to_module};
    $module = $self->{current_signal_con_to_module};
    $signal = $self->{current_signal_con_to_module_signal};
    $signal = $self->{current_signal_con_to_module_signal};
    $i      = $self->{current_signal_con_to};
    $i      = $self->{current_signal_con_to};
 
 
    $ctref = $self->{modules}{$module}{signals}{$signal}{con_to};
    $ctref = $self->{modules}{$module}{signals}{$signal}{con_to};
    if (@{$ctref} > $i ) {
    if (@{$ctref} > $i ) {
        $self->{current_signal_con_to}++;
        $self->{current_signal_con_to}++;
        return ( $ctref->[$i]{signal},$ctref->[$i]{module},$ctref->[$i]{inst});
        return ( $ctref->[$i]{signal},$ctref->[$i]{module},$ctref->[$i]{inst});
    }
    }
    else {
    else {
        return ();
        return ();
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_first_instantiator
=head1 get_first_instantiator
 
 
Get the first thing that instantiates this module.
Get the first thing that instantiates this module.
 
 
  Arguments:  - module name
  Arguments:  - module name
 
 
  Returns:    - a 4 element list: instantiating module, file, instance name, line
  Returns:    - a 4 element list: instantiating module, file, instance name, line
 
 
  Example:
  Example:
                ($im,$f,$i) = $vdata->get_first_instantiator($m );
                ($im,$f,$i) = $vdata->get_first_instantiator($m );
 
 
=cut
=cut
# Get the first thing that instantiates or empty list if none.
# Get the first thing that instantiates or empty list if none.
#  Returns: { module, file, inst }
#  Returns: { module, file, inst }
sub get_first_instantiator{
sub get_first_instantiator{
    my ($self,$module) = @_;
    my ($self,$module) = @_;
 
 
    if ( exists( $self->{modules}{$module} )) {
    if ( exists( $self->{modules}{$module} )) {
        $self->{current_instantiator}       =0;
        $self->{current_instantiator}       =0;
        $self->{current_instantiator_module}=$module;
        $self->{current_instantiator_module}=$module;
        return $self->get_next_instantiator();
        return $self->get_next_instantiator();
    }
    }
    else {
    else {
        return ();
        return ();
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_next_instantiator
=head1 get_next_instantiator
 
 
Get the first thing that instantiates the module specified in
Get the first thing that instantiates the module specified in
get_first_instantiator (or _by_context).
get_first_instantiator (or _by_context).
 
 
  Returns:    - a 4 element list: instantiating module, file,
  Returns:    - a 4 element list: instantiating module, file,
                                    instance name, line
                                    instance name, line
 
 
  Example:
  Example:
                ($im,$f,$i) = $vdata->get_next_instantiator();
                ($im,$f,$i) = $vdata->get_next_instantiator();
 
 
=cut
=cut
sub get_next_instantiator{
sub get_next_instantiator{
    my ($self) = @_;
    my ($self) = @_;
    my ($module,$i);
    my ($module,$i);
 
 
    $module = $self->{current_instantiator_module};
    $module = $self->{current_instantiator_module};
    $i      = $self->{current_instantiator};
    $i      = $self->{current_instantiator};
 
 
    if (@{$self->{modules}{$module}{inst_by}} > $i ) {
    if (@{$self->{modules}{$module}{inst_by}} > $i ) {
        $self->{current_instantiator}++;
        $self->{current_instantiator}++;
        return ($self->{modules}{$module}{inst_by}[$i]{module},
        return ($self->{modules}{$module}{inst_by}[$i]{module},
                $self->{modules}{$module}{inst_by}[$i]{file},
                $self->{modules}{$module}{inst_by}[$i]{file},
                $self->{modules}{$module}{inst_by}[$i]{inst},
                $self->{modules}{$module}{inst_by}[$i]{inst},
                $self->{modules}{$module}{inst_by}[$i]{line} );
                $self->{modules}{$module}{inst_by}[$i]{line} );
    }
    }
    else {
    else {
        return ();
        return ();
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_first_instantiation
=head1 get_first_instantiation
 
 
Get the first thing that this module instantiates.
Get the first thing that this module instantiates.
 
 
  Arguments:  - module name
  Arguments:  - module name
 
 
  Returns:    - a 4 element list: instantiated module name, file,
  Returns:    - a 4 element list: instantiated module name, file,
                  instance name, and line number
                  instance name, and line number
 
 
  Example:
  Example:
                ($im,$f,$i,$l) = $vdata->get_first_instantiation($m);
                ($im,$f,$i,$l) = $vdata->get_first_instantiation($m);
 
 
=cut
=cut
sub get_first_instantiation{
sub get_first_instantiation{
    my ($self,$module) = @_;
    my ($self,$module) = @_;
 
 
    if ( exists( $self->{modules}{$module} )) {
    if ( exists( $self->{modules}{$module} )) {
        $self->{current_instantiation}       =0;
        $self->{current_instantiation}       =0;
        $self->{current_instantiation_module}=$module;
        $self->{current_instantiation_module}=$module;
        return $self->get_next_instantiation();
        return $self->get_next_instantiation();
    }
    }
    else {
    else {
        return ();
        return ();
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_next_instantiation
=head1 get_next_instantiation
 
 
Get the next thing that this module instantiates.
Get the next thing that this module instantiates.
 
 
 
 
  Returns:    - a 4 element list: instantiated module name, file,
  Returns:    - a 4 element list: instantiated module name, file,
                  instance name, and line number
                  instance name, and line number
 
 
  Example:
  Example:
                ($im,$f,$i,$l) = $vdata->get_next_instantiation();
                ($im,$f,$i,$l) = $vdata->get_next_instantiation();
 
 
=cut
=cut
sub get_next_instantiation{
sub get_next_instantiation{
    my ($self) = @_;
    my ($self) = @_;
    my ($module,$i);
    my ($module,$i);
 
 
    $module = $self->{current_instantiation_module};
    $module = $self->{current_instantiation_module};
    $i      = $self->{current_instantiation};
    $i      = $self->{current_instantiation};
 
 
    if (@{$self->{modules}{$module}{instances}} > $i ) {
    if (@{$self->{modules}{$module}{instances}} > $i ) {
        $self->{current_instantiation}++;
        $self->{current_instantiation}++;
        return ($self->{modules}{$module}{instances}[$i]{module},
        return ($self->{modules}{$module}{instances}[$i]{module},
                $self->{modules}{$module}{instances}[$i]{file},
                $self->{modules}{$module}{instances}[$i]{file},
                $self->{modules}{$module}{instances}[$i]{inst_name},
                $self->{modules}{$module}{instances}[$i]{inst_name},
                $self->{modules}{$module}{instances}[$i]{line} );
                $self->{modules}{$module}{instances}[$i]{line} );
    }
    }
    else {
    else {
        return ();
        return ();
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_current_instantiations_port_con
=head1 get_current_instantiations_port_con
 
 
Gets the port connections for the current instantiations (which is got
Gets the port connections for the current instantiations (which is got
using get_first_instantiation and get_next_instantiation). If the
using get_first_instantiation and get_next_instantiation). If the
instantiation does not use .port(...) syntax and rvp does not have the
instantiation does not use .port(...) syntax and rvp does not have the
access to the source of the module then the port names will be returned as
access to the source of the module then the port names will be returned as
numbers in connection order starting at 0.
numbers in connection order starting at 0.
 
 
 
 
  Returns:    - A hash (well, really a list that can be assigned to a hash).
  Returns:    - A hash (well, really a list that can be assigned to a hash).
               The keys of the hash are the port names. The values of the
               The keys of the hash are the port names. The values of the
               hash is everything (except comments) that appeared in the
               hash is everything (except comments) that appeared in the
               brackets in the verilog.
               brackets in the verilog.
 
 
  Example:    %port_con = $vdata->get_current_instantiations_port_con();
  Example:    %port_con = $vdata->get_current_instantiations_port_con();
              foreach $port (keys %port_con) { ...
              foreach $port (keys %port_con) { ...
 
 
=cut
=cut
sub get_current_instantiations_port_con{
sub get_current_instantiations_port_con{
    my ($self) = @_;
    my ($self) = @_;
    my ($module,$i);
    my ($module,$i);
 
 
    $module = $self->{current_instantiation_module};
    $module = $self->{current_instantiation_module};
    $i      = $self->{current_instantiation} -  1;
    $i      = $self->{current_instantiation} -  1;
 
 
    if (@{$self->{modules}{$module}{instances}} > $i ) {
    if (@{$self->{modules}{$module}{instances}} > $i ) {
        return (%{$self->{modules}{$module}{instances}[$i]{connections}});
        return (%{$self->{modules}{$module}{instances}[$i]{connections}});
    }
    }
    else {
    else {
        return {};
        return {};
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_current_instantiations_parameters
=head1 get_current_instantiations_parameters
 
 
Gets the parameters for the current instantiations (which is set using
Gets the parameters for the current instantiations (which is set using
get_first_instantiation and get_next_instantiation).  If the
get_first_instantiation and get_next_instantiation).  If the
instantiation parameters does not use the verilog 2001 .name(...)
instantiation parameters does not use the verilog 2001 .name(...)
syntax and rvp does not have the access to the source of the module
syntax and rvp does not have the access to the source of the module
then the parameter names will be returned as numbers reflecting the
then the parameter names will be returned as numbers reflecting the
order (starting at 0).
order (starting at 0).
 
 
 
 
  Returns:    - A hash (well, really a list that can be assigned to a hash).
  Returns:    - A hash (well, really a list that can be assigned to a hash).
               The keys of the hash are the parameters names. The values of the
               The keys of the hash are the parameters names. The values of the
               hash is everything (except comments) in the value.
               hash is everything (except comments) in the value.
 
 
  Example:    %parameters = $vdata->get_current_instantiations_parameters();
  Example:    %parameters = $vdata->get_current_instantiations_parameters();
              foreach my $p (keys %parameters) { ...
              foreach my $p (keys %parameters) { ...
 
 
=cut
=cut
sub get_current_instantiations_parameters{
sub get_current_instantiations_parameters{
    my ($self) = @_;
    my ($self) = @_;
    my ($module,$i);
    my ($module,$i);
 
 
    $module = $self->{current_instantiation_module};
    $module = $self->{current_instantiation_module};
    $i      = $self->{current_instantiation} -  1;
    $i      = $self->{current_instantiation} -  1;
 
 
    my %r;
    my %r;
    if (@{$self->{modules}{$module}{instances}} > $i ) {
    if (@{$self->{modules}{$module}{instances}} > $i ) {
        foreach my $p (keys %{$self->{modules}{$module}{instances}[$i]{parameters}}) {
        foreach my $p (keys %{$self->{modules}{$module}{instances}[$i]{parameters}}) {
            $r{$p}=$self->{modules}{$module}{instances}[$i]{parameters}{$p}{value};
            $r{$p}=$self->{modules}{$module}{instances}[$i]{parameters}{$p}{value};
        }
        }
    }
    }
 
 
    return %r;
    return %r;
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_modules_parameters
=head1 get_modules_parameters
 
 
Gets the parameters for a module.
Gets the parameters for a module.
 
 
  Arguments:  - module name
  Arguments:  - module name
 
 
  Returns:    - A hash (well, really a list that can be assigned to a hash).
  Returns:    - A hash (well, really a list that can be assigned to a hash).
               The keys of the hash are the parameters names. The values of the
               The keys of the hash are the parameters names. The values of the
               hash is everything (except comments) in the value.
               hash is everything (except comments) in the value.
 
 
  Example:    %parameters = $vdata->get_modules_parameters();
  Example:    %parameters = $vdata->get_modules_parameters();
              foreach my $p (keys %parameters) { ...
              foreach my $p (keys %parameters) { ...
 
 
=cut
=cut
sub get_modules_parameters{
sub get_modules_parameters{
    my ($self,$module) = @_;
    my ($self,$module) = @_;
 
 
    my %r;
    my %r;
    foreach my $p (keys %{$self->{modules}{$module}{parameters}}) {
    foreach my $p (keys %{$self->{modules}{$module}{parameters}}) {
        $r{$p}=$self->{modules}{$module}{parameters}{$p}{value};
        $r{$p}=$self->{modules}{$module}{parameters}{$p}{value};
    }
    }
    return %r;
    return %r;
}
}
 
 
#######################################################
#######################################################
################### Modified ###########################
################### Modified ###########################
#######################################################
#######################################################
 
 
=head1 get_modules_parameters_not_local
=head1 get_modules_parameters_not_local
 
 
Gets the parameters for a module.
Gets the parameters for a module.
 
 
  Arguments:  - module name
  Arguments:  - module name
 
 
  Returns:    - A hash (well, really a list that can be assigned to a hash).
  Returns:    - A hash (well, really a list that can be assigned to a hash).
               The keys of the hash are the parameters names. The values of the
               The keys of the hash are the parameters names. The values of the
               hash is everything (except comments) in the value.
               hash is everything (except comments) in the value.
 
 
  Example:    %parameters = $vdata->get_modules_parameters();
  Example:    %parameters = $vdata->get_modules_parameters();
              foreach my $p (keys %parameters) { ...
              foreach my $p (keys %parameters) { ...
 
 
=cut
=cut
sub get_modules_parameters_not_local{
sub get_modules_parameters_not_local{
    my ($self,$module) = @_;
    my ($self,$module) = @_;
 
 
    my %r;
    my %r;
    foreach my $p (keys %{$self->{modules}{$module}{parameters}}) {
    foreach my $p (keys %{$self->{modules}{$module}{parameters}}) {
        if ($self->{modules}{$module}{parameters}{$p}{ptype} ne "localparam"){
        if ($self->{modules}{$module}{parameters}{$p}{ptype} ne "localparam"){
                #print "$p\n";
                #print "$p\n";
                $r{$p}=$self->{modules}{$module}{parameters}{$p}{value};
                $r{$p}=$self->{modules}{$module}{parameters}{$p}{value};
        }
        }
    }
    }
    return %r;
    return %r;
}
}
 
 
 
 
 
 
 
 
=head1 get_modules_parameters_not_local_in_order
=head1 get_modules_parameters_not_local_in_order
 
 
Gets the parameter names in_order for a module.
Gets the parameter names in_order for a module.
 
 
 
 
 
 
=cut
=cut
sub get_modules_parameters_not_local_order{
sub get_modules_parameters_not_local_order{
    my ($self,$module) = @_;
    my ($self,$module) = @_;
        my @r=@{$self->{modules}{$module}{parameter_order}};#param/localparam inorder
        my @r=@{$self->{modules}{$module}{parameter_order}};#param/localparam inorder
        my @w; #parameter inorder
        my @w; #parameter inorder
        foreach my $p (@r) {
        foreach my $p (@r) {
                if ($self->{modules}{$module}{parameters}{$p}{ptype} ne "localparam"){
                if ($self->{modules}{$module}{parameters}{$p}{ptype} ne "localparam"){
                        push(@w,$p);
                        push(@w,$p);
                }
                }
 
 
        }
        }
 
 
        return @w;
        return @w;
}
}
 
 
 
 
 
 
 
 
=head1 get_module_ports_inorder
=head1 get_module_ports_inorder
 
 
Gets the parameter names in_order for a module.
Gets the parameter names in_order for a module.
 
 
 
 
 
 
=cut
=cut
sub get_module_ports_order{
sub get_module_ports_order{
    my ($self,$module) = @_;
    my ($self,$module) = @_;
        return @{$self->{modules}{$module}{port_order}};
        return @{$self->{modules}{$module}{port_order}};
}
}
 
 
 
 
 
 
 
 
 
 
 
 
###########################################################################
###########################################################################
 
 
=head1 get_define
=head1 get_define
 
 
Find out where a define is defined and what the value is
Find out where a define is defined and what the value is
 
 
  Arguments:  - name of the define
  Arguments:  - name of the define
             Optional arguments where a you want the correct location and
             Optional arguments where a you want the correct location and
               value for a particular use of a multiplely defined define:
               value for a particular use of a multiplely defined define:
              - file where define is used
              - file where define is used
              - line where define is used
              - line where define is used
 
 
  Returns:    - list with three elements: file, line, value
  Returns:    - list with three elements: file, line, value
                 or if the define does not exist it returns a empty list.
                 or if the define does not exist it returns a empty list.
                 if the define was defined on the command line it sets file=""
                 if the define was defined on the command line it sets file=""
                  and line=0
                  and line=0
 
 
 
 
  Example:    ($f,$l,$v) = $vdata->get_define($word,$file,$line);
  Example:    ($f,$l,$v) = $vdata->get_define($word,$file,$line);
 
 
=cut
=cut
sub get_define {
sub get_define {
    my ($self,$define,$file,$line) = @_;
    my ($self,$define,$file,$line) = @_;
 
 
    if ( !defined($self) || !defined($define) ||
    if ( !defined($self) || !defined($define) ||
         ( defined($file) && !defined($line) ) ) {
         ( defined($file) && !defined($line) ) ) {
        die "Get define takes either two or four arguments";
        die "Get define takes either two or four arguments";
    }
    }
 
 
    $define =~ s/^\`// ; # remove the ` if any
    $define =~ s/^\`// ; # remove the ` if any
 
 
    if (!exists( $self->{defines}{$define} )) {
    if (!exists( $self->{defines}{$define} )) {
        return ();
        return ();
    }
    }
    my $index = 0;
    my $index = 0;
    my $dh = $self->{defines}{$define};
    my $dh = $self->{defines}{$define};
 
 
    if (defined($file) &&
    if (defined($file) &&
        exists($dh->{used}{$file}) &&
        exists($dh->{used}{$file}) &&
        exists($dh->{used}{$file}{$line})) {
        exists($dh->{used}{$file}{$line})) {
        $index = $dh->{used}{$file}{$line};
        $index = $dh->{used}{$file}{$line};
    }
    }
 
 
 
 
    if ($index eq "XX") {   # define has been undefed
    if ($index eq "XX") {   # define has been undefed
        return ();
        return ();
    }
    }
 
 
    return ( $dh->{defined}[$index]{file},
    return ( $dh->{defined}[$index]{file},
             $dh->{defined}[$index]{line},
             $dh->{defined}[$index]{line},
             $dh->{defined}[$index]{value});
             $dh->{defined}[$index]{value});
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_context
=head1 get_context
 
 
Get the context (if any) for a line in a file.
Get the context (if any) for a line in a file.
 
 
  Arguments:  - file name
  Arguments:  - file name
              - line number
              - line number
 
 
  Returns:    - line number if there is a context, zero if there is none.
  Returns:    - line number if there is a context, zero if there is none.
 
 
  Example:      $l = $vdata->get_context($filename,$line);
  Example:      $l = $vdata->get_context($filename,$line);
 
 
=cut
=cut
sub get_context{
sub get_context{
    my ($self,$file,$line) = @_;
    my ($self,$file,$line) = @_;
 
 
    if ( exists( $self->{files}{$file}{contexts}{$line} )) {
    if ( exists( $self->{files}{$file}{contexts}{$line} )) {
        return $line;
        return $line;
    }
    }
    else {
    else {
        return 0;
        return 0;
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_module_start_by_context
=head1 get_module_start_by_context
 
 
Test if the context is a module definition start.
Test if the context is a module definition start.
 
 
  Arguments:  - file name
  Arguments:  - file name
              - line number
              - line number
 
 
  Returns:    - module name if it is a module start, 0 otherwise
  Returns:    - module name if it is a module start, 0 otherwise
 
 
  Example:     if($vdata->get_module_start_by_context($filename,$line))..
  Example:     if($vdata->get_module_start_by_context($filename,$line))..
 
 
=cut
=cut
# return true if the context for this line is a module start
# return true if the context for this line is a module start
sub get_module_start_by_context{
sub get_module_start_by_context{
    my ($self,$file,$line) = @_;
    my ($self,$file,$line) = @_;
 
 
    if ( exists( $self->{files}{$file}{contexts}{$line}{module_start})) {
    if ( exists( $self->{files}{$file}{contexts}{$line}{module_start})) {
        return $self->{files}{$file}{contexts}{$line}{module_start};
        return $self->{files}{$file}{contexts}{$line}{module_start};
    }
    }
    else {
    else {
        return 0;
        return 0;
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_has_value_by_context
=head1 get_has_value_by_context
 
 
Check if the context has a value (ie a new module or something). Contexts
Check if the context has a value (ie a new module or something). Contexts
that just turn on and off preprocessor ignoring do not have values.
that just turn on and off preprocessor ignoring do not have values.
 
 
  Arguments:  - file name
  Arguments:  - file name
              - line number
              - line number
 
 
  Returns:    - 1 if there is a value, 0 otherwise
  Returns:    - 1 if there is a value, 0 otherwise
 
 
  Example:    if ($vdata->get_has_value_by_context($file,$line))..
  Example:    if ($vdata->get_has_value_by_context($file,$line))..
 
 
=cut
=cut
sub get_has_value_by_context{
sub get_has_value_by_context{
    my ($self,$file,$line) = @_;
    my ($self,$file,$line) = @_;
 
 
    return exists( $self->{files}{$file}{contexts}{$line}{value});
    return exists( $self->{files}{$file}{contexts}{$line}{value});
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_context_name_type
=head1 get_context_name_type
 
 
Find the reason for a new context - is it a module / function or task.
Find the reason for a new context - is it a module / function or task.
Contexts that just turn on and off preprocessor ignoring do not have values.
Contexts that just turn on and off preprocessor ignoring do not have values.
 
 
  Arguments:  - file name
  Arguments:  - file name
              - line number
              - line number
 
 
  Returns:    - name
  Returns:    - name
              - type [ module | function | task ]
              - type [ module | function | task ]
 
 
  Example:    ($n,$t)=$vdata->get_context_name_type($file,$line);
  Example:    ($n,$t)=$vdata->get_context_name_type($file,$line);
 
 
=cut
=cut
sub get_context_name_type{
sub get_context_name_type{
    my ($self,$file,$line) = @_;
    my ($self,$file,$line) = @_;
    my ($name,$type);
    my ($name,$type);
 
 
    $type='';
    $type='';
    if (exists( $self->{files}{$file}{contexts}{$line}{value})) {
    if (exists( $self->{files}{$file}{contexts}{$line}{value})) {
        $name= $self->{files}{$file}{contexts}{$line}{value}{name};
        $name= $self->{files}{$file}{contexts}{$line}{value}{name};
        if (exists( $self->{files}{$file}{contexts}{$line}{value}{type})) {
        if (exists( $self->{files}{$file}{contexts}{$line}{value}{type})) {
            $type=$self->{files}{$file}{contexts}{$line}{value}{type};
            $type=$self->{files}{$file}{contexts}{$line}{value}{type};
            $type='module' if ($type eq 'primitive' || $type eq 'macromodule');
            $type='module' if ($type eq 'primitive' || $type eq 'macromodule');
        }
        }
        return ($name,$type);
        return ($name,$type);
    }
    }
    else {
    else {
        return ();
        return ();
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_pre_ignore_by_context
=head1 get_pre_ignore_by_context
 
 
Test if the context is preprocessor ignore.
Test if the context is preprocessor ignore.
 
 
  Arguments:  - file name
  Arguments:  - file name
              - line number
              - line number
 
 
  Returns:    - 1 if it is, 0 otherwise
  Returns:    - 1 if it is, 0 otherwise
 
 
  Example:    if ($vdata->get_pre_ignore_by_context($file,$line))..
  Example:    if ($vdata->get_pre_ignore_by_context($file,$line))..
 
 
=cut
=cut
sub get_pre_ignore_by_context{
sub get_pre_ignore_by_context{
    my ($self,$file,$line) = @_;
    my ($self,$file,$line) = @_;
 
 
    if (exists($self->{files}{$file}{contexts}{$line}{pre_ignore})) {
    if (exists($self->{files}{$file}{contexts}{$line}{pre_ignore})) {
        return $self->{files}{$file}{contexts}{$line}{pre_ignore};
        return $self->{files}{$file}{contexts}{$line}{pre_ignore};
    }
    }
    else {
    else {
        return 0;
        return 0;
    }
    }
 
 
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_first_instantiator_by_context
=head1 get_first_instantiator_by_context
 
 
Get the first thing that instantiates this module using the context. The
Get the first thing that instantiates this module using the context. The
context must be a module_start.
context must be a module_start.
 
 
  Arguments:  - file name (for context)
  Arguments:  - file name (for context)
              - line name (for context)
              - line name (for context)
 
 
  Returns:    - a 4 element list: instantiating module, file, instance name, line
  Returns:    - a 4 element list: instantiating module, file, instance name, line
 
 
  Example:
  Example:
              @i=$vdata->get_first_instantiator_by_context($f,$l );
              @i=$vdata->get_first_instantiator_by_context($f,$l );
 
 
=cut
=cut
sub get_first_instantiator_by_context{
sub get_first_instantiator_by_context{
    my ($self,$file,$line) = @_;
    my ($self,$file,$line) = @_;
 
 
    # note: the second exists() checks that the module still exists as
    # note: the second exists() checks that the module still exists as
    #  it could have been deleted because a duplicate was found
    #  it could have been deleted because a duplicate was found
    if (exists($self->{files}{$file}{contexts}{$line}{module_start}) &&
    if (exists($self->{files}{$file}{contexts}{$line}{module_start}) &&
        exists($self->{modules}
        exists($self->{modules}
               {$self->{files}{$file}{contexts}{$line}{module_start}}) &&
               {$self->{files}{$file}{contexts}{$line}{module_start}}) &&
        exists($self->{files}{$file}{contexts}{$line}{value}{inst_by})) {
        exists($self->{files}{$file}{contexts}{$line}{value}{inst_by})) {
        $self->{current_instantiator}       =0;
        $self->{current_instantiator}       =0;
        $self->{current_instantiator_module}=
        $self->{current_instantiator_module}=
            $self->{files}{$file}{contexts}{$line}{module_start};
            $self->{files}{$file}{contexts}{$line}{module_start};
        return $self->get_next_instantiator();
        return $self->get_next_instantiator();
    }
    }
    else {
    else {
        return ();
        return ();
    }
    }
 
 
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_inst_on_line
=head1 get_inst_on_line
 
 
Gets the instance name of a line in a file
Gets the instance name of a line in a file
 
 
  Arguments:  - file name
  Arguments:  - file name
              - line number
              - line number
 
 
  Returns:    - name if the line has an instance name, 0 otherwise
  Returns:    - name if the line has an instance name, 0 otherwise
 
 
  Example:    if ( $new_inst = $vdata->get_inst_on_line($file,$line) ) ...
  Example:    if ( $new_inst = $vdata->get_inst_on_line($file,$line) ) ...
 
 
=cut
=cut
sub get_inst_on_line{
sub get_inst_on_line{
    my ($self,$file,$line) = @_;
    my ($self,$file,$line) = @_;
 
 
    if ( exists( $self->{files}{$file}{instance_lines}{$line})){
    if ( exists( $self->{files}{$file}{instance_lines}{$line})){
        return $self->{files}{$file}{instance_lines}{$line};
        return $self->{files}{$file}{instance_lines}{$line};
    }
    }
    else {
    else {
        return 0;
        return 0;
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_signal_by_context
=head1 get_signal_by_context
 
 
Same as get_module_signal but works by specifying a context.
Same as get_module_signal but works by specifying a context.
 
 
  Arguments:  - context file name
  Arguments:  - context file name
              - context line number
              - context line number
              - signal name
              - signal name
 
 
  Returns:    same as get_module_signal
  Returns:    same as get_module_signal
 
 
  Example:
  Example:
 
 
=cut
=cut
# get a signal by context - returns: line, a_line, i_line, type, file
# get a signal by context - returns: line, a_line, i_line, type, file
sub get_signal_by_context{
sub get_signal_by_context{
    my ($self,$file,$cline,$sig) = @_;
    my ($self,$file,$cline,$sig) = @_;
 
 
    my $sigp;
    my $sigp;
 
 
    # in tasks and functions signals can come from module (m_signals)
    # in tasks and functions signals can come from module (m_signals)
    #  or from the task or function itself (which gets precedence).
    #  or from the task or function itself (which gets precedence).
    if (exists( $self->{files}{$file}{contexts}{$cline}{value}{signals}{$sig} )) {
    if (exists( $self->{files}{$file}{contexts}{$cline}{value}{signals}{$sig} )) {
        print " found signal $sig\n" if $debug;
        print " found signal $sig\n" if $debug;
        $sigp=$self->{files}{$file}{contexts}{$cline}{value}{signals}{$sig};
        $sigp=$self->{files}{$file}{contexts}{$cline}{value}{signals}{$sig};
    }
    }
    elsif (exists( $self->{files}{$file}{contexts}{$cline}{value}{m_signals}{$sig} )) {
    elsif (exists( $self->{files}{$file}{contexts}{$cline}{value}{m_signals}{$sig} )) {
        print " found m_signal $sig\n" if $debug;
        print " found m_signal $sig\n" if $debug;
        $sigp=$self->{files}{$file}{contexts}{$cline}{value}{m_signals}{$sig};
        $sigp=$self->{files}{$file}{contexts}{$cline}{value}{m_signals}{$sig};
    }
    }
    else {
    else {
        return ();
        return ();
    }
    }
 
 
    return ($sigp->{line},
    return ($sigp->{line},
            $sigp->{a_line},
            $sigp->{a_line},
            $sigp->{i_line},
            $sigp->{i_line},
            $sigp->{type},
            $sigp->{type},
            $sigp->{file},
            $sigp->{file},
            $sigp->{posedge},
            $sigp->{posedge},
            $sigp->{negedge},
            $sigp->{negedge},
            $sigp->{type2},
            $sigp->{type2},
            $sigp->{source}{file},
            $sigp->{source}{file},
            $sigp->{source}{line},
            $sigp->{source}{line},
            $sigp->{range},
            $sigp->{range},
            $sigp->{a_file},
            $sigp->{a_file},
            $sigp->{i_file},
            $sigp->{i_file},
            $sigp->{dimensions});
            $sigp->{dimensions});
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 get_t_or_f_by_context
=head1 get_t_or_f_by_context
 
 
Same as get_modules_t_or_f but works by specifying a context.
Same as get_modules_t_or_f but works by specifying a context.
 
 
  Arguments:  - context file name
  Arguments:  - context file name
              - context line number
              - context line number
              - task name
              - task name
 
 
  Returns:    - same as get_modules_t_or_f
  Returns:    - same as get_modules_t_or_f
 
 
  Example:
  Example:
 
 
=cut
=cut
sub get_t_or_f_by_context{
sub get_t_or_f_by_context{
    my ($self,$cfile,$cline,$t_or_f) = @_;
    my ($self,$cfile,$cline,$t_or_f) = @_;
 
 
    if (exists($self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f})) {
    if (exists($self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f})) {
        return($self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{type},
        return($self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{type},
               $self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{line},
               $self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{line},
               $self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{file},
               $self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{file},
               $self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{anchor});
               $self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{anchor});
    }
    }
    else {
    else {
        return ();
        return ();
    }
    }
}
}
###########################################################################
###########################################################################
 
 
=head1 get_parameter_by_context
=head1 get_parameter_by_context
 
 
Return the file and line for a named parameter using context
Return the file and line for a named parameter using context
 
 
  Arguments:  - context file name
  Arguments:  - context file name
              - context line number
              - context line number
              - parameter name
              - parameter name
 
 
  Returns:    - file and line of definition
  Returns:    - file and line of definition
 
 
  Example:
  Example:
 
 
=cut
=cut
sub get_parameter_by_context{
sub get_parameter_by_context{
    my ($self,$cfile,$cline,$parameter) = @_;
    my ($self,$cfile,$cline,$parameter) = @_;
 
 
    if (exists($self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter})) {
    if (exists($self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter})) {
        return($self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter}{file},
        return($self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter}{file},
               $self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter}{line});
               $self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter}{line});
    }
    }
    else {
    else {
        return ();
        return ();
    }
    }
}
}
###########################################################################
###########################################################################
 
 
=head1 get_anchors
=head1 get_anchors
 
 
Get the anchors for a line in a file.
Get the anchors for a line in a file.
 
 
 
 
  Returns:    - a list of anchors
  Returns:    - a list of anchors
 
 
  Example:   foreach $anchor ( $vdata->get_anchors($file,$line) ) ..
  Example:   foreach $anchor ( $vdata->get_anchors($file,$line) ) ..
 
 
=cut
=cut
sub get_anchors{
sub get_anchors{
    my ($self,$file,$line) = @_;
    my ($self,$file,$line) = @_;
 
 
    if (exists($self->{files}{$file}{anchors}{$line})) {
    if (exists($self->{files}{$file}{anchors}{$line})) {
        return @{$self->{files}{$file}{anchors}{$line}};
        return @{$self->{files}{$file}{anchors}{$line}};
    }
    }
    else {
    else {
        return ();
        return ();
    }
    }
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 expand_defines
=head1 expand_defines
 
 
Expand the defines in a line of verilog code.  for best use this
Expand the defines in a line of verilog code.  for best use this
should be called line by line, so that the defines get the correct
should be called line by line, so that the defines get the correct
values when defines are defined multiple times
values when defines are defined multiple times
 
 
  Arguments:  - a pointer to the string to expand the defines in
  Arguments:  - a pointer to the string to expand the defines in
              - the file the line is from
              - the file the line is from
              - the line number of the line
              - the line number of the line
 
 
  Returns:    - nothing
  Returns:    - nothing
 
 
  Example:   $vdata->expand_defines(\$line_to_expand,$file,$line);
  Example:   $vdata->expand_defines(\$line_to_expand,$file,$line);
 
 
=cut
=cut
###############################################################################
###############################################################################
#
#
sub expand_defines {
sub expand_defines {
    my ($self,$bufp,$file,$line) = @_;
    my ($self,$bufp,$file,$line) = @_;
 
 
    if (exists($self->{files}{$file}{define_lines}{$line})) {
    if (exists($self->{files}{$file}{define_lines}{$line})) {
        # do not expand on a `define line - it doesn't make sense to do so
        # do not expand on a `define line - it doesn't make sense to do so
        #  as the substitution of defines in the value only occurs at the
        #  as the substitution of defines in the value only occurs at the
        #  time of use when they could have different values!
        #  time of use when they could have different values!
        return;
        return;
    }
    }
 
 
 
 
    while ( $$bufp =~ m/^(.*?)\`($VID)/ ) {
    while ( $$bufp =~ m/^(.*?)\`($VID)/ ) {
        my $b = $1;
        my $b = $1;
        my $d = $2;
        my $d = $2;
        my $dq = quotemeta($d);
        my $dq = quotemeta($d);
        my $v;
        my $v;
        if ((undef,undef,$v) = $self->get_define($d,$file,$line)) {
        if ((undef,undef,$v) = $self->get_define($d,$file,$line)) {
            $$bufp =~ s/\`$dq/$v/;
            $$bufp =~ s/\`$dq/$v/;
        }
        }
        else {
        else {
            $$bufp =~ s/\`$dq/_BaCkQuOtE_$dq/;
            $$bufp =~ s/\`$dq/_BaCkQuOtE_$dq/;
        }
        }
 
 
    }
    }
    $$bufp =~ s/_BaCkQuOtE_/\`/g;
    $$bufp =~ s/_BaCkQuOtE_/\`/g;
}
}
 
 
 
 
###########################################################################
###########################################################################
 
 
=head1 verilog_gatetype_keywords
=head1 verilog_gatetype_keywords
 
 
 
 
  Returns:    - a list of verilog gatetype keywords
  Returns:    - a list of verilog gatetype keywords
 
 
  Example:   @keywords = rvp->verilog_gatetype_keywords();
  Example:   @keywords = rvp->verilog_gatetype_keywords();
 
 
=cut
=cut
sub verilog_gatetype_keywords {
sub verilog_gatetype_keywords {
    return (@verilog_gatetype_keywords);
    return (@verilog_gatetype_keywords);
}
}
###########################################################################
###########################################################################
 
 
=head1 verilog_compiler_keywords
=head1 verilog_compiler_keywords
 
 
  Returns:    - a list of verilog compiler keywords
  Returns:    - a list of verilog compiler keywords
 
 
  Example:   @keywords = rvp->verilog_compiler_keywords();
  Example:   @keywords = rvp->verilog_compiler_keywords();
 
 
=cut
=cut
sub verilog_compiler_keywords {
sub verilog_compiler_keywords {
    return (@verilog_compiler_keywords);
    return (@verilog_compiler_keywords);
}
}
###########################################################################
###########################################################################
 
 
=head1 verilog_signal_keywords
=head1 verilog_signal_keywords
 
 
  Returns:    - a list of verilog signal keywords
  Returns:    - a list of verilog signal keywords
 
 
  Example:   @keywords = rvp->verilog_signal_keywords();
  Example:   @keywords = rvp->verilog_signal_keywords();
 
 
=cut
=cut
sub verilog_signal_keywords {
sub verilog_signal_keywords {
    return (@verilog_signal_keywords);
    return (@verilog_signal_keywords);
}
}
 
 
 
 
###########################################################################
###########################################################################
 
 
=head1 chunk_read_init
=head1 chunk_read_init
 
 
Initialise a file for chunk reading (see chunk_read for more
Initialise a file for chunk reading (see chunk_read for more
details). It actually reads the whole file into a string, which
details). It actually reads the whole file into a string, which
chunk_read then reads a chunk at a time. The file is closed before
chunk_read then reads a chunk at a time. The file is closed before
chuck_read_init returns.
chuck_read_init returns.
 
 
  Arguments:  - the file to read (with path if needed)
  Arguments:  - the file to read (with path if needed)
              - tabstop: 0 = leave tabs alone
              - tabstop: 0 = leave tabs alone
                         N = turn tabs spaces with each tabstop=N
                         N = turn tabs spaces with each tabstop=N
  Returns:    - a handle to pass to chunk_read or 0 if file open fails
  Returns:    - a handle to pass to chunk_read or 0 if file open fails
 
 
  Example:
  Example:
            my $chunkRead = rvp->chunkr_read_init($f,$opts{tabstop});
            my $chunkRead = rvp->chunkr_read_init($f,$opts{tabstop});
 
 
=cut
=cut
sub chunk_read_init {
sub chunk_read_init {
 
 
    my ($class,$f,$tabstop) = @_;
    my ($class,$f,$tabstop) = @_;
    local (*F);
    local (*F);
 
 
    open(F,"<$f") || return 0;
    open(F,"<$f") || return 0;
 
 
    my $chunk = { type => "",
    my $chunk = { type => "",
                  text => "",
                  text => "",
                  isANewLine => 0,
                  isANewLine => 0,
                  isStart => 0,
                  isStart => 0,
                  isEnd => 1 ,
                  isEnd => 1 ,
                  line => 0 };
                  line => 0 };
 
 
    my $this = { chunk => $chunk ,
    my $this = { chunk => $chunk ,
                 tabstop => $tabstop ,
                 tabstop => $tabstop ,
                 linebuf => "" ,
                 linebuf => "" ,
                 state => 0 ,
                 state => 0 ,
                 fh => *F };
                 fh => *F };
    return $this;
    return $this;
}
}
 
 
###########################################################################
###########################################################################
 
 
=head1 chunk_read
=head1 chunk_read
 
 
Reads verilog a chunk at a time. The file is opened using
Reads verilog a chunk at a time. The file is opened using
chunk_read_init. Then chunk_read is used to read the file a chunk at a
chunk_read_init. Then chunk_read is used to read the file a chunk at a
time.  A chunk is a line or part of a line that is all the same type.
time.  A chunk is a line or part of a line that is all the same type.
 
 
  The types are:
  The types are:
              comment   - either // or /* */ comment
              comment   - either // or /* */ comment
              attribute - verilog 2001 (* *) atribute
              attribute - verilog 2001 (* *) atribute
              include   - a line containing `include "file"
              include   - a line containing `include "file"
              string    - a string
              string    - a string
              code      - anything else (verilog code, defines, compliler keywords)
              code      - anything else (verilog code, defines, compliler keywords)
 
 
Nothing is removed from the file, so if each chunk is printed after being read
Nothing is removed from the file, so if each chunk is printed after being read
you will end up with exactly the same file as you put in.
you will end up with exactly the same file as you put in.
 
 
  Arguments:  - handle (from chunk_read_init)
  Arguments:  - handle (from chunk_read_init)
 
 
  Returns:    - 0 at the end of file, or a hash ref with the following keys:
  Returns:    - 0 at the end of file, or a hash ref with the following keys:
              type       - one of the types (see above)
              type       - one of the types (see above)
              text       - the text read from the file
              text       - the text read from the file
              line       - the line number the text is on
              line       - the line number the text is on
              isANewLine - true if chunk is the first chunk of the line
              isANewLine - true if chunk is the first chunk of the line
              isStart    - true if the chunk is the start (eg "/*..." for
              isStart    - true if the chunk is the start (eg "/*..." for
                             a comment )
                             a comment )
              isEnd      - true if the chunk is the end ( eg "*/" )
              isEnd      - true if the chunk is the end ( eg "*/" )
                      NOTE: isEnd is set to undefined for a
                      NOTE: isEnd is set to undefined for a
                       type="code" that ends in a newline. This is
                       type="code" that ends in a newline. This is
                       because chunk_read doesn't know if the code is
                       because chunk_read doesn't know if the code is
                       ending or not. If you need to know in this case
                       ending or not. If you need to know in this case
                       you can read the next chunk and see what type it is.
                       you can read the next chunk and see what type it is.
 
 
  Example:
  Example:
            my $chunkRead = rvp->chunk_read_init($f,0);
            my $chunkRead = rvp->chunk_read_init($f,0);
            while ($chunk = rvp->chunk_read($chunkRead)) {
            while ($chunk = rvp->chunk_read($chunkRead)) {
                    print $chunk->{text} unless $chunk->{type} eq "comment";
                    print $chunk->{text} unless $chunk->{type} eq "comment";
            }
            }
 
 
=cut
=cut
sub chunk_read {
sub chunk_read {
   my ($class,$this) = @_;
   my ($class,$this) = @_;
 
 
   my $chunk = $this->{chunk};
   my $chunk = $this->{chunk};
   $chunk->{isStart} = $chunk->{isEnd};
   $chunk->{isStart} = $chunk->{isEnd};
   $chunk->{isEnd}  = 0;
   $chunk->{isEnd}  = 0;
   $chunk->{isANewLine} = 0;
   $chunk->{isANewLine} = 0;
 
 
   if ( $this->{linebuf} eq "" ) {
   if ( $this->{linebuf} eq "" ) {
       if (!defined($this->{linebuf} = readline($this->{fh}))) {
       if (!defined($this->{linebuf} = readline($this->{fh}))) {
           close($this->{fh});
           close($this->{fh});
           return 0;
           return 0;
       }
       }
       $chunk->{isANewLine} = 1;
       $chunk->{isANewLine} = 1;
       $chunk->{line}++;
       $chunk->{line}++;
       if ($this->{tabstop}!=0) {
       if ($this->{tabstop}!=0) {
           # 1 while is some stupid perl thing meaning while (cond) {} may be a bit faster?
           # 1 while is some stupid perl thing meaning while (cond) {} may be a bit faster?
           1 while ($this->{linebuf} =~ s/(^|\n)([^\t\n]*)(\t+)/
           1 while ($this->{linebuf} =~ s/(^|\n)([^\t\n]*)(\t+)/
                    $1. $2 . (" " x ($this->{tabstop} * length($3) -
                    $1. $2 . (" " x ($this->{tabstop} * length($3) -
                                     (length($2) % $this->{tabstop})))
                                     (length($2) % $this->{tabstop})))
                    /gsex);
                    /gsex);
       }
       }
   }
   }
 
 
 STATE_SWITCH:
 STATE_SWITCH:
   if ( $this->{state} == 0 ) {
   if ( $this->{state} == 0 ) {
       $chunk->{type} = "code";
       $chunk->{type} = "code";
       if ( $this->{linebuf} =~
       if ( $this->{linebuf} =~
            s%^(.*?)((/\*)|           # anything followed by /* comment
            s%^(.*?)((/\*)|           # anything followed by /* comment              
                     (//)|            #    or // comment
                     (//)|            #    or // comment
                     (\(\*(?!\s*\)))| #    or (* attribute (but not (*)
                     (\(\*(?!\s*\)))| #    or (* attribute (but not (*)
                     (\`include\s)|   #    or `include
                     (\`include\s)|   #    or `include
                     (\"))            #    or start of string
                     (\")|            #    or start of string
 
                     (import\s))      # import package
 
 
 
 
            %$2%ox ) {
            %$2%ox ) {
           $chunk->{isEnd} = 1;
           $chunk->{isEnd} = 1;
           $chunk->{text} = $1;
           $chunk->{text} = $1;
           if (defined($3)) {
           if (defined($3)) {
               $this->{state} = 1;  # long comment
               $this->{state} = 1;  # long comment
           }
           }
           elsif (defined($4)) {
           elsif (defined($4) ||defined($8) ) {
               $this->{state} = 2;  # short comment
               $this->{state} = 2;  # short comment
           }
           }
           elsif (defined($5)) {
           elsif (defined($5)) {
               $this->{state} = 3;  # attribute
               $this->{state} = 3;  # attribute
           }
           }
           elsif (defined($6)) {
           elsif (defined($6)) {
               $this->{state} = 4;  # include
               $this->{state} = 4;  # include
           }
           }
           elsif (defined($7)) {
           elsif (defined($7)) {
               $this->{state} = 5;  # string
               $this->{state} = 5;  # string
           }
           }
           else {
           else {
               die "chunk_read internal error!";
               die "chunk_read internal error!";
           }
           }
           if (!$chunk->{text}) {
           if (!$chunk->{text}) {
               # this happens if we are in state code and a new line
               # this happens if we are in state code and a new line
               #  starts with something that isn't code. So we change
               #  starts with something that isn't code. So we change
               #  and go back to the top.
               #  and go back to the top.
               $chunk->{isStart} = 1;
               $chunk->{isStart} = 1;
               $chunk->{isEnd}  = 0;
               $chunk->{isEnd}  = 0;
               goto STATE_SWITCH;
               goto STATE_SWITCH;
           }
           }
       }
       }
       else {
       else {
           $chunk->{text} = $this->{linebuf};
           $chunk->{text} = $this->{linebuf};
           $this->{linebuf} = "";
           $this->{linebuf} = "";
           # in this case we might be at end, but we don't really know!
           # in this case we might be at end, but we don't really know!
           $chunk->{isEnd}  = undef;
           $chunk->{isEnd}  = undef;
       }
       }
   }
   }
   elsif ( $this->{state} == 1 ) {
   elsif ( $this->{state} == 1 ) {
       $chunk->{type} = "comment";
       $chunk->{type} = "comment";
       # this first test is needed to work so /*/  */ works
       # this first test is needed to work so /*/  */ works
       if ( $chunk->{isStart} && $this->{linebuf} =~ s%^/\*%% ) {
       if ( $chunk->{isStart} && $this->{linebuf} =~ s%^/\*%% ) {
           $chunk->{text} = "/*";
           $chunk->{text} = "/*";
       }
       }
       else {
       else {
           $chunk->{text} = "";
           $chunk->{text} = "";
       }
       }
       if ( $this->{linebuf} =~ s%^(.*?\*/)%% ) {          # anything followed by */
       if ( $this->{linebuf} =~ s%^(.*?\*/)%% ) {          # anything followed by */
           $chunk->{text} .= $1;
           $chunk->{text} .= $1;
           $this->{state} = 0;
           $this->{state} = 0;
           $chunk->{isEnd} = 1;
           $chunk->{isEnd} = 1;
       }
       }
       else {
       else {
           $chunk->{text} .= $this->{linebuf};
           $chunk->{text} .= $this->{linebuf};
           $this->{linebuf} = "";
           $this->{linebuf} = "";
       }
       }
   }
   }
   elsif ( $this->{state} == 2 ) {
   elsif ( $this->{state} == 2 ) {
       $chunk->{type} = "comment";
       $chunk->{type} = "comment";
       $chunk->{text} = $this->{linebuf};
       $chunk->{text} = $this->{linebuf};
       $chunk->{isEnd} = 1;
       $chunk->{isEnd} = 1;
       $this->{linebuf} = "";
       $this->{linebuf} = "";
       if ( $chunk->{text} =~ s/\n$// ) {
       if ( $chunk->{text} =~ s/\n$// ) {
           $this->{linebuf} = "\n";
           $this->{linebuf} = "\n";
       }
       }
       $this->{state} = 0;
       $this->{state} = 0;
   }
   }
   elsif ( $this->{state} == 3 ) {
   elsif ( $this->{state} == 3 ) {
       $chunk->{type} = "attribute";
       $chunk->{type} = "attribute";
       if ( $this->{linebuf} =~ s%^(.*?\*\))%% ) {          # anything followed by *)
       if ( $this->{linebuf} =~ s%^(.*?\*\))%% ) {          # anything followed by *)
           $chunk->{text} = $1;
           $chunk->{text} = $1;
           $this->{state} = 0;
           $this->{state} = 0;
           $chunk->{isEnd} = 1;
           $chunk->{isEnd} = 1;
       }
       }
       else {
       else {
           $chunk->{text} = $this->{linebuf};
           $chunk->{text} = $this->{linebuf};
           $this->{linebuf} = "";
           $this->{linebuf} = "";
       }
       }
   }
   }
   elsif ( $this->{state} == 4 ) {
   elsif ( $this->{state} == 4 ) {
       $chunk->{type} = "include";
       $chunk->{type} = "include";
       $chunk->{isEnd} = 1;
       $chunk->{isEnd} = 1;
       if ( $this->{linebuf} =~ s%^(\`include\s+\".*?\")%% ) {
       if ( $this->{linebuf} =~ s%^(\`include\s+\".*?\")%% ) {
           $chunk->{text} = $1;
           $chunk->{text} = $1;
           $this->{state} = 0;
           $this->{state} = 0;
       }
       }
       else {
       else {
           # this is an error - just return the line as code - the parser will
           # this is an error - just return the line as code - the parser will
           #  report the error
           #  report the error
           $chunk->{type} = 0;
           $chunk->{type} = 0;
           $chunk->{text} = $this->{linebuf};
           $chunk->{text} = $this->{linebuf};
           $this->{linebuf} = "";
           $this->{linebuf} = "";
       }
       }
   }
   }
   elsif ( $this->{state} == 5 ) {
   elsif ( $this->{state} == 5 ) {
       $chunk->{type} = "string";
       $chunk->{type} = "string";
       # string all on one line
       # string all on one line
       if ( $this->{linebuf} =~ s%^(\"(?:(?:\\\\)|(?:\\\")|(?:[^\"]))*?\")%% ) {
       if ( $this->{linebuf} =~ s%^(\"(?:(?:\\\\)|(?:\\\")|(?:[^\"]))*?\")%% ) {
           $chunk->{text} = $1;
           $chunk->{text} = $1;
           $this->{state} = 0;
           $this->{state} = 0;
           $chunk->{isEnd} = 1;
           $chunk->{isEnd} = 1;
       }
       }
       # end of multiline string (doesn't start with quote)
       # end of multiline string (doesn't start with quote)
       elsif ( $this->{linebuf} =~ s%^([^\"](?:(?:\\\\)|(?:\\\")|(?:[^\"]))*?\")%% ) {
       elsif ( $this->{linebuf} =~ s%^([^\"](?:(?:\\\\)|(?:\\\")|(?:[^\"]))*?\")%% ) {
           $chunk->{text} = $1;
           $chunk->{text} = $1;
           $this->{state} = 0;
           $this->{state} = 0;
           $chunk->{isEnd} = 1;
           $chunk->{isEnd} = 1;
       }
       }
       # middle of multiline string
       # middle of multiline string
       else {
       else {
           $chunk->{text} = $this->{linebuf};
           $chunk->{text} = $this->{linebuf};
           $this->{linebuf} = "";
           $this->{linebuf} = "";
       }
       }
   }
   }
 
 
   return $chunk;
   return $chunk;
}
}
 
 
###############################################################################
###############################################################################
#  RVP internal functions from now on.... (they all start with _ to
#  RVP internal functions from now on.... (they all start with _ to
#   let you know they are internal
#   let you know they are internal
###############################################################################
###############################################################################
 
 
###############################################################################
###############################################################################
# search a file, putting the data in $self
# search a file, putting the data in $self
#   Note: be careful coding in the main loop... there are a few optimisations
#   Note: be careful coding in the main loop... there are a few optimisations
#    which result in big chunks of code being skipped if the line does not
#    which result in big chunks of code being skipped if the line does not
#    contain certain characters (eg ' " / *)
#    contain certain characters (eg ' " / *)
sub _search {
sub _search {
    my ($self,$f,$inc_dirs) = @_;
    my ($self,$f,$inc_dirs) = @_;
 
 
    my $verilog_compiler_keywords_regexp = "(?:" .
    my $verilog_compiler_keywords_regexp = "(?:" .
        join("|",@verilog_compiler_keywords) .
        join("|",@verilog_compiler_keywords) .
            ")";
            ")";
 
 
 
 
    my $file=_ffile($f);
    my $file=_ffile($f);
    _init_file($self->{files},$f);
    _init_file($self->{files},$f);
 
 
    print "Searching $f " unless $quiet;
    print "Searching $f " unless $quiet;
    my $chunkRead= rvp->chunk_read_init($f,0) ||
    my $chunkRead= rvp->chunk_read_init($f,0) ||
        die "Error: can not open file $f to read: $!\n";
        die "Error: can not open file $f to read: $!\n";
    my $file_dir = dirname($f);
    my $file_dir = dirname($f);
 
 
    my $rs = {};
    my $rs = {};
    $rs->{modules}   = $self->{modules};
    $rs->{modules}   = $self->{modules};
    $rs->{files}     = $self->{files};
    $rs->{files}     = $self->{files};
    $rs->{unres_mod} = $self->{unresolved_modules};
    $rs->{unres_mod} = $self->{unresolved_modules};
 
 
    $rs->{module}   = '';
    $rs->{module}   = '';
    $rs->{function} = '';
    $rs->{function} = '';
    $rs->{task}     = '';
    $rs->{task}     = '';
    $rs->{t}        = undef; # temp store
    $rs->{t}        = undef; # temp store
    $rs->{p}        = undef;
    $rs->{p}        = undef;
 
 
    my $printline = 1000;
    my $printline = 1000;
 
 
    my $ps = {};
    my $ps = {};
    my $nest=0;
    my $nest=0;
    my $nest_at_ignore;
    my $nest_at_ignore;
    my @ignore_from_elsif;
    my @ignore_from_elsif;
    my $ignoring=0;
    my $ignoring=0;
    my @fileStack =();
    my @fileStack =();
    my $pp_ignore;
    my $pp_ignore;
    my $chunk;
    my $chunk;
    while (1) {
    while (1) {
        while ($chunk = rvp->chunk_read($chunkRead)) {
        while ($chunk = rvp->chunk_read($chunkRead)) {
            $self->{files}{$file}{lines} = $chunk->{line};
            $self->{files}{$file}{lines} = $chunk->{line};
            if ($chunk->{line}>$printline && !$quiet) {
            if ($chunk->{line}>$printline && !$quiet) {
                $printline+=1000;
                $printline+=1000;
                $|=1; # turn on autoflush
                $|=1; # turn on autoflush
                print ".";
                print ".";
                $|=0 unless $debug; # turn off autoflush
                $|=0 unless $debug; # turn off autoflush
            }
            }
 
 
            # deal quickly with blank lines
            # deal quickly with blank lines
            if ( $chunk->{text} =~ m/^\s*\n/ ) {
            if ( $chunk->{text} =~ m/^\s*\n/ ) {
                next;
                next;
            }
            }
 
 
 
 
            if ( $chunk->{type} eq "code" ) {
            if ( $chunk->{type} eq "code" ) {
 
 
 
 
                ####################################################
                ####################################################
                # Optimisation: if there are no ` 
                # Optimisation: if there are no ` 
                #  we can parse the line now
                #  we can parse the line now
                if ( $chunk->{text} !~ m|[\`]| ) {
                if ( $chunk->{text} !~ m|[\`]| ) {
                    if ($nest && $ignoring) {
                    if ($nest && $ignoring) {
                        next;
                        next;
                    }
                    }
                    $self->_parse_line($chunk->{text},$file,$chunk->{line},$ps,$rs);
                    $self->_parse_line($chunk->{text},$file,$chunk->{line},$ps,$rs);
                    next;
                    next;
                }
                }
 
 
                # handle ifdefs
                # handle ifdefs
                if ($nest && $ignoring) {
                if ($nest && $ignoring) {
                    if ( $chunk->{text} =~ m/^\s*\`(?:ifdef|ifndef)\s+($VID)/ ) {
                    if ( $chunk->{text} =~ m/^\s*\`(?:ifdef|ifndef)\s+($VID)/ ) {
                        print " Found at line $chunk->{line} : if[n]def (nest=$nest)\n" if $debug;
                        print " Found at line $chunk->{line} : if[n]def (nest=$nest)\n" if $debug;
                        $nest++;
                        $nest++;
                    }
                    }
                    elsif ( $chunk->{text} =~ m/^\s*\`(else|(?:elsif\s+($VID)))/ ) {
                    elsif ( $chunk->{text} =~ m/^\s*\`(else|(?:elsif\s+($VID)))/ ) {
                        print " Found at line $chunk->{line} : $1 (nest=$nest)\n" if $debug;
                        print " Found at line $chunk->{line} : $1 (nest=$nest)\n" if $debug;
                        if ($1 eq 'else' ||
                        if ($1 eq 'else' ||
                            _parsing_is_defined($self->{defines},$2,
                            _parsing_is_defined($self->{defines},$2,
                                                $file,$chunk->{line})) {
                                                $file,$chunk->{line})) {
                            # true elsif or plain else
                            # true elsif or plain else
                            if ($nest == $nest_at_ignore &&
                            if ($nest == $nest_at_ignore &&
                                !$ignore_from_elsif[$nest]) {
                                !$ignore_from_elsif[$nest]) {
                                $ignoring=0;
                                $ignoring=0;
                                $$pp_ignore = $chunk->{line};
                                $$pp_ignore = $chunk->{line};
                            }
                            }
                        }
                        }
                    }
                    }
                    elsif ( $chunk->{text} =~ m/^\s*\`endif/ ) {
                    elsif ( $chunk->{text} =~ m/^\s*\`endif/ ) {
                        print " Found at line $chunk->{line} : endif (nest=$nest)\n" if $debug;
                        print " Found at line $chunk->{line} : endif (nest=$nest)\n" if $debug;
                        if ($nest == $nest_at_ignore) {
                        if ($nest == $nest_at_ignore) {
                            $ignoring=0;
                            $ignoring=0;
                            $$pp_ignore = $chunk->{line};
                            $$pp_ignore = $chunk->{line};
                        }
                        }
                        $nest--;
                        $nest--;
                    }
                    }
                    next;
                    next;
                }
                }
                # handle the case where the endif is on the same line as the ifdef
                # handle the case where the endif is on the same line as the ifdef
                #  (note: generally I only accept endif at the start of a line)
                #  (note: generally I only accept endif at the start of a line)
                if ( $chunk->{text} =~ m/\`(ifdef|ifndef)\s+($VID).*\`endif/ ) {
                if ( $chunk->{text} =~ m/\`(ifdef|ifndef)\s+($VID).*\`endif/ ) {
                    print "$file: ifdef and endif on same line\n" if $debug;
                    print "$file: ifdef and endif on same line\n" if $debug;
                    my $is_defined = _parsing_is_defined($self->{defines},$2,
                    my $is_defined = _parsing_is_defined($self->{defines},$2,
                                                         $file,$chunk->{line});
                                                         $file,$chunk->{line});
                    if ( (($1 eq 'ifdef' ) && !$is_defined) ||
                    if ( (($1 eq 'ifdef' ) && !$is_defined) ||
                         (($1 eq 'ifndef') &&  $is_defined)) {
                         (($1 eq 'ifndef') &&  $is_defined)) {
                        # replace ifdef with nothing
                        # replace ifdef with nothing
                        $chunk->{text} =~ s/\`(ifdef|ifndef)\s+($VID)(.*)\`endif//;
                        $chunk->{text} =~ s/\`(ifdef|ifndef)\s+($VID)(.*)\`endif//;
                    }
                    }
                    else {
                    else {
                        # replace ifdef with what is between the ifdef and endif
                        # replace ifdef with what is between the ifdef and endif
                        $chunk->{text} =~ s/\`(ifdef|ifndef)\s+($VID)(.*)\`endif/$3/;
                        $chunk->{text} =~ s/\`(ifdef|ifndef)\s+($VID)(.*)\`endif/$3/;
                    }
                    }
                }
                }
                if ( $chunk->{text} =~ m/^\s*\`(ifdef|ifndef)\s+($VID)/ ) {
                if ( $chunk->{text} =~ m/^\s*\`(ifdef|ifndef)\s+($VID)/ ) {
                    $nest++;
                    $nest++;
                    print " Found at line $chunk->{line} : $1 $2 (nest=$nest)\n" if $debug;
                    print " Found at line $chunk->{line} : $1 $2 (nest=$nest)\n" if $debug;
                    my $is_defined = _parsing_is_defined($self->{defines},$2,
                    my $is_defined = _parsing_is_defined($self->{defines},$2,
                                                         $file,$chunk->{line});
                                                         $file,$chunk->{line});
                    if ( (($1 eq 'ifdef' ) && !$is_defined) ||
                    if ( (($1 eq 'ifdef' ) && !$is_defined) ||
                         (($1 eq 'ifndef') &&  $is_defined)) {
                         (($1 eq 'ifndef') &&  $is_defined)) {
                        $ignoring=1;
                        $ignoring=1;
                        $self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore} = 'XX';
                        $self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore} = 'XX';
                        $pp_ignore = \$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore};
                        $pp_ignore = \$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore};
                        $nest_at_ignore=$nest;
                        $nest_at_ignore=$nest;
                        $ignore_from_elsif[$nest]=0;
                        $ignore_from_elsif[$nest]=0;
                    }
                    }
                    next;
                    next;
                }
                }
                if ( $chunk->{text} =~ m/^\s*\`(else|(?:elsif\s+($VID)))/ ) {
                if ( $chunk->{text} =~ m/^\s*\`(else|(?:elsif\s+($VID)))/ ) {
                    print " Found at line $chunk->{line} : $1 (nest=$nest)\n" if $debug;
                    print " Found at line $chunk->{line} : $1 (nest=$nest)\n" if $debug;
                    if ($nest) {
                    if ($nest) {
                        $ignoring=1;
                        $ignoring=1;
                        $self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore} = 'XX';
                        $self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore} = 'XX';
                        $pp_ignore = \$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore};
                        $pp_ignore = \$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore};
                        $nest_at_ignore=$nest;
                        $nest_at_ignore=$nest;
                        # an ignore from an elsif means you will never stop ignoring
                        # an ignore from an elsif means you will never stop ignoring
                        #   at this nest level
                        #   at this nest level
                        $ignore_from_elsif[$nest]=($1 ne 'else');
                        $ignore_from_elsif[$nest]=($1 ne 'else');
                    }
                    }
                    else {
                    else {
                        $self->_add_warning("$file:$chunk->{line}: found $1 without \`ifdef");
                        $self->_add_warning("$file:$chunk->{line}: found $1 without \`ifdef");
                    }
                    }
                    next;
                    next;
                }
                }
                if ( $chunk->{text} =~ m/^\s*\`endif/ ) {
                if ( $chunk->{text} =~ m/^\s*\`endif/ ) {
                    print " Found at line $chunk->{line} : endif (nest=$nest)\n" if $debug;
                    print " Found at line $chunk->{line} : endif (nest=$nest)\n" if $debug;
                    if ($nest) {
                    if ($nest) {
                        $nest--;
                        $nest--;
                    }
                    }
                    else {
                    else {
                        $self->_add_warning("$file:$chunk->{line}: found \`endif without \`ifdef");
                        $self->_add_warning("$file:$chunk->{line}: found \`endif without \`ifdef");
                    }
                    }
                    next;
                    next;
                }
                }
 
 
                # match define. Note: /s makes the .* match the \n too
                # match define. Note: /s makes the .* match the \n too
                if ( $chunk->{text} =~ m/^\s*\`define\s+($VID)(.*)/s ) {
                if ( $chunk->{text} =~ m/^\s*\`define\s+($VID)(.*)/s ) {
                    my $def = $1;
                    my $def = $1;
                    my $rest = defined($2)?$2:'';
                    my $rest = defined($2)?$2:'';
                    my $defLine = $chunk->{line};
                    my $defLine = $chunk->{line};
                    $self->{files}{$file}{define_lines}{$chunk->{line}} = 1;
                    $self->{files}{$file}{define_lines}{$chunk->{line}} = 1;
 
 
                    # _parsing_expand_defines is called to register the use
                    # _parsing_expand_defines is called to register the use
                    #  of any multiplely defined defines in the value part of
                    #  of any multiplely defined defines in the value part of
                    #  the define
                    #  the define
                    my $tmpValue=$rest;
                    my $tmpValue=$rest;
                    $self->_parsing_expand_defines(\$tmpValue,$file,$chunk->{line});
                    $self->_parsing_expand_defines(\$tmpValue,$file,$chunk->{line});
 
 
                    # handle multiline defines: read more stuff if line ends in backslash
                    # handle multiline defines: read more stuff if line ends in backslash
                    #  (revisit: verilog spec says leave the newline in the value)
                    #  (revisit: verilog spec says leave the newline in the value)
                    # also keep adding stuff to value until it ends in a newline or comment
                    # also keep adding stuff to value until it ends in a newline or comment
                    #  because strings are seperated out, `define T $display("test")
                    #  because strings are seperated out, `define T $display("test")
                    #  is delivered as chunks '`define T $display(' ,'"test"', ')\n'
                    #  is delivered as chunks '`define T $display(' ,'"test"', ')\n'
                    while ( (($rest =~ s|\\\n|| ) ||  ($rest !~ m/\n$/) )
                    while ( (($rest =~ s|\\\n|| ) ||  ($rest !~ m/\n$/) )
                            && ($chunk = rvp->chunk_read($chunkRead))) {
                            && ($chunk = rvp->chunk_read($chunkRead))) {
                        last if $chunk->{type} eq "comment";
                        last if $chunk->{type} eq "comment";
                        $rest .= $chunk->{text};
                        $rest .= $chunk->{text};
                        $self->{files}{$file}{define_lines}{$chunk->{line}} = 1;
                        $self->{files}{$file}{define_lines}{$chunk->{line}} = 1;
                        # _parsing_expand_defines call: see comment ~15 lines back
                        # _parsing_expand_defines call: see comment ~15 lines back
                        my $tmpValue=$chunk->{text};
                        my $tmpValue=$chunk->{text};
                        $self->_parsing_expand_defines(\$tmpValue,$file,$chunk->{line});
                        $self->_parsing_expand_defines(\$tmpValue,$file,$chunk->{line});
                    }
                    }
                    my $value = $rest;
                    my $value = $rest;
                    $value =~ s/^\s+(.*)(\n)?/$1/;
                    $value =~ s/^\s+(.*)(\n)?/$1/;
 
 
                    print " Found in $file line $defLine : define $def = $value\n"
                    print " Found in $file line $defLine : define $def = $value\n"
                        if $debug;
                        if $debug;
                    _add_define($self->{defines}, $def , $value , $file, $defLine );
                    _add_define($self->{defines}, $def , $value , $file, $defLine );
                    _add_anchor($self->{files}{$file}{anchors},$defLine,"");
                    _add_anchor($self->{files}{$file}{anchors},$defLine,"");
                    # Don't substitute now: [defines] shall be substituted after the 
                    # Don't substitute now: [defines] shall be substituted after the 
                    # original macro is substituted, not when it is defined(1364-2001 pg353)
                    # original macro is substituted, not when it is defined(1364-2001 pg353)
                    next;
                    next;
                }
                }
 
 
                if ( $chunk->{text} =~ m/^\s*\`undef\s+($VID)/ ) {
                if ( $chunk->{text} =~ m/^\s*\`undef\s+($VID)/ ) {
                    _undef_define($self->{defines},$1);
                    _undef_define($self->{defines},$1);
                    print " Found at line $chunk->{line} : undef $1\n" if $debug;
                    print " Found at line $chunk->{line} : undef $1\n" if $debug;
                    next;
                    next;
                }
                }
 
 
                if ( $chunk->{text} =~ m/^\s*$verilog_compiler_keywords_regexp/ ) {
                if ( $chunk->{text} =~ m/^\s*$verilog_compiler_keywords_regexp/ ) {
                    next;
                    next;
                }
                }
                $self->_parsing_expand_defines(\$chunk->{text},$file,$chunk->{line});
                $self->_parsing_expand_defines(\$chunk->{text},$file,$chunk->{line});
 
 
                # Note this is called from two other places (optimisations)
                # Note this is called from two other places (optimisations)
                $self->_parse_line($chunk->{text},$file,$chunk->{line},$ps,$rs);
                $self->_parse_line($chunk->{text},$file,$chunk->{line},$ps,$rs);
            }
            }
            elsif ( $chunk->{type} eq "include" ) {
            elsif ( $chunk->{type} eq "include" ) {
                if ($nest && $ignoring) {
                if ($nest && $ignoring) {
                    next;
                    next;
                }
                }
 
 
                $chunk->{text} =~ m/^\s*\`include\s+\"(.*?)\"/ ;
                $chunk->{text} =~ m/^\s*\`include\s+\"(.*?)\"/ ;
                # revisit - need to check for recursive includes
                # revisit - need to check for recursive includes
                print " Found at line $chunk->{line} : include $1\n" if $debug;
                print " Found at line $chunk->{line} : include $1\n" if $debug;
                $self->{files}{$file}{includes}{_ffile($1)}=$chunk->{line};
                $self->{files}{$file}{includes}{_ffile($1)}=$chunk->{line};
                my $inc_file = $1;
                my $inc_file = $1;
                my $inc_file_and_path = _scan_dirs($inc_file,$inc_dirs,$file_dir);
                my $inc_file_and_path = _scan_dirs($inc_file,$inc_dirs,$file_dir);
                if ($inc_file_and_path) {
                if ($inc_file_and_path) {
                    push(@fileStack,$chunkRead,$f);
                    push(@fileStack,$chunkRead,$f);
                    $f = $inc_file_and_path;
                    $f = $inc_file_and_path;
                    $file=_ffile($f);
                    $file=_ffile($f);
                    $file_dir = dirname($f);
                    $file_dir = dirname($f);
 
 
                    if (!exists($self->{files}{$file})) {
                    if (!exists($self->{files}{$file})) {
                        _init_file($self->{files},$f);
                        _init_file($self->{files},$f);
                        if (exists($rs->{modules}{$rs->{module}})) {
                        if (exists($rs->{modules}{$rs->{module}})) {
                            $self->{files}{$file}{contexts}{"1"}{value} =
                            $self->{files}{$file}{contexts}{"1"}{value} =
                                $rs->{modules}{$rs->{module}};
                                $rs->{modules}{$rs->{module}};
                        }
                        }
                    }
                    }
                    print "\n Include: $f " unless $quiet;
                    print "\n Include: $f " unless $quiet;
                    $chunkRead=rvp->chunk_read_init($f,0);
                    $chunkRead=rvp->chunk_read_init($f,0);
                }
                }
                else {
                else {
                    $self->_add_warning("$file:$chunk->{line}: Include file $inc_file not found");
                    $self->_add_warning("$file:$chunk->{line}: Include file $inc_file not found");
                }
                }
                next;
                next;
            }
            }
 
 
            if (defined($pp_ignore) && $pp_ignore eq "XX") { # no endif
            if (defined($pp_ignore) && $pp_ignore eq "XX") { # no endif
                $$pp_ignore = $chunk->{line};
                $$pp_ignore = $chunk->{line};
            }
            }
        }
        }
        # check if we were included from another file
        # check if we were included from another file
        if (0==scalar(@fileStack)) {
        if (0==scalar(@fileStack)) {
            print "Stack is empty\n" if $debug;
            print "Stack is empty\n" if $debug;
            last;
            last;
        }
        }
        else {
        else {
            $f    = pop(@fileStack);
            $f    = pop(@fileStack);
            $chunkRead = pop(@fileStack);
            $chunkRead = pop(@fileStack);
            $file = _ffile($f);
            $file = _ffile($f);
            $file_dir = dirname($f);
            $file_dir = dirname($f);
            print "\n Back to $f" unless $quiet;
            print "\n Back to $f" unless $quiet;
        }
        }
    }
    }
 
 
    print "\n" unless $quiet;
    print "\n" unless $quiet;
 
 
    $self->_check_end_state($file,$self->{files}{$file}{lines},$ps);
    $self->_check_end_state($file,$self->{files}{$file}{lines},$ps);
 
 
}
}
 
 
sub _open_file {
sub _open_file {
    my ($f) = @_;
    my ($f) = @_;
    local (*F);
    local (*F);
 
 
    print "Searching $f " unless $quiet;
    print "Searching $f " unless $quiet;
    open(F,"<$f") || die "Error: can not open file $f to read: $!\n ";
    open(F,"<$f") || die "Error: can not open file $f to read: $!\n ";
    return *F;
    return *F;
}
}
 
 
# only for use while parsing - returns the last defined value
# only for use while parsing - returns the last defined value
#  in a multiple define case, and also sets up the {used} info
#  in a multiple define case, and also sets up the {used} info
#  for use later when querying the database
#  for use later when querying the database
# returns ($value,$errcode)
# returns ($value,$errcode)
#  where $errcode = 0  value ok
#  where $errcode = 0  value ok
#                   1  value never defined
#                   1  value never defined
#                   2  value has been undefined
#                   2  value has been undefined
sub _parsing_get_define_value {
sub _parsing_get_define_value {
    my ($defines,$define,$file,$line) = @_;
    my ($defines,$define,$file,$line) = @_;
 
 
    if (!exists( $defines->{$define} )) {
    if (!exists( $defines->{$define} )) {
        return ('',1);
        return ('',1);
    }
    }
    my $index = 0;
    my $index = 0;
    my $dh = $defines->{$define};
    my $dh = $defines->{$define};
 
 
    if ( 1 < @{$dh->{defined}} ) {
    if ( 1 < @{$dh->{defined}} ) {
        $index = $#{$dh->{defined}};
        $index = $#{$dh->{defined}};
 
 
        $dh->{used}{$file}{$line} = $index;
        $dh->{used}{$file}{$line} = $index;
    }
    }
 
 
    if ($dh->{defined}[$index]{undefed}) {
    if ($dh->{defined}[$index]{undefed}) {
        $dh->{used}{$file}{$line} = "XX";
        $dh->{used}{$file}{$line} = "XX";
        return ('',2);
        return ('',2);
    }
    }
 
 
    return  ( $dh->{defined}[$index]{value} , 0 );
    return  ( $dh->{defined}[$index]{value} , 0 );
}
}
 
 
sub _parsing_is_defined {
sub _parsing_is_defined {
    my ($defines,$define,$file,$line) = @_;
    my ($defines,$define,$file,$line) = @_;
 
 
    my $v;
    my $v;
    my $errcode;
    my $errcode;
    ($v,$errcode) = _parsing_get_define_value($defines,$define,$file,$line);
    ($v,$errcode) = _parsing_get_define_value($defines,$define,$file,$line);
    if ( ($errcode == 1)  ||   # never defined
    if ( ($errcode == 1)  ||   # never defined
         ($errcode == 2) ) {   # defined then undefed
         ($errcode == 2) ) {   # defined then undefed
        return 0;
        return 0;
    }
    }
    elsif ($errcode == 0) {
    elsif ($errcode == 0) {
        return 1;
        return 1;
    }
    }
    else {
    else {
        die "parsing_is_defined internal error code=$errcode";
        die "parsing_is_defined internal error code=$errcode";
    }
    }
}
}
 
 
sub _undef_define {
sub _undef_define {
    my ($defines,$define) = @_;
    my ($defines,$define) = @_;
 
 
    if (exists( $defines->{$define} )) {
    if (exists( $defines->{$define} )) {
        my $index = $#{$defines->{$define}{defined}};
        my $index = $#{$defines->{$define}{defined}};
        $defines->{$define}{defined}[$index]{undefed} = 1;
        $defines->{$define}{defined}[$index]{undefed} = 1;
    }
    }
}
}
 
 
###############################################################################
###############################################################################
# for best use this should be called line by line, so that the
# for best use this should be called line by line, so that the
#  defines get the correct values when defines are defined multiple
#  defines get the correct values when defines are defined multiple
#  times
#  times
# - this function is only used during the initial parsing of the files
# - this function is only used during the initial parsing of the files
#  (it has the error reproting code in it), use expand_defines() other times
#  (it has the error reproting code in it), use expand_defines() other times
#  it also expands on define lines (used to register the use of multiple
#  it also expands on define lines (used to register the use of multiple
#   define defines) which expand_defines doesn't
#   define defines) which expand_defines doesn't
#
#
sub _parsing_expand_defines {
sub _parsing_expand_defines {
    my ($self,$bufp,$file,$line) = @_;
    my ($self,$bufp,$file,$line) = @_;
 
 
    my $defines = $self->{defines};
    my $defines = $self->{defines};
    while ( $$bufp =~ m/^(.*?)\`($VID)/ ) {
    while ( $$bufp =~ m/^(.*?)\`($VID)/ ) {
        my $b = $1;
        my $b = $1;
        my $d = $2;
        my $d = $2;
        my $dq = quotemeta($d);
        my $dq = quotemeta($d);
        my $v;
        my $v;
        my $errCode=0;
        my $errCode=0;
        ($v,$errCode)=_parsing_get_define_value($defines,$d,$file,$line);
        ($v,$errCode)=_parsing_get_define_value($defines,$d,$file,$line);
 
 
        if ($errCode == 0) {  # no error
        if ($errCode == 0) {  # no error
            $$bufp =~ s/\`$dq/$v/;
            $$bufp =~ s/\`$dq/$v/;
        }
        }
        else {
        else {
            if ($errCode == 2) {  # defined but then undefed
            if ($errCode == 2) {  # defined but then undefed
                $self->_add_warning("$file:$line: define `$d used after undef");
                $self->_add_warning("$file:$line: define `$d used after undef");
                $$bufp =~ s/\`$dq//;
                $$bufp =~ s/\`$dq//;
            }
            }
            elsif ($b =~ m/^\s*$/) {
            elsif ($b =~ m/^\s*$/) {
                $self->_add_warning("$file:$line: unknown define: `$d, guessing it is a compiler directive");
                $self->_add_warning("$file:$line: unknown define: `$d, guessing it is a compiler directive");
                $$bufp='';
                $$bufp='';
            }
            }
            else {
            else {
                $self->_add_warning("$file:$line: found undefined define `$d");
                $self->_add_warning("$file:$line: found undefined define `$d");
                $$bufp =~ s/\`$dq//;
                $$bufp =~ s/\`$dq//;
            }
            }
        }
        }
    }
    }
}
}
 
 
###############################################################################
###############################################################################
# Look through all the include/library directories for an include/library file
# Look through all the include/library directories for an include/library file
#  optional $file_dir is used when including - here a relative path is
#  optional $file_dir is used when including - here a relative path is
#   relative to the file doing the including, so check this it checks this
#   relative to the file doing the including, so check this it checks this
sub _scan_dirs {
sub _scan_dirs {
    my ($fname,$inc_dirs,$file_dir) = @_;
    my ($fname,$inc_dirs,$file_dir) = @_;
    my ($dir);
    my ($dir);
 
 
    if ( $fname =~ m|^/| ) { # an absolute path
    if ( $fname =~ m|^/| ) { # an absolute path
      return "$fname" if ( -r "$fname" && ! -d "$fname");
      return "$fname" if ( -r "$fname" && ! -d "$fname");
    }
    }
    if (defined($file_dir) && -r "$file_dir/$fname" && ! -d "$file_dir/$fname") {
    if (defined($file_dir) && -r "$file_dir/$fname" && ! -d "$file_dir/$fname") {
        return "$file_dir/$fname";
        return "$file_dir/$fname";
    }
    }
    else {
    else {
      foreach $dir (@{$inc_dirs}) {
      foreach $dir (@{$inc_dirs}) {
          $dir =~ s|/$||;
          $dir =~ s|/$||;
          return "$dir/$fname" if ( -r "$dir/$fname" && ! -d "$dir/$fname");
          return "$dir/$fname" if ( -r "$dir/$fname" && ! -d "$dir/$fname");
      }
      }
    }
    }
    return '';
    return '';
}
}
 
 
###############################################################################
###############################################################################
# Take a look through the unresolved modules , delete any that have already
# Take a look through the unresolved modules , delete any that have already
#  been found, and for the others look on the search path
#  been found, and for the others look on the search path
#
#
sub _resolve_modules {
sub _resolve_modules {
    my ($self,$lib_dirs, $lib_exts)= @_;
    my ($self,$lib_dirs, $lib_exts)= @_;
    my ($m,$file,@resolved,$lib_ext);
    my ($m,$file,@resolved,$lib_ext);
 
 
    @resolved=();
    @resolved=();
    foreach $m (sort (keys %{$self->{unresolved_modules}})) {
    foreach $m (sort (keys %{$self->{unresolved_modules}})) {
        if ( exists( $self->{modules}{$m} )) {
        if ( exists( $self->{modules}{$m} )) {
            delete( $self->{unresolved_modules}{$m} );
            delete( $self->{unresolved_modules}{$m} );
        }
        }
        else {
        else {
            foreach $lib_ext (@{$lib_exts}) {
            foreach $lib_ext (@{$lib_exts}) {
                if ($file = _scan_dirs("$m$lib_ext",$lib_dirs)){
                if ($file = _scan_dirs("$m$lib_ext",$lib_dirs)){
                    delete( $self->{unresolved_modules}{$m} );
                    delete( $self->{unresolved_modules}{$m} );
                    print "resolve_modules: found $m in $file\n" if $debug;
                    print "resolve_modules: found $m in $file\n" if $debug;
                    push(@resolved,$file);
                    push(@resolved,$file);
                    last;
                    last;
                }
                }
            }
            }
        }
        }
    }
    }
    return @resolved;
    return @resolved;
}
}
 
 
 
 
###############################################################################
###############################################################################
# Initialize fdata->{files}{FILE} which stores file data
# Initialize fdata->{files}{FILE} which stores file data
#
#
sub _init_file {
sub _init_file {
    my ($fdataf,$file) = @_;
    my ($fdataf,$file) = @_;
    my ($fb);
    my ($fb);
    $fb = _ffile($file);
    $fb = _ffile($file);
    $fdataf->{$fb} = {};                 # set up hash for each file
    $fdataf->{$fb} = {};                 # set up hash for each file
    $fdataf->{$fb}{full_name} = $file;
    $fdataf->{$fb}{full_name} = $file;
    $fdataf->{$fb}{anchors}  = {};
    $fdataf->{$fb}{anchors}  = {};
    $fdataf->{$fb}{modules}  = {};
    $fdataf->{$fb}{modules}  = {};
    $fdataf->{$fb}{contexts} = {};
    $fdataf->{$fb}{contexts} = {};
    $fdataf->{$fb}{includes} = {};
    $fdataf->{$fb}{includes} = {};
    $fdataf->{$fb}{inc_done} = 0;
    $fdataf->{$fb}{inc_done} = 0;
    $fdataf->{$fb}{lines}    = 0;
    $fdataf->{$fb}{lines}    = 0;
    $fdataf->{$fb}{instance_lines} = {};
    $fdataf->{$fb}{instance_lines} = {};
    $fdataf->{$fb}{define_lines} = {};
    $fdataf->{$fb}{define_lines} = {};
    $fdataf->{$fb}{included_by} = [];
    $fdataf->{$fb}{included_by} = [];
 
 
}
}
 
 
###############################################################################
###############################################################################
# Initialize fdata->{FILE}{modules}{MODULE} which stores 
# Initialize fdata->{FILE}{modules}{MODULE} which stores 
#  module (or macromodule or primitive) data
#  module (or macromodule or primitive) data
#
#
sub _init_module {
sub _init_module {
    my ($modules,$module,$file,$line,$type) = @_;
    my ($modules,$module,$file,$line,$type) = @_;
 
 
 
 
    die "Error: attempt to reinit module" if (exists($modules->{$module}));
    die "Error: attempt to reinit module" if (exists($modules->{$module}));
 
 
    $modules->{$module}{line}     = $line;
    $modules->{$module}{line}     = $line;
    $modules->{$module}{name}     = $module;
    $modules->{$module}{name}     = $module;
    $modules->{$module}{type}     = $type;
    $modules->{$module}{type}     = $type;
    $modules->{$module}{end}       = -1;
    $modules->{$module}{end}       = -1;
    $modules->{$module}{file}      = $file;
    $modules->{$module}{file}      = $file;
    $modules->{$module}{t_and_f}   = {}; # tasks and functions
    $modules->{$module}{t_and_f}   = {}; # tasks and functions
    $modules->{$module}{signals}   = {};
    $modules->{$module}{signals}   = {};
    $modules->{$module}{parameter_order}= [];
    $modules->{$module}{parameter_order}= [];
    $modules->{$module}{parameters}= {};
    $modules->{$module}{parameters}= {};
    $modules->{$module}{instances} = []; # things that this module instantiates
    $modules->{$module}{instances} = []; # things that this module instantiates
    $modules->{$module}{inst_by}   = []; # things that instantiated this module
    $modules->{$module}{inst_by}   = []; # things that instantiated this module
    $modules->{$module}{port_order} = [];
    $modules->{$module}{port_order} = [];
    $modules->{$module}{named_ports} = 1; # assume named ports in instantiations
    $modules->{$module}{named_ports} = 1; # assume named ports in instantiations
    $modules->{$module}{duplicate} = 0;   # set if another definition is found
    $modules->{$module}{duplicate} = 0;   # set if another definition is found
 
 
}
}
 
 
###############################################################################
###############################################################################
# Initialize fdata->{FILE}{modules}{MODULE}{t_and_f}{TF} which
# Initialize fdata->{FILE}{modules}{MODULE}{t_and_f}{TF} which
#  stores tasks and functions' data
#  stores tasks and functions' data
#
#
sub _init_t_and_f {
sub _init_t_and_f {
    my ($self,$module,$type,$tf,$file,$line,$anchor) = @_;
    my ($self,$module,$type,$tf,$file,$line,$anchor) = @_;
 
 
    if (exists($module->{t_and_f}{$tf})) {
    if (exists($module->{t_and_f}{$tf})) {
        $self->_add_warning("$file:$line new definition of $tf ".
        $self->_add_warning("$file:$line new definition of $tf ".
                    "(discarding previous from ".
                    "(discarding previous from ".
                    "$module->{t_and_f}{$tf}{file}:$module->{t_and_f}{$tf}{line})");
                    "$module->{t_and_f}{$tf}{file}:$module->{t_and_f}{$tf}{line})");
    }
    }
    $module->{t_and_f}{$tf} = {};
    $module->{t_and_f}{$tf} = {};
    $module->{t_and_f}{$tf}{type}      = $type;
    $module->{t_and_f}{$tf}{type}      = $type;
    $module->{t_and_f}{$tf}{name}      = $tf;
    $module->{t_and_f}{$tf}{name}      = $tf;
    $module->{t_and_f}{$tf}{line}      = $line;
    $module->{t_and_f}{$tf}{line}      = $line;
    $module->{t_and_f}{$tf}{end}       = -1;
    $module->{t_and_f}{$tf}{end}       = -1;
    $module->{t_and_f}{$tf}{file}      = $file;
    $module->{t_and_f}{$tf}{file}      = $file;
    $module->{t_and_f}{$tf}{signals}   = {};
    $module->{t_and_f}{$tf}{signals}   = {};
    $module->{t_and_f}{$tf}{anchor}    = $anchor;
    $module->{t_and_f}{$tf}{anchor}    = $anchor;
    # point up at things to share with module:
    # point up at things to share with module:
    #  - task and functions
    #  - task and functions
    #  - module signals
    #  - module signals
    $module->{t_and_f}{$tf}{t_and_f}    = $module->{t_and_f};
    $module->{t_and_f}{$tf}{t_and_f}    = $module->{t_and_f};
    $module->{t_and_f}{$tf}{parameters} = $module->{parameters};
    $module->{t_and_f}{$tf}{parameters} = $module->{parameters};
    $module->{t_and_f}{$tf}{parameter_order} = $module->{parameter_order};
    $module->{t_and_f}{$tf}{parameter_order} = $module->{parameter_order};
    $module->{t_and_f}{$tf}{m_signals}  = $module->{signals};
    $module->{t_and_f}{$tf}{m_signals}  = $module->{signals};
}
}
 
 
# note returns 1 if a signal is added (and an anchor needs to be dropped)
# note returns 1 if a signal is added (and an anchor needs to be dropped)
sub _init_signal  {
sub _init_signal  {
    my ($self,$signals,$name,$type,$type2,$range,$file,$line,$warnDuplicate,$dims) = @_;
    my ($self,$signals,$name,$type,$type2,$range,$file,$line,$warnDuplicate,$dims) = @_;
 
 
    if (exists( $signals->{$name} )) {
    if (exists( $signals->{$name} )) {
        if ($warnDuplicate) {
        if ($warnDuplicate) {
            if (($signals->{$name}{type} eq "output")||
            if (($signals->{$name}{type} eq "output")||
                ($signals->{$name}{type} eq "inout")||
                ($signals->{$name}{type} eq "inout")||
                ($signals->{$name}{type} eq "input")) {
                ($signals->{$name}{type} eq "input")) {
                if (($signals->{$name}{type} eq "input")
                if (($signals->{$name}{type} eq "input")
                    && ($type eq "reg")) {
                    && ($type eq "reg")) {
                    $self->_add_warning("$file:$line: ignoring definition".
                    $self->_add_warning("$file:$line: ignoring definition".
                                " of input $name as reg (defined as input at".
                                " of input $name as reg (defined as input at".
                                " $signals->{$name}{file}:$signals->{$name}{line})");
                                " $signals->{$name}{file}:$signals->{$name}{line})");
                }
                }
                else {
                else {
                    $signals->{$name}{type2}=$type;
                    $signals->{$name}{type2}=$type;
                }
                }
            }
            }
            elsif (($signals->{$name}{type} eq "reg")&&  # reg before output
            elsif (($signals->{$name}{type} eq "reg")&&  # reg before output
                   (($type eq "output") ||
                   (($type eq "output") ||
                    ($type eq "inout"))) {
                    ($type eq "inout"))) {
                $signals->{$name}{type}=$type;
                $signals->{$name}{type}=$type;
                $signals->{$name}{type2}="reg";
                $signals->{$name}{type2}="reg";
            }
            }
            else {
            else {
                $self->_add_warning("$file:$line: ignoring another definition".
                $self->_add_warning("$file:$line: ignoring another definition".
                            " of signal $name ($type) first seen as".
                            " of signal $name ($type) first seen as".
                            " $signals->{$name}{type} at".
                            " $signals->{$name}{type} at".
                            " $signals->{$name}{file}:$signals->{$name}{line}");
                            " $signals->{$name}{file}:$signals->{$name}{line}");
            }
            }
        }
        }
        return 0;
        return 0;
    }
    }
    else {
    else {
        $signals->{$name} = { type     => $type,
        $signals->{$name} = { type     => $type,
                              file     => $file,
                              file     => $file,
                              line     => $line,
                              line     => $line,
                              a_line   => -1,
                              a_line   => -1,
                              a_file   => "",
                              a_file   => "",
                              i_line   => -1,
                              i_line   => -1,
                              i_file   => "",
                              i_file   => "",
                              port_con => [],
                              port_con => [],
                              con_to   => [],
                              con_to   => [],
                              posedge  => 0,
                              posedge  => 0,
                              negedge  => 0,
                              negedge  => 0,
                              type2    => $type2,
                              type2    => $type2,
                              source   => { checked => 0, file => "" ,
                              source   => { checked => 0, file => "" ,
                                            line => "" },
                                            line => "" },
                              range    => $range,
                              range    => $range,
                              dimensions => $dims,
                              dimensions => $dims,
                              };
                              };
        return 1;
        return 1;
    }
    }
}
}
 
 
###############################################################################
###############################################################################
# Add an anchor to the list of anchors that need to be put in
# Add an anchor to the list of anchors that need to be put in
#  the file
#  the file
#
#
sub _add_anchor {
sub _add_anchor {
    my ($anchors,$line,$name) = @_;
    my ($anchors,$line,$name) = @_;
 
 
    my ($a,$no_name_exists);
    my ($a,$no_name_exists);
 
 
    if (! exists($anchors->{$line}) ) {
    if (! exists($anchors->{$line}) ) {
        $anchors->{$line} = [];
        $anchors->{$line} = [];
    }
    }
 
 
    if ( $name ) {
    if ( $name ) {
        push( @{$anchors->{$line}} , $name );
        push( @{$anchors->{$line}} , $name );
    }
    }
    else {
    else {
        # if no name is specified then you'll get the line number
        # if no name is specified then you'll get the line number
        #  as the name, but make sure this only happens once
        #  as the name, but make sure this only happens once
        $no_name_exists = 0;
        $no_name_exists = 0;
        foreach $a ( @{$anchors->{$line}} ) {
        foreach $a ( @{$anchors->{$line}} ) {
            if ($a eq $line) {
            if ($a eq $line) {
                $no_name_exists=1;
                $no_name_exists=1;
                last;
                last;
            }
            }
        }
        }
        push( @{$anchors->{$line}} , $line ) unless ($no_name_exists);
        push( @{$anchors->{$line}} , $line ) unless ($no_name_exists);
    }
    }
}
}
 
 
sub _add_define {
sub _add_define {
    my ($defines,$def_name,$def_value,$file,$line) = @_;
    my ($defines,$def_name,$def_value,$file,$line) = @_;
 
 
    $def_value = '' if (!defined($def_value));
    $def_value = '' if (!defined($def_value));
    $def_value =~ s/\s+$//; # remove whitespace from end of define
    $def_value =~ s/\s+$//; # remove whitespace from end of define
 
 
    if (!exists($defines->{$def_name})) {
    if (!exists($defines->{$def_name})) {
        $defines->{$def_name} = { defined => [] , used => {} };
        $defines->{$def_name} = { defined => [] , used => {} };
    }
    }
 
 
    if ( (1 == @{$defines->{$def_name}{defined}}) &&
    if ( (1 == @{$defines->{$def_name}{defined}}) &&
         ($defines->{$def_name}{defined}[0]{file} eq $file) &&
         ($defines->{$def_name}{defined}[0]{file} eq $file) &&
         ($defines->{$def_name}{defined}[0]{line} == $line) ) {
         ($defines->{$def_name}{defined}[0]{line} == $line) ) {
        # if the define is already defined once (and only once) and that 
        # if the define is already defined once (and only once) and that 
        #  was the same def (file & line the same - for instance in included
        #  was the same def (file & line the same - for instance in included
        #   file) then there is no need to do anything
        #   file) then there is no need to do anything
    }
    }
    else {
    else {
        push (@{$defines->{$def_name}{defined}},
        push (@{$defines->{$def_name}{defined}},
              { line => $line, file => $file ,
              { line => $line, file => $file ,
                value => $def_value, undefed => 0 });
                value => $def_value, undefed => 0 });
    }
    }
}
}
 
 
###############################################################################
###############################################################################
#   Cross referencing
#   Cross referencing
###############################################################################
###############################################################################
 
 
###############################################################################
###############################################################################
# Cross-reference all the files:
# Cross-reference all the files:
#  - find the modules and set up $self->{modules}
#  - find the modules and set up $self->{modules}
#  - store the data about where it is instatiated with each module
#  - store the data about where it is instatiated with each module
#  - check for self instantiation
#  - check for self instantiation
#  - check for files with modules + instances outside modules
#  - check for files with modules + instances outside modules
#  - set a_line for signals driven by output and i_line
#  - set a_line for signals driven by output and i_line
#
#
sub _cross_reference {
sub _cross_reference {
    my ($self) = @_;
    my ($self) = @_;
    my ($f,$m,$fr,$mr,$m2,$inst,$sig,$sigp,$port_con,$param,$i,$port,$con_to);
    my ($f,$m,$fr,$mr,$m2,$inst,$sig,$sigp,$port_con,$param,$i,$port,$con_to);
 
 
    # stores the instantiation data in an 
    # stores the instantiation data in an 
    #  array so that we can easily tell which modules
    #  array so that we can easily tell which modules
    #  are disconnected and which are the tops of the
    #  are disconnected and which are the tops of the
    #  hierarchy and makes it easier to go up
    #  hierarchy and makes it easier to go up
    foreach $m (sort (keys %{$self->{modules}})) {
    foreach $m (sort (keys %{$self->{modules}})) {
        print " Making inst_by for $m\n" if $debug;
        print " Making inst_by for $m\n" if $debug;
        foreach $m2 (sort (keys %{$self->{modules}})) {
        foreach $m2 (sort (keys %{$self->{modules}})) {
            foreach $inst (@{$self->{modules}{$m2}{instances}}) {
            foreach $inst (@{$self->{modules}{$m2}{instances}}) {
                if (($inst->{module} eq $m) &&
                if (($inst->{module} eq $m) &&
                    exists($self->{modules}{$m})) {
                    exists($self->{modules}{$m})) {
                    print "    inst by $m2\n" if $debug;
                    print "    inst by $m2\n" if $debug;
                    push( @{$self->{modules}{$m}{inst_by}},
                    push( @{$self->{modules}{$m}{inst_by}},
                           { module => $m2,
                           { module => $m2,
                             file   => $inst->{file},
                             file   => $inst->{file},
                             inst   => $inst->{inst_name} ,
                             inst   => $inst->{inst_name} ,
                             line   => $inst->{line} } );
                             line   => $inst->{line} } );
                }
                }
            }
            }
        }
        }
    }
    }
 
 
    # Find any modules that appear to instantiate themselves
    # Find any modules that appear to instantiate themselves
    #  (to prevent getting into infinite recursions later on)
    #  (to prevent getting into infinite recursions later on)
    foreach $m (sort (keys %{$self->{modules}})) {
    foreach $m (sort (keys %{$self->{modules}})) {
        print " Checking  self instantiations for $m\n" if $debug;
        print " Checking  self instantiations for $m\n" if $debug;
        foreach $inst (@{$self->{modules}{$m}{instances}}) {
        foreach $inst (@{$self->{modules}{$m}{instances}}) {
            if ($inst->{module} eq $m) {
            if ($inst->{module} eq $m) {
                $self->_add_warning("$inst->{file}:$inst->{line}: $m ".
                $self->_add_warning("$inst->{file}:$inst->{line}: $m ".
                            "instantiates itself");
                            "instantiates itself");
                $inst->{module} = '_ERROR_SELF_INSTANTIATION_';
                $inst->{module} = '_ERROR_SELF_INSTANTIATION_';
                # remove the port con for all signals not attached
                # remove the port con for all signals not attached
                foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
                foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
                    $sigp = $self->{modules}{$m}{signals}{$sig};
                    $sigp = $self->{modules}{$m}{signals}{$sig};
                    my $port_con_ok=[];
                    my $port_con_ok=[];
                    foreach $port_con (@{$sigp->{port_con}}) {
                    foreach $port_con (@{$sigp->{port_con}}) {
                        if ($port_con->{module} ne $m) { push(@$port_con_ok,$port_con); }
                        if ($port_con->{module} ne $m) { push(@$port_con_ok,$port_con); }
                        else {  print " Deleting connection for $sig\n" if $debug; }
                        else {  print " Deleting connection for $sig\n" if $debug; }
                    }
                    }
                    $sigp->{port_con} = $port_con_ok;
                    $sigp->{port_con} = $port_con_ok;
                }
                }
            }
            }
        }
        }
    }
    }
 
 
    # Go through instances without named ports (port will be a number instead) and
    # Go through instances without named ports (port will be a number instead) and
    #  resolve name if you can, otherwise delete. These can appear in signal's port_con
    #  resolve name if you can, otherwise delete. These can appear in signal's port_con
    #  lists and in instances connections lists.
    #  lists and in instances connections lists.
    foreach $m (sort (keys %{$self->{modules}})) {
    foreach $m (sort (keys %{$self->{modules}})) {
        if (0 == $self->{modules}{$m}{named_ports}) {
        if (0 == $self->{modules}{$m}{named_ports}) {
            $f = $self->{modules}{$m}{file}; # for error messages
            $f = $self->{modules}{$m}{file}; # for error messages
            print " Resolving numbered port connections in $m\n" if $debug;
            print " Resolving numbered port connections in $m\n" if $debug;
            foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
            foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
                print "   doing $sig\n" if $debug;
                print "   doing $sig\n" if $debug;
                $sigp = $self->{modules}{$m}{signals}{$sig};
                $sigp = $self->{modules}{$m}{signals}{$sig};
 
 
                foreach $port_con (@{$sigp->{port_con}}) {
                foreach $port_con (@{$sigp->{port_con}}) {
                    if ($port_con->{port} =~ m/^[0-9]/ ) {
                    if ($port_con->{port} =~ m/^[0-9]/ ) {
                        if ( exists( $self->{modules}{$port_con->{module}}) ) {
                        if ( exists( $self->{modules}{$port_con->{module}}) ) {
                            $m2 = $self->{modules}{$port_con->{module}};
                            $m2 = $self->{modules}{$port_con->{module}};
                            if (defined($m2->{port_order}[$port_con->{port}])) {
                            if (defined($m2->{port_order}[$port_con->{port}])) {
                                $port_con->{port}=$m2->{port_order}[$port_con->{port}];
                                $port_con->{port}=$m2->{port_order}[$port_con->{port}];
                            }
                            }
                            else {
                            else {
                                $self->_add_warning("$port_con->{file}:$port_con->{line}:".
                                $self->_add_warning("$port_con->{file}:$port_con->{line}:".
                                            " could not resolve port number to name");
                                            " could not resolve port number to name");
                            }
                            }
                        }
                        }
                    }
                    }
                }
                }
            }
            }
 
 
            foreach $inst (@{$self->{modules}{$m}{instances}}) {
            foreach $inst (@{$self->{modules}{$m}{instances}}) {
                if ( exists( $self->{modules}{$inst->{module}}) ) {
                if ( exists( $self->{modules}{$inst->{module}}) ) {
                    $m2 = $self->{modules}{$inst->{module}};
                    $m2 = $self->{modules}{$inst->{module}};
                    foreach $port (sort (keys %{$inst->{connections}})) {
                    foreach $port (sort (keys %{$inst->{connections}})) {
                        last if ($port !~ m/^[0-9]/); # if any are named, all are named
                        last if ($port !~ m/^[0-9]/); # if any are named, all are named
                        if (defined($m2->{port_order}[$port])) {
                        if (defined($m2->{port_order}[$port])) {
                            # move old connection to named port
                            # move old connection to named port
                            $inst->{connections}{$m2->{port_order}[$port]} =
                            $inst->{connections}{$m2->{port_order}[$port]} =
                                $inst->{connections}{$port};
                                $inst->{connections}{$port};
                            # remove old numbered port from hash
                            # remove old numbered port from hash
                            delete($inst->{connections}{$port});
                            delete($inst->{connections}{$port});
                        }
                        }
                        else {
                        else {
                            $self->_add_warning("$inst->{file}:$inst->{line}:".
                            $self->_add_warning("$inst->{file}:$inst->{line}:".
                                        "could not resolve port number $port to name)");
                                        "could not resolve port number $port to name)");
                        }
                        }
                    }
                    }
                }
                }
            }
            }
        }
        }
    }
    }
 
 
    # Go through all instances with parameter lists and try to resolve names parameter
    # Go through all instances with parameter lists and try to resolve names parameter
    #  
    #  
    foreach $m (sort (keys %{$self->{modules}})) {
    foreach $m (sort (keys %{$self->{modules}})) {
        foreach $inst (@{$self->{modules}{$m}{instances}}) {
        foreach $inst (@{$self->{modules}{$m}{instances}}) {
            if ($inst->{parameters}) {
            if ($inst->{parameters}) {
                if ( exists( $self->{modules}{$inst->{module}}) ) {
                if ( exists( $self->{modules}{$inst->{module}}) ) {
                    my $mp=$self->{modules}{$inst->{module}};
                    my $mp=$self->{modules}{$inst->{module}};
                    foreach my $p (sort (keys %{$inst->{parameters}})){
                    foreach my $p (sort (keys %{$inst->{parameters}})){
                        last if ( $p !~ m/^[0-9]+$/ );
                        last if ( $p !~ m/^[0-9]+$/ );
                        my $pn = $mp->{parameter_order}[$p];
                        my $pn = $mp->{parameter_order}[$p];
                        if ($pn) {
                        if ($pn) {
                            $inst->{parameters}{$pn} =
                            $inst->{parameters}{$pn} =
                                $inst->{parameters}{$p};
                                $inst->{parameters}{$p};
                            delete($inst->{parameters}{$p});
                            delete($inst->{parameters}{$p});
                            print "$inst->{parameters}{$pn}{file}:".
                            print "$inst->{parameters}{$pn}{file}:".
                                "$inst->{parameters}{$pn}{line}: ".
                                "$inst->{parameters}{$pn}{line}: ".
                                "Resolved $p to $pn = $inst->{parameters}{$pn}{value}\n"
                                "Resolved $p to $pn = $inst->{parameters}{$pn}{value}\n"
                                  if $debug;
                                  if $debug;
                        }
                        }
                        else {
                        else {
                            $self->_add_warning("$inst->{parameters}{$p}{file}:".
                            $self->_add_warning("$inst->{parameters}{$p}{file}:".
                                        "$inst->{parameters}{$p}{line} ".
                                        "$inst->{parameters}{$p}{line} ".
                                        "could not resolve parameter number $p to name");
                                        "could not resolve parameter number $p to name");
                        }
                        }
                    }
                    }
                }
                }
            }
            }
        }
        }
    }
    }
 
 
    # Go through all the modules and each signal inside
    # Go through all the modules and each signal inside
    #  looking at whether the signal is connected to any outputs
    #  looking at whether the signal is connected to any outputs
    #   (set the a_line on the first one if it is not already set)
    #   (set the a_line on the first one if it is not already set)
    #  Also, when you see a signal connected to an input (and that
    #  Also, when you see a signal connected to an input (and that
    #   submod is only instantiated once) reach down into the submod
    #   submod is only instantiated once) reach down into the submod
    #   and set the i_line of that signal, so that clicking on the
    #   and set the i_line of that signal, so that clicking on the
    #   input can pop you up to the line that input is driven in
    #   input can pop you up to the line that input is driven in
    #   one of the instantiations
    #   one of the instantiations
    foreach $m (sort (keys %{$self->{modules}})) {
    foreach $m (sort (keys %{$self->{modules}})) {
        print " Finding port connections in $m\n" if $debug;
        print " Finding port connections in $m\n" if $debug;
        foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
        foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
            print "   checking signal $sig\n" if $debug;
            print "   checking signal $sig\n" if $debug;
            $sigp = $self->{modules}{$m}{signals}{$sig};
            $sigp = $self->{modules}{$m}{signals}{$sig};
 
 
            foreach $port_con (@{$sigp->{port_con}}) {
            foreach $port_con (@{$sigp->{port_con}}) {
                if ( exists( $self->{modules}{$port_con->{module}}) ) {
                if ( exists( $self->{modules}{$port_con->{module}}) ) {
                    print "    connection to $port_con->{module}\n" if $debug;
                    print "    connection to $port_con->{module}\n" if $debug;
                    $m2 = $self->{modules}{$port_con->{module}};
                    $m2 = $self->{modules}{$port_con->{module}};
                    if (exists( $m2->{signals}{$port_con->{port}})) {
                    if (exists( $m2->{signals}{$port_con->{port}})) {
                        push(@{$m2->{signals}{$port_con->{port}}{con_to}},
                        push(@{$m2->{signals}{$port_con->{port}}{con_to}},
                             { signal => $sig , module => $m , inst => $port_con->{inst}});
                             { signal => $sig , module => $m , inst => $port_con->{inst}});
                        if ( ($m2->{signals}{$port_con->{port}}{type} eq
                        if ( ($m2->{signals}{$port_con->{port}}{type} eq
                              'output') &&
                              'output') &&
                            ($sigp->{a_line} == -1)) {
                            ($sigp->{a_line} == -1)) {
                            $sigp->{driven_by_port}=1;
                            $sigp->{driven_by_port}=1;
                            $sigp->{a_line} = $port_con->{line};
                            $sigp->{a_line} = $port_con->{line};
                            $sigp->{a_file} = $port_con->{file};
                            $sigp->{a_file} = $port_con->{file};
                            _add_anchor($self->{files}{$port_con->{file}}{anchors},
                            _add_anchor($self->{files}{$port_con->{file}}{anchors},
                                       $port_con->{line},'');
                                       $port_con->{line},'');
                        }
                        }
                        elsif ($m2->{signals}{$port_con->{port}}{type} eq
                        elsif ($m2->{signals}{$port_con->{port}}{type} eq
                               'input') {
                               'input') {
                            $m2->{signals}{$port_con->{port}}{driven_by_port}=1;
                            $m2->{signals}{$port_con->{port}}{driven_by_port}=1;
                            if (scalar(@{$m2->{inst_by}}) &&
                            if (scalar(@{$m2->{inst_by}}) &&
                                ($m2->{signals}{$port_con->{port}}{i_line}==-1)) {
                                ($m2->{signals}{$port_con->{port}}{i_line}==-1)) {
                                $m2->{signals}{$port_con->{port}}{i_line}=
                                $m2->{signals}{$port_con->{port}}{i_line}=
                                  $port_con->{line};
                                  $port_con->{line};
                                $m2->{signals}{$port_con->{port}}{i_file}=
                                $m2->{signals}{$port_con->{port}}{i_file}=
                                  $port_con->{file};
                                  $port_con->{file};
                                _add_anchor($self->{files}{$port_con->{file}}{anchors},
                                _add_anchor($self->{files}{$port_con->{file}}{anchors},
                                           $port_con->{line},'');
                                           $port_con->{line},'');
                                print "    set i_line $port_con->{port} ".
                                print "    set i_line $port_con->{port} ".
                                    "$port_con->{file}:$port_con->{line}\n" if $debug;
                                    "$port_con->{file}:$port_con->{line}\n" if $debug;
                            }
                            }
                        }
                        }
                    }
                    }
                }
                }
            }
            }
        }
        }
    }
    }
 
 
    # find all signal sources
    # find all signal sources
    foreach $m (sort (keys %{$self->{modules}})) {
    foreach $m (sort (keys %{$self->{modules}})) {
        print " Finding signal sources in $m\n" if $debug;
        print " Finding signal sources in $m\n" if $debug;
        foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
        foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
            $sigp = $self->{modules}{$m}{signals}{$sig};
            $sigp = $self->{modules}{$m}{signals}{$sig};
            next if $sigp->{source}{checked};
            next if $sigp->{source}{checked};
            print "   finding signal source for $sig of $m\n" if $debug;
            print "   finding signal source for $sig of $m\n" if $debug;
            $sigp->{source} = $self->_find_signal_source($sigp);
            $sigp->{source} = $self->_find_signal_source($sigp);
        }
        }
    }
    }
 
 
    # propagate the posedge, negedge stuff up the hierarchy
    # propagate the posedge, negedge stuff up the hierarchy
    foreach $m (sort (keys %{$self->{modules}})) {
    foreach $m (sort (keys %{$self->{modules}})) {
        # only do the recursion for top level modules
        # only do the recursion for top level modules
        if ( 0== @{$self->{modules}{$m}{inst_by}} ) {
        if ( 0== @{$self->{modules}{$m}{inst_by}} ) {
            $self->_prop_edges($m);
            $self->_prop_edges($m);
        }
        }
    }
    }
 
 
    # get included_by information
    # get included_by information
    foreach $f ( sort (keys %{$self->{files}} )) {
    foreach $f ( sort (keys %{$self->{files}} )) {
        foreach $i ($self->get_files_includes($f)) {
        foreach $i ($self->get_files_includes($f)) {
            if (exists $self->{files}{$i}) {
            if (exists $self->{files}{$i}) {
                push( @{$self->{files}{$i}{included_by}} , $f );
                push( @{$self->{files}{$i}{included_by}} , $f );
            }
            }
        }
        }
    }
    }
}
}
 
 
sub _find_signal_source {
sub _find_signal_source {
    my ($self,$sigp) = @_;
    my ($self,$sigp) = @_;
    my ($con_to,$port_con,$ret_val);
    my ($con_to,$port_con,$ret_val);
 
 
    if ($sigp->{source}{checked}) {
    if ($sigp->{source}{checked}) {
        print "     source already found\n" if $debug;
        print "     source already found\n" if $debug;
        $ret_val = $sigp->{source};
        $ret_val = $sigp->{source};
    }
    }
    else {
    else {
        $ret_val =  { checked => 1, file => '' , line => '' };
        $ret_val =  { checked => 1, file => '' , line => '' };
        if (exists($sigp->{driven_by_port})) {
        if (exists($sigp->{driven_by_port})) {
            print "     drive by port\n" if $debug;
            print "     drive by port\n" if $debug;
            foreach $con_to (@{$sigp->{con_to}}) {
            foreach $con_to (@{$sigp->{con_to}}) {
#               if ($self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}}{type} eq 'input') {
#               if ($self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}}{type} eq 'input') {
                if ($sigp->{type} eq 'input') {
                if ($sigp->{type} eq 'input') {
                    print "       following input $con_to->{signal} $con_to->{module} $con_to->{inst}\n" if $debug;
                    print "       following input $con_to->{signal} $con_to->{module} $con_to->{inst}\n" if $debug;
                    if (!exists($self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}}{i_line})) { die "Error: $con_to->{signal} does not exist $!"; }
                    if (!exists($self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}}{i_line})) { die "Error: $con_to->{signal} does not exist $!"; }
                    $ret_val = $self->_find_signal_source(
                    $ret_val = $self->_find_signal_source(
                                              $self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}});
                                              $self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}});
                }
                }
            }
            }
            foreach $port_con (@{$sigp->{port_con}}) {
            foreach $port_con (@{$sigp->{port_con}}) {
                if (exists ($self->{modules}{$port_con->{module}})) {
                if (exists ($self->{modules}{$port_con->{module}})) {
                    if (exists($self->{modules}{$port_con->{module}}{signals}{$port_con->{port}})) {
                    if (exists($self->{modules}{$port_con->{module}}{signals}{$port_con->{port}})) {
                        if ($self->{modules}{$port_con->{module}}{signals}{$port_con->{port}}{type} eq 'output') {
                        if ($self->{modules}{$port_con->{module}}{signals}{$port_con->{port}}{type} eq 'output') {
                            print "       following output $port_con->{port} $port_con->{module} $port_con->{inst}\n" if $debug;
                            print "       following output $port_con->{port} $port_con->{module} $port_con->{inst}\n" if $debug;
                            $ret_val = $self->_find_signal_source(
                            $ret_val = $self->_find_signal_source(
                                                          $self->{modules}{$port_con->{module}}{signals}{$port_con->{port}});
                                                          $self->{modules}{$port_con->{module}}{signals}{$port_con->{port}});
                        }
                        }
                    }
                    }
                    else {
                    else {
                        $self->_add_warning("$port_con->{file}:$port_con->{line}:".
                        $self->_add_warning("$port_con->{file}:$port_con->{line}:".
                                    " Connection to nonexistent port ".
                                    " Connection to nonexistent port ".
                                    " $port_con->{port} of module $port_con->{module}");
                                    " $port_con->{port} of module $port_con->{module}");
                    }
                    }
                }
                }
            }
            }
        }
        }
        else {
        else {
            if ($sigp->{a_line}==-1) {
            if ($sigp->{a_line}==-1) {
                if ($sigp->{type} eq 'input') {
                if ($sigp->{type} eq 'input') {
                    print "     signal is an input not driven at higher level\n" if $debug;
                    print "     signal is an input not driven at higher level\n" if $debug;
                    $ret_val =  { checked => 1, file => $sigp->{file} , line => $sigp->{line} };
                    $ret_val =  { checked => 1, file => $sigp->{file} , line => $sigp->{line} };
                }
                }
                else {
                else {
                    print "     signal has unknown source\n" if $debug;
                    print "     signal has unknown source\n" if $debug;
                }
                }
            }
            }
            else {
            else {
                print "     signal is driven in this module\n" if $debug;
                print "     signal is driven in this module\n" if $debug;
                $ret_val =  { checked => 1 , file => $sigp->{a_file} , line => $sigp->{a_line} };
                $ret_val =  { checked => 1 , file => $sigp->{a_file} , line => $sigp->{a_line} };
            }
            }
        }
        }
    }
    }
 
 
    $sigp->{source} = $ret_val;
    $sigp->{source} = $ret_val;
    return $ret_val;
    return $ret_val;
}
}
 
 
###############################################################################
###############################################################################
# Propagate posedge and negedge attributes of signals up the hierarchy
# Propagate posedge and negedge attributes of signals up the hierarchy
#
#
sub _prop_edges {
sub _prop_edges {
    my ($self,$m) = @_;
    my ($self,$m) = @_;
    my ($imod,@inst,$sig,$sigp,$port_con,$m2);
    my ($imod,@inst,$sig,$sigp,$port_con,$m2);
 
 
    print "Prop_edges $m\n" if $debug;
    print "Prop_edges $m\n" if $debug;
 
 
    for ( ($imod) = $self->get_first_instantiation($m) ;
    for ( ($imod) = $self->get_first_instantiation($m) ;
          $imod;
          $imod;
          ($imod) = $self->get_next_instantiation()) {
          ($imod) = $self->get_next_instantiation()) {
        push(@inst,$imod) if (exists( $self->{modules}{$imod}));
        push(@inst,$imod) if (exists( $self->{modules}{$imod}));
    }
    }
    foreach $imod (@inst) { $self->_prop_edges($imod); }
    foreach $imod (@inst) { $self->_prop_edges($imod); }
 
 
    # Propagate all the edges up the hierarchy
    # Propagate all the edges up the hierarchy
    foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
    foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
        print "   checking signal $sig\n" if $debug;
        print "   checking signal $sig\n" if $debug;
        $sigp = $self->{modules}{$m}{signals}{$sig};
        $sigp = $self->{modules}{$m}{signals}{$sig};
 
 
        foreach $port_con (@{$sigp->{port_con}}) {
        foreach $port_con (@{$sigp->{port_con}}) {
            if ( exists( $self->{modules}{$port_con->{module}}) ) {
            if ( exists( $self->{modules}{$port_con->{module}}) ) {
                print "    connection to $port_con->{module}\n" if $debug;
                print "    connection to $port_con->{module}\n" if $debug;
                $m2 = $self->{modules}{$port_con->{module}};
                $m2 = $self->{modules}{$port_con->{module}};
                if (exists( $m2->{signals}{$port_con->{port}})) {
                if (exists( $m2->{signals}{$port_con->{port}})) {
                    print "Propagating posedge on $sig from $port_con->{module} to $m\n"
                    print "Propagating posedge on $sig from $port_con->{module} to $m\n"
                        if ($debug && (!$sigp->{posedge})  && $m2->{signals}{$port_con->{port}}{posedge});
                        if ($debug && (!$sigp->{posedge})  && $m2->{signals}{$port_con->{port}}{posedge});
                    $sigp->{posedge} |= $m2->{signals}{$port_con->{port}}{posedge};
                    $sigp->{posedge} |= $m2->{signals}{$port_con->{port}}{posedge};
                    $sigp->{negedge} |= $m2->{signals}{$port_con->{port}}{negedge};
                    $sigp->{negedge} |= $m2->{signals}{$port_con->{port}}{negedge};
                }
                }
            }
            }
        }
        }
    }
    }
}
}
 
 
 
 
###############################################################################
###############################################################################
# given a source file name work out the file without the path
# given a source file name work out the file without the path
#
#
sub _ffile {
sub _ffile {
    my ($sfile) = @_;
    my ($sfile) = @_;
 
 
    $sfile =~ s/^.*[\/\\]//;
    $sfile =~ s/^.*[\/\\]//;
 
 
    return $sfile;
    return $sfile;
}
}
 
 
sub _add_warning {
sub _add_warning {
    my ($self,$p) = @_;
    my ($self,$p) = @_;
 
 
    print "Warning:$p\n" if $debug;
    print "Warning:$p\n" if $debug;
    push (@{$self->{problems}},"Warning:$p");
    push (@{$self->{problems}},"Warning:$p");
}
}
sub _add_confused {
sub _add_confused {
    my ($self,$p) = @_;
    my ($self,$p) = @_;
 
 
    print "Confused:$p\n" if $debug;
    print "Confused:$p\n" if $debug;
    push (@{$self->{problems}},"Confused:$p");
    push (@{$self->{problems}},"Confused:$p");
}
}
 
 
###############################################################################
###############################################################################
# 
# 
BEGIN {
BEGIN {
$baseEval = {
$baseEval = {
  START => {
  START => {
    MODULE => '$rs->{t}={ type=>$match, line=>$line };',
    MODULE => '$rs->{t}={ type=>$match, line=>$line };',
  },
  },
  MODULE => {
  MODULE => {
    SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
    SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
    # if you add to this also edit {AFTER_INST}{COMMA}
    # if you add to this also edit {AFTER_INST}{COMMA}
    INST => '$rs->{t}={ mod=>$match, line=>$line, name=>"" , port=>0 ,
    INST => '$rs->{t}={ mod=>$match, line=>$line, name=>"" , port=>0 ,
                        params=>{}, param_number=>0 , portName=>"" , vids=>[]};',
                        params=>{}, param_number=>0 , portName=>"" , vids=>[]};',
  },
  },
  MODULE_NAME => {
  MODULE_NAME => {
    NAME => 'my $nState="MODULE_PPL";
    NAME => 'my $nState="MODULE_PPL";
             my $type = $rs->{t}{type};  $rs->{t}=undef;',
             my $type = $rs->{t}{type};  $rs->{t}=undef;',
  },
  },
  IN_CONCAT => {
  IN_CONCAT => {
    VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line}) if (exists($rs->{t}{vids}));',
    VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line}) if (exists($rs->{t}{vids}));',
  },
  },
  IN_BRACKET => {
  IN_BRACKET => {
    VID => 'IN_CONCAT:VID',
    VID => 'IN_CONCAT:VID',
  },
  },
  SCALARED_OR_VECTORED => {
  SCALARED_OR_VECTORED => {
    TYPE => 'if ($match eq "reg") { $rs->{t}{type2} = "reg"; }'
    TYPE => 'if ($match eq "reg") { $rs->{t}{type2} = "reg"; }'
  },
  },
  SIGNAL_NAME => {
  SIGNAL_NAME => {
    VID => '$rs->{t}{name}=$match; $rs->{t}{line}=$line;',
    VID => '$rs->{t}{name}=$match; $rs->{t}{line}=$line;',
  },
  },
  SIGNAL_AFTER_EQUALS => {
  SIGNAL_AFTER_EQUALS => {
    END => '$rs->{t}=undef;',
    END => '$rs->{t}=undef;',
  },
  },
  INST_PARAM_BRACKET => {
  INST_PARAM_BRACKET => {
    NO_BRACKET => '$self->_add_warning("$file:$line: possible missing brackets after \# in instantiation");',
    NO_BRACKET => '$self->_add_warning("$file:$line: possible missing brackets after \# in instantiation");',
  },
  },
  INST_NAME => {
  INST_NAME => {
    VID => '$rs->{t}{name}=$match;',
    VID => '$rs->{t}{name}=$match;',
  },
  },
  INST_PORTS => {
  INST_PORTS => {
    COMMA => '$rs->{t}{port}++;',
    COMMA => '$rs->{t}{port}++;',
  },
  },
  INST_PORT_NAME => {
  INST_PORT_NAME => {
    NAME => '$rs->{t}{portName}=$match;
    NAME => '$rs->{t}{portName}=$match;
             $rs->{t}{vids} = [];', # throw away any instance parameters picked up
             $rs->{t}{vids} = [];', # throw away any instance parameters picked up
  },
  },
  INST_NAMED_PORT_CON => {
  INST_NAMED_PORT_CON => {
    VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line});',
    VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line});',
  },
  },
  INST_NAMED_PORT_CON_AFTER => {
  INST_NAMED_PORT_CON_AFTER => {
    COMMA => 'if ($rs->{t}{portName} eq "") { $rs->{t}{portName}=$rs->{t}{port}++; }
    COMMA => 'if ($rs->{t}{portName} eq "") { $rs->{t}{portName}=$rs->{t}{port}++; }
                 my @vids = @{$rs->{t}{vids}};
                 my @vids = @{$rs->{t}{vids}};
                 my $portName = $rs->{t}{portName};
                 my $portName = $rs->{t}{portName};
                 $rs->{t}{portName}="";
                 $rs->{t}{portName}="";
                 $rs->{t}{vids}=[];',
                 $rs->{t}{vids}=[];',
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
  },
  },
  INST_NUMBERED_PORT => {
  INST_NUMBERED_PORT => {
    COMMA   => 'INST_NAMED_PORT_CON_AFTER:COMMA',
    COMMA   => 'INST_NAMED_PORT_CON_AFTER:COMMA',
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
    VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line});',
    VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line});',
  },
  },
  AFTER_INST => {
  AFTER_INST => {
    SEMICOLON => '$rs->{t}=undef;',
    SEMICOLON => '$rs->{t}=undef;',
    COMMA     => '$rs->{t}{line}=$line;
    COMMA     => '$rs->{t}{line}=$line;
                  $rs->{t}{name}="";
                  $rs->{t}{name}="";
                  $rs->{t}{port}=0;
                  $rs->{t}{port}=0;
                  $rs->{t}{portName}="";
                  $rs->{t}{portName}="";
                  $rs->{t}{vids}=[];',
                  $rs->{t}{vids}=[];',
  },
  },
  SIGNAL_AFTER_NAME => {
  SIGNAL_AFTER_NAME => {
    SEMICOLON => '$rs->{t}=undef;',
    SEMICOLON => '$rs->{t}=undef;',
  },
  },
  IN_EVENT_BRACKET => {
  IN_EVENT_BRACKET => {
    EDGE => '$rs->{t}={ type=>$match };',
    EDGE => '$rs->{t}={ type=>$match };',
  },
  },
  IN_EVENT_BRACKET_EDGE => {
  IN_EVENT_BRACKET_EDGE => {
    VID => 'my $edgeType = $rs->{t}{type}; $rs->{t}=undef;',
    VID => 'my $edgeType = $rs->{t}{type}; $rs->{t}=undef;',
  },
  },
  STMNT => {
  STMNT => {
    ASSIGN_OR_TASK => '$rs->{t}={ vids=>[{name=>$match,line=>$line}]};',
    ASSIGN_OR_TASK => '$rs->{t}={ vids=>[{name=>$match,line=>$line}]};',
    HIER_ASSIGN_OR_TASK => '$rs->{t}={ vids=>[]};',
    HIER_ASSIGN_OR_TASK => '$rs->{t}={ vids=>[]};',
    CONCAT             => '$rs->{t}={ vids=>[]};',
    CONCAT             => '$rs->{t}={ vids=>[]};',
  },
  },
  STMNT_ASSIGN_OR_TASK => { # copy of STMNT_ASSIGN
  STMNT_ASSIGN_OR_TASK => { # copy of STMNT_ASSIGN
    EQUALS    => 'my @vids = @{$rs->{t}{vids}}; $rs->{t}=undef;',
    EQUALS    => 'my @vids = @{$rs->{t}{vids}}; $rs->{t}=undef;',
# Revisit: this arc doesn't exist anymore - put this into smnt_semicolon
# Revisit: this arc doesn't exist anymore - put this into smnt_semicolon
#    SEMICOLON => '$rs->{t}=undef;', 
#    SEMICOLON => '$rs->{t}=undef;', 
    BRACKET   => '$rs->{t}=undef;',
    BRACKET   => '$rs->{t}=undef;',
  },
  },
  STMNT_ASSIGN => { # copy of STMNT_ASSIGN_OR_TASK
  STMNT_ASSIGN => { # copy of STMNT_ASSIGN_OR_TASK
    EQUALS => 'STMNT_ASSIGN_OR_TASK:EQUALS',
    EQUALS => 'STMNT_ASSIGN_OR_TASK:EQUALS',
  },
  },
  IN_SIG_RANGE => {
  IN_SIG_RANGE => {
    END => '$rs->{t}{range}=$fromLastPos;',
    END => '$rs->{t}{range}=$fromLastPos;',
  },
  },
  IN_MEM_RANGE => {
  IN_MEM_RANGE => {
    END => 'push(@{$rs->{t}{dimensions}},$fromLastPos);',
    END => 'push(@{$rs->{t}{dimensions}},$fromLastPos);',
  },
  },
  ANSI_PORTS_TYPE => { # V2001 ansi ports
  ANSI_PORTS_TYPE => { # V2001 ansi ports
    TYPE =>  '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
    TYPE =>  '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
  },
  },
  ANSI_PORTS_TYPE2 => { # V2001 ansi ports
  ANSI_PORTS_TYPE2 => { # V2001 ansi ports
    TYPE => 'if ($match eq "reg") { $rs->{t}{type2} = "reg"; }',
    TYPE => 'if ($match eq "reg") { $rs->{t}{type2} = "reg"; }',
  },
  },
  ANSI_PORTS_SIGNAL_NAME => { # V2001 ansi ports
  ANSI_PORTS_SIGNAL_NAME => { # V2001 ansi ports
    VID => '$rs->{t}{name}=$match; $rs->{t}{line}=$line;',
    VID => '$rs->{t}{name}=$match; $rs->{t}{line}=$line;',
  },
  },
};
};
 
 
############################################################
############################################################
# debugEval
# debugEval
############################################################
############################################################
$debugEval = {
$debugEval = {
  ANSI_PORTS_SIGNAL_NAME => {
  ANSI_PORTS_SIGNAL_NAME => {
    VID => 'print "Found $rs->{t}{type} $rs->{t}{name} $rs->{t}{range} [$line]\n";',
    VID => 'print "Found $rs->{t}{type} $rs->{t}{name} $rs->{t}{range} [$line]\n";',
  },
  },
  SIGNAL_NAME => {
  SIGNAL_NAME => {
    VID => 'print "Found $rs->{t}{type} $rs->{t}{name} $rs->{t}{range} [$line]\n";',
    VID => 'print "Found $rs->{t}{type} $rs->{t}{name} $rs->{t}{range} [$line]\n";',
  },
  },
  INST_BRACKET => {
  INST_BRACKET => {
    PORTS => 'print "found instance $rs->{t}{name} of $rs->{t}{mod} [$rs->{t}{line}]\n";',
    PORTS => 'print "found instance $rs->{t}{name} of $rs->{t}{mod} [$rs->{t}{line}]\n";',
  },
  },
  INST_NAMED_PORT_CON_AFTER => {
  INST_NAMED_PORT_CON_AFTER => {
    COMMA => 'my @vidnames;
    COMMA => 'my @vidnames;
            foreach my $vid (@vids) {push @vidnames,$vid->{name};}
            foreach my $vid (@vids) {push @vidnames,$vid->{name};}
            print " Port $portName connected to ".join(",",@vidnames)."\n";',
            print " Port $portName connected to ".join(",",@vidnames)."\n";',
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
  },
  },
  INST_NUMBERED_PORT => {
  INST_NUMBERED_PORT => {
    COMMA   => 'INST_NAMED_PORT_CON_AFTER:COMMA',
    COMMA   => 'INST_NAMED_PORT_CON_AFTER:COMMA',
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
  },
  },
};
};
 
 
 
 
############################################################
############################################################
# rvpEval
# rvpEval
############################################################
############################################################
 
 
$rvpEval = {
$rvpEval = {
  MODULE => {
  MODULE => {
    ENDMODULE => 'if ((($rs->{p}{type} eq "primitive")&&($match ne "endprimitive"))||
    ENDMODULE => 'if ((($rs->{p}{type} eq "primitive")&&($match ne "endprimitive"))||
                         (($rs->{p}{type} ne "primitive")&&($match eq "endprimitive"))){
                         (($rs->{p}{type} ne "primitive")&&($match eq "endprimitive"))){
                     $self->_add_warning("$file:$line: module of type".
                     $self->_add_warning("$file:$line: module of type".
                                 " $rs->{p}{type} ended by $match");
                                 " $rs->{p}{type} ended by $match");
                  }
                  }
                  $rs->{modules}{$rs->{module}}{end} = $line;
                  $rs->{modules}{$rs->{module}}{end} = $line;
                  $rs->{module}   = "";
                  $rs->{module}   = "";
                  $rs->{files}{$file}{contexts}{$line}{value}= { name=>"",type=>"" };
                  $rs->{files}{$file}{contexts}{$line}{value}= { name=>"",type=>"" };
                  $rs->{p}= undef;',
                  $rs->{p}= undef;',
    PARAM => '$rs->{t} = { ptype => $match };', # parameter of localparam
    PARAM => '$rs->{t} = { ptype => $match };', # parameter of localparam
  },
  },
  MODULE_NAME => {
  MODULE_NAME => {
    NAME => 'if (exists($rs->{modules}{$match})) {
    NAME => 'if (exists($rs->{modules}{$match})) {
                 $nState = "IGNORE_MODULE";
                 $nState = "IGNORE_MODULE";
                 $rs->{modules}{$match}{duplicate} = 1;
                 $rs->{modules}{$match}{duplicate} = 1;
                 $self->_add_warning("$file:$line ignoring new definition of ".
                 $self->_add_warning("$file:$line ignoring new definition of ".
                          "module $match, previous was at ".
                          "module $match, previous was at ".
                          "$rs->{modules}{$match}{file}:$rs->{modules}{$match}{line})");
                          "$rs->{modules}{$match}{file}:$rs->{modules}{$match}{line})");
             }
             }
             else {
             else {
               $rs->{module}=$match;
               $rs->{module}=$match;
               _init_module($rs->{modules},$rs->{module},$file,$line,$type);
               _init_module($rs->{modules},$rs->{module},$file,$line,$type);
               $rs->{files}{$file}{modules}{$rs->{module}} = $rs->{modules}{$rs->{module}};
               $rs->{files}{$file}{modules}{$rs->{module}} = $rs->{modules}{$rs->{module}};
               _add_anchor($rs->{files}{$file}{anchors},$line,$rs->{module});
               _add_anchor($rs->{files}{$file}{anchors},$line,$rs->{module});
               $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};
               $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};
               $rs->{files}{$file}{contexts}{$line}{module_start}= $rs->{module};
               $rs->{files}{$file}{contexts}{$line}{module_start}= $rs->{module};
             }',
             }',
  },
  },
  MODULE_PORTS => {
  MODULE_PORTS => {
    VID => 'push(@{$rs->{p}{port_order}},$match);',
    VID => 'push(@{$rs->{p}{port_order}},$match);',
  },
  },
  FUNCTION => {
  FUNCTION => {
    NAME => '$rs->{function}=$match;
    NAME => '$rs->{function}=$match;
                      $self->_init_t_and_f($rs->{modules}{$rs->{module}},"function",
                      $self->_init_t_and_f($rs->{modules}{$rs->{module}},"function",
                      $rs->{function},$file,$line,$rs->{module}."_".$rs->{function});
                      $rs->{function},$file,$line,$rs->{module}."_".$rs->{function});
                      _add_anchor($rs->{files}{$file}{anchors},$line,$rs->{module}."_".$rs->{function});
                      _add_anchor($rs->{files}{$file}{anchors},$line,$rs->{module}."_".$rs->{function});
                      $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}}{t_and_f}{$rs->{function}};',
                      $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}}{t_and_f}{$rs->{function}};',
  },
  },
  TASK => {
  TASK => {
    NAME => '$rs->{task}=$match;
    NAME => '$rs->{task}=$match;
                      $self->_init_t_and_f($rs->{modules}{$rs->{module}},"task",
                      $self->_init_t_and_f($rs->{modules}{$rs->{module}},"task",
                                   $rs->{task},$file,$line,$rs->{module}. "_" .$rs->{task});
                                   $rs->{task},$file,$line,$rs->{module}. "_" .$rs->{task});
                      _add_anchor($rs->{files}{$file}{anchors},$line,$rs->{module}. "_" . $rs->{task});
                      _add_anchor($rs->{files}{$file}{anchors},$line,$rs->{module}. "_" . $rs->{task});
                      $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}}{t_and_f}{$rs->{task}};',
                      $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}}{t_and_f}{$rs->{task}};',
  },
  },
  ENDTASK => {
  ENDTASK => {
    ENDTASK => '$rs->{modules}{$rs->{module}}{t_and_f}{$rs->{task}}{end} = $line;
    ENDTASK => '$rs->{modules}{$rs->{module}}{t_and_f}{$rs->{task}}{end} = $line;
                $rs->{task}="";
                $rs->{task}="";
                $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};',
                $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};',
  },
  },
  T_SIGNAL => {
  T_SIGNAL => {
     SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"" , block=>0};',
     SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"" , block=>0};',
     ENDTASK => 'ENDTASK:ENDTASK',
     ENDTASK => 'ENDTASK:ENDTASK',
     PARAM => 'MODULE:PARAM', # not realy needed yet because T/F parameters are ignored
     PARAM => 'MODULE:PARAM', # not realy needed yet because T/F parameters are ignored
  },
  },
  ENDFUNCTION => {
  ENDFUNCTION => {
      ENDFUNCTION => '$rs->{modules}{$rs->{module}}{t_and_f}{$rs->{function}}{end} = $line;
      ENDFUNCTION => '$rs->{modules}{$rs->{module}}{t_and_f}{$rs->{function}}{end} = $line;
                     $rs->{function}="";
                     $rs->{function}="";
                     $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};',
                     $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};',
  },
  },
  F_SIGNAL => {
  F_SIGNAL => {
     SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
     SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
     ENDFUNCTION => 'ENDFUNCTION:ENDFUNCTION',
     ENDFUNCTION => 'ENDFUNCTION:ENDFUNCTION',
     PARAM => 'MODULE:PARAM', # not realy needed yet because T/F parameters are ignored
     PARAM => 'MODULE:PARAM', # not realy needed yet because T/F parameters are ignored
  },
  },
  BLOCK_SIGNAL => {
  BLOCK_SIGNAL => {
     SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"" , block=>1};',
     SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"" , block=>1};',
  },
  },
  PARAM_NAME => {
  PARAM_NAME => {
    NAME => 'if ( ($rs->{function} eq "") && ($rs->{task} eq "")) { # ignore parameters in tasks and functions
    NAME => 'if ( ($rs->{function} eq "") && ($rs->{task} eq "")) { # ignore parameters in tasks and functions
              $rs->{t}= { file => $file, line => $line , value => "" ,
              $rs->{t}= { file => $file, line => $line , value => "" ,
                          ptype => $rs->{t}{ptype}}; # ptype is same as the last one
                          ptype => $rs->{t}{ptype}}; # ptype is same as the last one
              push(@{$rs->{p}{parameter_order}}, $match)
              push(@{$rs->{p}{parameter_order}}, $match)
                    unless ($rs->{t}{ptype} eq "localparam");
                    unless ($rs->{t}{ptype} eq "localparam");
              $rs->{p}{parameters}{$match}=$rs->{t};
              $rs->{p}{parameters}{$match}=$rs->{t};
              _add_anchor($rs->{files}{$file}{anchors},$line,""); }',
              _add_anchor($rs->{files}{$file}{anchors},$line,""); }',
  },
  },
  PPL_PARAM => {
  PPL_PARAM => {
     PARAM => '$rs->{t} = { ptype => "parameter" };', # this can't be a localparam
     PARAM => '$rs->{t} = { ptype => "parameter" };', # this can't be a localparam
  },
  },
  PPL_NAME => {
  PPL_NAME => {
     NAME => 'PARAM_NAME:NAME',
     NAME => 'PARAM_NAME:NAME',
  },
  },
  PARAM_AFTER_EQUALS => {
  PARAM_AFTER_EQUALS => {
    COMMA     => '$rs->{t}{value} = $fromLastPos;',
    COMMA     => '$rs->{t}{value} = $fromLastPos;',
    SEMICOLON => 'PARAM_AFTER_EQUALS:COMMA',
    SEMICOLON => 'PARAM_AFTER_EQUALS:COMMA',
  },
  },
  PPL_AFTER_EQUALS => {
  PPL_AFTER_EQUALS => {
     COMMA   => 'PARAM_AFTER_EQUALS:COMMA',
     COMMA   => 'PARAM_AFTER_EQUALS:COMMA',
     END     => 'PARAM_AFTER_EQUALS:COMMA',
     END     => 'PARAM_AFTER_EQUALS:COMMA',
  },
  },
  ASSIGN => {
  ASSIGN => {
    VID => 'if ( exists($rs->{p}{signals}{$match}) &&
    VID => 'if ( exists($rs->{p}{signals}{$match}) &&
                              ($rs->{p}{signals}{$match}{a_line} == -1)) {
                              ($rs->{p}{signals}{$match}{a_line} == -1)) {
               $rs->{p}{signals}{$match}{a_line} = $line;
               $rs->{p}{signals}{$match}{a_line} = $line;
               $rs->{p}{signals}{$match}{a_file} = $file;
               $rs->{p}{signals}{$match}{a_file} = $file;
               _add_anchor($rs->{files}{$file}{anchors},$line,"");
               _add_anchor($rs->{files}{$file}{anchors},$line,"");
            }',
            }',
  },
  },
  SIGNAL_NAME => { # note skip signals local to a block ({block}==1)
  SIGNAL_NAME => { # note skip signals local to a block ({block}==1)
    VID => 'if ($rs->{t}{block} != 1) {
    VID => 'if ($rs->{t}{block} != 1) {
              $self->_init_signal($rs->{p}{signals},$match,$rs->{t}{type},$rs->{t}{type2},
              $self->_init_signal($rs->{p}{signals},$match,$rs->{t}{type},$rs->{t}{type2},
                        $rs->{t}{range},$file,$line,1,$rs->{t}{dimensions})
                        $rs->{t}{range},$file,$line,1,$rs->{t}{dimensions})
               && _add_anchor($rs->{files}{$file}{anchors},$line,"");
               && _add_anchor($rs->{files}{$file}{anchors},$line,"");
            }',
            }',
  },
  },
  SIGNAL_AFTER_NAME => { # don't assign a_line for reg at definition, as this is 
  SIGNAL_AFTER_NAME => { # don't assign a_line for reg at definition, as this is 
                         #   only the initial value
                         #   only the initial value
    ASSIGN => 'if ($rs->{t}{block} != 1) {
    ASSIGN => 'if ($rs->{t}{block} != 1) {
                if ( $rs->{p}{signals}{$rs->{t}{name}}{type} ne "reg" ) {
                if ( $rs->{p}{signals}{$rs->{t}{name}}{type} ne "reg" ) {
                  $rs->{p}{signals}{$rs->{t}{name}}{a_line}=$rs->{t}{line};
                  $rs->{p}{signals}{$rs->{t}{name}}{a_line}=$rs->{t}{line};
                  $rs->{p}{signals}{$rs->{t}{name}}{a_file}=$file;
                  $rs->{p}{signals}{$rs->{t}{name}}{a_file}=$file;
                  _add_anchor($rs->{files}{$file}{anchors},$rs->{t}{line},"");
                  _add_anchor($rs->{files}{$file}{anchors},$rs->{t}{line},"");
                }
                }
               }',
               }',
  },
  },
  INST_PARAM_VALUE => {
  INST_PARAM_VALUE => {
    # Note: the code is nearly the same in INST_PARAM_VALUE:COMMA,
    # Note: the code is nearly the same in INST_PARAM_VALUE:COMMA,
    #   and INST_PARAM_BRACKET:NO_BRACKET, but the first uses $fromLastPos
    #   and INST_PARAM_BRACKET:NO_BRACKET, but the first uses $fromLastPos
    #   and the second uses $match to capture the parameter value
    #   and the second uses $match to capture the parameter value
    COMMA => 'my $inst_num= $#{$rs->{p}{instances}};
    COMMA => 'my $inst_num= $#{$rs->{p}{instances}};
              $rs->{t}{params}{$rs->{t}{param_number}} =
              $rs->{t}{params}{$rs->{t}{param_number}} =
                     { file => $file , line => $line , value => $fromLastPos };
                     { file => $file , line => $line , value => $fromLastPos };
              $rs->{t}{param_number}++;',
              $rs->{t}{param_number}++;',
    END   => 'INST_PARAM_VALUE:COMMA',
    END   => 'INST_PARAM_VALUE:COMMA',
  },
  },
  INST_PARAM_BRACKET => {
  INST_PARAM_BRACKET => {
    # Note: the code is nearly the same in INST_PARAM_VALUE:COMMA,
    # Note: the code is nearly the same in INST_PARAM_VALUE:COMMA,
    #   and INST_PARAM_BRACKET:NO_BRACKET, but the first uses $fromLastPos
    #   and INST_PARAM_BRACKET:NO_BRACKET, but the first uses $fromLastPos
    #   and the second uses $match to capture the parameter value
    #   and the second uses $match to capture the parameter value
    NO_BRACKET => 'my $inst_num= $#{$rs->{p}{instances}};
    NO_BRACKET => 'my $inst_num= $#{$rs->{p}{instances}};
              $rs->{t}{params}{$rs->{t}{param_number}} =
              $rs->{t}{params}{$rs->{t}{param_number}} =
                     { file => $file , line => $line , value => $match };
                     { file => $file , line => $line , value => $match };
              $rs->{t}{param_number}++;',
              $rs->{t}{param_number}++;',
  },
  },
  INST_BRACKET => {
  INST_BRACKET => {
    PORTS => '$rs->{unres_mod}{$rs->{t}{mod}}=$rs->{t}{mod};
    PORTS => '$rs->{unres_mod}{$rs->{t}{mod}}=$rs->{t}{mod};
              $rs->{files}{$file}{instance_lines}{$rs->{t}{line}} = $rs->{t}{mod};
              $rs->{files}{$file}{instance_lines}{$rs->{t}{line}} = $rs->{t}{mod};
              push( @{$rs->{p}{instances}} , { module => $rs->{t}{mod} ,
              push( @{$rs->{p}{instances}} , { module => $rs->{t}{mod} ,
                                               inst_name => $rs->{t}{name} ,
                                               inst_name => $rs->{t}{name} ,
                                               file => $file,
                                               file => $file,
                                               line => $rs->{t}{line},
                                               line => $rs->{t}{line},
                                               parameters => $rs->{t}{params},
                                               parameters => $rs->{t}{params},
                                               connections => {} });
                                               connections => {} });
              _add_anchor($rs->{files}{$file}{anchors},$rs->{t}{line},
              _add_anchor($rs->{files}{$file}{anchors},$rs->{t}{line},
                         $rs->{module}."_".$rs->{t}{name});',
                         $rs->{module}."_".$rs->{t}{name});',
  },
  },
  INST_NAMED_PORT_CON_AFTER => {
  INST_NAMED_PORT_CON_AFTER => {
    COMMA =>   'my $inst_num= $#{$rs->{p}{instances}};
    COMMA =>   'my $inst_num= $#{$rs->{p}{instances}};
              $rs->{p}{instances}[$inst_num]{connections}{$portName}=$fromLastPos;
              $rs->{p}{instances}[$inst_num]{connections}{$portName}=$fromLastPos;
              if ($portName =~ /^[0-9]/ ) { # clear named_ports flag if port is a number
              if ($portName =~ /^[0-9]/ ) { # clear named_ports flag if port is a number
                 $rs->{p}{named_ports} = 0;
                 $rs->{p}{named_ports} = 0;
              }
              }
              else { # remove the bracket from the end if a named port
              else { # remove the bracket from the end if a named port
                 $rs->{p}{instances}[$inst_num]{connections}{$portName}=~s/\)\s*$//s;
                 $rs->{p}{instances}[$inst_num]{connections}{$portName}=~s/\)\s*$//s;
              }
              }
              foreach my $s (@vids) {
              foreach my $s (@vids) {
                $self->_init_signal($rs->{p}{signals},$s->{name},"wire","","",$file,$s->{line},0,$rs->{t}{dimensions})
                $self->_init_signal($rs->{p}{signals},$s->{name},"wire","","",$file,$s->{line},0,$rs->{t}{dimensions})
                    && _add_anchor($rs->{files}{$file}{anchors},$s->{line},"");
                    && _add_anchor($rs->{files}{$file}{anchors},$s->{line},"");
                 push( @{$rs->{p}{signals}{$s->{name}}{port_con}},
                 push( @{$rs->{p}{signals}{$s->{name}}{port_con}},
                        { port   => $portName ,
                        { port   => $portName ,
                          line   => $s->{line},
                          line   => $s->{line},
                          file   => $file,
                          file   => $file,
                          module => $rs->{t}{mod} ,
                          module => $rs->{t}{mod} ,
                          inst   => $rs->{t}{name} });
                          inst   => $rs->{t}{name} });
              }',
              }',
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
  },
  },
  INST_NUMBERED_PORT => {
  INST_NUMBERED_PORT => {
    COMMA   => 'INST_NAMED_PORT_CON_AFTER:COMMA',
    COMMA   => 'INST_NAMED_PORT_CON_AFTER:COMMA',
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
  },
  },
  IN_EVENT_BRACKET_EDGE => {
  IN_EVENT_BRACKET_EDGE => {
    VID => 'if (exists($rs->{p}{signals}{$match})) {
    VID => 'if (exists($rs->{p}{signals}{$match})) {
               $rs->{p}{signals}{$match}{$edgeType}=1; };',
               $rs->{p}{signals}{$match}{$edgeType}=1; };',
  },
  },
 
 
  STMNT_ASSIGN_OR_TASK => { # copy of STMNT_ASSIGN
  STMNT_ASSIGN_OR_TASK => { # copy of STMNT_ASSIGN
    EQUALS => 'foreach my $s (@vids) {
    EQUALS => 'foreach my $s (@vids) {
                 my $sigp = undef;
                 my $sigp = undef;
                 if ( exists($rs->{p}{signals}{$s->{name}} )) {
                 if ( exists($rs->{p}{signals}{$s->{name}} )) {
                      $sigp = $rs->{p}{signals}{$s->{name}};
                      $sigp = $rs->{p}{signals}{$s->{name}};
                 }
                 }
                 elsif ( exists($rs->{p}{m_signals}) &&
                 elsif ( exists($rs->{p}{m_signals}) &&
                         exists($rs->{p}{m_signals}{$s->{name}}) ) {
                         exists($rs->{p}{m_signals}{$s->{name}}) ) {
                      $sigp = $rs->{p}{m_signals}{$s->{name}};
                      $sigp = $rs->{p}{m_signals}{$s->{name}};
                 }
                 }
                 if (defined($sigp) && ($sigp->{a_line}==-1)) {
                 if (defined($sigp) && ($sigp->{a_line}==-1)) {
                      $sigp->{a_line}=$s->{line};
                      $sigp->{a_line}=$s->{line};
                      $sigp->{a_file}=$file;
                      $sigp->{a_file}=$file;
                      _add_anchor($rs->{files}{$file}{anchors},$s->{line},"");
                      _add_anchor($rs->{files}{$file}{anchors},$s->{line},"");
                 }
                 }
               }',
               }',
  },
  },
  STMNT_ASSIGN => { # copy of STMNT_ASSIGN_OR_TASK
  STMNT_ASSIGN => { # copy of STMNT_ASSIGN_OR_TASK
    EQUALS => 'STMNT_ASSIGN_OR_TASK:EQUALS',
    EQUALS => 'STMNT_ASSIGN_OR_TASK:EQUALS',
  },
  },
  ANSI_PORTS_SIGNAL_NAME => { # V2001 ansi ports
  ANSI_PORTS_SIGNAL_NAME => { # V2001 ansi ports
    VID => '$self->_init_signal($rs->{p}{signals},$match,$rs->{t}{type},$rs->{t}{type2},
    VID => '$self->_init_signal($rs->{p}{signals},$match,$rs->{t}{type},$rs->{t}{type2},
                        $rs->{t}{range},$file,$line,1,$rs->{t}{dimensions});
                        $rs->{t}{range},$file,$line,1,$rs->{t}{dimensions});
            push(@{$rs->{p}{port_order}},$match) if exists $rs->{p}{port_order};
            push(@{$rs->{p}{port_order}},$match) if exists $rs->{p}{port_order};
            _add_anchor($rs->{files}{$file}{anchors},$line,"");',
            _add_anchor($rs->{files}{$file}{anchors},$line,"");',
  },
  },
};
};
 
 
############################################################
############################################################
# language definition
# language definition
############################################################
############################################################
 
 
$vid_vnum_or_string =
$vid_vnum_or_string =
[ { arcName=> 'HVID',   regexp=> '$HVID', nextState=> ['$ps->{curState}'] ,}, # hier id
[ { arcName=> 'HVID',   regexp=> '$HVID', nextState=> ['$ps->{curState}'] ,}, # hier id
  { arcName=> 'VID',    regexp=> '$VID' , nextState=> ['$ps->{curState}'] ,},
  { arcName=> 'VID',    regexp=> '$VID' , nextState=> ['$ps->{curState}'] ,},
  { arcName=> 'NUMBER', regexp=> '$VNUM', nextState=> ['$ps->{curState}'] ,},
  { arcName=> 'NUMBER', regexp=> '$VNUM', nextState=> ['$ps->{curState}'] ,},
  { arcName=> 'STRING', regexp=> '\\"',   nextState=> ['IN_STRING','$ps->{curState}'],},
  { arcName=> 'STRING', regexp=> '\\"',   nextState=> ['IN_STRING','$ps->{curState}'],},
];
];
 
 
$languageDef =
$languageDef =
[
[
 {
 {
 stateName =>     'START',
 stateName =>     'START',
 confusedNextState => 'START',
 confusedNextState => 'START',
 search =>
 search =>
  [
  [
   { arcName   => 'MODULE' ,        regexp => '\b(?:module|macromodule|primitive)\b',
   { arcName   => 'MODULE' ,        regexp => '\b(?:module|macromodule|primitive)\b',
     nextState => ['MODULE_NAME'] ,},
     nextState => ['MODULE_NAME'] ,},
   { arcName   => 'CONFIG',        regexp => '\bconfig\b', # V2001
   { arcName   => 'CONFIG',        regexp => '\bconfig\b', # V2001
     nextState => ['CONFIG'] , },
     nextState => ['CONFIG'] , },
   { arcName   => 'LIBRARY',        regexp => '\blibrary\b', # V2001
   { arcName   => 'LIBRARY',        regexp => '\blibrary\b', # V2001
     nextState => ['LIBRARY'] , },
     nextState => ['LIBRARY'] , },
  ],
  ],
 },
 },
 {
 {
 stateName =>     'MODULE',
 stateName =>     'MODULE',
 confusedNextState => 'MODULE',
 confusedNextState => 'MODULE',
 search =>
 search =>
  [
  [
   { arcName   => 'ENDMODULE' ,     regexp => '\b(?:end(?:module|primitive))\b',
   { arcName   => 'ENDMODULE' ,     regexp => '\b(?:end(?:module|primitive))\b',
     nextState => ['START'] ,  },
     nextState => ['START'] ,  },
   { arcName   => 'FUNCTION',       regexp => '\bfunction\b',
   { arcName   => 'FUNCTION',       regexp => '\bfunction\b',
     nextState => ['FUNCTION'] , },
     nextState => ['FUNCTION'] , },
   { arcName   => 'TASK',           regexp => '\btask\b',
   { arcName   => 'TASK',           regexp => '\btask\b',
     nextState => ['TASK'] ,  },
     nextState => ['TASK'] ,  },
   { arcName   => 'PARAM',      regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
   { arcName   => 'PARAM',      regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
     nextState => ['PARAM_TYPE','MODULE'] ,  },
     nextState => ['PARAM_TYPE','MODULE'] ,  },
   { arcName   => 'SPECIFY',        regexp => '\bspecify\b',
   { arcName   => 'SPECIFY',        regexp => '\bspecify\b',
     nextState => ['SPECIFY'] , },
     nextState => ['SPECIFY'] , },
   { arcName   => 'TABLE',          regexp => '\btable\b',
   { arcName   => 'TABLE',          regexp => '\btable\b',
     nextState => ['TABLE'] ,  },
     nextState => ['TABLE'] ,  },
   { arcName   => 'EVENT_DECLARATION' ,    regexp => '\bevent\b' ,
   { arcName   => 'EVENT_DECLARATION' ,    regexp => '\bevent\b' ,
     nextState => ['EVENT_DECLARATION'] ,  },
     nextState => ['EVENT_DECLARATION'] ,  },
   { arcName   => 'DEFPARAM' ,       regexp => '\bdefparam\b' ,
   { arcName   => 'DEFPARAM' ,       regexp => '\bdefparam\b' ,
     nextState => ['DEFPARAM'] , },
     nextState => ['DEFPARAM'] , },
   { arcName   => 'GATE' ,           regexp => "$verilog_gatetype_regexp" ,
   { arcName   => 'GATE' ,           regexp => "$verilog_gatetype_regexp" ,
     nextState => ['GATE'] ,   },
     nextState => ['GATE'] ,   },
   { arcName   => 'ASSIGN' ,         regexp => '\bassign\b' ,
   { arcName   => 'ASSIGN' ,         regexp => '\bassign\b' ,
     nextState => ['ASSIGN'] , },
     nextState => ['ASSIGN'] , },
   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
     nextState => ['DRIVE_STRENGTH','MODULE'] , },
     nextState => ['DRIVE_STRENGTH','MODULE'] , },
   { arcName   => 'INITIAL_OR_ALWAYS', regexp => '\b(?:initial|always)\b' ,
   { arcName   => 'INITIAL_OR_ALWAYS', regexp => '\b(?:initial|always)\b' ,
     nextState => ['STMNT','MODULE'] , },
     nextState => ['STMNT','MODULE'] , },
   { arcName   => 'GENERATE',       regexp => '\bgenerate\b', # V2001
   { arcName   => 'GENERATE',       regexp => '\bgenerate\b', # V2001
     nextState => ['GENERATE'] , },
     nextState => ['GENERATE'] , },
 
 
 
 
   { arcName   => 'INST',          regexp    => '$VID' ,
   { arcName   => 'INST',          regexp    => '$VID' ,
     nextState => ['INST_PARAM'] , },
     nextState => ['INST_PARAM'] , },
   # don't put any more states here because $VID matches almost anything
   # don't put any more states here because $VID matches almost anything
   ],
   ],
 },################ END OF MODULE STATE
 },################ END OF MODULE STATE
 {
 {
 stateName =>     'MODULE_NAME',
 stateName =>     'MODULE_NAME',
 search =>   # $nState is usually MODULE_PPL, but is set to
 search =>   # $nState is usually MODULE_PPL, but is set to
             #   IGNORE_MODULE when a duplicate module is found
             #   IGNORE_MODULE when a duplicate module is found
  [ { arcName   => 'NAME',  regexp => '$VID' , nextState => ['$nState'] , }, ],
  [ { arcName   => 'NAME',  regexp => '$VID' , nextState => ['$nState'] , }, ],
 },
 },
 {
 {
 stateName =>     'IGNORE_MODULE' ,  # just look for endmodule
 stateName =>     'IGNORE_MODULE' ,  # just look for endmodule
 allowAnything => 1,
 allowAnything => 1,
 search => [
 search => [
   { arcName   => 'ENDMODULE' , regexp    => '\bendmodule\b',
   { arcName   => 'ENDMODULE' , regexp    => '\bendmodule\b',
     nextState => ['START'], },
     nextState => ['START'], },
   @$vid_vnum_or_string,
   @$vid_vnum_or_string,
  ],
  ],
 },
 },
 {
 {
 stateName =>     'MODULE_PPL' ,  # v2001 module_parameter_port_list (A.1.3)
 stateName =>     'MODULE_PPL' ,  # v2001 module_parameter_port_list (A.1.3)
 failNextState => ['MODULE_PORTS'],
 failNextState => ['MODULE_PORTS'],
 search => [ { regexp    => '#',  nextState => ['PPL_BRACKET'], }, ],
 search => [ { regexp    => '#',  nextState => ['PPL_BRACKET'], }, ],
 },
 },
 {
 {
 stateName =>     'MODULE_PORTS' ,  # just look for signals until ;
 stateName =>     'MODULE_PORTS' ,  # just look for signals until ;
 allowAnything => 1,
 allowAnything => 1,
 search => [
 search => [
   { arcName   => 'TYPE' , regexp    => '\b(?:input|output|inout)\b',  # V2001 ansi ports
   { arcName   => 'TYPE' , regexp    => '\b(?:input|output|inout)\b',  # V2001 ansi ports
     nextState => ['ANSI_PORTS_TYPE','MODULE'], resetPos => 1, },
     nextState => ['ANSI_PORTS_TYPE','MODULE'], resetPos => 1, },
   { arcName   => 'END', regexp    => ';' , nextState => ['MODULE'] , },
   { arcName   => 'END', regexp    => ';' , nextState => ['MODULE'] , },
   @$vid_vnum_or_string,
   @$vid_vnum_or_string,
  ],
  ],
 },
 },
 {
 {
 stateName =>     'FUNCTION' ,
 stateName =>     'FUNCTION' ,
 search => [
 search => [
    { arcName => 'RANGE', regexp => '\[', nextState => ['IN_RANGE','FUNCTION'] , },
    { arcName => 'RANGE', regexp => '\[', nextState => ['IN_RANGE','FUNCTION'] , },
    { arcName => 'TYPE',  regexp => '\b(?:real|integer|time|realtime)\b',
    { arcName => 'TYPE',  regexp => '\b(?:real|integer|time|realtime)\b',
      nextState => ['FUNCTION'] ,  },
      nextState => ['FUNCTION'] ,  },
    { arcName => 'SIGNED', regexp => '\bsigned\b' ,nextState => ['FUNCTION'] ,  }, # V2001
    { arcName => 'SIGNED', regexp => '\bsigned\b' ,nextState => ['FUNCTION'] ,  }, # V2001
    { arcName => 'AUTO',   regexp => '\bautomatic\b' ,nextState => ['FUNCTION'] ,  }, # V2001
    { arcName => 'AUTO',   regexp => '\bautomatic\b' ,nextState => ['FUNCTION'] ,  }, # V2001
    { arcName => 'NAME',  regexp => '$VID' , nextState => ['FUNCTION_AFTER_NAME'] ,
    { arcName => 'NAME',  regexp => '$VID' , nextState => ['FUNCTION_AFTER_NAME'] ,
    },
    },
   ],
   ],
 },
 },
 {
 {
 stateName =>     'FUNCTION_AFTER_NAME' ,
 stateName =>     'FUNCTION_AFTER_NAME' ,
 search => [
 search => [
    { arcName => 'SEMICOLON', regexp => ';', nextState => ['F_SIGNAL'] , },
    { arcName => 'SEMICOLON', regexp => ';', nextState => ['F_SIGNAL'] , },
    { arcName => 'BRACKET',  regexp => '\(' ,   # V2001
    { arcName => 'BRACKET',  regexp => '\(' ,   # V2001
      nextState => ['ANSI_PORTS_TYPE','F_SIGNAL'] ,  },
      nextState => ['ANSI_PORTS_TYPE','F_SIGNAL'] ,  },
  ],
  ],
 },
 },
 {
 {
 stateName =>     'TASK' ,
 stateName =>     'TASK' ,
 search => [
 search => [
   { arcName => 'AUTO', regexp => '\bautomatic\b', nextState => ['TASK'],}, # V2001
   { arcName => 'AUTO', regexp => '\bautomatic\b', nextState => ['TASK'],}, # V2001
   { arcName => 'NAME', regexp => '$VID', nextState => ['TASK_AFTER_NAME'],},],
   { arcName => 'NAME', regexp => '$VID', nextState => ['TASK_AFTER_NAME'],},],
 },
 },
 {
 {
 stateName =>     'TASK_AFTER_NAME' ,
 stateName =>     'TASK_AFTER_NAME' ,
 search => [
 search => [
    { arcName => 'SEMICOLON', regexp => ';', nextState => ['T_SIGNAL'] , },
    { arcName => 'SEMICOLON', regexp => ';', nextState => ['T_SIGNAL'] , },
    { arcName => 'BRACKET',  regexp => '\(' ,   # V2001
    { arcName => 'BRACKET',  regexp => '\(' ,   # V2001
      nextState => ['ANSI_PORTS_TYPE','T_SIGNAL'] ,  },
      nextState => ['ANSI_PORTS_TYPE','T_SIGNAL'] ,  },
  ],
  ],
 },
 },
 {
 {
 stateName =>     'T_SIGNAL' ,
 stateName =>     'T_SIGNAL' ,
 failNextState => ['STMNT','ENDTASK'],
 failNextState => ['STMNT','ENDTASK'],
 search => [
 search => [
   { arcName   => 'ENDTASK',        regexp => '\bendtask\b',
   { arcName   => 'ENDTASK',        regexp => '\bendtask\b',
     nextState => ['MODULE'] , },
     nextState => ['MODULE'] , },
   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
     nextState => ['DRIVE_STRENGTH','T_SIGNAL'] , },
     nextState => ['DRIVE_STRENGTH','T_SIGNAL'] , },
   { arcName   => 'PARAM',      regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
   { arcName   => 'PARAM',      regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
     nextState => ['PARAM_TYPE','T_SIGNAL'] ,  },
     nextState => ['PARAM_TYPE','T_SIGNAL'] ,  },
   ],
   ],
 },
 },
 {
 {
 stateName =>     'ENDTASK',
 stateName =>     'ENDTASK',
 search => [
 search => [
   { arcName   => 'ENDTASK',        regexp => '\bendtask\b',
   { arcName   => 'ENDTASK',        regexp => '\bendtask\b',
     nextState => ['MODULE'] , },
     nextState => ['MODULE'] , },
   ],
   ],
 },
 },
 {
 {
 stateName =>     'F_SIGNAL' ,
 stateName =>     'F_SIGNAL' ,
 failNextState => ['STMNT','ENDFUNCTION'],
 failNextState => ['STMNT','ENDFUNCTION'],
 search => [
 search => [
   { arcName   => 'ENDFUNCTION',     regexp => '\bendfunction\b',
   { arcName   => 'ENDFUNCTION',     regexp => '\bendfunction\b',
     nextState => ['MODULE'] , },
     nextState => ['MODULE'] , },
   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
     nextState => ['DRIVE_STRENGTH','F_SIGNAL'] , },
     nextState => ['DRIVE_STRENGTH','F_SIGNAL'] , },
   { arcName   => 'PARAM',      regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
   { arcName   => 'PARAM',      regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
     nextState => ['PARAM_TYPE','F_SIGNAL'] ,  },
     nextState => ['PARAM_TYPE','F_SIGNAL'] ,  },
   ],
   ],
 },
 },
 {
 {
 stateName =>     'ENDFUNCTION',
 stateName =>     'ENDFUNCTION',
 search => [
 search => [
   { arcName   => 'ENDFUNCTION',     regexp => '\bendfunction\b',
   { arcName   => 'ENDFUNCTION',     regexp => '\bendfunction\b',
     nextState => ['MODULE'] , },
     nextState => ['MODULE'] , },
   ],
   ],
 },
 },
 {
 {
 stateName =>     'PARAM_TYPE',
 stateName =>     'PARAM_TYPE',
 failNextState => ['PARAM_NAME'],
 failNextState => ['PARAM_NAME'],
 search => [
 search => [
    { arcName   => 'RANGE', regexp    => '\[' ,
    { arcName   => 'RANGE', regexp    => '\[' ,
      nextState => ['IN_RANGE','PARAM_NAME'] , },
      nextState => ['IN_RANGE','PARAM_NAME'] , },
    { arcName   => 'SIGNED', regexp    => '\bsigned\b' ,
    { arcName   => 'SIGNED', regexp    => '\bsigned\b' ,
      nextState => ['PARAM_TYPE'] , },  # may be followed by a range
      nextState => ['PARAM_TYPE'] , },  # may be followed by a range
    { arcName   => 'OTHER', regexp    => '\b(?:integer|real|realtime|time)\b' ,
    { arcName   => 'OTHER', regexp    => '\b(?:integer|real|realtime|time)\b' ,
      nextState => ['PARAM_NAME'] , },
      nextState => ['PARAM_NAME'] , },
   ],
   ],
 },
 },
 {
 {
 stateName =>     'PARAM_NAME',
 stateName =>     'PARAM_NAME',
 search => [
 search => [
    { arcName   => 'NAME',  regexp    => '$VID' ,
    { arcName   => 'NAME',  regexp    => '$VID' ,
      nextState => ['PARAMETER_EQUAL','PARAM_AFTER_EQUALS'] , },
      nextState => ['PARAMETER_EQUAL','PARAM_AFTER_EQUALS'] , },
   ],
   ],
 },
 },
 {
 {
 stateName =>     'PARAMETER_EQUAL',
 stateName =>     'PARAMETER_EQUAL',
  search => [ { regexp    => '=' , storePos => 1, }, ]
  search => [ { regexp    => '=' , storePos => 1, }, ]
 },
 },
 {
 {
 stateName =>     'PARAM_AFTER_EQUALS',
 stateName =>     'PARAM_AFTER_EQUALS',
 allowAnything => 1,
 allowAnything => 1,
 search =>
 search =>
  [
  [
   { arcName   => 'CONCAT',      regexp    => '{' ,
   { arcName   => 'CONCAT',      regexp    => '\{' ,
     nextState => ['IN_CONCAT','PARAM_AFTER_EQUALS'] ,  },
     nextState => ['IN_CONCAT','PARAM_AFTER_EQUALS'] ,  },
   { arcName   => 'COMMA',       regexp    => ',' ,
   { arcName   => 'COMMA',       regexp    => ',' ,
     nextState => ['PARAM_NAME'] ,    },
     nextState => ['PARAM_NAME'] ,    },
   { arcName   => 'SEMICOLON',   regexp    => ';' , },
   { arcName   => 'SEMICOLON',   regexp    => ';' , },
   @$vid_vnum_or_string,
   @$vid_vnum_or_string,
  ]
  ]
 },
 },
 {
 {
 stateName =>     'IN_CONCAT',
 stateName =>     'IN_CONCAT',
 allowAnything => 1,
 allowAnything => 1,
 search =>
 search =>
  [
  [
   { arcName   => 'CONCAT' ,   regexp    => '{' ,
   { arcName   => 'CONCAT' ,   regexp    => '\{' ,
     nextState => ['IN_CONCAT','IN_CONCAT'] ,     },
     nextState => ['IN_CONCAT','IN_CONCAT'] ,     },
   { arcName   => 'END' ,      regexp    => '}' , }, # pop up
   { arcName   => 'END' ,      regexp    => '}' , }, # pop up
   @$vid_vnum_or_string,
   @$vid_vnum_or_string,
  ]
  ]
 },
 },
 {
 {
 stateName =>     'IN_RANGE',
 stateName =>     'IN_RANGE',
 allowAnything => 1,
 allowAnything => 1,
 search =>
 search =>
  [
  [
   { arcName   => 'RANGE' , regexp    => '\[' ,
   { arcName   => 'RANGE' , regexp    => '\[' ,
     nextState => ['IN_RANGE','IN_RANGE'] , },
     nextState => ['IN_RANGE','IN_RANGE'] , },
   { arcName   => 'END' ,   regexp    => '\]' , }, # pop up
   { arcName   => 'END' ,   regexp    => '\]' , }, # pop up
   @$vid_vnum_or_string,
   @$vid_vnum_or_string,
  ]
  ]
 },
 },
 {
 {
 stateName =>     'IN_SIG_RANGE', # just like in range, but stores
 stateName =>     'IN_SIG_RANGE', # just like in range, but stores
 allowAnything => 1,
 allowAnything => 1,
 search =>
 search =>
  [
  [
   { arcName   => 'RANGE' , regexp    => '\[' ,
   { arcName   => 'RANGE' , regexp    => '\[' ,
     nextState => ['IN_SIG_RANGE','IN_SIG_RANGE'] , },
     nextState => ['IN_SIG_RANGE','IN_SIG_RANGE'] , },
   { arcName   => 'END' ,   regexp    => '\]' , }, # pop up
   { arcName   => 'END' ,   regexp    => '\]' , }, # pop up
   @$vid_vnum_or_string,
   @$vid_vnum_or_string,
  ]
  ]
 },
 },
 {
 {
 stateName =>     'IN_MEM_RANGE', # just like in range, but stores
 stateName =>     'IN_MEM_RANGE', # just like in range, but stores
 allowAnything => 1,
 allowAnything => 1,
 search =>
 search =>
  [
  [
   { arcName   => 'RANGE' , regexp    => '\[' ,
   { arcName   => 'RANGE' , regexp    => '\[' ,
     nextState => ['IN_MEM_RANGE','IN_MEM_RANGE'] , },
     nextState => ['IN_MEM_RANGE','IN_MEM_RANGE'] , },
   { arcName   => 'END' ,   regexp    => '\]' , }, # pop up
   { arcName   => 'END' ,   regexp    => '\]' , }, # pop up
   @$vid_vnum_or_string,
   @$vid_vnum_or_string,
  ]
  ]
 },
 },
 {
 {
 stateName =>     'IN_BRACKET',
 stateName =>     'IN_BRACKET',
 allowAnything => 1,
 allowAnything => 1,
 search =>
 search =>
  [
  [
   { arcName   => 'BRACKET' ,  regexp    => '\(' ,
   { arcName   => 'BRACKET' ,  regexp    => '\(' ,
     nextState => ['IN_BRACKET','IN_BRACKET'] ,   },
     nextState => ['IN_BRACKET','IN_BRACKET'] ,   },
   { arcName   => 'END' ,      regexp    => '\)' ,  }, # pop up
   { arcName   => 'END' ,      regexp    => '\)' ,  }, # pop up
   @$vid_vnum_or_string,
   @$vid_vnum_or_string,
  ]
  ]
 },
 },
 {
 {
 stateName =>     'IN_STRING',
 stateName =>     'IN_STRING',
 allowAnything => 1,
 allowAnything => 1,
 search =>
 search =>
  [ # note: put \" in regexp so that emacs colouring doesn't get confused
  [ # note: put \" in regexp so that emacs colouring doesn't get confused
   { arcName   => 'ESCAPED_QUOTE' ,  regexp => '\\\\\\"' , # match \"
   { arcName   => 'ESCAPED_QUOTE' ,  regexp => '\\\\\\"' , # match \"
     nextState => ['IN_STRING'] , },
     nextState => ['IN_STRING'] , },
   # match \\ (to make sure that \\" does not match \"
   # match \\ (to make sure that \\" does not match \"
   { arcName   => 'ESCAPE' ,         regexp => '\\\\\\\\' ,
   { arcName   => 'ESCAPE' ,         regexp => '\\\\\\\\' ,
     nextState => ['IN_STRING'] , },
     nextState => ['IN_STRING'] , },
   { arcName   => 'END' ,            regexp => '\\"' , }, # match " and pop up
   { arcName   => 'END' ,            regexp => '\\"' , }, # match " and pop up
  ]
  ]
 },
 },
 {
 {
 stateName =>     'SPECIFY',
 stateName =>     'SPECIFY',
 allowAnything => 1,
 allowAnything => 1,
 search => [ { regexp => '\bendspecify\b' , nextState => ['MODULE'] ,},
 search => [ { regexp => '\bendspecify\b' , nextState => ['MODULE'] ,},
               @$vid_vnum_or_string,],
               @$vid_vnum_or_string,],
 },
 },
 {
 {
 stateName =>     'TABLE',
 stateName =>     'TABLE',
 allowAnything => 1,
 allowAnything => 1,
 search => [ { regexp => '\bendtable\b'   , nextState => ['MODULE'] ,},
 search => [ { regexp => '\bendtable\b'   , nextState => ['MODULE'] ,},
             @$vid_vnum_or_string,],
             @$vid_vnum_or_string,],
 },
 },
 {
 {
 stateName =>     'EVENT_DECLARATION' ,  # just look for ;
 stateName =>     'EVENT_DECLARATION' ,  # just look for ;
 allowAnything => 1,
 allowAnything => 1,
 search => [ {  regexp    => ';' ,    nextState => ['MODULE'] , },
 search => [ {  regexp    => ';' ,    nextState => ['MODULE'] , },
             @$vid_vnum_or_string,],
             @$vid_vnum_or_string,],
 },
 },
 {
 {
 stateName =>     'DEFPARAM' ,  # just look for ;
 stateName =>     'DEFPARAM' ,  # just look for ;
 allowAnything => 1,
 allowAnything => 1,
 search => [ {  regexp    => ';' ,    nextState => ['MODULE'] , },
 search => [ {  regexp    => ';' ,    nextState => ['MODULE'] , },
             @$vid_vnum_or_string,],
             @$vid_vnum_or_string,],
 },
 },
 {
 {
  # REVISIT: could find signal driven by gate here (is output always the first one??)
  # REVISIT: could find signal driven by gate here (is output always the first one??)
 stateName =>     'GATE' ,
 stateName =>     'GATE' ,
 allowAnything => 1,
 allowAnything => 1,
 search => [ {  regexp    => ';' ,    nextState => ['MODULE'] , },
 search => [ {  regexp    => ';' ,    nextState => ['MODULE'] , },
             @$vid_vnum_or_string,],
             @$vid_vnum_or_string,],
 },
 },
 {
 {
 stateName =>     'ASSIGN',
 stateName =>     'ASSIGN',
 allowAnything => 1,
 allowAnything => 1,
 search =>
 search =>
  [
  [
   { arcName   => 'RANGE' ,   regexp    => '\[' ,
   { arcName   => 'RANGE' ,   regexp    => '\[' ,
     nextState => ['IN_RANGE','ASSIGN'] ,      },
     nextState => ['IN_RANGE','ASSIGN'] ,      },
   { arcName   => 'EQUALS' ,  regexp    => '=' ,
   { arcName   => 'EQUALS' ,  regexp    => '=' ,
     nextState => ['ASSIGN_AFTER_EQUALS'] ,    },
     nextState => ['ASSIGN_AFTER_EQUALS'] ,    },
   @$vid_vnum_or_string,
   @$vid_vnum_or_string,
  ]
  ]
 },
 },
 {
 {
 stateName =>     'ASSIGN_AFTER_EQUALS' ,
 stateName =>     'ASSIGN_AFTER_EQUALS' ,
 allowAnything => 1,
 allowAnything => 1,
  search =>
  search =>
   [
   [
    { arcName=>'COMMA',     regexp => ',',
    { arcName=>'COMMA',     regexp => ',',
      nextState => ['ASSIGN'],},
      nextState => ['ASSIGN'],},
    { arcName=>'CONCAT',    regexp => '{',
    { arcName=>'CONCAT',    regexp => '\{',
      nextState => ['IN_CONCAT','ASSIGN_AFTER_EQUALS'],},
      nextState => ['IN_CONCAT','ASSIGN_AFTER_EQUALS'],},
    # don't get confused by function calls (which can also contain commas)
    # don't get confused by function calls (which can also contain commas)
    {   arcName=>'BRACKET',   regexp => '\(',
    {   arcName=>'BRACKET',   regexp => '\(',
        nextState => ['IN_BRACKET','ASSIGN_AFTER_EQUALS'],},
        nextState => ['IN_BRACKET','ASSIGN_AFTER_EQUALS'],},
    {   arcName=>'END',       regexp => ';',
    {   arcName=>'END',       regexp => ';',
        nextState => ['MODULE'],},
        nextState => ['MODULE'],},
    @$vid_vnum_or_string,
    @$vid_vnum_or_string,
   ],
   ],
 },
 },
 {
 {
 stateName =>     'DRIVE_STRENGTH',  # signal defs - drive strength or charge strength
 stateName =>     'DRIVE_STRENGTH',  # signal defs - drive strength or charge strength
 failNextState => ['SCALARED_OR_VECTORED'],
 failNextState => ['SCALARED_OR_VECTORED'],
 search => [ { regexp => '\(', nextState => ['IN_BRACKET','SCALARED_OR_VECTORED'],}],
 search => [ { regexp => '\(', nextState => ['IN_BRACKET','SCALARED_OR_VECTORED'],}],
 },
 },
 { # REVISIT: V2001 - the name of this is misleading now
 { # REVISIT: V2001 - the name of this is misleading now
 stateName =>     'SCALARED_OR_VECTORED',  # for signal defs
 stateName =>     'SCALARED_OR_VECTORED',  # for signal defs
 failNextState => ['SIGNAL_RANGE'],
 failNextState => ['SIGNAL_RANGE'],
 search => [ { regexp => '\b(?:scalared|vectored)\b', nextState => ['SIGNAL_RANGE'],},
 search => [ { regexp => '\b(?:scalared|vectored)\b', nextState => ['SIGNAL_RANGE'],},
             { arcName => 'TYPE' , regexp => "$verilog_sigs_regexp", # V2001
             { arcName => 'TYPE' , regexp => "$verilog_sigs_regexp", # V2001
               nextState => ['SCALARED_OR_VECTORED'],},
               nextState => ['SCALARED_OR_VECTORED'],},
             { regexp => '\b(?:signed)\b', nextState => ['SCALARED_OR_VECTORED'],},], # V2001
             { regexp => '\b(?:signed)\b', nextState => ['SCALARED_OR_VECTORED'],},], # V2001
 },
 },
 {
 {
 stateName =>     'SIGNAL_RANGE',          # for signal defs
 stateName =>     'SIGNAL_RANGE',          # for signal defs
  failNextState => ['SIGNAL_DELAY'],
  failNextState => ['SIGNAL_DELAY'],
 search => [ { regexp => '\[', nextState => ['IN_SIG_RANGE','SIGNAL_DELAY'],
 search => [ { regexp => '\[', nextState => ['IN_SIG_RANGE','SIGNAL_DELAY'],
               storePos => 1,}, ],
               storePos => 1,}, ],
 },
 },
 {
 {
 stateName =>     'SIGNAL_DELAY',          # for signal defs
 stateName =>     'SIGNAL_DELAY',          # for signal defs
 failNextState => ['SIGNAL_NAME'],
 failNextState => ['SIGNAL_NAME'],
 search => [ { regexp => '\#', nextState => ['DELAY_VALUE','SIGNAL_NAME'],},  ],
 search => [ { regexp => '\#', nextState => ['DELAY_VALUE','SIGNAL_NAME'],},  ],
 },
 },
 {
 {
 stateName =>     'SIGNAL_NAME',           # for signal defs
 stateName =>     'SIGNAL_NAME',           # for signal defs
  search => [ { arcName   => 'VID' , regexp    => '$VID',
  search => [ { arcName   => 'VID' , regexp    => '$VID',
               nextState => ['SIGNAL_AFTER_NAME'], }, ],
               nextState => ['SIGNAL_AFTER_NAME'], }, ],
 },
 },
 { # for signal defs
 { # for signal defs
 stateName =>     'SIGNAL_AFTER_NAME',
 stateName =>     'SIGNAL_AFTER_NAME',
 search =>
 search =>
  [
  [
   { regexp => ',',  nextState => ['SIGNAL_NAME'],},
   { regexp => ',',  nextState => ['SIGNAL_NAME'],},
   { regexp => '\[', nextState => ['IN_MEM_RANGE','SIGNAL_AFTER_NAME'],
   { regexp => '\[', nextState => ['IN_MEM_RANGE','SIGNAL_AFTER_NAME'],
     storePos => 1 , }, # memories
     storePos => 1 , }, # memories
   { arcName => 'SEMICOLON' , regexp => ';',},  # pop up
   { arcName => 'SEMICOLON' , regexp => ';',},  # pop up
   { arcName => 'ASSIGN',     regexp => '=', nextState => ['SIGNAL_AFTER_EQUALS'],}
   { arcName => 'ASSIGN',     regexp => '=', nextState => ['SIGNAL_AFTER_EQUALS'],}
  ],
  ],
 },
 },
 {
 {
 stateName =>     'SIGNAL_AFTER_EQUALS' ,
 stateName =>     'SIGNAL_AFTER_EQUALS' ,
 allowAnything => 1,
 allowAnything => 1,
 search =>
 search =>
   [
   [
    { regexp => ',',    nextState => ['SIGNAL_NAME'],},
    { regexp => ',',    nextState => ['SIGNAL_NAME'],},
    { regexp => '{',    nextState => ['IN_CONCAT','SIGNAL_AFTER_EQUALS'],},
    { regexp => '\{',    nextState => ['IN_CONCAT','SIGNAL_AFTER_EQUALS'],},
    { regexp => '\(',   nextState => ['IN_BRACKET','SIGNAL_AFTER_EQUALS'],},
    { regexp => '\(',   nextState => ['IN_BRACKET','SIGNAL_AFTER_EQUALS'],},
    { arcName => 'END', regexp => ';', }, # pop up
    { arcName => 'END', regexp => ';', }, # pop up
    @$vid_vnum_or_string,
    @$vid_vnum_or_string,
   ],
   ],
 },
 },
 {
 {
 stateName =>     'INST_PARAM',
 stateName =>     'INST_PARAM',
 failNextState => ['INST_NAME'],
 failNextState => ['INST_NAME'],
 search => [ { regexp => '\#', nextState=> ['INST_PARAM_BRACKET'],},],
 search => [ { regexp => '\#', nextState=> ['INST_PARAM_BRACKET'],},],
 },
 },
 {
 {
 stateName =>     'INST_PARAM_BRACKET',
 stateName =>     'INST_PARAM_BRACKET',
 search => [ { arcName => 'BRACKET' ,
 search => [ { arcName => 'BRACKET' ,
               regexp => '\(',
               regexp => '\(',
               storePos => 1,
               storePos => 1,
               nextState=> ['INST_PARAM_VALUE'],},
               nextState=> ['INST_PARAM_VALUE'],},
             # this is here to catch and illegal case which DC accepts
             # this is here to catch and illegal case which DC accepts
             { arcName => 'NO_BRACKET' ,
             { arcName => 'NO_BRACKET' ,
               regexp => '($VID|$VNUM)',
               regexp => '($VID|$VNUM)',
               nextState=> ['INST_NAME'],}, ],
               nextState=> ['INST_NAME'],}, ],
 },
 },
 {
 {
 stateName =>     'INST_PARAM_VALUE',
 stateName =>     'INST_PARAM_VALUE',
 allowAnything => 1,
 allowAnything => 1,
 search => [
 search => [
   { regexp => '\(', nextState=> ['IN_BRACKET','INST_PARAM_VALUE'],},
   { regexp => '\(', nextState=> ['IN_BRACKET','INST_PARAM_VALUE'],},
   { regexp => '\[', nextState => ['IN_RANGE','INST_PARAM_VALUE'],},
   { regexp => '\[', nextState => ['IN_RANGE','INST_PARAM_VALUE'],},
   { regexp => '\{', nextState => ['IN_CONCAT','INST_PARAM_VALUE'],},
   { regexp => '\{', nextState => ['IN_CONCAT','INST_PARAM_VALUE'],},
   { arcName => 'COMMA' ,
   { arcName => 'COMMA' ,
     regexp => ',',
     regexp => ',',
     storePos => 1,
     storePos => 1,
     nextState=> ['INST_PARAM_VALUE'],},
     nextState=> ['INST_PARAM_VALUE'],},
   { arcName => 'END' ,
   { arcName => 'END' ,
     regexp => '\)',
     regexp => '\)',
     nextState=> ['INST_NAME'],},
     nextState=> ['INST_NAME'],},
  ],
  ],
 },
 },
 {
 {
 stateName =>     'INST_NAME',
 stateName =>     'INST_NAME',
 failNextState => ['INST_BRACKET'],
 failNextState => ['INST_BRACKET'],
 search =>
 search =>
  [
  [
   { arcName   => 'VID' ,       regexp => '$VID',
   { arcName   => 'VID' ,       regexp => '$VID',
     nextState => ['INST_RANGE'],      },
     nextState => ['INST_RANGE'],      },
  ],
  ],
 },
 },
 {
 {
 stateName =>     'INST_NO_NAME' ,
 stateName =>     'INST_NO_NAME' ,
 allowAnything => 1,
 allowAnything => 1,
 search => [ { regexp => ';' , }, @$vid_vnum_or_string,],
 search => [ { regexp => ';' , }, @$vid_vnum_or_string,],
 },
 },
 {
 {
 stateName =>     'INST_RANGE',
 stateName =>     'INST_RANGE',
 failNextState => ['INST_BRACKET'],
 failNextState => ['INST_BRACKET'],
 search => [ { regexp => '\[', nextState => ['IN_RANGE','INST_BRACKET'],}, ],
 search => [ { regexp => '\[', nextState => ['IN_RANGE','INST_BRACKET'],}, ],
 },
 },
 {
 {
 stateName =>     'INST_BRACKET',
 stateName =>     'INST_BRACKET',
 search => [ { arcName => 'PORTS' , regexp => '\(', nextState => ['INST_PORTS'],},],
 search => [ { arcName => 'PORTS' , regexp => '\(', nextState => ['INST_PORTS'],},],
 },
 },
 {
 {
 stateName =>     'INST_PORTS',
 stateName =>     'INST_PORTS',
 failNextState => ['INST_NUMBERED_PORT'],
 failNextState => ['INST_NUMBERED_PORT'],
 failStorePos => 1,
 failStorePos => 1,
 search =>
 search =>
  [
  [
   { arcName => 'COMMA', regexp => ',',   nextState => ['INST_PORTS'], },
   { arcName => 'COMMA', regexp => ',',   nextState => ['INST_PORTS'], },
   { regexp => '\.',  nextState => ['INST_PORT_NAME'],  },
   { regexp => '\.',  nextState => ['INST_PORT_NAME'],  },
   { regexp => '\)',  nextState => ['AFTER_INST'], },
   { regexp => '\)',  nextState => ['AFTER_INST'], },
  ],
  ],
 },
 },
 {
 {
 stateName =>     'INST_PORT_NAME',
 stateName =>     'INST_PORT_NAME',
 search => [ { arcName   => 'NAME' , regexp => '$VID',
 search => [ { arcName   => 'NAME' , regexp => '$VID',
               nextState => ['INST_NAMED_PORT_BRACKET','INST_NAMED_PORT_CON',
               nextState => ['INST_NAMED_PORT_BRACKET','INST_NAMED_PORT_CON',
                             'INST_NAMED_PORT_CON_AFTER'], }, ],
                             'INST_NAMED_PORT_CON_AFTER'], }, ],
 },
 },
 {
 {
   stateName => 'INST_NAMED_PORT_BRACKET',
   stateName => 'INST_NAMED_PORT_BRACKET',
   search => [ { regexp => '\(' , storePos => 1, },]
   search => [ { regexp => '\(' , storePos => 1, },]
 },
 },
 {
 {
 stateName =>     'INST_NAMED_PORT_CON',
 stateName =>     'INST_NAMED_PORT_CON',
 allowAnything => 1,
 allowAnything => 1,
 search =>
 search =>
  [
  [
   { regexp => '\[' , nextState => ['IN_RANGE','INST_NAMED_PORT_CON'] , },
   { regexp => '\[' , nextState => ['IN_RANGE','INST_NAMED_PORT_CON'] , },
   { regexp => '\{' , nextState => ['IN_CONCAT','INST_NAMED_PORT_CON'] , },
   { regexp => '\{' , nextState => ['IN_CONCAT','INST_NAMED_PORT_CON'] , },
   { regexp => '\(' ,
   { regexp => '\(' ,
     nextState => ['INST_NAMED_PORT_CON','INST_NAMED_PORT_CON'], },
     nextState => ['INST_NAMED_PORT_CON','INST_NAMED_PORT_CON'], },
   { arcName => 'END', regexp    => '\)' , },   # pop up 
   { arcName => 'END', regexp    => '\)' , },   # pop up 
   @$vid_vnum_or_string,
   @$vid_vnum_or_string,
  ]
  ]
 },
 },
 {
 {
 stateName =>     'INST_NAMED_PORT_CON_AFTER',
 stateName =>     'INST_NAMED_PORT_CON_AFTER',
 search =>
 search =>
  [
  [
   { arcName => 'BRACKET', regexp => '\)' ,
   { arcName => 'BRACKET', regexp => '\)' ,
     nextState => ['AFTER_INST']},
     nextState => ['AFTER_INST']},
   { arcName => 'COMMA' ,  regexp => ',' ,
   { arcName => 'COMMA' ,  regexp => ',' ,
     nextState => ['INST_DOT']},
     nextState => ['INST_DOT']},
  ]
  ]
 },
 },
 { stateName => 'INST_DOT',
 { stateName => 'INST_DOT',
   search =>
   search =>
    [
    [
     { regexp => '\.' , nextState => ['INST_PORT_NAME']},
     { regexp => '\.' , nextState => ['INST_PORT_NAME']},
     { regexp => ','  , nextState => ['INST_DOT']},   # blank port
     { regexp => ','  , nextState => ['INST_DOT']},   # blank port
    ]
    ]
 },
 },
 {
 {
 stateName =>     'INST_NUMBERED_PORT',
 stateName =>     'INST_NUMBERED_PORT',
 allowAnything => 1,
 allowAnything => 1,
 search =>
 search =>
  [
  [
   { regexp => '\[', nextState => ['IN_RANGE','INST_NUMBERED_PORT'],},
   { regexp => '\[', nextState => ['IN_RANGE','INST_NUMBERED_PORT'],},
   { regexp => '\{', nextState => ['IN_CONCAT','INST_NUMBERED_PORT'],},
   { regexp => '\{', nextState => ['IN_CONCAT','INST_NUMBERED_PORT'],},
   { regexp => '\(', nextState => ['IN_BRACKET','INST_NUMBERED_PORT'],},
   { regexp => '\(', nextState => ['IN_BRACKET','INST_NUMBERED_PORT'],},
   { arcName => 'BRACKET' , regexp => '\)', nextState => ['AFTER_INST'], },
   { arcName => 'BRACKET' , regexp => '\)', nextState => ['AFTER_INST'], },
   { arcName => 'COMMA' ,   regexp => ',' , nextState => ['INST_NUMBERED_PORT'],
   { arcName => 'COMMA' ,   regexp => ',' , nextState => ['INST_NUMBERED_PORT'],
     storePos => 1, },
     storePos => 1, },
     @$vid_vnum_or_string,
     @$vid_vnum_or_string,
  ]
  ]
 },
 },
 { stateName => 'AFTER_INST',
 { stateName => 'AFTER_INST',
   search => [
   search => [
    { arcName => 'SEMICOLON', regexp => ';', nextState => ['MODULE'], },
    { arcName => 'SEMICOLON', regexp => ';', nextState => ['MODULE'], },
    { arcName => 'COMMA',     regexp => ',', nextState => ['INST_NAME'], },
    { arcName => 'COMMA',     regexp => ',', nextState => ['INST_NAME'], },
   ]
   ]
 },
 },
 {
 {
 stateName =>     'STMNT',
 stateName =>     'STMNT',
 search =>
 search =>
  [
  [
   { arcName   => 'IF',                     regexp => '\bif\b' ,
   { arcName   => 'IF',                     regexp => '\bif\b' ,
     nextState => ['BRACKET','IN_BRACKET','STMNT','MAYBE_ELSE'] ,},
     nextState => ['BRACKET','IN_BRACKET','STMNT','MAYBE_ELSE'] ,},
   { arcName   => 'REPEAT_WHILE_FOR_WAIT',  regexp => '\b(?:repeat|while|for|wait)\b' ,
   { arcName   => 'REPEAT_WHILE_FOR_WAIT',  regexp => '\b(?:repeat|while|for|wait)\b' ,
     nextState => ['BRACKET','IN_BRACKET','STMNT'] ,  },
     nextState => ['BRACKET','IN_BRACKET','STMNT'] ,  },
   { arcName   => 'FOREVER',                regexp => '\bforever\b' ,
   { arcName   => 'FOREVER',                regexp => '\bforever\b' ,
     nextState => ['STMNT'] , },
     nextState => ['STMNT'] , },
   { arcName   => 'CASE',                   regexp => '\bcase[xz]?\b' ,
   { arcName   => 'CASE',                   regexp => '\bcase[xz]?\b' ,
     nextState => ['BRACKET','IN_BRACKET','CASE_ITEM'] , },
     nextState => ['BRACKET','IN_BRACKET','CASE_ITEM'] , },
   { arcName   => 'BEGIN',                  regexp => '\bbegin\b' ,
   { arcName   => 'BEGIN',                  regexp => '\bbegin\b' ,
     nextState => ['BLOCK_NAME','IN_SEQ_BLOCK'] , },
     nextState => ['BLOCK_NAME','IN_SEQ_BLOCK'] , },
   { arcName   => 'FORK',                   regexp => '\bfork\b' ,
   { arcName   => 'FORK',                   regexp => '\bfork\b' ,
     nextState => ['BLOCK_NAME','IN_PAR_BLOCK'] , },
     nextState => ['BLOCK_NAME','IN_PAR_BLOCK'] , },
   { arcName   => 'DELAY',                  regexp => '\#' ,
   { arcName   => 'DELAY',                  regexp => '\#' ,
     nextState => ['DELAY_VALUE','STMNT'] , },
     nextState => ['DELAY_VALUE','STMNT'] , },
   { arcName   => 'EVENT_CONTROL',          regexp => '\@' ,
   { arcName   => 'EVENT_CONTROL',          regexp => '\@' ,
     nextState => ['EVENT_CONTROL'] , },
     nextState => ['EVENT_CONTROL'] , },
   { arcName   => 'SYSTEM_TASK',            regexp    => '\$$VID' ,
   { arcName   => 'SYSTEM_TASK',            regexp    => '\$$VID' ,
     nextState => ['SYSTEM_TASK'] , },
     nextState => ['SYSTEM_TASK'] , },
   { arcName   => 'DISABLE_ASSIGN_DEASSIGN_FORCE_RELEASE',
   { arcName   => 'DISABLE_ASSIGN_DEASSIGN_FORCE_RELEASE',
     regexp    => '\b(?:disable|assign|deassign|force|release)\b',
     regexp    => '\b(?:disable|assign|deassign|force|release)\b',
     nextState => ['STMNT_JUNK_TO_SEMICOLON'] , }, # just throw stuff away
     nextState => ['STMNT_JUNK_TO_SEMICOLON'] , }, # just throw stuff away
   # a assignment to a hierarchical thing mustn't collect the vid
   # a assignment to a hierarchical thing mustn't collect the vid
   #  like a normal assign as hierarchical nets/signals will confuse downstream code
   #  like a normal assign as hierarchical nets/signals will confuse downstream code
   { arcName   => 'HIER_ASSIGN_OR_TASK',           regexp => '$HVID' ,
   { arcName   => 'HIER_ASSIGN_OR_TASK',           regexp => '$HVID' ,
     nextState => ['STMNT_ASSIGN_OR_TASK'] , },
     nextState => ['STMNT_ASSIGN_OR_TASK'] , },
   { arcName   => 'ASSIGN_OR_TASK',        regexp => '$VID' ,
   { arcName   => 'ASSIGN_OR_TASK',        regexp => '$VID' ,
     nextState => ['STMNT_ASSIGN_OR_TASK'] , },
     nextState => ['STMNT_ASSIGN_OR_TASK'] , },
   { arcName   => 'CONCAT',                regexp => '{' ,
   { arcName   => 'CONCAT',                regexp => '\{' ,
     nextState => ['IN_CONCAT','STMNT_ASSIGN'] ,  },
     nextState => ['IN_CONCAT','STMNT_ASSIGN'] ,  },
   { arcName   => 'NULL',                  regexp => ';' ,
   { arcName   => 'NULL',                  regexp => ';' ,
     }, # pop up
     }, # pop up
   { arcName   => 'POINTY_THING',          regexp    => '->' , # not sure what this is!
   { arcName   => 'POINTY_THING',          regexp    => '->' , # not sure what this is!
     nextState => ['POINTY_THING_NAME'] ,  },
     nextState => ['POINTY_THING_NAME'] ,  },
  ],
  ],
 },
 },
 {
 {
 stateName =>     'MAYBE_ELSE',
 stateName =>     'MAYBE_ELSE',
 failNextState => [] , # don't get confused, just pop the stack for the next state
 failNextState => [] , # don't get confused, just pop the stack for the next state
 search => [{ arcName => 'ELSE', regexp => '\belse\b' , nextState => ['STMNT'],},]
 search => [{ arcName => 'ELSE', regexp => '\belse\b' , nextState => ['STMNT'],},]
 },
 },
 {
 {
 stateName =>     'BLOCK_NAME',
 stateName =>     'BLOCK_NAME',
 failNextState => [] , # don't get confused, just pop the stack for the next state
 failNextState => [] , # don't get confused, just pop the stack for the next state
 search => [{ arcName => 'COLON', regexp    => ':' ,
 search => [{ arcName => 'COLON', regexp    => ':' ,
              nextState => ['BLOCK_NAME_AFTER_COLON'] ,},]
              nextState => ['BLOCK_NAME_AFTER_COLON'] ,},]
 },
 },
 {
 {
 stateName =>     'BLOCK_NAME_AFTER_COLON',
 stateName =>     'BLOCK_NAME_AFTER_COLON',
 search => [ { arcName   => 'VID', regexp => '$VID' , nextState => ['BLOCK_SIGNAL'],}, ]
 search => [ { arcName   => 'VID', regexp => '$VID' , nextState => ['BLOCK_SIGNAL'],}, ]
 },
 },
 {
 {
 stateName =>     'BLOCK_SIGNAL' ,
 stateName =>     'BLOCK_SIGNAL' ,
 failNextState => [], # don't get confused, just pop the stack for the next state
 failNextState => [], # don't get confused, just pop the stack for the next state
 search => [
 search => [
   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
     nextState => ['DRIVE_STRENGTH','BLOCK_SIGNAL'] , },
     nextState => ['DRIVE_STRENGTH','BLOCK_SIGNAL'] , },
   ],
   ],
 },
 },
 
 
 
 
 {
 {
 stateName =>     'IN_SEQ_BLOCK',
 stateName =>     'IN_SEQ_BLOCK',
 failNextState => ['STMNT','IN_SEQ_BLOCK'] ,
 failNextState => ['STMNT','IN_SEQ_BLOCK'] ,
 search => [{ arcName   => 'END', regexp    => '\bend\b' , }, ]
 search => [{ arcName   => 'END', regexp    => '\bend\b' , }, ]
 },
 },
 {
 {
 stateName =>     'IN_PAR_BLOCK',
 stateName =>     'IN_PAR_BLOCK',
 failNextState => ['STMNT','IN_PAR_BLOCK'] ,
 failNextState => ['STMNT','IN_PAR_BLOCK'] ,
 search => [{ arcName   => 'JOIN', regexp => '\bjoin\b' , }, ]
 search => [{ arcName   => 'JOIN', regexp => '\bjoin\b' , }, ]
 },
 },
 {
 {
 stateName =>     'DELAY_VALUE',
 stateName =>     'DELAY_VALUE',
 search =>
 search =>
  [{ arcName => 'NUMBER',  regexp => '$VNUM', nextState => ['DELAY_COLON1'] },
  [{ arcName => 'NUMBER',  regexp => '$VNUM', nextState => ['DELAY_COLON1'] },
   { arcName => 'ID',      regexp => '$VID',  nextState => ['DELAY_COLON1'], },
   { arcName => 'ID',      regexp => '$VID',  nextState => ['DELAY_COLON1'], },
   { arcName => 'BRACKET', regexp => '\(',    nextState => ['IN_BRACKET','DELAY_COLON1'],},]
   { arcName => 'BRACKET', regexp => '\(',    nextState => ['IN_BRACKET','DELAY_COLON1'],},]
 },
 },
 {
 {
 stateName =>     'DELAY_COLON1',
 stateName =>     'DELAY_COLON1',
 failNextState => [] , # popup
 failNextState => [] , # popup
 search => [{ arcName   => 'COLON', regexp => ':' , nextState => ['DELAY_VALUE2'] },]
 search => [{ arcName   => 'COLON', regexp => ':' , nextState => ['DELAY_VALUE2'] },]
 },
 },
 {
 {
 stateName =>     'DELAY_VALUE2',
 stateName =>     'DELAY_VALUE2',
 search =>
 search =>
  [{ arcName => 'NUMBER',  regexp => '$VNUM', nextState => ['DELAY_COLON2'] },
  [{ arcName => 'NUMBER',  regexp => '$VNUM', nextState => ['DELAY_COLON2'] },
   { arcName => 'ID',      regexp => '$VID',  nextState => ['DELAY_COLON2'], },
   { arcName => 'ID',      regexp => '$VID',  nextState => ['DELAY_COLON2'], },
   { arcName => 'BRACKET', regexp => '\(',    nextState => ['IN_BRACKET','DELAY_COLON2'],},]
   { arcName => 'BRACKET', regexp => '\(',    nextState => ['IN_BRACKET','DELAY_COLON2'],},]
 },
 },
 {
 {
 stateName =>     'DELAY_COLON2',
 stateName =>     'DELAY_COLON2',
 search => [{ arcName   => 'COLON', regexp => ':' , nextState => ['DELAY_VALUE3'] },]
 search => [{ arcName   => 'COLON', regexp => ':' , nextState => ['DELAY_VALUE3'] },]
 },
 },
 {
 {
 stateName =>     'DELAY_VALUE3',
 stateName =>     'DELAY_VALUE3',
 search =>
 search =>
  [{ arcName => 'NUMBER',  regexp => '$VNUM', },
  [{ arcName => 'NUMBER',  regexp => '$VNUM', },
   { arcName => 'ID',      regexp => '$VID',  },
   { arcName => 'ID',      regexp => '$VID',  },
   { arcName => 'BRACKET', regexp => '\(',  nextState => ['IN_BRACKET'],}, ]
   { arcName => 'BRACKET', regexp => '\(',  nextState => ['IN_BRACKET'],}, ]
 },
 },
 {
 {
 stateName =>     'EVENT_CONTROL',
 stateName =>     'EVENT_CONTROL',
 search =>
 search =>
  [
  [
   { arcName => 'ID',      regexp => '(?:$HVID|$VID)', nextState => ['STMNT'], },
   { arcName => 'ID',      regexp => '(?:$HVID|$VID)', nextState => ['STMNT'], },
   { arcName => 'STAR',    regexp => '\*', nextState => ['STMNT'], }, # V2001
   { arcName => 'STAR',    regexp => '\*', nextState => ['STMNT'], }, # V2001
   { arcName => 'BRACKET', regexp => '\(',
   { arcName => 'BRACKET', regexp => '\(',
     nextState => ['IN_EVENT_BRACKET','STMNT'], },
     nextState => ['IN_EVENT_BRACKET','STMNT'], },
  ]
  ]
 },
 },
 {
 {
 stateName =>     'IN_EVENT_BRACKET',
 stateName =>     'IN_EVENT_BRACKET',
 allowAnything => 1,
 allowAnything => 1,
 search =>
 search =>
  [
  [
   # must go before vid_vnum_or_string as posedge and negedge look like VIDs
   # must go before vid_vnum_or_string as posedge and negedge look like VIDs
   { arcName => 'EDGE' ,           regexp    => '\b(?:posedge|negedge)\b' ,
   { arcName => 'EDGE' ,           regexp    => '\b(?:posedge|negedge)\b' ,
     nextState => ['IN_EVENT_BRACKET_EDGE'] , },
     nextState => ['IN_EVENT_BRACKET_EDGE'] , },
   { arcName   => 'BRACKET' ,      regexp    => '\(' ,
   { arcName   => 'BRACKET' ,      regexp    => '\(' ,
     nextState => ['IN_EVENT_BRACKET','IN_EVENT_BRACKET'] , },
     nextState => ['IN_EVENT_BRACKET','IN_EVENT_BRACKET'] , },
   { arcName => 'STAR',    regexp => '\*', nextState => ['IN_EVENT_BRACKET'], }, # V2001
   { arcName => 'STAR',    regexp => '\*', nextState => ['IN_EVENT_BRACKET'], }, # V2001
   { arcName   => 'END' ,          regexp    => '\)' , }, # popup
   { arcName   => 'END' ,          regexp    => '\)' , }, # popup
   @$vid_vnum_or_string,
   @$vid_vnum_or_string,
  ]
  ]
 },
 },
 { # in theory there could be an expression here, I just take the first VID
 { # in theory there could be an expression here, I just take the first VID
 stateName =>     'IN_EVENT_BRACKET_EDGE',
 stateName =>     'IN_EVENT_BRACKET_EDGE',
 failNextState => ['IN_EVENT_BRACKET'] ,
 failNextState => ['IN_EVENT_BRACKET'] ,
 search => [{ arcName => 'VID', regexp => '$VID', nextState => ['IN_EVENT_BRACKET'],},],
 search => [{ arcName => 'VID', regexp => '$VID', nextState => ['IN_EVENT_BRACKET'],},],
 },
 },
 {
 {
 stateName =>     'STMNT_ASSIGN_OR_TASK',
 stateName =>     'STMNT_ASSIGN_OR_TASK',
 failNextState => ['STMNT_SEMICOLON'],
 failNextState => ['STMNT_SEMICOLON'],
 search =>
 search =>
  [
  [
   { arcName => 'EQUALS',          regexp => '[<]?=',
   { arcName => 'EQUALS',          regexp => '[<]?=',
     nextState => ['STMNT_JUNK_TO_SEMICOLON'], },
     nextState => ['STMNT_JUNK_TO_SEMICOLON'], },
   { arcName => 'RANGE',           regexp => '\[',
   { arcName => 'RANGE',           regexp => '\[',
     nextState => ['IN_RANGE','STMNT_ASSIGN'],},
     nextState => ['IN_RANGE','STMNT_ASSIGN'],},
   { arcName => 'BRACKET',         regexp => '\(',     # task with params
   { arcName => 'BRACKET',         regexp => '\(',     # task with params
     nextState => ['IN_BRACKET','STMNT_SEMICOLON'],  },
     nextState => ['IN_BRACKET','STMNT_SEMICOLON'],  },
  ]
  ]
 },
 },
 {
 {
 stateName =>     'STMNT_ASSIGN',
 stateName =>     'STMNT_ASSIGN',
 search =>
 search =>
  [
  [
   { arcName => 'EQUALS', regexp => '[<]?=',
   { arcName => 'EQUALS', regexp => '[<]?=',
     nextState => ['STMNT_JUNK_TO_SEMICOLON'],},
     nextState => ['STMNT_JUNK_TO_SEMICOLON'],},
   { arcName => 'RANGE',           regexp => '\[',
   { arcName => 'RANGE',           regexp => '\[',
     nextState => ['IN_RANGE','STMNT_ASSIGN'],},
     nextState => ['IN_RANGE','STMNT_ASSIGN'],},
  ],
  ],
 },
 },
 {
 {
 stateName =>     'SYSTEM_TASK',
 stateName =>     'SYSTEM_TASK',
 failNextState => ['STMNT_SEMICOLON'],
 failNextState => ['STMNT_SEMICOLON'],
 search =>
 search =>
  [
  [
   { arcName => 'BRACKET',           regexp => '\(',
   { arcName => 'BRACKET',           regexp => '\(',
     nextState => ['IN_BRACKET','STMNT_SEMICOLON'], },    ],
     nextState => ['IN_BRACKET','STMNT_SEMICOLON'], },    ],
 },
 },
 {
 {
 stateName =>     'POINTY_THING_NAME',
 stateName =>     'POINTY_THING_NAME',
 search => [{ arcName => 'VID', regexp => '(?:$HVID|$VID)', nextState => ['STMNT_SEMICOLON'], }, ],
 search => [{ arcName => 'VID', regexp => '(?:$HVID|$VID)', nextState => ['STMNT_SEMICOLON'], }, ],
 },
 },
 {
 {
 stateName =>     'CASE_ITEM',
 stateName =>     'CASE_ITEM',
 allowAnything => 1,
 allowAnything => 1,
 search =>
 search =>
  [
  [
   { arcName => 'END',             regexp => '\bendcase\b',  },
   { arcName => 'END',             regexp => '\bendcase\b',  },
   { arcName => 'COLON',           regexp => ':',
   { arcName => 'COLON',           regexp => ':',
     nextState => ['STMNT','CASE_ITEM'], },
     nextState => ['STMNT','CASE_ITEM'], },
   { arcName => 'DEFAULT',         regexp => '\bdefault\b',
   { arcName => 'DEFAULT',         regexp => '\bdefault\b',
     nextState => ['MAYBE_COLON','STMNT','CASE_ITEM'], },
     nextState => ['MAYBE_COLON','STMNT','CASE_ITEM'], },
   # don't get confused by colons in ranges
   # don't get confused by colons in ranges
   { arcName => 'RANGE',           regexp => '\[',
   { arcName => 'RANGE',           regexp => '\[',
     nextState => ['IN_RANGE','CASE_ITEM'], },
     nextState => ['IN_RANGE','CASE_ITEM'], },
    @$vid_vnum_or_string,
    @$vid_vnum_or_string,
  ],
  ],
 },
 },
 {
 {
 stateName =>     'MAYBE_COLON',
 stateName =>     'MAYBE_COLON',
 failNextState => [],
 failNextState => [],
 search => [ { regexp    => ':' , }, ]
 search => [ { regexp    => ':' , }, ]
 },
 },
 { # look for ;  but also allow the ending of a statement with an end 
 { # look for ;  but also allow the ending of a statement with an end 
   #   even though it is not really legal (verilog seems to accept it, so I do too)
   #   even though it is not really legal (verilog seems to accept it, so I do too)
 stateName =>     'STMNT_JUNK_TO_SEMICOLON' ,
 stateName =>     'STMNT_JUNK_TO_SEMICOLON' ,
 allowAnything => 1,
 allowAnything => 1,
 search => [
 search => [
             { regexp => ';' , },
             { regexp => ';' , },
             # popup and reset pos to  before the end/join cope with nosemicolon case
             # popup and reset pos to  before the end/join cope with nosemicolon case
             { regexp => '\b(?:end|join|endtask|endfunction)\b' , resetPos => 1, },
             { regexp => '\b(?:end|join|endtask|endfunction)\b' , resetPos => 1, },
             @$vid_vnum_or_string,
             @$vid_vnum_or_string,
           ],
           ],
 },
 },
 {
 {
 stateName => 'STMNT_SEMICOLON',
 stateName => 'STMNT_SEMICOLON',
 search => [ { regexp => ';'  , },
 search => [ { regexp => ';'  , },
             # popup and reset pos to  before the end/join cope with nosemicolon case
             # popup and reset pos to  before the end/join cope with nosemicolon case
             { regexp => '\b(?:end|join|endtask|endfunction)\b' , resetPos => 1, },
             { regexp => '\b(?:end|join|endtask|endfunction)\b' , resetPos => 1, },
           ],
           ],
 },
 },
 { stateName => 'BRACKET',   search => [ { regexp => '\(' , },] },
 { stateName => 'BRACKET',   search => [ { regexp => '\(' , },] },
 { stateName => 'SEMICOLON', search => [ { regexp => ';'  , },] },
 { stateName => 'SEMICOLON', search => [ { regexp => ';'  , },] },
 # V2001
 # V2001
 {
 {
 stateName =>     'CONFIG',
 stateName =>     'CONFIG',
 allowAnything => 1,
 allowAnything => 1,
 search => [ { regexp => '\bendconfig\b' , nextState => ['START'] ,},
 search => [ { regexp => '\bendconfig\b' , nextState => ['START'] ,},
               @$vid_vnum_or_string,],
               @$vid_vnum_or_string,],
 },
 },
 {
 {
 stateName =>     'LIBRARY' ,  # just look for ;
 stateName =>     'LIBRARY' ,  # just look for ;
 allowAnything => 1,
 allowAnything => 1,
 search => [ {  regexp    => ';' ,    nextState => ['START'] , },
 search => [ {  regexp    => ';' ,    nextState => ['START'] , },
             @$vid_vnum_or_string,],
             @$vid_vnum_or_string,],
 },
 },
 {
 {
 stateName =>     'GENERATE',
 stateName =>     'GENERATE',
 allowAnything => 1,
 allowAnything => 1,
 search => [ { regexp => '\bendgenerate\b' , nextState => ['MODULE'] ,},
 search => [ { regexp => '\bendgenerate\b' , nextState => ['MODULE'] ,},
               @$vid_vnum_or_string,],
               @$vid_vnum_or_string,],
 },
 },
 
 
 
 
 
 
 { # V2001 ansi module ports
 { # V2001 ansi module ports
 stateName =>     'ANSI_PORTS_TYPE',
 stateName =>     'ANSI_PORTS_TYPE',
 failNextState => ['ANSI_PORTS_TYPE2'],
 failNextState => ['ANSI_PORTS_TYPE2'],
 search => [ { arcName => 'TYPE' , regexp => '\b(?:input|output|inout)\b',
 search => [ { arcName => 'TYPE' , regexp => '\b(?:input|output|inout)\b',
               nextState => ['ANSI_PORTS_TYPE2'],},
               nextState => ['ANSI_PORTS_TYPE2'],},
             # a null list. note this is only possible for a task or function
             # a null list. note this is only possible for a task or function
             #  (a null module port list can't look like an ansi port list)
             #  (a null module port list can't look like an ansi port list)
             #  but it is not legal acording to the BNF. I allow it any way.
             #  but it is not legal acording to the BNF. I allow it any way.
             { regexp => '\)', nextState => ['SEMICOLON'], },
             { regexp => '\)', nextState => ['SEMICOLON'], },
             ],
             ],
 },
 },
 { # V2001 ansi module ports
 { # V2001 ansi module ports
 stateName =>     'ANSI_PORTS_TYPE2',
 stateName =>     'ANSI_PORTS_TYPE2',
 failNextState => ['ANSI_PORTS_SIGNAL_RANGE'],
 failNextState => ['ANSI_PORTS_SIGNAL_RANGE'],
 search => [ { arcName => 'TYPE' , regexp => "$verilog_sigs_regexp",
 search => [ { arcName => 'TYPE' , regexp => "$verilog_sigs_regexp",
               nextState => ['ANSI_PORTS_TYPE2'],},
               nextState => ['ANSI_PORTS_TYPE2'],},
             { regexp => '\b(?:signed)\b', nextState => ['ANSI_PORTS_TYPE2'],},],
             { regexp => '\b(?:signed)\b', nextState => ['ANSI_PORTS_TYPE2'],},],
 },
 },
 { # V2001 ansi module ports
 { # V2001 ansi module ports
 stateName =>     'ANSI_PORTS_SIGNAL_RANGE',          # for signal defs
 stateName =>     'ANSI_PORTS_SIGNAL_RANGE',          # for signal defs
  failNextState => ['ANSI_PORTS_SIGNAL_NAME'],
  failNextState => ['ANSI_PORTS_SIGNAL_NAME'],
 search => [ { regexp => '\[', nextState => ['IN_SIG_RANGE','ANSI_PORTS_SIGNAL_NAME'],
 search => [ { regexp => '\[', nextState => ['IN_SIG_RANGE','ANSI_PORTS_SIGNAL_NAME'],
               storePos => 1,}, ],
               storePos => 1,}, ],
 },
 },
 { # V2001 ansi module ports
 { # V2001 ansi module ports
 stateName =>     'ANSI_PORTS_SIGNAL_NAME',
 stateName =>     'ANSI_PORTS_SIGNAL_NAME',
  search => [
  search => [
   { arcName   => 'TYPE' , regexp    => '\b(?:input|output|inout)\b',
   { arcName   => 'TYPE' , regexp    => '\b(?:input|output|inout)\b',
     nextState => ['ANSI_PORTS_TYPE'], resetPos => 1, },
     nextState => ['ANSI_PORTS_TYPE'], resetPos => 1, },
   { arcName   => 'VID' , regexp    => '$VID',
   { arcName   => 'VID' , regexp    => '$VID',
     nextState => ['ANSI_PORTS_SIGNAL_AFTER_NAME'], },
     nextState => ['ANSI_PORTS_SIGNAL_AFTER_NAME'], },
  ],
  ],
 },
 },
 { # V2001 ansi module ports
 { # V2001 ansi module ports
 stateName =>     'ANSI_PORTS_SIGNAL_AFTER_NAME',
 stateName =>     'ANSI_PORTS_SIGNAL_AFTER_NAME',
 search =>
 search =>
  [
  [
   { regexp => ',',  nextState => ['ANSI_PORTS_SIGNAL_NAME'],},
   { regexp => ',',  nextState => ['ANSI_PORTS_SIGNAL_NAME'],},
   { regexp => '\[', nextState => ['IN_MEM_RANGE','ANSI_PORTS_SIGNAL_AFTER_NAME'],}, # memories
   { regexp => '\[', nextState => ['IN_MEM_RANGE','ANSI_PORTS_SIGNAL_AFTER_NAME'],}, # memories
   { regexp => '\)', nextState => ['SEMICOLON'], } # semicolon, then pop up
   { regexp => '\)', nextState => ['SEMICOLON'], } # semicolon, then pop up
  ],
  ],
 },
 },
 { # v2001 module_parameter_port_list (A.1.3)
 { # v2001 module_parameter_port_list (A.1.3)
 stateName =>     'PPL_BRACKET' ,
 stateName =>     'PPL_BRACKET' ,
 search => [ { regexp    => '\(',  nextState => ['PPL_PARAM'], }, ],
 search => [ { regexp    => '\(',  nextState => ['PPL_PARAM'], }, ],
 },
 },
 { # v2001 module_parameter_port_list (A.1.3)
 { # v2001 module_parameter_port_list (A.1.3)
 stateName =>     'PPL_PARAM' ,
 stateName =>     'PPL_PARAM' ,
 search => [ { arcName=>'PARAM', regexp=>'\bparameter\b', nextState => ['PPL_TYPE'],},],
 search => [ { arcName=>'PARAM', regexp=>'\bparameter\b', nextState => ['PPL_TYPE'],},],
 },
 },
 { # v2001 module_parameter_port_list (A.1.3)
 { # v2001 module_parameter_port_list (A.1.3)
 stateName =>     'PPL_TYPE',
 stateName =>     'PPL_TYPE',
 failNextState => ['PPL_NAME'],
 failNextState => ['PPL_NAME'],
 search => [
 search => [
    { arcName   => 'RANGE', regexp    => '\[' ,
    { arcName   => 'RANGE', regexp    => '\[' ,
      nextState => ['IN_RANGE','PPL_NAME'] , },
      nextState => ['IN_RANGE','PPL_NAME'] , },
    { arcName   => 'SIGNED', regexp    => '\bsigned\b' ,
    { arcName   => 'SIGNED', regexp    => '\bsigned\b' ,
      nextState => ['PPL_TYPE'] , },  # may be followed by a range
      nextState => ['PPL_TYPE'] , },  # may be followed by a range
    { arcName   => 'OTHER', regexp    => '\b(?:integer|real|realtime|time)\b' ,
    { arcName   => 'OTHER', regexp    => '\b(?:integer|real|realtime|time)\b' ,
      nextState => ['PPL_NAME'] , },
      nextState => ['PPL_NAME'] , },
   ],
   ],
 },
 },
 { # v2001 module_parameter_port_list (A.1.3)
 { # v2001 module_parameter_port_list (A.1.3)
 stateName =>     'PPL_NAME',
 stateName =>     'PPL_NAME',
 search => [
 search => [
    { arcName   => 'NAME',  regexp    => '$VID' ,
    { arcName   => 'NAME',  regexp    => '$VID' ,
      nextState => ['PARAMETER_EQUAL','PPL_AFTER_EQUALS'] , },
      nextState => ['PARAMETER_EQUAL','PPL_AFTER_EQUALS'] , },
   ],
   ],
 },
 },
 { # v2001 module_parameter_port_list (A.1.3)
 { # v2001 module_parameter_port_list (A.1.3)
 stateName =>     'PPL_AFTER_EQUALS',
 stateName =>     'PPL_AFTER_EQUALS',
 allowAnything => 1,
 allowAnything => 1,
 search =>
 search =>
  [
  [
   { arcName   => 'CONCAT',      regexp    => '{' ,
   { arcName   => 'CONCAT',      regexp    => '\{' ,
     nextState => ['IN_CONCAT','PPL_AFTER_EQUALS'] ,  },
     nextState => ['IN_CONCAT','PPL_AFTER_EQUALS'] ,  },
   { arcName   => 'BRACKET',      regexp    => '\(' ,
   { arcName   => 'BRACKET',      regexp    => '\(' ,
     nextState => ['IN_BRACKET','PPL_AFTER_EQUALS'] ,  },
     nextState => ['IN_BRACKET','PPL_AFTER_EQUALS'] ,  },
   { arcName   => 'COMMA',       regexp    => ',' ,
   { arcName   => 'COMMA',       regexp    => ',' ,
     nextState => ['PPL_PARAM_OR_NAME'] ,    },
     nextState => ['PPL_PARAM_OR_NAME'] ,    },
   { arcName   => 'END',       regexp    => '\)' ,
   { arcName   => 'END',       regexp    => '\)' ,
     nextState => ['MODULE_PORTS'] ,    },
     nextState => ['MODULE_PORTS'] ,    },
   @$vid_vnum_or_string,
   @$vid_vnum_or_string,
  ]
  ]
 },
 },
 { # v2001 module_parameter_port_list (A.1.3)
 { # v2001 module_parameter_port_list (A.1.3)
 stateName =>     'PPL_PARAM_OR_NAME' ,
 stateName =>     'PPL_PARAM_OR_NAME' ,
 failNextState => ['PPL_NAME'],
 failNextState => ['PPL_NAME'],
 search => [ { regexp    => '\bparameter\b',  nextState => ['PPL_TYPE'], }, ],
 search => [ { regexp    => '\bparameter\b',  nextState => ['PPL_TYPE'], }, ],
 },
 },
];
];
}
}
 
 
 
 
############################################################
############################################################
# make the parser, and return it as a string
# make the parser, and return it as a string
############################################################
############################################################
 
 
 
 
sub _make_parser {
sub _make_parser {
    my ($evalDefs,$genDebugCode) = @_;
    my ($evalDefs,$genDebugCode) = @_;
 
 
    _check_data_structures($evalDefs);
    _check_data_structures($evalDefs);
 
 
    my $perlCode; # the perl code we are making
    my $perlCode; # the perl code we are making
 
 
    my $debugPrint =  $genDebugCode ? 'print "---- $ps->{curState} $file:$line (".pos($code).")\\n" if defined $ps->{curState} && defined pos($code);':'';
    my $debugPrint =  $genDebugCode ? 'print "---- $ps->{curState} $file:$line (".pos($code).")\\n" if defined $ps->{curState} && defined pos($code);':'';
#    vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
#    vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    $perlCode .= <<EOF;
    $perlCode .= <<EOF;
sub _parse_line {
sub _parse_line {
 
 
  my (\$self,\$code,\$file,\$line,\$ps,\$rs) = \@_;
  my (\$self,\$code,\$file,\$line,\$ps,\$rs) = \@_;
 
 
  if (!exists(\$ps->{curState})){
  if (!exists(\$ps->{curState})){
      \$ps->{curState} = undef;
      \$ps->{curState} = undef;
      \$ps->{prevState}= undef;
      \$ps->{prevState}= undef;
      \$ps->{nextStateStack}= ["START"];
      \$ps->{nextStateStack}= ["START"];
      \$ps->{storing}= 0;
      \$ps->{storing}= 0;
      \$ps->{stored}= "";
      \$ps->{stored}= "";
      \$ps->{confusedNextState}= "START";
      \$ps->{confusedNextState}= "START";
  }
  }
 
 
  my \$storePos = -1;
  my \$storePos = -1;
  my \$lastPos = 0;
  my \$lastPos = 0;
  my \$posMark;
  my \$posMark;
  my \$fromLastPos;
  my \$fromLastPos;
  PARSE_LINE_LOOP: while (1) {
  PARSE_LINE_LOOP: while (1) {
 
 
    \$lastPos = pos(\$code) if (defined(pos(\$code)));
    \$lastPos = pos(\$code) if (defined(pos(\$code)));
 
 
    if ( \$code =~ m/\\G\\s*\\Z/gs ) {
    if ( \$code =~ m/\\G\\s*\\Z/gs ) {
        last PARSE_LINE_LOOP;
        last PARSE_LINE_LOOP;
    }
    }
    else {
    else {
        pos(\$code) = \$lastPos;
        pos(\$code) = \$lastPos;
    }
    }
 
 
    \$code =~ m/\\G\\s*/gs ; # skip any whitespace
    \$code =~ m/\\G\\s*/gs ; # skip any whitespace
 
 
    \$ps->{prevState} = \$ps->{curState};
    \$ps->{prevState} = \$ps->{curState};
    \$ps->{curState} = pop(\@{\$ps->{nextStateStack}}) or
    \$ps->{curState} = pop(\@{\$ps->{nextStateStack}}) or
        die "Error: No next state after \$ps->{prevState} ".
        die "Error: No next state after \$ps->{prevState} ".
            "\$file line \$line :\n \$code";
            "\$file line \$line :\n \$code";
    $debugPrint
    $debugPrint
 
 
    goto \$ps->{curState};
    goto \$ps->{curState};
    die \"Confused: Bad state \$ps->{curState}\";
    die \"Confused: Bad state \$ps->{curState}\";
 
 
    CONFUSED:
    CONFUSED:
        \$posMark = '';
        \$posMark = '';
        # make the position marker: tricky because code can contain tabs
        # make the position marker: tricky because code can contain tabs
        #  which we want to match in the blank space before the ^
        #  which we want to match in the blank space before the ^
        \$posMark = substr(\$code,0,\$lastPos);
        \$posMark = substr(\$code,0,\$lastPos);
        \$posMark =~ tr/\t/ /c ; # turn anything that isn't a tab into a space
        \$posMark =~ tr/\t/ /c ; # turn anything that isn't a tab into a space
        \$posMark .= "^" ;
        \$posMark .= "^" ;
        if (substr(\$code,length(\$code)-1,1) ne "\\n") { \$posMark="\\n".\$posMark; }
        if (substr(\$code,length(\$code)-1,1) ne "\\n") { \$posMark="\\n".\$posMark; }
        \$self->_add_confused("\$file:\$line: in state \$ps->{prevState}:\\n".
        \$self->_add_confused("\$file:\$line: in state \$ps->{prevState}:\\n".
                    "\$code".\$posMark);
                    "\$code".\$posMark);
        \@{\$ps->{nextStateStack}} = (\$ps->{confusedNextState});
        \@{\$ps->{nextStateStack}} = (\$ps->{confusedNextState});
       return; # ignore the rest of the line
       return; # ignore the rest of the line
EOF
EOF
#    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 
 
 
  foreach my $state (@$languageDef) {
  foreach my $state (@$languageDef) {
      my $stateName = $state->{stateName};
      my $stateName = $state->{stateName};
      my $allowAnything    = exists($state->{allowAnything}) && $state->{allowAnything};
      my $allowAnything    = exists($state->{allowAnything}) && $state->{allowAnything};
      my $re = $allowAnything ? '' : '\G'; # allowAnything==0 forces a match 
      my $re = $allowAnything ? '' : '\G'; # allowAnything==0 forces a match 
      #  where we left off last time
      #  where we left off last time
      $perlCode.= "    $stateName:\n";
      $perlCode.= "    $stateName:\n";
 
 
      if (exists($state->{confusedNextState})) {
      if (exists($state->{confusedNextState})) {
          $perlCode.= "      \$ps->{confusedNextState}=\"$state->{confusedNextState}\";\n";
          $perlCode.= "      \$ps->{confusedNextState}=\"$state->{confusedNextState}\";\n";
      }
      }
 
 
      if (exists($state->{search})) {
      if (exists($state->{search})) {
          my @searchTerms=();
          my @searchTerms=();
          foreach my $search (@{$state->{search}}) {
          foreach my $search (@{$state->{search}}) {
              push @searchTerms, $search->{regexp};
              push @searchTerms, $search->{regexp};
          }
          }
          $re .= "(?:(". join(")|(",@searchTerms)."))";
          $re .= "(?:(". join(")|(",@searchTerms)."))";
 
 
          my $failNextState='';
          my $failNextState='';
 
 
          if (exists($state->{failNextState})) {
          if (exists($state->{failNextState})) {
              if (scalar(@{$state->{failNextState}}) != 0) {
              if (scalar(@{$state->{failNextState}}) != 0) {
                  $failNextState="\"".
                  $failNextState="\"".
                      join('","',reverse(@{$state->{failNextState}})).
                      join('","',reverse(@{$state->{failNextState}})).
                          "\"";
                          "\"";
              }
              }
              # else leave it set at nothing - means just popup
              # else leave it set at nothing - means just popup
          }
          }
          else {
          else {
              $failNextState='"CONFUSED"';
              $failNextState='"CONFUSED"';
          }
          }
          $perlCode.= "        if (\$code =~ m/$re/gos) {\n";
          $perlCode.= "        if (\$code =~ m/$re/gos) {\n";
 
 
          my $elsif2="if";
          my $elsif2="if";
          my $i=0;
          my $i=0;
          foreach my $search (@{$state->{search}}) {
          foreach my $search (@{$state->{search}}) {
              $i++;
              $i++;
 
 
              my $arcName = exists($search->{arcName}) ? $search->{arcName} : '';
              my $arcName = exists($search->{arcName}) ? $search->{arcName} : '';
 
 
              $perlCode.= "          $elsif2 (defined(\$$i)) {\n";
              $perlCode.= "          $elsif2 (defined(\$$i)) {\n";
              if ($genDebugCode) {
              if ($genDebugCode) {
                  $perlCode.="           print \"----  -$arcName (\$$i)->\\n\";\n";
                  $perlCode.="           print \"----  -$arcName (\$$i)->\\n\";\n";
                  $perlCode.="           \$takenArcs->{'$stateName'}{$i}++;\n";
                  $perlCode.="           \$takenArcs->{'$stateName'}{$i}++;\n";
              }
              }
              $elsif2="elsif";
              $elsif2="elsif";
              if (exists($search->{resetPos}) && $search->{resetPos}) {
              if (exists($search->{resetPos}) && $search->{resetPos}) {
                  $perlCode.="           pos(\$code)=pos(\$code)-length(\$$i);\n";
                  $perlCode.="           pos(\$code)=pos(\$code)-length(\$$i);\n";
              }
              }
              if (exists($search->{arcName})) {
              if (exists($search->{arcName})) {
                  $perlCode.=  # "            " . 
                  $perlCode.=  # "            " . 
                      _make_eval_code($evalDefs,$stateName,
                      _make_eval_code($evalDefs,$stateName,
                                   $search->{arcName},$i,$genDebugCode);
                                   $search->{arcName},$i,$genDebugCode);
              }
              }
              if (exists $search->{nextState}) {
              if (exists $search->{nextState}) {
                  $perlCode.= "       push (\@{\$ps->{nextStateStack}}, \"".
                  $perlCode.= "       push (\@{\$ps->{nextStateStack}}, \"".
                      join('","',reverse(@{$search->{nextState}}))."\");\n";
                      join('","',reverse(@{$search->{nextState}}))."\");\n";
              }
              }
              if (exists($search->{storePos}) && $search->{storePos}) {
              if (exists($search->{storePos}) && $search->{storePos}) {
                  $perlCode.= "       \$ps->{storing} == 0 or\n";
                  $perlCode.= "       \$ps->{storing} == 0 or\n";
                  $perlCode.= "            die \"Setting storing ".
                  $perlCode.= "            die \"Setting storing ".
                      "flag when it is already set: $stateName:$arcName\";\n";
                      "flag when it is already set: $stateName:$arcName\";\n";
                  $perlCode.= "       \$storePos       = pos(\$code);\n";
                  $perlCode.= "       \$storePos       = pos(\$code);\n";
                  $perlCode.= "       \$ps->{storing}  = 1;\n";
                  $perlCode.= "       \$ps->{storing}  = 1;\n";
                  $perlCode.= "       \$ps->{stored}   = '';\n";
                  $perlCode.= "       \$ps->{stored}   = '';\n";
              }
              }
              $perlCode.= "       }\n";
              $perlCode.= "       }\n";
          }
          }
          $perlCode.= "      }\n";
          $perlCode.= "      }\n";
 
 
          if ($allowAnything) {
          if ($allowAnything) {
              $perlCode.= "      else { ".
              $perlCode.= "      else { ".
                  "push(\@{\$ps->{nextStateStack}},\"$stateName\"); last  PARSE_LINE_LOOP; }\n";
                  "push(\@{\$ps->{nextStateStack}},\"$stateName\"); last  PARSE_LINE_LOOP; }\n";
          }
          }
          else {
          else {
              $perlCode.= "      else {\n";
              $perlCode.= "      else {\n";
              if (exists($state->{failStorePos}) && $state->{failStorePos}) {
              if (exists($state->{failStorePos}) && $state->{failStorePos}) {
                  $perlCode.= "       \$ps->{storing} == 0 or\n";
                  $perlCode.= "       \$ps->{storing} == 0 or\n";
                  $perlCode.= "            die \"Setting storing ".
                  $perlCode.= "            die \"Setting storing ".
                      "flag when it is already set: $stateName:fail\";\n";
                      "flag when it is already set: $stateName:fail\";\n";
                  #NB:uses lastPos here because there was no match, so can't 
                  #NB:uses lastPos here because there was no match, so can't 
                  #  use pos(code)
                  #  use pos(code)
                  $perlCode.= "       \$storePos       = \$lastPos;\n";
                  $perlCode.= "       \$storePos       = \$lastPos;\n";
                  $perlCode.= "       \$ps->{storing}  = 1;\n";
                  $perlCode.= "       \$ps->{storing}  = 1;\n";
                  $perlCode.= "       \$ps->{stored}   = '';\n";
                  $perlCode.= "       \$ps->{stored}   = '';\n";
              }
              }
              if ($failNextState) {
              if ($failNextState) {
                  $perlCode.="push(\@{\$ps->{nextStateStack}},$failNextState);";
                  $perlCode.="push(\@{\$ps->{nextStateStack}},$failNextState);";
              }
              }
              $perlCode.= " pos(\$code)=\$lastPos; }\n";
              $perlCode.= " pos(\$code)=\$lastPos; }\n";
          }
          }
      }
      }
      $perlCode.= "    next PARSE_LINE_LOOP;\n";
      $perlCode.= "    next PARSE_LINE_LOOP;\n";
  }
  }
  $perlCode.= "  }\n";
  $perlCode.= "  }\n";
  $perlCode.= "  if (\$storePos!=-1) { \$ps->{stored}=substr(\$code,\$storePos);}\n";
  $perlCode.= "  if (\$storePos!=-1) { \$ps->{stored}=substr(\$code,\$storePos);}\n";
  $perlCode.= "  elsif ( \$ps->{storing} ) {   \$ps->{stored} .= \$code; }\n";
  $perlCode.= "  elsif ( \$ps->{storing} ) {   \$ps->{stored} .= \$code; }\n";
  $perlCode.= "}\n";
  $perlCode.= "}\n";
 
 
  return $perlCode;
  return $perlCode;
}
}
 
 
sub _make_eval_code {
sub _make_eval_code {
    my ($evalDefs,$stateName,$arcName,$matchNo,$genDebugCode) = @_;
    my ($evalDefs,$stateName,$arcName,$matchNo,$genDebugCode) = @_;
 
 
    my $eval='';
    my $eval='';
 
 
    foreach my $evalDef (@$evalDefs) {
    foreach my $evalDef (@$evalDefs) {
 
 
        if (exists($evalDef->{$stateName}{$arcName})) {
        if (exists($evalDef->{$stateName}{$arcName})) {
            if ( $evalDef->{$stateName}{$arcName} =~ m/^(\w+?):(\w+?)$/ ) {
            if ( $evalDef->{$stateName}{$arcName} =~ m/^(\w+?):(\w+?)$/ ) {
                $eval.=$evalDef->{$1}{$2};
                $eval.=$evalDef->{$1}{$2};
            }
            }
            else {
            else {
                $eval.=$evalDef->{$stateName}{$arcName};
                $eval.=$evalDef->{$stateName}{$arcName};
            }
            }
            $eval.="\n";
            $eval.="\n";
        }
        }
    }
    }
    # replace $match variable with the actual number of the match
    # replace $match variable with the actual number of the match
    $eval=~ s/\$match/\$$matchNo/g;
    $eval=~ s/\$match/\$$matchNo/g;
 
 
    # if fromLastPos is used then generate the code to work it out
    # if fromLastPos is used then generate the code to work it out
    if ($eval =~ /\$fromLastPos/) {
    if ($eval =~ /\$fromLastPos/) {
        my $e;
        my $e;
        $e .= "\$ps->{storing}==1 or die \"fromLastPos used and storing was not set\";\n";
        $e .= "\$ps->{storing}==1 or die \"fromLastPos used and storing was not set\";\n";
        $e .= "if (\$storePos==-1) {\n"; # on another line
        $e .= "if (\$storePos==-1) {\n"; # on another line
        $e .= "   \$fromLastPos=\$ps->{stored}."; # what was before
        $e .= "   \$fromLastPos=\$ps->{stored}."; # what was before
        $e .= "       substr(\$code,0,pos(\$code)-length(\$$matchNo));\n"; # some of this line
        $e .= "       substr(\$code,0,pos(\$code)-length(\$$matchNo));\n"; # some of this line
        $e .= "}\n";
        $e .= "}\n";
        $e .= "else {\n";
        $e .= "else {\n";
        $e .= "   \$fromLastPos=substr(\$code,\$storePos,pos(\$code)".
        $e .= "   \$fromLastPos=substr(\$code,\$storePos,pos(\$code)".
            "-\$storePos-length(\$$matchNo));\n";
            "-\$storePos-length(\$$matchNo));\n";
        $e .= "}\n";
        $e .= "}\n";
        $e .= "\$ps->{storing}=0;\n";
        $e .= "\$ps->{storing}=0;\n";
        $e .= "\$ps->{stored}='';\n";
        $e .= "\$ps->{stored}='';\n";
        $eval = $e . $eval;
        $eval = $e . $eval;
 
 
    }
    }
    return $eval;
    return $eval;
}
}
 
 
sub _check_end_state {
sub _check_end_state {
  my ($self,$file,$line,$ps) = @_;
  my ($self,$file,$line,$ps) = @_;
 
 
  if (!exists($ps->{curState})){
  if (!exists($ps->{curState})){
      # parse_line was never called, file only contained comments, defines etc
      # parse_line was never called, file only contained comments, defines etc
      return;
      return;
  }
  }
  $ps->{prevState} = $ps->{curState};
  $ps->{prevState} = $ps->{curState};
  $ps->{curState} = pop(@{$ps->{nextStateStack}}) or
  $ps->{curState} = pop(@{$ps->{nextStateStack}}) or
      $self->_add_confused("$file:$line:".
      $self->_add_confused("$file:$line:".
                          "No next state after $ps->{prevState} at EOF");
                          "No next state after $ps->{prevState} at EOF");
 
 
  if ($ps->{curState} ne 'START') {
  if ($ps->{curState} ne 'START') {
      $self->_add_confused("$file:$line:".
      $self->_add_confused("$file:$line:".
                          " at EOF in state $ps->{curState}".
                          " at EOF in state $ps->{curState}".
                          (($ps->{curState} eq 'CONFUSED')?
                          (($ps->{curState} eq 'CONFUSED')?
                                           ",prevState was $ps->{prevState}":""));
                                           ",prevState was $ps->{prevState}":""));
  }
  }
  if (@{$ps->{nextStateStack}}) {
  if (@{$ps->{nextStateStack}}) {
      $self->_add_confused("$file:$line:".
      $self->_add_confused("$file:$line:".
                          " at EOF, state stack not empty: ".
                          " at EOF, state stack not empty: ".
                          join(" ",@{$ps->{nextStateStack}}));
                          join(" ",@{$ps->{nextStateStack}}));
  }
  }
 
 
  # at the moment I don't check these:
  # at the moment I don't check these:
  # $ps->{storing}= 0;  
  # $ps->{storing}= 0;  
  # $ps->{stored}= "";
  # $ps->{stored}= "";
 
 
}
}
 
 
sub _check_data_structures {
sub _check_data_structures {
    my ($evalDefs) = @_;
    my ($evalDefs) = @_;
 
 
    my %stateNames;
    my %stateNames;
    my %statesUnused;
    my %statesUnused;
 
 
    foreach my $sp (@$languageDef) {
    foreach my $sp (@$languageDef) {
        die "Not hash!" unless ref($sp) eq "HASH";
        die "Not hash!" unless ref($sp) eq "HASH";
        if (!exists($sp->{stateName})) {  die "State without name!"; }
        if (!exists($sp->{stateName})) {  die "State without name!"; }
        die "Duplicate state$sp->{stateName}" if exists $stateNames{$sp->{stateName}};
        die "Duplicate state$sp->{stateName}" if exists $stateNames{$sp->{stateName}};
        $stateNames{$sp->{stateName}} = $sp;
        $stateNames{$sp->{stateName}} = $sp;
    }
    }
 
 
    %statesUnused = %stateNames;
    %statesUnused = %stateNames;
    # check language def first
    # check language def first
    foreach my $sp (@$languageDef) {
    foreach my $sp (@$languageDef) {
        my %t = %$sp;
        my %t = %$sp;
        if (!exists($sp->{search})) {  die "State without search!"; }
        if (!exists($sp->{search})) {  die "State without search!"; }
        die "search $sp->{stateName} not array" unless ref($t{search}) eq "ARRAY";
        die "search $sp->{stateName} not array" unless ref($t{search}) eq "ARRAY";
        my %arcNames;
        my %arcNames;
        foreach my $arc (@{$sp->{search}}) {
        foreach my $arc (@{$sp->{search}}) {
            my %a = %$arc;
            my %a = %$arc;
            die "arc without regexp in $sp->{stateName}" unless exists $a{regexp};
            die "arc without regexp in $sp->{stateName}" unless exists $a{regexp};
            delete $a{regexp};
            delete $a{regexp};
            if (exists($a{nextState})) {
            if (exists($a{nextState})) {
                die "nextState not array"  unless ref($a{nextState}) eq "ARRAY";
                die "nextState not array"  unless ref($a{nextState}) eq "ARRAY";
                foreach my $n (@{$a{nextState}}) {
                foreach my $n (@{$a{nextState}}) {
                    next if ($n =~ m/^\$/); #can't check variable ones
                    next if ($n =~ m/^\$/); #can't check variable ones
                    die "Bad Next state $n"
                    die "Bad Next state $n"
                        unless exists $stateNames{$n};
                        unless exists $stateNames{$n};
                    delete($statesUnused{$n}) if exists $statesUnused{$n};
                    delete($statesUnused{$n}) if exists $statesUnused{$n};
                }
                }
                delete $a{nextState};
                delete $a{nextState};
            }
            }
            if (exists($a{arcName})) {
            if (exists($a{arcName})) {
                die "Duplicate arc $a{arcName}" if exists $arcNames{$a{arcName}};
                die "Duplicate arc $a{arcName}" if exists $arcNames{$a{arcName}};
                $arcNames{$a{arcName}} = 1;
                $arcNames{$a{arcName}} = 1;
                delete $a{arcName};
                delete $a{arcName};
            }
            }
            delete $a{resetPos};
            delete $a{resetPos};
            delete $a{storePos};
            delete $a{storePos};
            foreach my $k (sort (keys %a)) {
            foreach my $k (sort (keys %a)) {
                die "Bad key $k in arc of state $t{stateName}";
                die "Bad key $k in arc of state $t{stateName}";
            }
            }
        }
        }
        delete $t{stateName};
        delete $t{stateName};
        delete $t{search};
        delete $t{search};
        delete $t{allowAnything} if exists $t{allowAnything};
        delete $t{allowAnything} if exists $t{allowAnything};
 
 
        if (exists($t{confusedNextState})) {
        if (exists($t{confusedNextState})) {
            die "Bad Next confused state $t{confusedNextState}"
            die "Bad Next confused state $t{confusedNextState}"
                unless exists $stateNames{$t{confusedNextState}};
                unless exists $stateNames{$t{confusedNextState}};
            delete $t{confusedNextState};
            delete $t{confusedNextState};
        }
        }
 
 
        foreach my $n (@{$t{failNextState}}) {
        foreach my $n (@{$t{failNextState}}) {
            next if ($n =~ m/^\$/); #can't check variable ones
            next if ($n =~ m/^\$/); #can't check variable ones
            die "Bad Next fail state $n"
            die "Bad Next fail state $n"
                unless exists $stateNames{$n};
                unless exists $stateNames{$n};
            delete($statesUnused{$n}) if exists $statesUnused{$n};
            delete($statesUnused{$n}) if exists $statesUnused{$n};
        }
        }
        delete $t{failNextState} if exists $t{failNextState};
        delete $t{failNextState} if exists $t{failNextState};
        delete $t{failStorePos}  if exists $t{failStorePos};
        delete $t{failStorePos}  if exists $t{failStorePos};
        foreach my $k (sort (keys %t)) {
        foreach my $k (sort (keys %t)) {
            die "Bad key $k in languageDef state $sp->{stateName}";
            die "Bad key $k in languageDef state $sp->{stateName}";
        }
        }
    }
    }
 
 
    # REVISIT: MODULE PORTS looks like it is unused because it is got to
    # REVISIT: MODULE PORTS looks like it is unused because it is got to
    #  by setting $nState - should have a flag in language def that turns
    #  by setting $nState - should have a flag in language def that turns
    #  off this check on a per state basis.
    #  off this check on a per state basis.
    foreach my $state (sort (keys %statesUnused)) {
    foreach my $state (sort (keys %statesUnused)) {
        #die "State $state was not used";
        #die "State $state was not used";
        print "Warning: State $state looks like it was not used\n" if $debug;
        print "Warning: State $state looks like it was not used\n" if $debug;
    }
    }
 
 
    foreach my $evalDef (@$evalDefs) {
    foreach my $evalDef (@$evalDefs) {
        foreach my $state (sort (keys %$evalDef)) {
        foreach my $state (sort (keys %$evalDef)) {
            if (!exists($stateNames{$state})) {
            if (!exists($stateNames{$state})) {
                die "Couldn't find state $state";
                die "Couldn't find state $state";
            }
            }
            my $statep = $stateNames{$state};
            my $statep = $stateNames{$state};
 
 
            foreach my $arc (sort (keys %{$evalDef->{$state}})) {
            foreach my $arc (sort (keys %{$evalDef->{$state}})) {
                my $found = 0;
                my $found = 0;
                foreach my $s (@{$statep->{search}}) {
                foreach my $s (@{$statep->{search}}) {
                    if (exists($s->{arcName}) && ($s->{arcName} eq $arc)) {
                    if (exists($s->{arcName}) && ($s->{arcName} eq $arc)) {
                        $found=1;
                        $found=1;
                        last;
                        last;
                    }
                    }
                }
                }
                if ($found == 0) {
                if ($found == 0) {
                    die "No arc $arc in state $state";
                    die "No arc $arc in state $state";
                }
                }
                if ( $evalDef->{$state}{$arc} =~ m/^(\w+?):(\w+?)$/ ) {
                if ( $evalDef->{$state}{$arc} =~ m/^(\w+?):(\w+?)$/ ) {
                    die "No code found for $evalDef->{$state}{$arc}"
                    die "No code found for $evalDef->{$state}{$arc}"
                        unless exists $evalDef->{$1}{$2};
                        unless exists $evalDef->{$1}{$2};
                }
                }
            }
            }
        }
        }
    }
    }
}
}
 
 
 
 
sub _check_coverage {
sub _check_coverage {
 
 
    print "\n\nCoverage Information:\n";
    print "\n\nCoverage Information:\n";
    foreach my $sp (@$languageDef) {
    foreach my $sp (@$languageDef) {
        if (!exists($takenArcs->{$sp->{stateName}})) {
        if (!exists($takenArcs->{$sp->{stateName}})) {
            print " State $sp->{stateName}: no arcs take (except fail maybe)\n";
            print " State $sp->{stateName}: no arcs take (except fail maybe)\n";
        }
        }
        else {
        else {
            my $i=0;
            my $i=0;
            foreach my $arc (@{$sp->{search}}) {
            foreach my $arc (@{$sp->{search}}) {
                $i++;
                $i++;
                if (!exists( $takenArcs->{$sp->{stateName}}{$i} )) {
                if (!exists( $takenArcs->{$sp->{stateName}}{$i} )) {
                    my $arcName = $i;
                    my $arcName = $i;
                    $arcName = $arc->{arcName} if exists $arc->{arcName};
                    $arcName = $arc->{arcName} if exists $arc->{arcName};
                    print " Arc $arcName of $sp->{stateName} was never taken\n";
                    print " Arc $arcName of $sp->{stateName} was never taken\n";
                }
                }
            }
            }
        }
        }
    }
    }
}
}
 
 
 
 
###########################################################################
###########################################################################
 
 
# when doing require or use we must return 1
# when doing require or use we must return 1
1;
1;
 
 
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.