This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
inline.h: Move some fcn '{' to column 1
[perl5.git] / regen / embed_lib.pl
CommitLineData
cdde42af
NC
1#!/usr/bin/perl -w
2use strict;
3
4# read embed.fnc and regen/opcodes, needed by regen/embed.pl and makedef.pl
5
6require 5.004; # keep this compatible, an old perl is all we may have before
7 # we build the new one
8
9# Records the current pre-processor state:
10my @state;
11# Nested structure to group functions by the pre-processor conditions that
12# control when they are compiled:
13my %groups;
14
15sub current_group {
16 my $group = \%groups;
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) {
21 $group->{$_} ||= {};
22 $group = $group->{$_};
23 }
24 return $group->{''} ||= [];
25}
26
27sub add_level {
28 my ($level, $indent, $wanted) = @_;
29 my $funcs = $level->{''};
30 my @entries;
31 if ($funcs) {
32 if (!defined $wanted) {
33 @entries = @$funcs;
34 } else {
35 foreach (@$funcs) {
ff5af78d
KW
36 if ($_->[0] =~ /[AC]/) { # 'C' is like 'A' for our purposes
37 # here
cdde42af
NC
38 push @entries, $_ if $wanted eq 'A';
39 } elsif ($_->[0] =~ /E/) {
40 push @entries, $_ if $wanted eq 'E';
41 } else {
42 push @entries, $_ if $wanted eq '';
43 }
44 }
45 }
46 @entries = sort {$a->[2] cmp $b->[2]} @entries;
47 }
48 foreach (sort grep {length $_} keys %$level) {
49 my @conditional = add_level($level->{$_}, $indent . ' ', $wanted);
50 push @entries,
51 ["#${indent}if $_"], @conditional, ["#${indent}endif"]
52 if @conditional;
53 }
54 return @entries;
55}
56
57sub setup_embed {
58 my $prefix = shift || '';
1ae6ead9 59 open IN, '<', $prefix . 'embed.fnc' or die $!;
cdde42af
NC
60
61 my @embed;
c0b58684
DM
62 my %seen;
63 my $macro_depth = 0;
cdde42af
NC
64
65 while (<IN>) {
66 chomp;
67 next if /^:/;
68 next if /^$/;
69 while (s|\\$||) {
70 $_ .= <IN>;
71 chomp;
72 }
73 s/\s+$//;
74 my @args;
75 if (/^\s*(#|$)/) {
76 @args = $_;
77 }
78 else {
79 @args = split /\s*\|\s*/, $_;
80 }
c0b58684
DM
81 if (@args == 1) {
82 if ($args[0] !~ /^#\s*(?:if|ifdef|ifndef|else|endif)/) {
83 die "Illegal line $. '$args[0]' in embed.fnc";
84 }
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;
cdde42af 88 }
c0b58684
DM
89 else {
90 die "Illegal line (less than 3 fields) in embed.fnc:$.: $_"
91 unless @args >= 3;
92 my $name = $args[2];
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};
98 }
99 $seen{$name} = 1;
100 }
101
cdde42af
NC
102 push @embed, \@args;
103 }
c0b58684 104 die "More #if than #endif by the end of embed.fnc" if $macro_depth != 0;
cdde42af
NC
105
106 close IN or die "Problem reading embed.fnc: $!";
107
1ae6ead9 108 open IN, '<', $prefix . 'regen/opcodes' or die $!;
cdde42af
NC
109 {
110 my %syms;
111
112 while (<IN>) {
113 chomp;
114 next unless $_;
115 next if /^#/;
116 my $check = (split /\t+/, $_)[2];
117 next if $syms{$check}++;
118
119 # These are all indirectly referenced by globals.c.
120 push @embed, ['pR', 'OP *', $check, 'NN OP *o'];
121 }
122 }
123 close IN or die "Problem reading regen/opcodes: $!";
124
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.
131
132 my $current = current_group();
133
134 foreach (@embed) {
135 if (@$_ > 1) {
136 push @$current, $_;
137 next;
138 }
139 $_->[0] =~ s/^#\s+/#/;
140 $_->[0] =~ /^\S*/;
141 $_->[0] =~ s/^#ifdef\s+(\S+)/#if defined($1)/;
142 $_->[0] =~ s/^#ifndef\s+(\S+)/#if !defined($1)/;
143 if ($_->[0] =~ /^#if\s*(.*)/) {
144 push @state, $1;
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;
150 pop @state;
151 } else {
152 die "Unhandled pre-processor directive '$_->[0]' in embed.fnc";
153 }
154 $current = current_group();
155 }
156
157 return ([add_level(\%groups, '')],
158 [add_level(\%groups, '', '')], # core
159 [add_level(\%groups, '', 'E')], # ext
160 [add_level(\%groups, '', 'A')]); # api
161}
162
1631;