| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package CodeGen::Cpppp::CParser; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = '0.005'; # VERSION |
|
4
|
|
|
|
|
|
|
# ABSTRACT: C Parser Utility Library |
|
5
|
|
|
|
|
|
|
|
|
6
|
4
|
|
|
4
|
|
258332
|
use v5.20; |
|
|
4
|
|
|
|
|
17
|
|
|
7
|
4
|
|
|
4
|
|
25
|
use warnings; |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
259
|
|
|
8
|
4
|
|
|
4
|
|
25
|
use Carp; |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
357
|
|
|
9
|
4
|
|
|
4
|
|
763
|
use experimental 'signatures', 'postderef'; |
|
|
4
|
|
|
|
|
5127
|
|
|
|
4
|
|
|
|
|
43
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
sub new { |
|
12
|
0
|
|
|
0
|
0
|
0
|
my $class= shift; |
|
13
|
|
|
|
|
|
|
my $self= bless { |
|
14
|
|
|
|
|
|
|
!(@_ & 1)? @_ |
|
15
|
0
|
0
|
0
|
|
|
0
|
: @_ == 1 && ref $_[0] eq 'HASH'? %{$_[0]} |
|
|
0
|
0
|
|
|
|
0
|
|
|
16
|
|
|
|
|
|
|
: Carp::croak("Expected hashref or even-length list") |
|
17
|
|
|
|
|
|
|
}, $class; |
|
18
|
|
|
|
|
|
|
} |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub tokenize { |
|
22
|
20
|
|
|
20
|
1
|
306471
|
my ($class, undef, $tok_lim)= @_; |
|
23
|
20
|
50
|
|
|
|
72
|
my $textref= ref $_[1] eq 'SCALAR'? $_[1] : \$_[1]; |
|
24
|
20
|
|
|
|
|
79
|
$class->_get_tokens($textref, $tok_lim); |
|
25
|
|
|
|
|
|
|
} |
|
26
|
|
|
|
|
|
|
|
|
27
|
74
|
|
|
74
|
|
189
|
sub CodeGen::Cpppp::CParser::Token::type { $_[0][0] } |
|
28
|
8
|
|
|
8
|
|
21
|
sub CodeGen::Cpppp::CParser::Token::value { $_[0][1] } |
|
29
|
36
|
|
|
36
|
|
80
|
sub CodeGen::Cpppp::CParser::Token::src_pos { $_[0][2] } |
|
30
|
13
|
|
|
13
|
|
26
|
sub CodeGen::Cpppp::CParser::Token::src_len { $_[0][3] } |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
our %keywords= map +($_ => 1), qw( |
|
33
|
|
|
|
|
|
|
auto break case char const continue default do double else enum extern |
|
34
|
|
|
|
|
|
|
float for goto if int long register return short signed sizeof static |
|
35
|
|
|
|
|
|
|
struct switch typedef union unsigned void volatile while |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
inline _Bool _Complex _Imaginary |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
__FUNCTION__ __PRETTY_FUNCTION__ __alignof __alignof__ __asm |
|
40
|
|
|
|
|
|
|
__asm__ __attribute __attribute__ __builtin_offsetof __builtin_va_arg |
|
41
|
|
|
|
|
|
|
__complex __complex__ __const __extension__ __func__ __imag __imag__ |
|
42
|
|
|
|
|
|
|
__inline __inline__ __label__ __null __real __real__ |
|
43
|
|
|
|
|
|
|
__restrict __restrict__ __signed __signed__ __thread __typeof |
|
44
|
|
|
|
|
|
|
__volatile __volatile__ |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
restrict |
|
47
|
|
|
|
|
|
|
); |
|
48
|
|
|
|
|
|
|
our %named_escape= ( |
|
49
|
|
|
|
|
|
|
a => "\a", b => "\b", e => "\e", f => "\f", |
|
50
|
|
|
|
|
|
|
n => "\n", r => "\r", t => "\t", v => "\x0B" |
|
51
|
|
|
|
|
|
|
); |
|
52
|
|
|
|
|
|
|
our %tokens_before_infix_minus= map +($_ => 1), ( |
|
53
|
|
|
|
|
|
|
']', ')', 'integer','real','ident', |
|
54
|
|
|
|
|
|
|
); |
|
55
|
|
|
|
|
|
|
sub _get_tokens { |
|
56
|
20
|
|
|
20
|
|
42
|
my ($class, $textref, $tok_lim)= @_; |
|
57
|
20
|
50
|
|
|
|
122
|
pos($$textref)= 0 unless defined pos($$textref); |
|
58
|
20
|
|
|
|
|
43
|
my @tokens; |
|
59
|
20
|
|
|
|
|
32
|
local our $_type; |
|
60
|
20
|
|
|
|
|
29
|
local our $_value; |
|
61
|
20
|
|
|
|
|
35
|
local our $_error; |
|
62
|
20
|
|
33
|
|
|
223
|
while ((!defined $tok_lim || --$tok_lim >= 0) |
|
|
|
|
66
|
|
|
|
|
|
63
|
|
|
|
|
|
|
&& $$textref =~ m{ |
|
64
|
|
|
|
|
|
|
\G |
|
65
|
|
|
|
|
|
|
(?> \s* ) \K # ignore whitespace |
|
66
|
|
|
|
|
|
|
(?| |
|
67
|
|
|
|
|
|
|
# single-line comment |
|
68
|
|
|
|
|
|
|
// ( [^\r\n]* ) |
|
69
|
4
|
|
|
|
|
23
|
(?{ $_type= 'comment' }) |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# block comment |
|
72
|
|
|
|
|
|
|
| /\* ( (?: [^*]+ | \* (?=[^/]) )* ) ( \*/ | \Z ) |
|
73
|
7
|
50
|
|
|
|
17
|
(?{ $_type= 'comment'; $_error= "Reached end of input looking for '*/'" unless $2 }) |
|
|
7
|
|
|
|
|
64
|
|
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# Preprocessor directive |
|
76
|
|
|
|
|
|
|
| \# \s* ( (?: [^\r\n\\]+ | \\ \r? \n | \\ (?=[^\r\n]) )* ) |
|
77
|
0
|
|
|
|
|
0
|
(?{ $_type= 'directive' }) |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# string literal |
|
80
|
|
|
|
|
|
|
| " (?{ '' }) |
|
81
|
|
|
|
|
|
|
(?| |
|
82
|
6
|
|
|
|
|
35
|
([^"\\]+) (?{ $^R . $1 }) |
|
83
|
1
|
|
|
|
|
42
|
| \\x ([0-9A-Fa-f]+) (?{ $^R . chr(hex $1) }) |
|
84
|
2
|
|
|
|
|
11
|
| \\ ([0-9]{1,3}) (?{ $^R . chr(oct $1) }) |
|
85
|
|
|
|
|
|
|
| \\ \r?\n |
|
86
|
2
|
|
66
|
|
|
35
|
| \\ (.) (?{ $^R . ($named_escape{$1} // $1) }) |
|
87
|
|
|
|
|
|
|
)* |
|
88
|
|
|
|
|
|
|
( " | \Z ) |
|
89
|
6
|
50
|
|
|
|
15
|
(?{ $_type= 'string'; $_value= $^R; $_error= q{Reached end of input looking for '"'} unless $2 }) |
|
|
6
|
|
|
|
|
11
|
|
|
|
6
|
|
|
|
|
56
|
|
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# character constant |
|
92
|
|
|
|
|
|
|
| ' (?| |
|
93
|
|
|
|
|
|
|
([^'\\]) (?{ $1 }) |
|
94
|
0
|
|
|
|
|
0
|
| \\x ([0-9A-Fa-f]+) (?{ chr(hex $1) }) |
|
95
|
0
|
|
|
|
|
0
|
| \\ ([0-9]{1,3}) (?{ chr(oct $1) }) |
|
96
|
0
|
|
0
|
|
|
0
|
| \\ (.) (?{ $named_escape{$1} // $1 }) |
|
97
|
|
|
|
|
|
|
) |
|
98
|
|
|
|
|
|
|
( '? ) |
|
99
|
1
|
0
|
|
|
|
2
|
(?{ $_type= 'char'; $_value= $^R; $_error= q{Unterminated character constant} unless $2 }) |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
6
|
|
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# identifier |
|
102
|
|
|
|
|
|
|
| ( [A-Za-z_] \w* ) |
|
103
|
17
|
100
|
|
|
|
350
|
(?{ $_type= $keywords{$1}? 'keyword' : 'ident' }) |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# real number |
|
106
|
|
|
|
|
|
|
| ( (?: [0-9]+ \. [0-9]* | \. [0-9]+ ) (?: e -? [0-9]+ )? [lLfF]? ) |
|
107
|
0
|
|
|
|
|
0
|
(?{ $_type= 'real' }) |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
| # integer |
|
110
|
|
|
|
|
|
|
(?| |
|
111
|
1
|
|
|
|
|
7
|
0x([A-Fa-f0-9]+) (?{ $_value= hex($1) }) |
|
112
|
0
|
|
|
|
|
0
|
| 0([0-7]+) (?{ $_value= oct($1) }) |
|
113
|
|
|
|
|
|
|
| ([0-9]+) |
|
114
|
|
|
|
|
|
|
) |
|
115
|
|
|
|
|
|
|
[uU]?[lL]* |
|
116
|
14
|
|
|
|
|
67
|
(?{ $_type= 'integer' }) |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
| # punctuation and operators |
|
119
|
|
|
|
|
|
|
( \+\+ | -- | -> | \+=? | -=? | \*=? | /=? | %=? | >>=? | >=? | <<=? | <=? |
|
120
|
|
|
|
|
|
|
| \&\&=? | \&=? | \|\|=? | \|=? | \^=? | ==? | !=? | \? | ~ |
|
121
|
|
|
|
|
|
|
| [\[\]\(\)\{\};,.:] |
|
122
|
|
|
|
|
|
|
) |
|
123
|
38
|
|
|
|
|
186
|
(?{ $_type= $1 }) |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
| # all other characters |
|
126
|
1
|
|
|
|
|
2
|
(.) (?{ $_type= 'unknown'; $_error= q{parse error} }) |
|
|
1
|
|
|
|
|
2
|
|
|
127
|
|
|
|
|
|
|
) |
|
128
|
|
|
|
|
|
|
}xcg |
|
129
|
|
|
|
|
|
|
) { |
|
130
|
88
|
100
|
100
|
|
|
595
|
my @token= ($_type, $_value // $1, $-[0], $+[0] - $-[0], defined $_error? ($_error) : ()); |
|
131
|
|
|
|
|
|
|
# disambiguate negative number from minus operator |
|
132
|
88
|
100
|
66
|
|
|
522
|
if (($_type eq 'integer' || $_type eq 'real') |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
133
|
|
|
|
|
|
|
&& @tokens && $tokens[-1][0] eq '-' |
|
134
|
|
|
|
|
|
|
&& (@tokens == 1 || !$tokens_before_infix_minus{$tokens[-2]->type}) |
|
135
|
|
|
|
|
|
|
) { |
|
136
|
2
|
|
|
|
|
33
|
$token[1]= -$token[1]; |
|
137
|
2
|
|
|
|
|
6
|
$token[2]= $tokens[-1][2]; |
|
138
|
2
|
|
|
|
|
7
|
$token[3]= $+[0] - $tokens[-1][2]; |
|
139
|
2
|
|
|
|
|
5
|
@{$tokens[-1]}= @token; |
|
|
2
|
|
|
|
|
7
|
|
|
140
|
|
|
|
|
|
|
} else { |
|
141
|
86
|
|
|
|
|
196
|
push @tokens, bless \@token, 'CodeGen::Cpppp::CParser::Token'; |
|
142
|
|
|
|
|
|
|
} |
|
143
|
88
|
|
|
|
|
645
|
($_error, $_value)= (undef, undef); |
|
144
|
|
|
|
|
|
|
} |
|
145
|
20
|
|
|
|
|
121
|
return @tokens; |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
1; |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
__END__ |