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

require 5.006_001;
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=>2, -output=>\*STDOUT);
    exit (1);
}

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-2018 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:
