Ken Thompson sent e-mail in to explain that there can be labels mid-line, such as
sys write; 1:0; 4 so I modified the assembler logic to support this, and added some code to write_test.s to verify that it works.
This commit is contained in:
@@ -20,16 +20,23 @@ my @Mline; # Source lines associated with mem locations
|
|||||||
my $origline; # The current input line of code
|
my $origline; # The current input line of code
|
||||||
|
|
||||||
my $stage = 1; # Pass one or pass two
|
my $stage = 1; # Pass one or pass two
|
||||||
|
my $debug = 0; # Run in debug mode
|
||||||
|
|
||||||
### Main program ###
|
### Main program ###
|
||||||
|
|
||||||
|
# Optional debug argument
|
||||||
|
if ( ( @ARGV > 0 ) && ( $ARGV[0] eq "-d" ) ) {
|
||||||
|
$debug = 1;
|
||||||
|
shift(@ARGV);
|
||||||
|
}
|
||||||
|
|
||||||
# Check the arguments
|
# Check the arguments
|
||||||
die("Usage: $0 file1.s [file2.s ...]\n") if ( @ARGV < 1 );
|
die("Usage: $0 [-d] file1.s [file2.s ...]\n") if ( @ARGV < 1 );
|
||||||
|
|
||||||
# Define the syscalls as variables so that
|
# Define the syscalls as variables so that
|
||||||
# I don't have to hand-code the logic below.
|
# I don't have to hand-code the logic below.
|
||||||
# Also, start with the location counter at zero
|
# Also, start with the location counter at zero
|
||||||
%Var= (
|
%Var = (
|
||||||
'.' => 0,
|
'.' => 0,
|
||||||
save => 1,
|
save => 1,
|
||||||
getuid => 2,
|
getuid => 2,
|
||||||
@@ -68,15 +75,15 @@ foreach my $file (@ARGV) {
|
|||||||
# Now do it all again, pass two
|
# Now do it all again, pass two
|
||||||
$Var{'.'} = 0;
|
$Var{'.'} = 0;
|
||||||
$stage = 2;
|
$stage = 2;
|
||||||
|
print("Now in stage 2\n") if ($debug);
|
||||||
foreach my $file (@ARGV) {
|
foreach my $file (@ARGV) {
|
||||||
parse_file($file);
|
parse_file($file);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Now print out the contents of memory
|
# Now print out the contents of memory
|
||||||
for my $i ( 0 .. $#Mem ) {
|
for my $i ( 0 .. $#Mem ) {
|
||||||
if (defined($Mem[$i])) {
|
if ( defined( $Mem[$i] ) ) {
|
||||||
printf("%06o: %06o\t%s\n",
|
printf( "%06o: %06o\t%s\n", $i, $Mem[$i], $Mline[$i] || "" );
|
||||||
$i, $Mem[$i], $Mline[$i] || "");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,39 +98,39 @@ sub parse_file {
|
|||||||
# Lose the end of line and any leading/trailing whitespace
|
# Lose the end of line and any leading/trailing whitespace
|
||||||
# Discard any comments and preceding comment whitespace
|
# Discard any comments and preceding comment whitespace
|
||||||
chomp($line);
|
chomp($line);
|
||||||
$origline= $line;
|
$origline = $line;
|
||||||
$line =~ s{^\s+}{};
|
$line =~ s{^\s+}{};
|
||||||
$line =~ s{\s+$}{};
|
$line =~ s{\s+$}{};
|
||||||
$line =~ s{\s*\".*}{};
|
$line =~ s{\s*\".*}{};
|
||||||
#print("=>$line<=\n");
|
#print("=>$line<=\n");
|
||||||
|
|
||||||
# Split into a section with possible labels and a
|
# Split the line into commands that are ; separated
|
||||||
# section with definitely no labels. The ? makes the
|
# and parse each one
|
||||||
# first pattern less greedy. Labels and statements.
|
foreach my $cmd ( split( /;\s*/, $line ) ) {
|
||||||
$line =~ m{(.*?)([^:]*$)};
|
|
||||||
my $labelsect = $1;
|
|
||||||
my $stmntsect = $2;
|
|
||||||
|
|
||||||
#print(">$labelsect< >$stmntsect<\n");
|
# Split into a section with possible labels and a
|
||||||
|
# statement section with definitely no labels. The ?
|
||||||
|
# makes the first pattern less greedy.
|
||||||
|
#print("cmd is >$cmd<\n");
|
||||||
|
$cmd =~ m{(.*?)([^:]*$)};
|
||||||
|
my $labelsect = $1;
|
||||||
|
my $statement = $2;
|
||||||
|
|
||||||
|
#print(">$labelsect< >$statement<\n");
|
||||||
|
|
||||||
# Split $labelsect into labels using the : character
|
# Split $labelsect into labels using the : character
|
||||||
my @labellist = split( /:\s*/, $labelsect );
|
my @labellist = split( /:\s*/, $labelsect );
|
||||||
|
|
||||||
# Split $stmntsect into statements using the ; character
|
|
||||||
# Trim any whitespace first
|
|
||||||
$stmntsect =~ s{^\s+}{};
|
|
||||||
my @stmntlist = split( /;\s*/, $stmntsect );
|
|
||||||
|
|
||||||
# First pass: parse the labels
|
# First pass: parse the labels
|
||||||
if ( $stage == 1 ) {
|
if ( $stage == 1 ) {
|
||||||
foreach my $l (@labellist) { parse_label($l); }
|
foreach my $l (@labellist) {
|
||||||
|
parse_label($l);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Parse the statements on both passes
|
# Parse the statements on both passes
|
||||||
foreach my $s (@stmntlist) {
|
parse_statement($statement);
|
||||||
parse_statement($s);
|
|
||||||
}
|
}
|
||||||
#print("\n");
|
|
||||||
}
|
}
|
||||||
close($IN);
|
close($IN);
|
||||||
}
|
}
|
||||||
@@ -153,6 +160,12 @@ sub parse_statement {
|
|||||||
my $location = $Var{'.'};
|
my $location = $Var{'.'};
|
||||||
#printf( "Location: 0%o\n", $location );
|
#printf( "Location: 0%o\n", $location );
|
||||||
|
|
||||||
|
# Empty statement, nothing to do
|
||||||
|
return if ( $statement =~ m{^\s*$} );
|
||||||
|
|
||||||
|
# Lose any leading whitespace
|
||||||
|
$statement =~ s{^\s*}{};
|
||||||
|
|
||||||
# It's an assignment statement: lhs = rhs
|
# It's an assignment statement: lhs = rhs
|
||||||
if ( $statement =~ m{(\S+)\s*=\s*(\S+)} ) {
|
if ( $statement =~ m{(\S+)\s*=\s*(\S+)} ) {
|
||||||
my $lhs = $1;
|
my $lhs = $1;
|
||||||
@@ -163,6 +176,7 @@ sub parse_statement {
|
|||||||
my $result = parse_expression($rhs);
|
my $result = parse_expression($rhs);
|
||||||
die("expression $rhs has no value in assignment\n")
|
die("expression $rhs has no value in assignment\n")
|
||||||
if ( !defined($result) );
|
if ( !defined($result) );
|
||||||
|
|
||||||
#printf( "Setting variable %s to 0%o\n", $lhs, $result );
|
#printf( "Setting variable %s to 0%o\n", $lhs, $result );
|
||||||
$Var{$lhs} = $result;
|
$Var{$lhs} = $result;
|
||||||
return;
|
return;
|
||||||
@@ -190,8 +204,8 @@ sub parse_expression {
|
|||||||
|
|
||||||
# If it's a defined variable ( . , .. , etc.)
|
# If it's a defined variable ( . , .. , etc.)
|
||||||
# return the value
|
# return the value
|
||||||
return($Var{$expression})
|
return ( $Var{$expression} )
|
||||||
if (defined($Var{$expression}));
|
if ( defined( $Var{$expression} ) );
|
||||||
|
|
||||||
# If it's a numeric literal, simply return it
|
# If it's a numeric literal, simply return it
|
||||||
if ( $expression =~ m{^-?\d+$} ) {
|
if ( $expression =~ m{^-?\d+$} ) {
|
||||||
@@ -338,7 +352,7 @@ sub parse_expression {
|
|||||||
my $instruction = $inst{$word1};
|
my $instruction = $inst{$word1};
|
||||||
|
|
||||||
# Is this an indirect instruction?
|
# Is this an indirect instruction?
|
||||||
my $indirect = defined($word3) && ($word3 eq "i") ? 020000 : 0;
|
my $indirect = defined($word3) && ( $word3 eq "i" ) ? 020000 : 0;
|
||||||
|
|
||||||
# We have an expression for this instruction
|
# We have an expression for this instruction
|
||||||
if ( ( $stage == 2 ) && defined($word2) ) {
|
if ( ( $stage == 2 ) && defined($word2) ) {
|
||||||
@@ -380,10 +394,10 @@ sub parse_expression {
|
|||||||
die("Unable to subtract $word1 on pass two\n")
|
die("Unable to subtract $word1 on pass two\n")
|
||||||
if ( !defined($diff) );
|
if ( !defined($diff) );
|
||||||
}
|
}
|
||||||
|
|
||||||
#print("Did a subtraction and got $diff\n");
|
#print("Did a subtraction and got $diff\n");
|
||||||
return ($diff);
|
return ($diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
die("I have no idea what $expression is in pass two\n") if ( $stage == 2 );
|
die("I have no idea what $expression is in pass two\n") if ( $stage == 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,6 +409,7 @@ sub add {
|
|||||||
my $val2 = parse_expression($b);
|
my $val2 = parse_expression($b);
|
||||||
#print("Adding $val1 + $val2\n");
|
#print("Adding $val1 + $val2\n");
|
||||||
return (undef) if ( !defined($val1) || !defined($val2) );
|
return (undef) if ( !defined($val1) || !defined($val2) );
|
||||||
|
|
||||||
#print( " with a good value of ", $val1 + $val2, "\n" );
|
#print( " with a good value of ", $val1 + $val2, "\n" );
|
||||||
return ( $val1 + $val2 );
|
return ( $val1 + $val2 );
|
||||||
}
|
}
|
||||||
@@ -407,6 +422,7 @@ sub subtract {
|
|||||||
my $val2 = parse_expression($b);
|
my $val2 = parse_expression($b);
|
||||||
#print("Subtracting $val1 - $val2\n");
|
#print("Subtracting $val1 - $val2\n");
|
||||||
return (undef) if ( !defined($val1) || !defined($val2) );
|
return (undef) if ( !defined($val1) || !defined($val2) );
|
||||||
|
|
||||||
#print( " with a good value of ", $val1 - $val2, "\n" );
|
#print( " with a good value of ", $val1 - $val2, "\n" );
|
||||||
return ( $val1 - $val2 );
|
return ( $val1 - $val2 );
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -11,7 +11,13 @@ main:
|
|||||||
lac d1
|
lac d1
|
||||||
sys write; hello; 7
|
sys write; hello; 7
|
||||||
|
|
||||||
" open file fred
|
" Test if the assembler can dac into a mid-line label
|
||||||
|
lac helloptr
|
||||||
|
dac 1f
|
||||||
|
lac d1
|
||||||
|
sys write; 1:0; 7
|
||||||
|
|
||||||
|
" Try to open file fred
|
||||||
sys open; fred; 0; 0
|
sys open; fred; 0; 0
|
||||||
|
|
||||||
" read 5 words into the buffer from stdin: type in 10 or more characters!
|
" read 5 words into the buffer from stdin: type in 10 or more characters!
|
||||||
@@ -42,6 +48,7 @@ out: 0
|
|||||||
|
|
||||||
" Hello, world\n, two ASCII chars per word
|
" Hello, world\n, two ASCII chars per word
|
||||||
hello: 0110145; 0154154; 0157054; 040; 0167157; 0162154; 0144012
|
hello: 0110145; 0154154; 0157054; 040; 0167157; 0162154; 0144012
|
||||||
|
helloptr: hello
|
||||||
|
|
||||||
" fred as a string, NUL terminated
|
" fred as a string, NUL terminated
|
||||||
fred: 0146162; 0145144; 0
|
fred: 0146162; 0145144; 0
|
||||||
|
|||||||
Reference in New Issue
Block a user