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) {
37 push @entries, $_ if $wanted eq 'A';
38 } elsif ($_->[0] =~ /E/) {
39 push @entries, $_ if $wanted eq 'E';
41 push @entries, $_ if $wanted eq '';
45 @entries = sort {$a->[2] cmp $b->[2]} @entries;
47 foreach (sort grep {length $_} keys %$level) {
48 my @conditional = add_level($level->{$_}, $indent . ' ', $wanted);
50 ["#${indent}if $_"], @conditional, ["#${indent}endif"]
57 my $prefix = shift || '';
58 open IN, '<', $prefix . 'embed.fnc' or die $!;
78 @args = split /\s*\|\s*/, $_;
81 if ($args[0] !~ /^#\s*(?:if|ifdef|ifndef|else|endif)/) {
82 die "Illegal line $. '$args[0]' in embed.fnc";
84 $macro_depth++ if $args[0] =~/^#\s*if(n?def)?\b/;
85 $macro_depth-- if $args[0] =~/^#\s*endif\b/;
86 die "More #endif than #if in embed.fnc:$." if $macro_depth < 0;
89 die "Illegal line (less than 3 fields) in embed.fnc:$.: $_"
92 # only check for duplicates outside of #if's - otherwise
93 # they may be alternate definitions of the same function
94 if ($macro_depth == 0) {
95 die "Duplicate function name: '$name' in embed.fnc:$."
96 if exists $seen{$name};
103 die "More #if than #endif by the end of embed.fnc" if $macro_depth != 0;
105 close IN or die "Problem reading embed.fnc: $!";
107 open IN, '<', $prefix . 'regen/opcodes' or die $!;
115 my $check = (split /\t+/, $_)[2];
116 next if $syms{$check}++;
118 # These are all indirectly referenced by globals.c.
119 push @embed, ['pR', 'OP *', $check, 'NN OP *o'];
122 close IN or die "Problem reading regen/opcodes: $!";
124 # Cluster entries in embed.fnc that have the same #ifdef guards.
125 # Also, split out at the top level the three classes of functions.
126 # Output structure is actually the same as input structure - an
127 # (ordered) list of array references, where the elements in the
128 # reference determine what it is - a reference to a 1-element array is a
129 # pre-processor directive, a reference to 2+ element array is a function.
131 my $current = current_group();
138 $_->[0] =~ s/^#\s+/#/;
140 $_->[0] =~ s/^#ifdef\s+(\S+)/#if defined($1)/;
141 $_->[0] =~ s/^#ifndef\s+(\S+)/#if !defined($1)/;
142 if ($_->[0] =~ /^#if\s*(.*)/) {
144 } elsif ($_->[0] =~ /^#else\s*$/) {
145 die "Unmatched #else in embed.fnc" unless @state;
146 $state[-1] = "!($state[-1])";
147 } elsif ($_->[0] =~ m!^#endif\s*(?:/\*.*\*/)?$!) {
148 die "Unmatched #endif in embed.fnc" unless @state;
151 die "Unhandled pre-processor directive '$_->[0]' in embed.fnc";
153 $current = current_group();
156 return ([add_level(\%groups, '')],
157 [add_level(\%groups, '', '')], # core
158 [add_level(\%groups, '', 'E')], # ext
159 [add_level(\%groups, '', 'A')]); # api