4 # read embed.fnc and regen/opcodes, needed by regen/embed.pl and makedef.pl
6 require 5.004; # keep this compatible, an old perl is all we may have before
9 # Records the current pre-processor state:
11 # Nested structure to group functions by the pre-processor conditions that
12 # control when they are compiled:
17 # Nested #if blocks are effectively &&ed together
18 # For embed.fnc, ordering within the && isn't relevant, so we can
19 # sort them to try to group more functions together.
20 foreach (sort @state) {
22 $group = $group->{$_};
24 return $group->{''} ||= [];
28 my ($level, $indent, $wanted) = @_;
29 my $funcs = $level->{''};
32 if (!defined $wanted) {
36 if ($_->[0] =~ /[AC]/) { # 'C' is like 'A' for our purposes
38 push @entries, $_ if $wanted eq 'A';
39 } elsif ($_->[0] =~ /E/) {
40 push @entries, $_ if $wanted eq 'E';
42 push @entries, $_ if $wanted eq '';
46 @entries = sort {$a->[2] cmp $b->[2]} @entries;
48 foreach (sort grep {length $_} keys %$level) {
49 my @conditional = add_level($level->{$_}, $indent . ' ', $wanted);
51 ["#${indent}if $_"], @conditional, ["#${indent}endif"]
58 my $prefix = shift || '';
59 open IN, '<', $prefix . 'embed.fnc' or die $!;
79 @args = split /\s*\|\s*/, $_;
82 if ($args[0] !~ /^#\s*(?:if|ifdef|ifndef|else|endif)/) {
83 die "Illegal line $. '$args[0]' in embed.fnc";
85 $macro_depth++ if $args[0] =~/^#\s*if(n?def)?\b/;
86 $macro_depth-- if $args[0] =~/^#\s*endif\b/;
87 die "More #endif than #if in embed.fnc:$." if $macro_depth < 0;
90 die "Illegal line (less than 3 fields) in embed.fnc:$.: $_"
93 # only check for duplicates outside of #if's - otherwise
94 # they may be alternate definitions of the same function
95 if ($macro_depth == 0) {
96 die "Duplicate function name: '$name' in embed.fnc:$."
97 if exists $seen{$name};
104 die "More #if than #endif by the end of embed.fnc" if $macro_depth != 0;
106 close IN or die "Problem reading embed.fnc: $!";
108 open IN, '<', $prefix . 'regen/opcodes' or die $!;
116 my $check = (split /\t+/, $_)[2];
117 next if $syms{$check}++;
119 # These are all indirectly referenced by globals.c.
120 push @embed, ['pR', 'OP *', $check, 'NN OP *o'];
123 close IN or die "Problem reading regen/opcodes: $!";
125 # Cluster entries in embed.fnc that have the same #ifdef guards.
126 # Also, split out at the top level the three classes of functions.
127 # Output structure is actually the same as input structure - an
128 # (ordered) list of array references, where the elements in the
129 # reference determine what it is - a reference to a 1-element array is a
130 # pre-processor directive, a reference to 2+ element array is a function.
132 my $current = current_group();
139 $_->[0] =~ s/^#\s+/#/;
141 $_->[0] =~ s/^#ifdef\s+(\S+)/#if defined($1)/;
142 $_->[0] =~ s/^#ifndef\s+(\S+)/#if !defined($1)/;
143 if ($_->[0] =~ /^#if\s*(.*)/) {
145 } elsif ($_->[0] =~ /^#else\s*$/) {
146 die "Unmatched #else in embed.fnc" unless @state;
147 $state[-1] = "!($state[-1])";
148 } elsif ($_->[0] =~ m!^#endif\s*(?:/\*.*\*/)?$!) {
149 die "Unmatched #endif in embed.fnc" unless @state;
152 die "Unhandled pre-processor directive '$_->[0]' in embed.fnc";
154 $current = current_group();
157 return ([add_level(\%groups, '')],
158 [add_level(\%groups, '', '')], # core
159 [add_level(\%groups, '', 'E')], # ext
160 [add_level(\%groups, '', 'A')]); # api