Re: Store data into array by looping?
by tybalt89 (Monsignor) on Apr 10, 2019 at 00:52 UTC
|
Looks like you are taking the same course as Output not correct
Anyway, here's a small simulator I wrote from that input (slightly modified for case)
that processes your input and simulates the circuit, providing all inputs and producing
a table with all outputs.
It stores gates in a hash keyed by output name where the value is perl code to evaluate the output from the inputs.
This allows easy simulation later when all gates are combined to a generated sub call 'async'.
This form of gate storage may or may not be what you are looking for.
#!/usr/bin/perl
# https://perlmonks.org/?node_id=1226380
# https://perlmonks.org/?node_id=1232356
use strict;
use warnings;
my (%gates, @inputs, @wires, @outputs, $depends, %bits, $topologicalor
+der);
while( <DATA> ) # inpu
+t section
{
print;
if( /^nand /gi )
{
my ( undef, $out, $ina, $inb) = /\w+/g;
$gates{$out} and die "\nDUPLICATE: $out\n";
$gates{$out} = "1 ^ (\$bits{'$ina'} & \$bits{'$inb'})";
$depends .= "$out $ina $inb\n";
}
elsif( /^output /gi ) { push @outputs, /\w+/g; }
elsif( /^input /gi ) { push @inputs, /\w+/g; }
elsif( /^wire /gi ) { push @wires, /\w+/g; }
}
my @all = (@inputs, @wires, @outputs);
#use Data::Dump 'dd'; dd \%gates;
%gates or die "no gates found";
$depends =~ s/ $_\b//g for @inputs; # topological orde
+r section
while( $depends =~ s/^(\w+)\n//m )
{
$topologicalorder .= "\$bits{$1} = $gates{$1};\n";
$depends =~ s/ $1\b//g;
}
length $depends and die "CIRCULAR or UNDEFINED:\n<$depends>";
print $topologicalorder;
eval "sub async { $topologicalorder }";
my $fmt = "@{[ map '%' . y///c . 's', @all ]}\n"; # outpu
+t section
printf $fmt, @all;
@bits{@all} = ('u') x @all;
for ( glob '{0,1}' x @inputs )
{
@bits{@inputs} = map 0 + $_, split //;
async();
printf $fmt, @bits{@all};
}
__DATA__
module circuit_17 (N1,N2,N3,N6,N7,N22,N23);
input N1,N2,N3,N6,N7;
output N22,N23;
wire N10,N11,N16,N19;
nand nand2_1 (N10,N1,N3);
nand nand2_2 (N11,N3,N6);
nand nand2_3 (N16,N11,N2);
nand nand2_4 (N19,N11,N7);
nand nand2_5 (N22,N10,N16);
nand nand2_6 (N23,N16,N19);
endmodule
Seems to work. May have issues if you start using tri-state output logic.
| [reply] [d/l] |
Re: Store data into array by looping?
by LanX (Saint) on Apr 09, 2019 at 16:56 UTC
|
$gate_type = $1;
$gate_name = $2;
$output_gate = $3;
$input_A = $4;
$input_B = $5;
push @input_A, $input_A; # column 2
be warned that this will collect over all modules in your file.
| [reply] [d/l] |
Re: Store data into array by looping?
by hdb (Monsignor) on Apr 10, 2019 at 09:51 UTC
|
Assuming eventually your input will be a file with multiple modules, you could parse it into a more complex data structure (array of module data, where each module is represented as a hash):
use strict;
use warnings;
use Data::Dumper;
my @modules;
while(<DATA>){
push @modules, { name => $1 } if /^module (\w+) \(.*\)/;
$modules[ -1 ]->{ input } = [ split /,/, $1 ] if /^input (.*);/
+;
$modules[ -1 ]->{ output } = [ split /,/, $1 ] if /^output (.*);
+/;
$modules[ -1 ]->{ wire } = [ split /,/, $1 ] if /^wire (.*);/;
next if /^endmodule/;
if( /^(nand|nor|other)/ ) {
push @{ $modules[ -1 ]->{ gates } }, {};
@{ $modules[ -1 ]->{ gates }[-1] }{ qw( type name output input
+_A input_B) } = split /[\s\(\),;]+/;
}
}
print Dumper \@modules;
__DATA__
module circuit_17 (N1,N2,N3,N6,N7,N22,N23);
input N1,N2,N3,N6,N7;
output N22,N23;
wire N10,N11,N16,N19;
nand nand2_1 (N10,N1,N3);
nand nand2_2 (N11,N3,N6);
nand nand2_3 (N16,N11,N2);
nand nand2_4 (N19,N11,N7);
nand nand2_5 (N22,N10,N16);
nand nand2_6 (N23,N16,N19);
endmodule
resulting in
$VAR1 = [
{
'input' => [
'N1',
'N2',
'N3',
'N6',
'N7'
],
'gates' => [
{
'input_A' => 'N1',
'name' => 'nand2_1',
'type' => 'nand',
'input_B' => 'N3',
'output' => 'N10'
},
{
'input_A' => 'N3',
'name' => 'nand2_2',
'type' => 'nand',
'input_B' => 'N6',
'output' => 'N11'
},
{
'input_A' => 'N11',
'name' => 'nand2_3',
'type' => 'nand',
'input_B' => 'N2',
'output' => 'N16'
},
{
'input_A' => 'N11',
'name' => 'nand2_4',
'type' => 'nand',
'input_B' => 'N7',
'output' => 'N19'
},
{
'input_A' => 'N10',
'name' => 'nand2_5',
'type' => 'nand',
'input_B' => 'N16',
'output' => 'N22'
},
{
'input_A' => 'N16',
'name' => 'nand2_6',
'type' => 'nand',
'input_B' => 'N19',
'output' => 'N23'
}
],
'name' => 'circuit_17',
'wire' => [
'N10',
'N11',
'N16',
'N19'
],
'output' => [
'N22',
'N23'
]
}
];
| [reply] [d/l] [select] |
Re: Store data into array by looping?
by FreeBeerReekingMonk (Deacon) on Apr 09, 2019 at 20:20 UTC
|
Hello ameezys. You do not give much information on how you want the gate information stored. It depends on what you want to do with it.
I only see nand in your example, but there are not's and's etc.
If you want to easily loop over only nand or only not then I suggest:
$GATE{$gate_type}{$gate_name} = { ... hash object with fields ... }
And then build arrays of these objects to loop over them. (the %LINK variable). As pointers/references, so hopefully RAM efficient.
But you can also store hash objects in an array (but I did not do that in the code) which makes it less cluttered, but harder to loop through.
First I modified the regexp a bit so that it is tolerant to a space here and there. But a separate regexp needs to be made to handle the not as it has less parameters
To have the array you want, just loop over the keys:
# Obtain the @input_A array from %LINK
my @input_A_from_link = keys %{$LINK{'input_A'}};
die Dumper(\@input_A_from_link);
or, if you do not want the helper hash, directly from the data (using a oneliner):
# get all input_A for nand, not, and, etc..
my @all_input_A = map { my $g = $_; @_=keys $GATE{$g}; map {$GATE{$g}{
+$_}->{'A'}} @_ } keys %GATE;
die Dumper(\@all_input_A);
The code (sorry, a bit messy):
#!/usr/bin/perl
use warnings;
use Data::Dumper;
use [METAMOD://List::MoreUtils] qw/ uniq /;
my %GATE;
my %LINK;
while(<DATA>){
chomp;
my $gate_DATA = $_;
if (defined($gate_DATA) && ($gate_DATA =~ /(.*)\s+(.*)\s+\(\s*(.*)\s
+*,\s*(.*)\s*,\s*(.*)\s*\);/) && ($gate_DATA !~ /module/) ){
# $gate_type = $1;
# $gate_name = $2;
$output_gate = $3;
$input_A = $4;
$input_B = $5;
die "Line $.: FATAL Redefinition of gate $gate_DATA\n" if(defined
+$GATE{$gate_type}{$gate_name});
$GATE{$gate_type}{$gate_name} = {
'name' => $gate_name,
'type' => $gate_type,
'out' => $output_gate,
'A' => $input_A,
'B' => $input_B,
};
push @{$LINK{'input_A'}{$input_A}}, $GATE{$gate_type}{$gate_name};
push @{$LINK{'input_B'}{$input_B}}, $GATE{$gate_type}{$gate_name};
push @{$LINK{'output'}{$output_gate}}, $GATE{$gate_type}{$gate_nam
+e};
}
}
# uncomment to Show the structure of %GATE
# die Dumper(\%GATE);
# uncomment to Show the structure of %LINK
# die Dumper(\%LINK);
# Yeah, %LINK is a hash of a hash of an array of a referenced hash
# die Dumper($LINK{'input_A'}{'N11'}[0]->{'A'});
# die Dumper($LINK{'output'}{'N19'}[0]->{'A'});
# loop over input_A and show where it outputs to
for my $gate (keys %{$LINK{'input_A'}}){
my @outputs = map { $_->{'out'} } grep { defined $_->{'out'} } @{$LI
+NK{'input_A'}{$gate}};
print "input gate $gate has output @outputs\n";
}
# This is how you access the data of one gate:
# print $GATE{'nor'}{'NOR2_1'}->{'out'};
# get nand input_A, note the use of uniq to have a unique list (still
+not sorted, though)
my @nand_input_A = uniq map { $GATE{'nand'}{$_}->{'A'} } keys %{$GATE{
+'nand'}};
# get all input_A for nand, not, and, etc..
my @all_input_A = map { my $g = $_; @_=keys $GATE{$_}; map {$GATE{$g}{
+$_}->{'A'}} @_ } keys %GATE;
# get all input_A for nand, not, and, etc... but this time, use readab
+le perl
my @all_input_A_normal;
for my $gate_type (keys %GATE){
for my $gate_name (keys %{$GATE{$gate_type}}){
if(defined $GATE{$gate_type}{$gate_name}->{'A'}){
push @all_input_A_normal, $GATE{$gate_type}{$gate_name}->{'A'};
}
}
}
print Dumper(\@all_input_A_normal);
__DATA__
nand nand2_1 (N10,N1,N3);
nand nand2_2 (N11,N3,N6);
nand nand2_3 (N16,N11,N2);
nand nand2_4 (N19,N11,N7);
nand nand2_5 (N22,N10,N16);
nand nand2_6 (N23,N16,N19);
nor NOR2_1 (N6875, N6722, N6476);
| [reply] [d/l] [select] |
Re: Store data into array by looping?
by Marshall (Canon) on Apr 09, 2019 at 20:22 UTC
|
A few tips:
- Your regex is not the best. .* is "dangerous" and fraught with unintended consequences. You can go far with just \w and \s.
- Forget this $1,$2 stuff. Assign directly as shown below
- The if() is true if the regex matches, else it is false. as shown below
- I have many question, but this will help you get started...
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my @gate_data;
while (my $line = <DATA>)
{
if (my($gate_type,$gate_name,$ouput_gate,$input_A, $input_B)
= $line =~ /^(\w+)\s+(\w+)\s+\((\w+),(\w+),(\w+)\)/)
{
print "$gate_type, $gate_name,$ ouput_gate, $input_A, $input_B\n
+";
push @gate_data,[$gate_type, $gate_name,$ ouput_gate, $input_A,
+$input_B];
}
}
print "@$_\n" for @gate_data;
=prints
nand, nand2_1,N10, N1, N3
nand, nand2_2,N11, N3, N6
nand, nand2_3,N16, N11, N2
nand, nand2_4,N19, N11, N7
nand, nand2_5,N22, N10, N16
nand, nand2_6,N23, N16, N19
nand nand2_1 N10 N1 N3
nand nand2_2 N11 N3 N6
nand nand2_3 N16 N11 N2
nand nand2_4 N19 N11 N7
nand nand2_5 N22 N10 N16
nand nand2_6 N23 N16 N19
=cut
__DATA__
module circuit_17 (N1,N2,N3,N6,N7,N22,N23);
input N1,N2,N3,N6,N7;
output N22,N23;
wire N10,N11,N16,N19;
nand nand2_1 (N10,N1,N3);
nand nand2_2 (N11,N3,N6);
nand nand2_3 (N16,N11,N2);
nand nand2_4 (N19,N11,N7);
nand nand2_5 (N22,N10,N16);
nand nand2_6 (N23,N16,N19);
endmodule
Update: It appears that this output is coming from sort of wiring program. What you show here is the human readable output. There will another form of output designed as input for whatever machine is going to further fiddle with this data. I suggest you forget about parsing this data format and get whatever that other data output is. It will already be structured into records designed to handle all of the various gate types and other parts like flip-flops, registers, etc. Reverse engineering that data structure seems pointless to me. | [reply] [d/l] |
Re: Store data into array by looping?
by holli (Abbot) on Apr 12, 2019 at 16:09 UTC
|
Regular expressions like it's still 1998. If I may:
use warnings;
use strict;
use Regexp::Grammars;
use Data::Dumper;
my $data = join "", <DATA>;
my $matcher = qr{
<debug: off>
<nocontext:>
^
<Module>
<[Commands]>+
<EndModule>
$
<token: Module>
module \s <Name> \s <BracketedNodes>; \n
<token: EndModule>
endmodule \n?
<token: Commands>
( <Input>|<Output>|<Wire>|<Nand> );\n
<token: Nand>
nand \s <Name> \s <BracketedNodes>
<token: Input>
input \s <Nodes>
<token: Output>
output \s <Nodes>
<token: Wire>
wire \s <Nodes>
<token: Name>
[\p{L}\d_]+
<token: Node>
N\d+
<token: Nodes>
<[Node]>+ % ,
<token: BracketedNodes>
\(<Nodes>\)
};
if ( $data =~ $matcher )
{
print Dumper \%/; #/
}
else
{
print "NO MATCH";
}
__DATA__
module circuit_17 (N1,N2,N3,N6,N7,N22,N23);
input N1,N2,N3,N6,N7;
output N22,N23;
wire N10,N11,N16,N19;
nand nand2_1 (N10,N1,N3);
nand nand2_2 (N11,N3,N6);
nand nand2_3 (N16,N11,N2);
nand nand2_4 (N19,N11,N7);
nand nand2_5 (N22,N10,N16);
nand nand2_6 (N23,N16,N19);
endmodule
Yields
Now for sanity checking you can inspect the result hash, but malformed data will simply not match the regex. If you want useful error messages you can add callbacks to the grammar.
holli
You can lead your users to water, but alas, you cannot drown them.
| [reply] [d/l] [select] |
Re: Store data into array by looping?
by FreeBeerReekingMonk (Deacon) on Apr 10, 2019 at 22:08 UTC
|
Replying on the UPDATE (you really should create a new question, as older questions get ignored in favour of new questions).
Just capture nand2_1 into a variable, like you already did, and then just break it into bits, like so:
my $gate_name = 'nand2_1';
my ($gtype, $gfirst, $gsecond) = ($gate_name =~ /^(\w+)(\d+)_(\d+)/);
print "# $gtype # $gfirst # $gsecond #\n";
output:
# nand # 2 # 1 #
| [reply] [d/l] [select] |