4 # read embed.fnc and regen/opcodes, needed by regen/embed.pl, makedef.pl,
5 # autodoc.pl and t/porting/diag.t
7 require 5.004; # keep this compatible, an old perl is all we may have before
10 # Records the current pre-processor state:
12 # Nested structure to group functions by the pre-processor conditions that
13 # control when they are compiled:
18 # Nested #if blocks are effectively &&ed together
19 # For embed.fnc, ordering within the && isn't relevant, so we can
20 # sort them to try to group more functions together.
21 foreach (sort @state) {
23 $group = $group->{$_};
25 return $group->{''} ||= [];
29 my ($level, $indent, $wanted) = @_;
30 my $funcs = $level->{''};
33 if (!defined $wanted) {
37 if ($_->[0] =~ /[AC]/) { # 'C' is like 'A' for our purposes
39 push @entries, $_ if $wanted eq 'A';
40 } elsif ($_->[0] =~ /E/) {
41 push @entries, $_ if $wanted eq 'E';
43 push @entries, $_ if $wanted eq '';
47 @entries = sort {$a->[2] cmp $b->[2]} @entries;
49 foreach (sort grep {length $_} keys %$level) {
50 my @conditional = add_level($level->{$_}, $indent . ' ', $wanted);
52 ["#${indent}if $_"], @conditional, ["#${indent}endif"]
59 my $prefix = shift || '';
60 open IN, '<', $prefix . 'embed.fnc' or die $!;
80 @args = split /\s*\|\s*/, $_;
83 if ($args[0] !~ /^#\s*(?:if|ifdef|ifndef|else|endif)/) {
84 die "Illegal line $. '$args[0]' in embed.fnc";
86 $macro_depth++ if $args[0] =~/^#\s*if(n?def)?\b/;
87 $macro_depth-- if $args[0] =~/^#\s*endif\b/;
88 die "More #endif than #if in embed.fnc:$." if $macro_depth < 0;
91 die "Illegal line (less than 3 fields) in embed.fnc:$.: $_"
94 # only check for duplicates outside of #if's - otherwise
95 # they may be alternate definitions of the same function
96 if ($macro_depth == 0) {
97 die "Duplicate function name: '$name' in embed.fnc:$."
98 if exists $seen{$name};
105 die "More #if than #endif by the end of embed.fnc" if $macro_depth != 0;
107 close IN or die "Problem reading embed.fnc: $!";
109 open IN, '<', $prefix . 'regen/opcodes' or die $!;
117 my $check = (split /\t+/, $_)[2];
118 next if $syms{$check}++;
120 # These are all indirectly referenced by globals.c.
121 push @embed, ['pR', 'OP *', $check, 'NN OP *o'];
124 close IN or die "Problem reading regen/opcodes: $!";
126 # Cluster entries in embed.fnc that have the same #ifdef guards.
127 # Also, split out at the top level the three classes of functions.
128 # Output structure is actually the same as input structure - an
129 # (ordered) list of array references, where the elements in the
130 # reference determine what it is - a reference to a 1-element array is a
131 # pre-processor directive, a reference to 2+ element array is a function.
133 my $current = current_group();
140 $_->[0] =~ s/^#\s+/#/;
142 $_->[0] =~ s/^#ifdef\s+(\S+)/#if defined($1)/;
143 $_->[0] =~ s/^#ifndef\s+(\S+)/#if !defined($1)/;
144 if ($_->[0] =~ /^#if\s*(.*)/) {
146 } elsif ($_->[0] =~ /^#else\s*$/) {
147 die "Unmatched #else in embed.fnc" unless @state;
148 $state[-1] = "!($state[-1])";
149 } elsif ($_->[0] =~ m!^#endif\s*(?:/\*.*\*/)?$!) {
150 die "Unmatched #endif in embed.fnc" unless @state;
153 die "Unhandled pre-processor directive '$_->[0]' in embed.fnc";
155 $current = current_group();
158 return ([add_level(\%groups, '')],
159 [add_level(\%groups, '', '')], # core
160 [add_level(\%groups, '', 'E')], # ext
161 [add_level(\%groups, '', 'A')]); # api