line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Hardware::Vhdl::Lexer;
|
2
|
|
|
|
|
|
|
|
3
|
3
|
|
|
3
|
|
203871
|
use Class::Std;
|
|
3
|
|
|
|
|
46463
|
|
|
3
|
|
|
|
|
21
|
|
4
|
3
|
|
|
3
|
|
289
|
use Carp;
|
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
207
|
|
5
|
3
|
|
|
3
|
|
3574
|
use Readonly;
|
|
3
|
|
|
|
|
9719
|
|
|
3
|
|
|
|
|
292
|
|
6
|
3
|
|
|
3
|
|
24
|
use strict;
|
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
94
|
|
7
|
3
|
|
|
3
|
|
17
|
use warnings;
|
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
2992
|
|
8
|
|
|
|
|
|
|
#use diagnostics;
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=for To do:
|
11
|
|
|
|
|
|
|
'use charnames' instead of \012 and \015
|
12
|
|
|
|
|
|
|
test get_nhistory and get_linesource
|
13
|
|
|
|
|
|
|
use regexp-generating module for number-matching regexps
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=cut
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
our $VERSION = "1.00";
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# Create storage for object attributes...
|
20
|
|
|
|
|
|
|
my %nhistory :ATTR( :default<1> :get :init_arg );
|
21
|
|
|
|
|
|
|
my %linesource :ATTR( :default :get );
|
22
|
|
|
|
|
|
|
my %line :ATTR( :default );
|
23
|
|
|
|
|
|
|
my %source_func :ATTR;
|
24
|
|
|
|
|
|
|
my %history :ATTR;
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub START {
|
27
|
53
|
|
|
53
|
0
|
77372
|
my ($self, $obj_ID, $arg_ref) = @_;
|
28
|
53
|
|
|
|
|
98
|
my $class = ref($self);
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# check that a linesource was specified
|
31
|
53
|
100
|
|
|
|
239
|
croak "$class constructor requires a linesource to be specified"
|
32
|
|
|
|
|
|
|
if !defined $arg_ref->{linesource};
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
{
|
35
|
52
|
|
|
|
|
56
|
my $sourcetype = ref $arg_ref->{linesource};
|
|
52
|
|
|
|
|
89
|
|
36
|
|
|
|
|
|
|
# store the source of lines as a subroutine reference
|
37
|
|
|
|
|
|
|
$source_func{$obj_ID} =
|
38
|
|
|
|
|
|
|
$sourcetype eq q{} ? croak "${class}->new 'linesource' parameter is not of a valid type (it is not a reference)" :
|
39
|
9
|
|
|
9
|
|
102
|
$sourcetype eq 'GLOB' ? sub { readline( $arg_ref->{linesource} ) } :
|
40
|
|
|
|
|
|
|
$sourcetype eq 'ARRAY' ? _arrayref_to_sub($arg_ref->{linesource}) :
|
41
|
|
|
|
|
|
|
$sourcetype eq 'SCALAR' ? _scalarref_to_sub($arg_ref->{linesource}) :
|
42
|
|
|
|
|
|
|
$sourcetype eq 'CODE' ? $arg_ref->{linesource} :
|
43
|
|
|
|
|
|
|
#~ $sourcetype ne 'REF' && |
44
|
|
|
|
|
|
|
eval "$sourcetype->can('get_next_line')"
|
45
|
98
|
|
|
98
|
|
334
|
? sub { $arg_ref->{linesource}->get_next_line } :
|
46
|
52
|
100
|
|
|
|
2544
|
croak "${class}->new 'linesource' parameter is not of a valid type (type is '$sourcetype')";
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
}
|
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# set up initial history values
|
51
|
48
|
|
|
|
|
791
|
for my $i ( 1 .. $self->get_nhistory ) { $history{$obj_ID}->[ $i - 1 ] = q{} }
|
|
57
|
|
|
|
|
378
|
|
52
|
|
|
|
|
|
|
#@{ $history{$obj_ID} } = q{} x $self->get_nhistory;
|
53
|
|
|
|
|
|
|
|
54
|
48
|
|
|
|
|
150
|
pos($line{$obj_ID}) = 0;
|
55
|
|
|
|
|
|
|
|
56
|
48
|
|
|
|
|
164
|
return $self;
|
57
|
|
|
|
|
|
|
}
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub _arrayref_to_sub {
|
60
|
|
|
|
|
|
|
# given an array ref, return a ref to a sub which returns the lines in sequence and then returns undef
|
61
|
1
|
|
|
1
|
|
2
|
my $array_ref = shift;
|
62
|
1
|
|
|
|
|
2
|
my $i = 0;
|
63
|
|
|
|
|
|
|
return sub {
|
64
|
18
|
|
|
18
|
|
40
|
return $array_ref->[ $i++ ];
|
65
|
1
|
|
|
|
|
7
|
};
|
66
|
|
|
|
|
|
|
}
|
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
sub _scalarref_to_sub {
|
69
|
|
|
|
|
|
|
# given a scalar ref, return a ref to a sub which returns the line and then returns undef
|
70
|
1
|
|
|
1
|
|
2
|
my $scalar_ref = shift;
|
71
|
1
|
|
|
|
|
3
|
my $i = 0;
|
72
|
|
|
|
|
|
|
return sub {
|
73
|
2
|
100
|
|
2
|
|
9
|
return $i++ == 0 ? ${ $scalar_ref } : undef;
|
|
1
|
|
|
|
|
4
|
|
74
|
1
|
|
|
|
|
6
|
};
|
75
|
|
|
|
|
|
|
}
|
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# after use charnames qw( :full );
|
78
|
|
|
|
|
|
|
# \N{CR} is character 13 = 015
|
79
|
|
|
|
|
|
|
# \N{LF} is character 10 = 012
|
80
|
|
|
|
|
|
|
#my $NEW_LINE = qr/ \N{CR}\N{LF}? | \N{LF}\N{CR}? /xms;
|
81
|
|
|
|
|
|
|
my Readonly $NEW_LINE = qr/ \015\012? | \012\015? /xms;
|
82
|
|
|
|
|
|
|
my Readonly $WHITESPACE = qr/ [^\S\012\015]+ /xms;
|
83
|
|
|
|
|
|
|
my Readonly $COMMENT = qr/ -- [^\015\012]* /xms;
|
84
|
|
|
|
|
|
|
my Readonly $BIT_VECTOR_LITERAL = qr/ [BOX] ".+?" /xms;
|
85
|
|
|
|
|
|
|
my Readonly $BASED_NUMBER = qr/
|
86
|
|
|
|
|
|
|
(?: [23456789] | 1[0123456] ) # the base (2-16)
|
87
|
|
|
|
|
|
|
\# [\d_A-F]+ \# # the number
|
88
|
|
|
|
|
|
|
/xmsi;
|
89
|
|
|
|
|
|
|
my Readonly $BASE10_REAL = qr/ -? \d [\d_]* (?: \. \d*)? (?: E -? \d+)? /xmsi;
|
90
|
|
|
|
|
|
|
my Readonly $IDENTIFIER = qr/ (?: \\ [^\\]+ \\) | (?: \w+ ) /xms;
|
91
|
|
|
|
|
|
|
my Readonly $PUNCTUATION = qr{
|
92
|
|
|
|
|
|
|
[:<>/]= | => | <> | \*\* # 2-character punctuations
|
93
|
|
|
|
|
|
|
| [ \.\,\+\-\*\=\:\;\&\'\(\)\<\>\|\/ ]
|
94
|
|
|
|
|
|
|
}xms;
|
95
|
|
|
|
|
|
|
my Readonly $DBL_QUOTED = qr/
|
96
|
|
|
|
|
|
|
" # opening quote
|
97
|
|
|
|
|
|
|
.*? # contents of the quotes
|
98
|
|
|
|
|
|
|
(?
|
99
|
|
|
|
|
|
|
(?:\\\\)* # an even number of backslashes
|
100
|
|
|
|
|
|
|
" # closing quote
|
101
|
|
|
|
|
|
|
/xms;
|
102
|
|
|
|
|
|
|
my Readonly $CHAR_LITERAL = qr/
|
103
|
|
|
|
|
|
|
'.' # a character in single-quotes
|
104
|
|
|
|
|
|
|
(?= # followed by...
|
105
|
|
|
|
|
|
|
(?: .'.' )* # any number of following character literals
|
106
|
|
|
|
|
|
|
(?! .' ) # without leaving us with an unmatched single-quote
|
107
|
|
|
|
|
|
|
.* # and anything that follows
|
108
|
|
|
|
|
|
|
)
|
109
|
|
|
|
|
|
|
/xms;
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub _as_str :STRINGIFY {
|
112
|
0
|
|
|
0
|
|
0
|
my $self = shift;
|
113
|
0
|
|
|
|
|
0
|
return scalar $self->get_next_token();
|
114
|
3
|
|
|
3
|
|
21
|
}
|
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
28
|
|
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub get_next_token {
|
117
|
392
|
|
|
392
|
1
|
4098
|
my $self = shift;
|
118
|
392
|
|
|
|
|
673
|
my $obj_ID = ident $self;
|
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# get another line from the line-source if needed
|
121
|
392
|
100
|
66
|
|
|
1911
|
if ( defined $line{$obj_ID} && pos($line{$obj_ID}) >= length $line{$obj_ID} ) {
|
122
|
143
|
|
|
|
|
146
|
$line{$obj_ID} = &{ $source_func{$obj_ID} };
|
|
143
|
|
|
|
|
241
|
|
123
|
143
|
100
|
|
|
|
765
|
pos($line{$obj_ID}) = 0 if defined $line{$obj_ID};
|
124
|
|
|
|
|
|
|
}
|
125
|
|
|
|
|
|
|
# an undef line means the end of the VHDL source - no more tokens
|
126
|
392
|
100
|
|
|
|
871
|
return if !defined $line{$obj_ID};
|
127
|
|
|
|
|
|
|
|
128
|
347
|
50
|
|
|
|
7176
|
my ($token, $match) =
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
129
|
|
|
|
|
|
|
$line{$obj_ID} =~ m/\G ($NEW_LINE) /gcxms ? ($1, 'wn') : # newline
|
130
|
|
|
|
|
|
|
$line{$obj_ID} =~ m/\G ($WHITESPACE) /gcxms ? ($1, 'ws') : # whitespace
|
131
|
|
|
|
|
|
|
substr( $line{$obj_ID}, pos($line{$obj_ID}), 1 ) eq q{"}
|
132
|
|
|
|
|
|
|
? ($self->_dquoted_string(), 'cs') : # string literal
|
133
|
|
|
|
|
|
|
$line{$obj_ID} =~ m/\G ($COMMENT) /gcxms ? ($1, 'r' ) : # comment
|
134
|
|
|
|
|
|
|
$line{$obj_ID} =~ m/\G ($CHAR_LITERAL) /gcxms ? ($1, 'cc') : # single-character literal
|
135
|
|
|
|
|
|
|
$line{$obj_ID} =~ m/\G ($BIT_VECTOR_LITERAL) /gcxms ? ($1, 'cb') : # bit_vector literal
|
136
|
|
|
|
|
|
|
$line{$obj_ID} =~ m/\G ($BASED_NUMBER) /gcxms ? ($1, 'cn') : # specified-base integer numeric literal
|
137
|
|
|
|
|
|
|
$line{$obj_ID} =~ m/\G ($BASE10_REAL) /gcxms ? ($1, 'cn') : # base-10 numeric literal
|
138
|
|
|
|
|
|
|
$line{$obj_ID} =~ m/\G ($IDENTIFIER) /gcxms ? ($1, 'ci') : # extended identifier or keyword
|
139
|
|
|
|
|
|
|
$line{$obj_ID} =~ m/\G ($PUNCTUATION) /gcxms ? ($1, 'cp') : # punctuation
|
140
|
|
|
|
|
|
|
$line{$obj_ID} =~ m/\G (.) /gcxms ? ($1, 'cu') : # unexpected character
|
141
|
|
|
|
|
|
|
croak "Internal error (token failed to match anything): "
|
142
|
|
|
|
|
|
|
. "Please file a bug report, showing what input caused this error\n";
|
143
|
|
|
|
|
|
|
|
144
|
347
|
100
|
|
|
|
753
|
if ( substr( $match, 0, 1 ) eq 'c' ) {
|
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# not whitespace or comment, so add it to the code history
|
147
|
252
|
|
|
|
|
235
|
push @{ $history{$obj_ID} }, $token;
|
|
252
|
|
|
|
|
499
|
|
148
|
252
|
|
|
|
|
291
|
while ( @{ $history{$obj_ID} } > $self->get_nhistory ) {
|
|
504
|
|
|
|
|
1327
|
|
149
|
252
|
|
|
|
|
1086
|
shift @{ $history{$obj_ID} };
|
|
252
|
|
|
|
|
458
|
|
150
|
|
|
|
|
|
|
}
|
151
|
|
|
|
|
|
|
}
|
152
|
|
|
|
|
|
|
|
153
|
347
|
100
|
|
|
|
2575
|
return wantarray ? ( $token, $match ) : $token;
|
154
|
|
|
|
|
|
|
}
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
sub _dquoted_string {
|
157
|
14
|
|
|
14
|
|
20
|
my $self = shift;
|
158
|
14
|
|
|
|
|
27
|
my $obj_ID = ident $self;
|
159
|
|
|
|
|
|
|
# this method should only be called when we already know we have an open-quote at the match-start point of $line{$obj_ID}
|
160
|
14
|
|
|
|
|
16
|
while (1) {
|
161
|
14
|
100
|
|
|
|
153
|
if ( $line{$obj_ID} =~ /\G ($DBL_QUOTED) /gcxms ) {
|
162
|
12
|
|
|
|
|
46
|
return $1;
|
163
|
|
|
|
|
|
|
}
|
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# can't match a closing quote - get another line from the source
|
166
|
2
|
|
|
|
|
3
|
my $nextline = &{ $source_func{$obj_ID} };
|
|
2
|
|
|
|
|
6
|
|
167
|
2
|
50
|
|
|
|
12
|
if ( !defined $nextline ) {
|
168
|
|
|
|
|
|
|
# reached EOF without finding closing quote: we're done
|
169
|
2
|
|
|
|
|
3
|
my $start_pos = pos $line{$obj_ID};
|
170
|
2
|
|
|
|
|
5
|
pos $line{$obj_ID} = length $line{$obj_ID};
|
171
|
2
|
|
|
|
|
8
|
return substr $line{$obj_ID}, $start_pos;
|
172
|
|
|
|
|
|
|
}
|
173
|
0
|
|
|
|
|
0
|
$line{$obj_ID} .= $nextline;
|
174
|
|
|
|
|
|
|
}
|
175
|
|
|
|
|
|
|
}
|
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub history {
|
178
|
46
|
|
|
46
|
1
|
15885
|
my $self = shift;
|
179
|
46
|
|
|
|
|
55
|
my $age = shift;
|
180
|
46
|
|
|
|
|
88
|
my $obj_ID = ident $self;
|
181
|
|
|
|
|
|
|
|
182
|
46
|
|
|
|
|
1282
|
croak "more (" . ( $age + 1 ),
|
183
|
|
|
|
|
|
|
") history requested than has been stored ("
|
184
|
|
|
|
|
|
|
. ( $nhistory{$obj_ID} ) . ")"
|
185
|
46
|
100
|
|
|
|
47
|
if $age >= @{ $history{$obj_ID} };
|
186
|
34
|
|
|
|
|
163
|
return $history{$obj_ID}->[ -1 - $age ];
|
187
|
|
|
|
|
|
|
}
|
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
1; # End of Hardware::Vhdl::Lexer
|
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
__END__
|