#!/usr/bin/env perl
# See copyright, etc in below POD section.
######################################################################

use warnings;
use Getopt::Long;
use IO::File;
use Pod::Usage;
use Data::Dumper; $Data::Dumper::Indent=1;
use strict;
use vars qw($Debug);

#======================================================================

our $Tree;
our %OpMap;
gentree();

#======================================================================
# main

$Debug = 0;
my $opt_filename;
autoflush STDOUT 1;
autoflush STDERR 1;
if (! GetOptions(
          "help"        => \&usage,
          "debug"       => \&debug,
          "<>"          => \&parameter,
    )) {
    usage();
}

vread($opt_filename);
#print Dumper($Tree);
vwrite();

print '(query-replace-regexp "(\\([0-9a-z_]+\\))" "\\1" nil nil nil)',"\n";

#----------------------------------------------------------------------

sub usage {
    pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
    exit(1);  # Unreachable
}

sub debug {
    $Debug = 1;
}

sub parameter {
    my $param = shift;
    if (!$opt_filename) {
        $opt_filename = $param;
    } else {
        die "%Error: Unknown parameter: $param\n";
    }
}

#######################################################################

sub vread {
    my $filename = shift;
    my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
    my $lasthier="";
    $Tree = {
        op => 'NETLIST',
        t => [[],[],[],[],[],],
    };
    my @stack;
    $stack[1] = $Tree;
    while (defined (my $line = $fh->getline)) {
        if ($line =~ /^\s+(\S+):\s+(\S+)\s+0x\S+\s+{(\d+)}\s+w(\d+)\s+(.*)$/) {
            my $hier = $1;
            my $op = $2;
            my $lineno = $3;
            my $width = $4;
            my $etc = $5;

            $etc =~ s/__DOT__/./g;
            $etc =~ s/__PVT__//g;

            my $self = {
                op => $op,
                #width =>  $width,
                #lineno => $lineno,
                #line => $line,
                etc => $etc,
                args => [split(/[ \t]+/,$etc)],
                t => [[],[],[],[],[],],
            };

            my @hiers = (1,split(/:/,$hier));
            my $depth = $#hiers+1;
            my $newchild = $hiers[$#hiers];

            #print "DD $depth $newchild $op\n";

            push @{$stack[$depth-1]->{t}[$newchild]}, $self;
            $stack[$depth] = $self;

            $lasthier = $hier;
            #print "   $lasthier\n";
            #print Dumper($Tree);
        }
    }
}

######################################################################

our $Indent = 0;
use vars qw($Code_Self);
use vars qw($Avoid_Hex);

sub vwrite {
    $Indent = 0;
    print vwrite_rec($Tree);
}

sub vwrite_rec {
    my $self = shift;
    #print "/*$self->{op}*/";
    my $code = $OpMap{$self->{op}} or die "%Error: No map for $self->{op},";
    local $Code_Self = $self;
    #print Dumper($self->{t}[3]),"\n";
    &$code;
}

######################################################################
# Tree functions

sub p { print join("",@_); }

sub exists1 { return defined $Code_Self->{t}[1][0]; }
sub exists2 { return defined $Code_Self->{t}[2][0]; }
sub exists3 { return defined $Code_Self->{t}[3][0]; }
sub exists4 { return defined $Code_Self->{t}[4][0]; }
sub exists5 { return defined $Code_Self->{t}[5][0]; }

sub t1 { foreach my $r (@{$Code_Self->{t}[1]}) { vwrite_rec($r); } }
sub t2 { foreach my $r (@{$Code_Self->{t}[2]}) { vwrite_rec($r); } }
sub t3 { foreach my $r (@{$Code_Self->{t}[3]}) { vwrite_rec($r); } }
sub t4 { foreach my $r (@{$Code_Self->{t}[4]}) { vwrite_rec($r); } }
sub t5 { foreach my $r (@{$Code_Self->{t}[5]}) { vwrite_rec($r); } }
sub p1 { p "("; t1; p ")";}
sub p2 { p "("; t2; p ")";}
sub p3 { p "("; t3; p ")";}
sub p4 { p "("; t4; p ")";}
sub p5 { p "("; t5; p ")";}
sub a1 { p $Code_Self->{args}[0]; }
sub a2 { p $Code_Self->{args}[1]; }
sub a3 { p $Code_Self->{args}[2]; }
sub a4 { p $Code_Self->{args}[3]; }
sub a5 { p $Code_Self->{args}[4]; }
sub a6 { p $Code_Self->{args}[5]; }
sub a7 { p $Code_Self->{args}[6]; }

sub indentInc { $Indent+=2; }
sub indentDec { $Indent-=2; }
sub nl { p "\n"," "x$Indent; }

######################################################################

# nl is a newline
# p# indicates to add parens
# t# indicates tree reference
# a# indicates info from dump where n1 is the width.

sub gentree {
%OpMap = (
  'NULLNODE'    => sub { "" },
  'NETLIST'     => sub { nl;t1;t2;t3;t4;t5; },
  'ACTIVE'      => sub { p "always_act @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
  'ADD'         => sub { p1;p " + ";p2; },
  'ALWAYS'      => sub { p "always @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
  'ALWAYSPOST'  => sub { p "ALWAYSPOST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'AND'         => sub { p1;p " & ";p2; },
  'ARRAYSEL'    => sub { t1;p "[";t2;p "]"; },
  'ASSIGN'      => sub { t2;p " = ";t1;p ";";nl; },
  'ASSIGNDLY'   => sub { t2;p " <= ";t1;p ";";nl; },
  'ASSIGNPOST'  => sub { p "ASSIGNPOST what{";t1;p " = ";t2;p ";";nl; },
  'ASSIGNPRE'   => sub { p "ASSIGNPRE what{";t1;p " = ";t2;p ";";nl; },
  'ASSIGNW'     => sub { p "assign ";t2;p " = ";t1;p ";";nl; },
  'ATTROF'      => sub { p "ATTROF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'BEGIN'       => sub { p "begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
  'BITSEL'      => sub { t1;local $Avoid_Hex=1; p "[";t2;p "]"; },
  'CASE'        => sub { p "CASE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'CASEITEM'    => sub { p "CASEITEM what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'CAST'        => sub { p "CAST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'CCALL'       => sub { p "CCALL what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'CELL'        => sub { a1;p " ";a7;p " (/*CELL*/);"; nl; },
  'CFUNC'       => sub { p "CFUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'CHANGEDET'   => sub { p "CHANGEDET what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'CINCLUDE'    => sub { p "CINCLUDE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'COMMENT'     => sub { p "//COMMENT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl;nl; },
  'CONCAT'      => sub { p "{";p1;p ",";p2;p "}"; },
  'CONDITIONAL' => sub { p1;p " ? ";p2;p " : ";p3; },
  'CONST'       => sub { p_const(); },
  'COVER'       => sub { p "COVER what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'CRETURN'     => sub { p "CRETURN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'CSTMT'       => sub { p "CSTMT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'DEFPARAM'    => sub { p "defparam ";p1;p " = ";p2;p ";";nl; },
  'DISPLAY'     => sub { p '$write("';p1;p "\",";p2;p3;p4;p5;p ");";nl; },
  'DIV'         => sub { p1;p " / ";p2; },
  'EQ'          => sub { p1;p " == ";p2; },
  'EQCASE'      => sub { p1;p " === ";p2; },
  'EXTEND'      => sub { t1; },
  'EXTRACT'     => sub { t1;local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
  'FINISH'      => sub { p '$finish;';nl },
  'FOR'         => sub { p "for (";p1;p ",";p2;p ",";p3;p ") begin";indentInc;nl;p4;p5;indentDec;p "end";nl; },
  'FUNC'        => sub { p "FUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'FUNCREF'     => sub { p "FUNCREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'GT'          => sub { p1;p " > ";p2; },
  'GTE'         => sub { p1;p " >= ";p2; },
  'IF'          => sub { p "if (";p1;p ") begin";indentInc;nl;t2;indentDec;if (exists3) {p "end else begin";indentInc;nl;t3;indentDec;} p "end"; nl; },
  'INITARRAY'   => sub { p "INITARRAY what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'INITIAL'     => sub { p "initial begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
  'LOGAND'      => sub { p1;p " && ";p2; },
  'LOGNOT'      => sub { p1;p " || ";p2; },
  'LOGOR'       => sub { p "!";p1; },
  'LT'          => sub { p1;p " < ";p2; },
  'LTE'         => sub { p1;p " <= ";p2; },
  'MODDIV'      => sub { p1;p " % ";p2; },
  'MODULE'      => sub { p "module ";a1;p " (/*AUTOARG*/);";indentInc;nl;t1;t2;t3;t4;t5;indentDec;nl;p "endmodule";nl; },
  'MUL'         => sub { p1;p " * ";p2; },
  'NEQ'         => sub { p1;p " != ";p2; },
  'NEQCASE'     => sub { p1;p " !== ";p2; },
  'NOT'         => sub { p " ~";p1; },
  'OR'          => sub { p1;p " | ";p2; },
  'PIN'         => sub { p ";p ";p1;p " (";p2;p "),";nl; },
  'PORT'        => sub { p ""; },
  'PRAGMA'      => sub { p "PRAGMA what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'RAND'        => sub { p '$rand'; },
  'RANGE'       => sub { t1; local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
  'REDAND'      => sub { p "&(";p1;p ")"; },
  'REDOR'       => sub { p "|(";p1;p ")"; },
  'REDXNOR'     => sub { p "~|(";p1;p ")"; },
  'REDXOR'      => sub { p "~^(";p1;p ")"; },
  'REPLICATE'   => sub { p "{";p1;p "{";p2;p "}}"; },
  'SCCTOR'      => sub { p "SCCTOR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'SCHDR'       => sub { p "SCHDR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'SCIMP'       => sub { p "SCIMP what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'SCINT'       => sub { p "SCINT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'SCOPE'       => sub { t1;t2;t3;t4;t5; },
  'SENITEM'     => sub { a1;p " ";t1; },
  'SENTREE'     => sub { t1;t2;t3;t4;t5; },
  'SHIFTL'      => sub { p1;p " << ";p2; },
  'SHIFTR'      => sub { p1;p " >> ";p2; },
  'STOP'        => sub { p '$stop;';nl; },
  'SUB'         => sub { p1;p " - ";p2; },
  'TASK'        => sub { p "TASK what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'TASKREF'     => sub { p "TASKREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'TEXT'        => sub { p "TEXT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'TIME'        => sub { p '$time'; },
  'TOPSCOPE'    => sub { t1;t2;t3;t4;t5; },
  'TRACE'       => sub { p "TRACE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'UCFUNC'      => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ")"; },
  'UCSTMT'      => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ");";nl; },
  'NEGATE'      => sub { p " -";p1; },
  'VAR'         => sub { p_var(); },
  'VARPIN'      => sub { p "VARPIN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
  'VARREF'      => sub { a1; },
  'VARSCOPE'    => sub { },
  'WHILE'       => sub { t1; p "while (";t2;p ") begin";indentInc;nl;t3;t4;indentDec;p "end";nl; },
  'WORDSEL'     => sub { p1;p "[";p2;p ":";p3;p "]"; },
  'XNOR'        => sub { p1;p " ~^ ";p2; },
  'XOR'         => sub { p1;p " ^";p2; },
);
}

sub p_var {
    my $self = $Code_Self;
    if ($self->{etc} =~ /\[I\]/) {
        print "input";
    } elsif ($self->{etc} =~ /\[O\]/) {
        print "output";
    } else {
        print "reg";
    }
    p "\t";
    {
        local $Avoid_Hex=1;
        t1;
    }
    p "\t";
    a1;
    if (exists2()) {
        p " = ";
        t2;
    }
    p ";";
    nl;
}

sub p_const {
    my $v = $Code_Self->{args}[0];
    if ($v =~ /\?32\?h(.*)$/
        || ($Avoid_Hex && $v =~ /^[0-9?]*h(.*)$/)) {
        print hex $1;
    } else {
        print $v;
    }
}

#######################################################################
__END__

=pod

=head1 NAME

vtree_importer -

=head1 SYNOPSIS

  vtree_importer *.log

=head1 DESCRIPTION

dd

=head1 ARGUMENTS

=over 4

=item --help

Displays this message and program version and exits.

=back

=head1 DISTRIBUTION

Copyright 2005-2020 by Wilson Snyder.  Verilator is free software; you can
redistribute it and/or modify it under the terms of either the GNU Lesser
General Public License Version 3 or the Perl Artistic License Version 2.0.

=head1 AUTHORS

Wilson Snyder <wsnyder@wsnyder.org>

=head1 SEE ALSO

=cut

######################################################################
### Local Variables:
### compile-command: "./vtree_importer "
### End:
