home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / nasm097s.zip / INSNS.PL < prev    next >
Perl Script  |  1997-10-02  |  5KB  |  163 lines

  1. #!/usr/bin/perl
  2. #
  3. # insns.pl   produce insnsa.c and insnsd.c from insns.dat
  4. #
  5. # The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  6. # Julian Hall. All rights reserved. The software is
  7. # redistributable under the licence given in the file "Licence"
  8. # distributed in the NASM archive.
  9.  
  10. print STDERR "Reading insns.dat...\n";
  11.  
  12. $fname = "insns.dat" unless $fname = $ARGV[0];
  13. open (F, $fname) || die "unable to open $fname";
  14.  
  15. $line = 0;
  16. $opcodes = 0;
  17. $insns = 0;
  18. while (<F>) {
  19.   $line++;
  20.   next if /^\s*;/;   # comments
  21.   chomp;
  22.   split;
  23.   next if $#_ == -1; # blank lines
  24.   (warn "line $line does not contain four fields\n"), next if $#_ != 3;
  25.   ($formatted, $nd) = &format(@_);
  26.   if ($formatted) {
  27.     $insns++;
  28.     $aname = "aa_$_[0]";
  29.     push @$aname, $formatted;
  30.   }
  31.   $opcodes[$opcodes++] = $_[0], $done{$_[0]} = 1 if !$done{$_[0]};
  32.   if ($formatted && !$nd) {
  33.     push @big, $formatted;
  34.     foreach $i (&startbyte($_[2])) {
  35.       $aname = sprintf "dd_%02X",$i;
  36.       push @$aname, $#big;
  37.     }
  38.   }
  39. }
  40.  
  41. close F;
  42.  
  43. print STDERR "Writing insnsa.c...\n";
  44.  
  45. open A, ">insnsa.c";
  46.  
  47. print A "/* This file auto-generated from insns.dat by insns.pl" .
  48.         " - don't edit it */\n\n";
  49. print A "#include <stdio.h>\n";
  50. print A "#include \"nasm.h\"\n";
  51. print A "#include \"insns.h\"\n";
  52. print A "\n";
  53.  
  54. foreach $i (@opcodes) {
  55.   print A "static struct itemplate instrux_${i}[] = {\n";
  56.   $aname = "aa_$i";
  57.   foreach $j (@$aname) {
  58.     print A "    $j\n";
  59.   }
  60.   print A "    {-1}\n};\n\n";
  61. }
  62. print A "struct itemplate *nasm_instructions[] = {\n";
  63. foreach $i (@opcodes) {
  64.   print A "    instrux_${i},\n";
  65. }
  66. print A "};\n";
  67.  
  68. close A;
  69.  
  70. print STDERR "Writing insnsd.c...\n";
  71.  
  72. open D, ">insnsd.c";
  73.  
  74. print D "/* This file auto-generated from insns.dat by insns.pl" .
  75.         " - don't edit it */\n\n";
  76. print D "#include <stdio.h>\n";
  77. print D "#include \"nasm.h\"\n";
  78. print D "#include \"insns.h\"\n";
  79. print D "\n";
  80.  
  81. print D "static struct itemplate instrux[] = {\n";
  82. foreach $j (@big) {
  83.   print D "    $j\n";
  84. }
  85. print D "    {-1}\n};\n\n";
  86.  
  87. for ($c=0; $c<256; $c++) {
  88.   $h = sprintf "%02X", $c;
  89.   print D "static struct itemplate *itable_${h}[] = {\n";
  90.   $aname = "dd_$h";
  91.   foreach $j (@$aname) {
  92.     print D "    instrux + $j,\n";
  93.   }
  94.   print D "    NULL\n};\n\n";
  95. }
  96.  
  97. print D "struct itemplate **itable[] = {\n";
  98. for ($c=0; $c<256; $c++) {
  99.   printf D "    itable_%02X,\n", $c;
  100. }
  101. print D "};\n";
  102.  
  103. close D;
  104.  
  105. printf STDERR "Done: %d instructions\n", $insns;
  106.  
  107. sub format {
  108.   local ($opcode, $operands, $codes, $flags) = @_;
  109.   local $num, $nd = 0;
  110.  
  111.   return (undef, undef) if $operands eq "ignore";
  112.  
  113.   # format the operands
  114.   $operands =~ s/:/|colon,/g;
  115.   $operands =~ s/mem(\d+)/mem|bits$1/g;
  116.   $operands =~ s/mem/memory/g;
  117.   $operands =~ s/memory_offs/mem_offs/g;
  118.   $operands =~ s/imm(\d+)/imm|bits$1/g;
  119.   $operands =~ s/imm/immediate/g;
  120.   $operands =~ s/rm(\d+)/regmem|bits$1/g;
  121.   $num = 3;
  122.   $operands = '0,0,0', $num = 0 if $operands eq 'void';
  123.   $operands .= ',0', $num-- while $operands !~ /,.*,/;
  124.   $operands =~ tr/a-z/A-Z/;
  125.  
  126.   # format the flags
  127.   $flags =~ s/,/|IF_/g;
  128.   $flags =~ s/(\|IF_ND|IF_ND\|)//, $nd = 1 if $flags =~ /IF_ND/;
  129.   $flags = "IF_" . $flags;
  130.  
  131.   ("{I_$opcode, $num, {$operands}, \"$codes\", $flags},", $nd);
  132. }
  133.  
  134. # Here we determine the range of possible starting bytes for a given
  135. # instruction. We need only consider the codes:
  136. # \1 \2 \3     mean literal bytes, of course
  137. # \4 \5 \6 \7  mean PUSH/POP of segment registers: special case
  138. # \10 \11 \12  mean byte plus register value
  139. # \17          means byte zero
  140. # \330         means byte plus condition code
  141. # \0 or \340   mean give up and return empty set
  142. sub startbyte {
  143.   local ($codes) = @_;
  144.   local $word, @range;
  145.  
  146.   while (1) {
  147.     die "couldn't get code in '$codes'" if $codes !~ /^(\\[^\\]+)(\\.*)?$/;
  148.     $word = $1, $codes = $2;
  149.     return (hex $1) if $word =~ /^\\[123]$/ && $codes =~ /^\\x(..)/;
  150.     return (0x07, 0x17, 0x1F) if $word eq "\\4";
  151.     return (0xA1, 0xA9) if $word eq "\\5";
  152.     return (0x06, 0x0E, 0x16, 0x1E) if $word eq "\\6";
  153.     return (0xA0, 0xA8) if $word eq "\\7";
  154.     $start=hex $1, $r=8, last if $word =~ /^\\1[012]$/ && $codes =~/^\\x(..)/;
  155.     return (0) if $word eq "\\17";
  156.     $start=hex $1, $r=16, last if $word =~ /^\\330$/ && $codes =~ /^\\x(..)/;
  157.     return () if $word eq "\\0" || $word eq "\\340";
  158.   }
  159.   @range = ();
  160.   push @range, $start++ while ($r-- > 0);
  161.   @range;
  162. }
  163.