#!/usr/bin/perl -w # eas -- Eta ASsembler. # SCCSID("@(#)/export/home/staff/mike/src/language/eta/src/SCCS/s.eas 1.1") # # EAS format (Eta ASsembler) is a simple way to drive the ETA virtual # machine while still knowing what you're doing. The eight opcodes # and their arguments are represented in a simple, transparent form. # # We also provide comments (introduced by '#'), decimal constants, # character constants (introduced by a single quote), address # constants (referenced by '<' and defined by '>'), and file-inclusion # (introduced by '*') # # (We use the Getopt::Std package in preference to the officially # preferred Getopt::Long in part because that manual for the latter is # fifteen times as long as that for the former. Remember the One-Page # Principle!) # # Still to be done: # Maybe add macros (pseudo-instructions) for common idioms? # Better still, a define-and-use-macros facility. use strict; use integer; use FileHandle; use Getopt::Std; sub gather_prog(*); sub get_word(\$); sub render_num($); my @iset = ('E', 'T', 'A', 'O', 'I', 'N', 'S', 'H'); my %opts; getopts("dO", \%opts); #print("%opts: ", join(" ", map { "$_=$opts{$_}" } keys %opts), "\n"); @iset = ('O', 'I', 'L', 'o', 'i', 'l', '0', '1') if $opts{"O"}; my @digits = @iset; ($digits[0], $digits[7]) = ($digits[7], $digits[0]); if (!$opts{"O"}) { foreach my $x (@digits) { $x = lc($x) } } my @lines; my %labels; my $fh = *ARGV; gather_prog(*ARGV); # assemble my $address = 0; LINE: while ($address < @lines) { my $line = $lines[$address]; while (my $word = get_word($line)) { for ($word) { if (/^E$/i || /^dividE$/i) { print($iset[0]); } elsif (/^T$/i || /^Transfer$/i) { print($iset[1]); } elsif (/^A$/i || /^Address$/i) { print($iset[2]); } elsif (/^O$/i || /^Output$/i) { print($iset[3]); } elsif (/^I$/i || /^Input$/i) { print($iset[4]); } elsif (/^N/i) { my $arg = "BLIBBER"; #print STDERR "Number: '$_'\n"; my $c = substr($_, 1, 1); #print STDERR "\$c = '$c'\n"; if (defined($c)) { if (($c ge "0" && $c le "9") || $c eq "<" || $c eq "'") { $arg = substr($_, 1); } else { $arg = get_word($line); } } #print STDERR "\$arg = '$arg'\n"; if ($arg =~ "^'") { $arg = ord(substr($arg, 1)); } elsif ($arg =~ /^) { s/#.*//; s/[ \t]*$//; while (s/^>([^:]*):[ \t]*//) { die "duplicate label '$1'" if $1 && exists $labels{$1}; $labels{$1} = @lines+1; print STDERR "set label '$1' to ", $labels{$1}, "\n" if $opts{'d'}; } if (/^\*/) { chomp(my $fn = substr($_, 1)); my $nfh = new FileHandle("<$fn") or die "can't open '$fn': $!"; gather_prog($nfh); $nfh->close(); } else { push(@lines, $_) if !/^$/; } } } sub get_word(\$) { my $ref = shift(); my $text = $$ref; $text =~ m/\s*(\S*)\s*(.*)/; $$ref = $2; return $1; } sub render_num($) { my $arg = shift(); my @stack; while ($arg != 0) { push(@stack, $arg % 7); $arg /= 7; } print(map { $digits[$_] } reverse(@stack)); print($digits[7]); }