Skip to content

Instantly share code, notes, and snippets.

@jeffreykegler
Forked from pstuifzand/MonthTotals.pm
Last active December 15, 2015 08:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeffreykegler/5231568 to your computer and use it in GitHub Desktop.
Save jeffreykegler/5231568 to your computer and use it in GitHub Desktop.
"Totaal"
"Omzet totaal excl"
"Omzet hoog tarief" [field=subtotaal_hoog]
"Omzet laag tarief" [field=subtotaal_laag]
"Omzet nultarief (0%)" [field=subtotaal_geen]
"Btw totaal"
"Btw hoog tarief" [field=btw_hoog]
"Btw laag tarief" [field=btw_laag]
"Verzendkosten" [field=vrachtkosten]
package MonthTotals;
use 5.010;
use strict;
use Marpa::R2;
use Data::Dumper;
sub new {
my ($class) = @_;
my $self = bless {
grammar => Marpa::R2::Scanless::G->new({
default_action => '::array',
source => \<<'SOURCE',
:start ::= source
source ::= lines | lines newline
lines ::= line+ separator => newline
line ::= indents label ws '[field=' value ']'
| indents label
| label ws '[field=' value ']'
| label
indents ~ indent*
indent ~ [ ] [ ] [ ] [ ]
| [\t]
newline ~ [\n]
label ~ ["] label_in ["]
label_in ~ [^"]+
value ~ [\w]+
ws ~ [ \t]+
SOURCE
}),
}, $class;
return $self;
}
sub parse {
my ($self, $input) = @_;
my $re = Marpa::R2::Scanless::R->new({ grammar => $self->{grammar} });
$re->read(\$input);
my $t = $re->value;
return $$t;
}
1;
use 5.010;
use File::Slurp 'read_file';
use MonthTotals;
sub sum {
my $t=0;
for (@_) {
$t+=$_;
}
$t;
}
# propagate values up the tree
sub assign_values {
my $tree = shift;
if (@{$tree->[1]}) {
my @val;
for (@{$tree->[1]}) {
push @val, assign_values($_);
}
$tree->[0]{value} = \@val;
return @val;
}
return @{$tree->[0]{value}};
}
# build a list from a tree
sub make_list {
my $tree = shift;
if (@{$tree->[1]}) {
my @val = ($tree->[0]);
for (@{$tree->[1]}) {
push @val, make_list($_);
}
return @val;
}
return $tree->[0];
}
# build a tree from a list
sub list {
my ($value_cb, $list) = @_;
return if @$list == 0;
my $x = shift @$list;
my @in;
while (@$list) {
my $v = $list->[0];
last if $value_cb->($v) <= $value_cb->($x);
shift @$list;
push @in, $v;
}
return [$x, [list($value_cb, \@in)]], list($value_cb, $list);
}
my $m = MonthTotals->new;
my $input = read_file('monthtotal.txt');
my $v = $m->parse($input);
my @spec;
my $max_indent = 0;
for my $line (@$v) {
my $s = {};
$s->{indents} = @{$line->[0]};
$s->{label} = $line->[1];
$s->{label} =~ s/^"//;
$s->{label} =~ s/"$//;
$s->{value} = [$line->[4]];
$max_indent = $max_indent > $s->{indents} ? $max_indent : $s->{indents};
push @spec, $s;
}
for my $s (@spec) {
$s->{indents_after} = $max_indent - $s->{indents};
}
my $tree = [list(sub { return $_[0]->{indents} }, \@spec)];
assign_values($tree->[0]);
my @list = make_list($tree->[0]);
my $input = {
btw_hoog => 21,
btw_laag => 6,
subtotaal_hoog => 100,
subtotaal_laag => 100,
subtotaal_geen => 0,
vrachtkosten => 100,
};
for (@list) {
my $indent=("\t"x$_->{indents});
my $indenta=("\t"x$_->{indents_after});
say(sprintf('%s%-40s%s%8d', $indent, $_->{label}, $indent, sum(map{$input->{$_}}@{$_->{value}})));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment