1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
package MatrixParser;
use strict;
use warnings;
use feature qw(say signatures);
no warnings 'experimental::signatures';
use List::Util qw(none);
use MatrixParser::Lexer;
sub new ( $class, $input ) {
my $self = {
lexer => MatrixParser::Lexer->new($input),
corners => [],
row => 0,
col => 0,
element_count => undef,
};
$self->{lookahead} = $self->{lexer}->next_token;
return bless $self, $class;
}
# returns an array of hashes with the corner positions (1s) from the input
# matrix. each hash contains the corner positions for the corresponding row in
# the input matrix
sub corners($self) {
while ( $self->{lookahead} ) {
$self->_parse_row;
}
return $self->{corners};
}
sub _parse_row($self) {
my $start = $self->_expect('[');
my $count = 0;
while ( !$self->_match(']') ) {
$self->_parse_element;
$count++;
}
$self->_expect(']');
if ( defined $self->{element_count} && $self->{element_count} != $count ) {
$self->_unexpected_element_count( $start, $count );
}
$self->{element_count} = $count;
$self->{col} = 0;
$self->{row}++;
return;
}
sub _parse_element($self) {
if ( $self->_match('1') ) {
$self->{corners}[ $self->{row} ]{ $self->{col} } = 1;
}
elsif ( !$self->_match('0') ) {
$self->_unexpected_token( $self->{lookahead}, '1|0' );
}
$self->{col}++;
return $self->_next_token()->lexeme;
}
sub _match ( $self, $expect ) {
$self->_unexpected_eof()
if !$self->{lookahead};
return $self->{lookahead}->lexeme eq $expect;
}
sub _expect ( $self, $expect ) {
my $token = $self->_next_token();
return $token if $token->lexeme eq $expect;
$self->_unexpected_token( $token, $expect );
}
sub _next_token($self) {
my $token = $self->{lookahead};
$self->{lookahead} = $self->{lexer}->next_token;
return $token;
}
sub _unexpected_token ( $self, $got, $expect ) {
die sprintf(
"unexpected character in line %d at position %d. Got '%s', expect: '%s'\n",
$got->line, $got->pos, $got->lexeme, $expect );
}
sub _unexpected_element_count ( $self, $start, $count ) {
die sprintf(
"unexpected element count in row %d starting at line %d at position %d. Got %d, expect: %d \n",
$self->{row} + 1,
$start->line, $start->pos, $count, $self->{element_count}
);
}
sub _unexpected_eof ( $self ) {
die sprintf(
"unexpected end of input at line %d at position %d.\n",
$self->{lexer}{line},
$self->{lexer}{pos}
);
}
1;
|