nasm/misc/emacstbl.pl
H. Peter Anvin 2d5cf17130 misc/emacstbl.pl: add NASM version to output, add to Makefile
Include the version number in the output (misc/nasmtok.el) and add a
rule for generating it to the Makefiles.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2022-11-17 12:52:52 -08:00

216 lines
4.4 KiB
Perl
Executable File

#!/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);