#!/usr/bin/perl # # Automatically produce some tables useful for a NASM major mode # use integer; use strict; use File::Spec; my($outfile, $srcdir, $objdir) = @ARGV; if (!defined($outfile)) { die "Usage: $0 outfile srcdir objdir\n"; } $srcdir = File::Spec->curdir() unless (defined($srcdir)); $objdir = $srcdir unless (defined($objdir)); my %tokens = (); sub xpush($@) { my $ref = shift @_; $$ref = [] unless (defined($$ref)); return push(@$$ref, @_); } # Combine some specific token types my %override = ( 'id' => 'special', 'float' => 'function', 'floatize' => 'function', 'strfunc' => 'function', 'ifunc' => 'function', 'insn' => 'instruction', 'reg' => 'register', 'seg' => 'special', 'wrt' => 'special' ); sub read_tokhash_c($) { my($tokhash_c) = @_; open(my $th, '<', $tokhash_c) or die "$0:$tokhash_c: $!\n"; my $l; my $tokendata = 0; while (defined($l = <$th>)) { if ($l =~ /\bstruct tokendata tokendata\[/) { $tokendata = 1; next; } elsif (!$tokendata) { next; } last if ($l =~ /\}\;/); if ($l =~ /^\s*\{\s*\"(.*?)\",.*?,\s*TOKEN_(\w+),.*\}/) { my $token = $1; my $type = lc($2); if ($override{$type}) { $type = $override{$type}; } elsif ($token !~ /^\w/) { $type = 'operator'; } elsif ($token =~ /^__\?masm_.*\?__$/) { next; } xpush(\$tokens{$type}, $token); if ($token =~ /^__\?(.*)\?__$/) { # Also encode the "user" (macro) form without __?...?__ xpush(\$tokens{$type}, $1); } } } close($th); } sub read_pptok_c($) { my($pptok_c) = @_; open(my $pt, '<', $pptok_c) or die "$0:$pptok_c: $!\n"; my $l; my $pp_dir = 0; while (defined($l = <$pt>)) { if ($l =~ /\bpp_directives\[/) { $pp_dir = 1; next; } elsif (!$pp_dir) { next; } last if ($l =~ /\}\;/); if ($l =~ /^\s*\"(.*?)\"/) { xpush(\$tokens{'pp-directive'}, $1); } } close($pt); } sub read_directiv_dat($) { my($directiv_dat) = @_; open(my $dd, '<', $directiv_dat) or die "$0:$directiv_dat: $!\n"; my $l; my $directiv = 0; while (defined($l = <$dd>)) { if ($l =~ /^\; ---.*?(pragma)?/) { $directiv = ($1 ne 'pragma'); next; } elsif (!$directiv) { next; } if ($l =~ /^\s*(\w+)/) { xpush(\$tokens{'directive'}, $1); } } close($dd); } my $version; sub read_version($) { my($vfile) = @_; open(my $v, '<', $vfile) or die "$0:$vfile: $!\n"; $version = <$v>; chomp $version; close($v); } sub make_lines($$@) { my $maxline = shift @_; my $indent = shift @_; # The first line isn't explicitly indented and the last line # doesn't end in "\n"; assumed the surrounding formatter wants # do control that my $linepos = 0; my $linewidth = $maxline - $indent; my $line = ''; my @lines = (); foreach my $w (@_) { my $l = length($w); if ($linepos > 0 && $linepos+$l+1 >= $linewidth) { $line .= "\n" . (' ' x $indent); push(@lines, $line); $linepos = 0; $line = ''; } if ($linepos > 0) { $line .= ' '; $linepos++; } $line .= $w; $linepos += $l; } if ($linepos > 0) { push(@lines, $line); } return @lines; } sub quote_for_emacs(@) { return map { s/[\\\"\']/\\$1/g; '"'.$_.'"' } @_; } sub write_output($) { my($outfile) = @_; open(my $out, '>', $outfile) or die "$0:$outfile: $!\n"; my($vol,$dir,$file) = File::Spec->splitpath($outfile); print $out ";;; ${file} --- lists of NASM assembler tokens\n"; print $out ";;;\n"; print $out ";;; This file contains list of tokens from the NASM x86\n"; print $out ";;; assembler, automatically extracted from NASM ${version}.\n"; print $out ";;;\n"; print $out ";;; This file is intended to be (require)d from a `nasm-mode\'\n"; print $out ";;; major mode definition.\n"; foreach my $type (sort keys(%tokens)) { print $out "\n(defconst nasm-${type}\n"; print $out " \'("; print $out make_lines(78, 4, quote_for_emacs(sort @{$tokens{$type}})); print $out ")\n"; print $out " \"NASM ${version} ${type} tokens for `nasm-mode\'.\")\n"; } close($out); } read_tokhash_c(File::Spec->catfile($objdir, 'asm', 'tokhash.c')); read_pptok_c(File::Spec->catfile($objdir, 'asm', 'pptok.c')); read_directiv_dat(File::Spec->catfile($srcdir, 'asm', 'directiv.dat')); read_version(File::Spec->catfile($srcdir, 'version')); write_output($outfile);