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:
Warren Toomey
2016-02-26 06:52:43 +10:00
parent f9b8c8eeb2
commit 018af6f43e
2 changed files with 87 additions and 64 deletions
+36 -20
View File
@@ -20,11 +20,18 @@ 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.
@@ -68,6 +75,7 @@ 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);
} }
@@ -75,8 +83,7 @@ foreach my $file (@ARGV) {
# 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] || "");
} }
} }
@@ -97,33 +104,33 @@ sub parse_file {
$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;
@@ -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
View File
@@ -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