19 use Data
::Dump
'dump';
25 my($what, $in, $out) = @ARGV;
26 my %info = load_pptok
();
32 my $jump = $jump{lc $what};
35 my $return = $jump->(%info);
36 print $return if defined $return;
43 $filename = 'pptok.dat' unless @_;
52 use autodie qw
'open close';
53 open( my $file, '<', $filename ) or die;
55 while( my $line = <$file> ){
56 $line =~ s/^\s+//; # Remove leading whitespace
57 $line =~ s/\s*(?:\#.*)?$//; # Remove comments and trailing whitespace
61 when( /^\* (.*) /x ){ push @conditions, $1; }
62 when( /^\% (.*) \*$/x ){ push @tokens_cond, $1; }
63 when( /^\% (.*) $/x ){ push @tokens, $1; }
70 @conditions = sort @conditions;
71 @tokens = sort @tokens;
72 @tokens_cond = sort @tokens_cond;
75 # Generate the expanded list including conditionals. The conditionals
76 # are at the beginning, padded to a power of 2, with the inverses
77 # interspersed; this allows a simple mask to pick out the condition.
79 while ((scalar @conditions) & (scalar @conditions)-1) {
80 push(@conditions, undef);
83 $first_uncond = $tokens[0];
86 for my $token ( @tokens_cond ){
87 for my $cond ( @conditions ){
89 push @tokens_cond_p, "${token}${cond}", "${token}n${cond}";
91 push @tokens_cond_p, undef, undef;
95 @tokens = ( @tokens_cond_p, @tokens );
100 conditions
=> [@conditions],
101 first_uncond
=> $first_uncond,
103 tokens_cond
=> [@tokens_cond],
104 #tokens_cond_p => \@tokens_cond_p
107 return %return if wantarray;
115 /* Automatically generated from $info{in} by $0 */
121 my $f = " PP_%-13s = %3d\n";
124 for my $token ( @
{$info{tokens
}} ){
125 if( defined($token) ){
126 #printf OUT " %-16s = %3d,\n", "PP_\U$token\E", $n;
127 $output .= sprintf $f, uc $token, $n;
132 $output .= sprintf $f, 'INVALID', -1;
137 enum pp_conditional {
141 for my $cc ( @
{$info{conditions
}} ) {
143 $output .= sprintf " PPC_IF%-10s = %3d,\n",uc $cc, $n;
148 my $pp_cond = (scalar(@
{$info{conditions
}})-1) << 1;
149 $output .= sprintf <<END, $pp_cond, uc $info{first_uncond};
152 #define PP_COND(x) ((enum pp_conditional)((x) & 0x%x))
153 #define PP_IS_COND(x) ((unsigned int)(x) < PP_%s)
154 #define PP_NEGATIVE(x) ((x) & 1)
158 use List
::MoreUtils
'zip';
160 for my $token( @
{$info{tokens_cond
}} ){
161 my $token = uc $token;
162 $output .= "#define CASE_PP_$token \\\n";
164 my @cond = map {uc $_} grep { defined $_ } '', @
{$info{conditions
}};
165 my @ncond = map {"N$_"} @cond;
167 @cond = zip
@cond, @ncond;
169 @cond = map { " case PP_${token}$_" } @cond;
171 $output .= join ": \\\n", @cond;
191 /* Automatically generated from $info{in} by $0 */
194 #include "compiler.h"
195 #include <inttypes.h>
206 # list of tokens, followed by list of the lengths of the tokens
208 my @tokens = @
{$info{tokens
}};
209 $output .= sprintf "const char * const pp_directives[%d] = {\n", scalar @tokens;
210 for my $d ( @tokens ){
212 $output .= " \"%$d\",\n";
214 $output .= " NULL,\n";
220 $output .= sprintf "const uint8_t pp_directives_len[%d] = {\n", scalar(@tokens);
221 for my $d (@tokens) {
222 $output .= sprintf " %d,\n", defined($d) ?
length($d)+1 : 0;
235 for my $token( @
{$info{tokens
}} ){
236 if (defined($token)) {
237 $tokens{'%'.$token} = $n;
238 if ($token =~ /[\@\[\]\\_]/) {
239 # Fail on characters which look like upper-case letters
240 # to the quick-and-dirty downcasing in the prehash
242 die "$info{in}: invalid character in token: $token";
254 my @hashinfo = gen_perfect_hash
(%tokens);
256 die "$0: no hash found\n";
260 # no longer needed, gen_perfect_hash now runs verify_hash_table
261 # verify_hash_table(\%tokens, \@hashinfo);
263 my ($n, $sv, $g) = @hashinfo;
266 die if ($n & ($n-1));
268 # Put a large value in unused slots. This makes it extremely unlikely
269 # that any combination that involves unused slot will pass the range test.
270 # This speeds up rejection of unrecognized tokens, i.e. identifiers.
272 enum preproc_token pp_token_hash(const char *token)
275 static const int16_t hash1[$n] = {
277 for( my $i = 0; $i < $n; $i++ ){
278 my $h = ${$g}[$i*2+0];
279 $output .= " ".(defined($h) ?
$h : 'UNUSED'). ",\n";
283 $output .= " static const int16_t hash2[$n] = {\n";
284 for( my $i = 0; $i < $n; $i++ ){
285 my $h = ${$g}[$i*2+1];
286 $output .= " ".( defined($h) ?
$h : 'UNUSED'). ",\n";
290 $output .= sprintf <<END, $$sv[0], $$sv[1], $n-1, $n-1, scalar @{$info{tokens}};
293 /* For correct overflow behavior, "ix" should be unsigned of the same
294 width as the hash arrays. */
297 crc = crc64i(UINT64_C(0x%08x%08x), token);
299 k2 = (uint32_t)(crc >> 32);
301 ix = hash1[k1 & 0x%x] + hash2[k2 & 0x%x];
305 if (!pp_directives[ix] || nasm_stricmp(pp_directives[ix], token))
323 # Automatically generated from $info{in} by $0
330 my @tokens = @
{$info{tokens
}};
332 my $len = $_ ?
length $_ : 0;
333 $longest = $len if $len > $longest;
337 for my $token ( @tokens ){
339 my $pad = ' ' x
( $longest - length $token );
340 $output .= " '%$token' $pad=> $n,\n";