| #!/usr/bin/perl |
| ## -------------------------------------------------------------------------- |
| ## |
| ## Copyright 1996-2009 The NASM Authors - All Rights Reserved |
| ## See the file AUTHORS included with the NASM distribution for |
| ## the specific copyright holders. |
| ## |
| ## Redistribution and use in source and binary forms, with or without |
| ## modification, are permitted provided that the following |
| ## conditions are met: |
| ## |
| ## * Redistributions of source code must retain the above copyright |
| ## notice, this list of conditions and the following disclaimer. |
| ## * Redistributions in binary form must reproduce the above |
| ## copyright notice, this list of conditions and the following |
| ## disclaimer in the documentation and/or other materials provided |
| ## with the distribution. |
| ## |
| ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
| ## CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
| ## INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| ## DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| ## NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| ## LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| ## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| ## OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
| ## EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| ## |
| ## -------------------------------------------------------------------------- |
| |
| # |
| # macros.pl produce macros.c from standard.mac |
| # |
| |
| require 'phash.ph'; |
| require 'asm/pptok.ph'; |
| |
| use bytes; |
| |
| my $fname; |
| my $line = 0; |
| my $index = 0; |
| my $tasm_count = 0; |
| my @pname; |
| |
| # Default names for various bytes |
| for (my $o = 0; $o < 256; $o++) { |
| my $c = chr($o); |
| if ($o < 32 || $o > 126) { |
| $pname[$o] = sprintf("%d", $o); |
| } elsif ($c =~ /^[\'\"\\]$/) { |
| $pname[$o] = "\'\\".$c."\'"; |
| } else { |
| $pname[$o] = "\'".$c."\'"; |
| } |
| } |
| |
| # |
| # Print out a string as a character array |
| # |
| sub charcify(@) { |
| my $l = ''; |
| my ($c, $o); |
| my $space = 1; |
| my $quote = 0; |
| |
| foreach $o (unpack("C*", join('',@_))) { |
| $c = pack("C", $o); |
| if ($quote) { |
| if ($o == $quote) { |
| $quote = 0; |
| } |
| } elsif ($c =~ /^[\'\"\`]$/) { |
| $quote = $o; |
| } else { |
| if ($c eq ' ') { |
| next if ($space); |
| $o = 32; |
| $c = ' '; |
| $space = 1; |
| } elsif ($o < 32 || $o > 126) { |
| $space = 1; # Implicit space after compacted directive |
| } else { |
| $space = 0; |
| } |
| } |
| $l .= $pname[$o]; |
| $l .= ','; |
| } |
| return $l; |
| } |
| |
| |
| # |
| # Generate macros.c |
| # |
| open(OUT, '>', 'macros/macros.c') or die "unable to open macros.c\n"; |
| |
| print OUT "/*\n"; |
| print OUT " * Do not edit - this file auto-generated by macros.pl from:\n"; |
| print OUT " * ", join("\n * ", @ARGV), "\n"; |
| print OUT " */\n"; |
| print OUT "\n"; |
| print OUT "#include \"tables.h\"\n"; |
| print OUT "#include \"nasmlib.h\"\n"; |
| print OUT "#include \"hashtbl.h\"\n"; |
| print OUT "#include \"outform.h\"\n"; |
| print OUT "\n"; |
| |
| my $name = undef; |
| my $npkg = 0; |
| my @pkg_list = (); |
| my %pkg_number = (); |
| my $pkg; |
| my @out_list = (); |
| my @std_list = (); |
| my $outfmt; |
| my $lastname; |
| my $z; |
| |
| my @pptok_list = sort { $pptok_hash{$a} <=> $pptok_hash{$b} } keys %pptok_hash; |
| my %pnum; |
| |
| foreach my $pt (@pptok_list) { |
| my $n = $pptok_hash{$pt}; |
| if ($pt !~ /[A-Z]/ && $n < 256-96) { |
| $n = ($n+128) & 255; |
| (my $et = $pt) =~ s/^\%/p_/; |
| printf OUT "#define %-24s %3d\n", $et, $n; |
| $pnum{$pt} = $n; |
| $pname[$n] = $et; |
| } |
| } |
| printf OUT "#define %-24s %3d\n\n", 'EOL', 127; |
| |
| foreach $args ( @ARGV ) { |
| my @file_list = glob ( $args ); |
| foreach $fname ( @file_list ) { |
| open(INPUT,'<', $fname) or die "$0: $fname: $!\n"; |
| while (<INPUT>) { |
| $line++; |
| chomp; |
| while (/^(.*)\\$/) { |
| $_ = $1; |
| $_ .= <INPUT>; |
| chomp; |
| $line++; |
| } |
| s/^\s*(([^\'\"\;]|\"[^\"]*\"|\'[^\']*\')*?)\s*(\;.*)?$/$1/; |
| s/\s+/ /g; |
| next if ($_ eq ''); |
| |
| if (m/^OUT:\s*(\S.*)$/) { |
| undef $pkg; |
| my @out_alias = split(/\s+/, $1); |
| if (defined($name)) { |
| printf OUT " /* %4d */ EOL\n", $index++; |
| print OUT "};\n#endif\n"; |
| undef $name; |
| } |
| $index = 0; |
| print OUT "\n"; |
| my $pfx = '#if'; |
| foreach my $al (@out_alias) { |
| print OUT $pfx, " defined(OF_\U${al}\E)"; |
| $pfx = ' ||'; |
| } |
| $name = $out_alias[0] . '_stdmac'; |
| print OUT "\nconst unsigned char ${name}[] = {\n"; |
| print OUT " /* From $fname */\n"; |
| $lastname = $fname; |
| } elsif (m/^STD:\s*(\S+)$/) { |
| undef $pkg; |
| my $std = $1; |
| if (defined($name)) { |
| printf OUT " /* %4d */ EOL\n", $index++; |
| print OUT "};\n#endif\n"; |
| undef $name; |
| } |
| $index = 0; |
| print OUT "\n#if 1"; |
| $name = 'nasm_stdmac_' . $std; |
| print OUT "\nconst unsigned char ${name}[] = {\n"; |
| print OUT " /* From $fname */\n"; |
| $lastname = $fname; |
| } elsif (m/^USE:\s*(\S+)$/) { |
| $pkg = $1; |
| if (defined($pkg_number{$pkg})) { |
| die "$0: $fname: duplicate package: $pkg\n"; |
| } |
| if (defined($name)) { |
| printf OUT " /* %4d */ EOL\n", $index++; |
| print OUT "};\n#endif\n"; |
| undef $name; |
| } |
| $index = 0; |
| print OUT "\n#if 1"; |
| $name = 'nasm_usemac_' . $pkg; |
| print OUT "\nstatic const unsigned char ${name}[] = {\n"; |
| print OUT " /* From $fname */\n"; |
| $lastname = $fname; |
| push(@pkg_list, $pkg); |
| $pkg_number{$pkg} = $npkg++; |
| $z = pack("C", $pnum{'%define'})."__?USE_\U$pkg\E?__"; |
| printf OUT " /* %4d */ %sEOL,\n", $index, charcify($z); |
| $z = pack("C", $pnum{'%defalias'})."__USE_\U$pkg\E__ __?USE\U$pkg\E?__"; |
| printf OUT " /* %4d */ %sEOL,\n", $index, charcify($z); |
| $index += length($z)+1; |
| } else { |
| my($s1, $s2, $pd, $ws); |
| |
| if (!defined($name)) { |
| die "$0: $fname: macro declarations outside a known block\n"; |
| } |
| |
| $s1 = $_; |
| $s2 = ''; |
| while ($s1 =~ /(\%[a-zA-Z_][a-zA-Z0-9_]*)((\s+)(.*)|)$/) { |
| $s2 .= "$'"; |
| $pd = $1; |
| $ws = $3; |
| $s1 = $4; |
| if (defined($pnum{$pd})) { |
| $s2 .= pack("C", $pnum{$pd}); |
| } else { |
| $s2 .= $pd.$ws; |
| } |
| } |
| $s2 .= $s1; |
| if (length($s2) > 0) { |
| if ($lastname ne $fname) { |
| print OUT "\n /* From $fname */\n"; |
| $lastname = $fname; |
| } |
| printf OUT " /* %4d */ %sEOL,\n", |
| $index, charcify($s2); |
| $index += length($s2)+1; |
| } |
| } |
| } |
| close(INPUT); |
| } |
| } |
| |
| if (defined($name)) { |
| printf OUT " /* %4d */ EOL\n", $index++; |
| print OUT "};\n#endif\n"; |
| undef $name; |
| } |
| |
| my @hashinfo = gen_perfect_hash(\%pkg_number); |
| if (!@hashinfo) { |
| die "$0: no hash found\n"; |
| } |
| # Paranoia... |
| verify_hash_table(\%pkg_number, \@hashinfo); |
| my ($n, $sv, $g) = @hashinfo; |
| die if ($n & ($n-1)); |
| $n <<= 1; |
| |
| printf OUT "const int use_package_count = %d;\n\n", $npkg; |
| |
| print OUT "const struct use_package *nasm_find_use_package(const char *name)\n"; |
| print OUT "{\n"; |
| print OUT " static const struct use_package packages[$npkg] = {\n"; |
| my $ix = 0; |
| foreach $pkg (@pkg_list) { |
| printf OUT " { \"%s\", nasm_usemac_%s, %d },\n", |
| $pkg, $pkg, $ix++; |
| } |
| print OUT " };\n"; |
| |
| # Put a large value in unused slots. This makes it extremely unlikely |
| # that any combination that involves unused slot will pass the range test. |
| # This speeds up rejection of unrecognized tokens, i.e. identifiers. |
| print OUT "#define INVALID_HASH_ENTRY (65535/3)\n"; |
| |
| print OUT " static const int16_t hashdata[$n] = {\n"; |
| for ($i = 0; $i < $n; $i++) { |
| my $h = ${$g}[$i]; |
| print OUT " ", defined($h) ? $h : 'INVALID_HASH_ENTRY', ",\n"; |
| } |
| print OUT " };\n"; |
| |
| print OUT " uint32_t k1, k2;\n"; |
| print OUT " uint64_t crc;\n"; |
| # For correct overflow behavior, "ix" should be unsigned of the same |
| # width as the hash arrays. |
| print OUT " uint16_t ix;\n"; |
| print OUT "\n"; |
| |
| printf OUT " crc = crc64i(UINT64_C(0x%08x%08x), name);\n", |
| $$sv[0], $$sv[1]; |
| printf OUT " k1 = ((uint32_t)crc & 0x%x) + 0;\n", $n-2; |
| printf OUT " k2 = ((uint32_t)(crc >> 32) & 0x%x) + 1;\n", $n-2; |
| print OUT "\n"; |
| printf OUT " ix = hashdata[k1] + hashdata[k2];\n"; |
| printf OUT " if (ix >= %d)\n", scalar(@pkg_list); |
| print OUT " return NULL;\n"; |
| print OUT "\n"; |
| print OUT " if (nasm_stricmp(packages[ix].package, name))\n"; |
| print OUT " return NULL;\n"; |
| print OUT "\n"; |
| print OUT " return &packages[ix];\n"; |
| print OUT "}\n"; |
| |
| close(OUT); |