Below is the current code for my assembler. Because of numerous complaints about size, readability, and formatting errors, this is now a previously imported version of the code rather than the "live version."
#!/usr/local/bin/perl
######################################################################
#
# This is ass.pl, an assembler for the Mac-1 instruction set.
# It was written by Chris Hardie and most recently revised on 12/07/97
#
# The program reads a program from a text file and outputs binary code
# in a text file, both defined by the user.
#
######################################################################
# Define user variables
$input_file = "/clients/users/silas/www/cs63/program/code/input.txt";
$output_file = "/clients/users/silas/www/cs63/program/code/output.txt";
$inst_size = 16;
# Main program
&create_set;
&input;
exit;
# Subroutines
sub create_set {
###############################
#
# This defines the Mac-1 instruction set and the binary equivalents
#
# I considered seperating the hash arrays by the number of bits contained
# in the binary equivalent of the instruction, but found that lookup is
# easier when it's all in one.
#
###############################
%all_commands = (
"LODD" => "0000",
"STOD" => "0001",
"ADDD" => "0010",
"SUBD" => "0011",
"JPOS" => "0100",
"JZER" => "0101",
"JUMP" => "0110",
"LOCO" => "0111",
"LODL" => "1000",
"STOL" => "1001",
"ADDL" => "1010",
"SUBL" => "1011",
"JNEG" => "1100",
"JNZE" => "1101",
"CALL" => "1110",
"INSP" => "11111100",
"DESP" => "11111110",
"PSHI" => "1111000000000000",
"POPI" => "1111001000000000",
"PUSH" => "1111010000000000",
"POP" => "1111011000000000",
"RETN" => "1111100000000000",
"SWAP" => "1111101000000000",
"HALT" => "1111111111111111"
);
# "HALT" added by me to accommodate "CALL STOP"
# For development only
%labels_tst = (
"PMUL" => "16",
"ANOTZ" => "17",
"BNOTZ" => "18",
"L1" => "19",
"L2" => "20",
"DONE" => "21",
"INNER" => "22",
"L3" => "23",
"MAIN" => "24",
"L4" => "25",
"C1" => "26",
"C20" => "27"
);
}
sub input {
###############################
#
# This reads input from a file; it is the driver for the rest of the
# program, as the bulk of operations performed are on an single line from
# the input file. This function calls &convert.
#
###############################
#########
# Pass I
#########
open(INPUT,"$input_file") || die "Could not open input file.\n";
$position = 0;
while ($line = <INPUT>) {
chop($line);
@array = split(/ /, $line);
$_ = $array[0];
if (/:/) {
$label = shift(@array);
chop($label);
$labels{$label} = $position;
}
$_ = $line;
if (!(/.*=.*/)) {
$position = $position + $inst_size;
}
}
close(INPUT);
#########
# Pass II
#########
open(INPUT,"$input_file") || die "Could not open input file.\n";
open(OUTPUT,">$output_file") || die "Could not open output file.\n";
$line_number = 0;
while ($line = <INPUT>) {
undef($inst); undef($var); undef($array);
chop($line);
$line_number++;
@array = split(/ /, $line);
# print $line;
# For debugging
$_ = $line;
if (/.*=.*/) {
($varname, $temp, $varvalue) = @array;
$symbols{$varname} = $varvalue;
next;
}
$_ = $array[0];
if (/:/) {
shift(@array);
}
($inst) = @array[0];
if (defined(@array[1])) {
($var) = @array[1];
}
print "Converting line $line_number:\n";
&convert;
}
close(INPUT);
close(OUTPUT);
}
sub convert {
###############################
#
# This converts the instructions to binary code.
#
# It is slightly tricky as it does some operations based on the hard coded
# instruction set and would not be able to handle an entirely new
# instruction set without some serious reworking. Then again, this is true
# of the entire program. This function calls &int2bin
#
#
###############################
@keys = keys %all_commands;
$found = 0;
foreach $key (@keys) {
$_ = $key;
if (/.*$inst.*/) {
$found = 1;
}
}
if ($found != 1) {
die "Invalid instruction \"$inst\" at line number $line_number\n";
}
$valid = 0;
$_ = $var;
if (/[a-zA-Z]/) {
@keys = keys %symbols;
$found = 0;
foreach $key (@keys) {
$_ = $key;
if (/.*$var.*/) {
$found = 1;
}
}
if ($found == 1) {
$valid = 1;
$var = $symbols{$var};
}
}
$_ = $var;
if ((/[a-zA-Z]/) && ($valid != 1)) {
@keys = keys %labels;
$found = 0;
foreach $key (@keys) {
$_ = $key;
if (/.*$var.*/) {
$found = 1;
}
}
if ($found == 1) {
$valid = 1;
$var = $labels{$var};
}
}
$_ = $var;
if (/[a-zA-Z]/) {
if ($valid != 1) {
die "Invalid parameter/label \"$var\" at line number
$line_number\n";
}
}
$binary_inst = $all_commands{$inst};
$inst_length = length($binary_inst);
SWITCH: {
if (($inst_length == 4) && (($var >= 4096) || ($var < 0) || ($var
eq ""))) {
die "Out of range paramater value \"$var\" at line number
$line_number\n";
}
if (($inst_length == 8) && (($var >= 256) || ($var < 0) || ($var
eq ""))) {
die "Out of range paramater value \"$var\" at line number
$line_number\n";
}
if (($inst_length == 16) && ($var ne "")) {
die "Unexpected paramater \"$var\" at line number $line_number\n";
}
}
$binary_var = int2bin($var);
$final = $binary_inst.$binary_var;
&output;
}
sub output {
###############################
#
# This is the output function. It writes the binary code to the output file.
#
###############################
# print "Input: $inst\n";
# print "Length of input: $inst_length\n";
# print "Inst in binary: $binary_inst\n";
# print "Var: $var\n";
# print "Var in binary: $binary_var\n";
# print "Final: $final\n";
print OUTPUT "$final\n";
}
sub int2bin {
###############################
#
# This converts a decimal integer to a binary number. It uses one of the
# methods we learned in class, dividing by two and examining remainders.
# Since the conversion doesn't always result in a binary number of the
# correct number of digits, this also prepends the appropriate "0"s to make
# it correct.
#
# This function takes one variable, an integer.
#
# This function returns a binary number.
#
###############################
($int) = @_;
$bin = "";
while ($int != 0) {
$temp = ($int / 2);
if ($temp != int $temp) {
$bin = "1" . $bin;
} else {
$bin = "0" . $bin;
}
$int = int $temp;
}
$places = $inst_size - length($bin) - $inst_length;
for ($temp = 0; $temp < $places; $temp++) {
$bin = "0".$bin;
}
return $bin;
}