| #!/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; |
| |
| # |
| # 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 =~ /\s/) { |
| next if ($space); |
| $o = 32; |
| $c = ' '; |
| $space = 1; |
| } elsif ($o > 126) { |
| $space = 1; # Implicit space after compacted directive |
| } else { |
| $space = 0; |
| } |
| } |
| |
| if ($o < 32 || $o > 126 || $c eq '"' || $c eq "\\") { |
| $l .= sprintf("%3d,", $o); |
| } else { |
| $c =~ s/\'/\\'/; # << sanitize single quote. |
| $l .= "\'".$c."\',"; |
| } |
| } |
| 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 $outfmt; |
| my $lastname; |
| my $z; |
| |
| 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++; |
| } |
| if (m/^OUT:\s*(.*\S)\s*$/) { |
| undef $pkg; |
| my @out_alias = split(/\s+/, $1); |
| if (defined($name)) { |
| printf OUT " /* %4d */ 0\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; |
| push(@out_list, $out_alias[0]); |
| $out_index{$out_alias[0]} = $index; |
| } elsif (m/^STD:\s*(.*\S)\s*$/) { |
| undef $pkg; |
| my @out_alias = split(/\s+/, $1); |
| if (defined($name)) { |
| printf OUT " /* %4d */ 0\n", $index++; |
| print OUT "};\n#endif\n"; |
| undef $name; |
| } |
| $index = 0; |
| print OUT "\n#if 1"; |
| $name = 'nasm_stdmac_' . $out_alias[0]; |
| print OUT "\nconst unsigned char ${name}[] = {\n"; |
| print OUT " /* From $fname */\n"; |
| $lastname = $fname; |
| push(@std_list, $out_alias[0]); |
| $std_index{$std_alias[0]} = $index; |
| } elsif (m/^USE:\s*(\S+)\s*$/) { |
| $pkg = $1; |
| if (defined($pkg_number{$pkg})) { |
| die "$0: $fname: duplicate package: $pkg\n"; |
| } |
| if (defined($name)) { |
| printf OUT " /* %4d */ 0\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", $pptok_hash{'%define'}+128)."__USE_\U$pkg\E__"; |
| printf OUT " /* %4d */ %s0,\n", $index, charcify($z); |
| $index += length($z)+1; |
| } elsif (m/^\s*((\s*([^\"\';\s]+|\"[^\"]*\"|\'[^\']*\'))*)\s*(;.*)?$/) { |
| my $s1, $s2, $pd, $ws; |
| |
| if (!defined($name)) { |
| die "$0: $fname: macro declarations outside a known block\n"; |
| } |
| |
| $s1 = $1; |
| $s2 = ''; |
| while ($s1 =~ /(\%[a-zA-Z_][a-zA-Z0-9_]*)((\s+)(.*)|)$/) { |
| $s2 .= "$'"; |
| $pd = $1; |
| $ws = $3; |
| $s1 = $4; |
| if (defined($pptok_hash{$pd}) && |
| $pptok_hash{$pd} <= 127) { |
| $s2 .= pack("C", $pptok_hash{$pd}+128); |
| } 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 */ %s0,\n", |
| $index, charcify($s2); |
| $index += length($s2)+1; |
| } |
| } else { |
| die "$fname:$line: error unterminated quote"; |
| } |
| } |
| close(INPUT); |
| } |
| } |
| |
| if (defined($name)) { |
| printf OUT " /* %4d */ 0\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)); |
| |
| print OUT "const unsigned char *nasm_stdmac_find_package(const char *package)\n"; |
| print OUT "{\n"; |
| print OUT " static const struct {\n"; |
| print OUT " const char *package;\n"; |
| print OUT " const unsigned char *macros;\n"; |
| print OUT " } packages[$npkg] = {\n"; |
| foreach $pkg (@pkg_list) { |
| printf OUT " { \"%s\", nasm_usemac_%s },\n", |
| $pkg, $pkg; |
| } |
| 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 UNUSED (65535/3)\n"; |
| |
| print OUT " static const int16_t hash1[$n] = {\n"; |
| for ($i = 0; $i < $n; $i++) { |
| my $h = ${$g}[$i*2+0]; |
| print OUT " ", defined($h) ? $h : 'UNUSED', ",\n"; |
| } |
| print OUT " };\n"; |
| |
| print OUT " static const int16_t hash2[$n] = {\n"; |
| for ($i = 0; $i < $n; $i++) { |
| my $h = ${$g}[$i*2+1]; |
| print OUT " ", defined($h) ? $h : 'UNUSED', ",\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), package);\n", |
| $$sv[0], $$sv[1]; |
| print OUT " k1 = (uint32_t)crc;\n"; |
| print OUT " k2 = (uint32_t)(crc >> 32);\n"; |
| print OUT "\n"; |
| printf OUT " ix = hash1[k1 & 0x%x] + hash2[k2 & 0x%x];\n", $n-1, $n-1; |
| 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, package))\n"; |
| print OUT " return NULL;\n"; |
| print OUT "\n"; |
| print OUT " return packages[ix].macros;\n"; |
| print OUT "}\n"; |
| |
| close(OUT); |