|
@@ -8,6 +8,8 @@ my $VERSION = 0.01;
|
|
|
|
|
|
# The array of intcodes making up the program
|
|
|
my @program;
|
|
|
+# A hash of labels and their corresponding starting line number
|
|
|
+my %labels;
|
|
|
# Opcodes that may be encounted and their corresponding ints
|
|
|
my %opcodes = (
|
|
|
"add" => "01",
|
|
@@ -41,8 +43,6 @@ sub parseAssembly
|
|
|
{
|
|
|
|
|
|
my @assembly = @_;
|
|
|
- # A hash of labels and their corresponding starting line number
|
|
|
- my %labels;
|
|
|
# The current instruction number
|
|
|
my $instructionNumber = 0;
|
|
|
|
|
@@ -67,7 +67,7 @@ sub parseAssembly
|
|
|
}
|
|
|
elsif($opcodes{$asmInstruction})
|
|
|
{
|
|
|
- parseOpcodeAndParams($opcodes{$asmInstruction}, \@parameters);
|
|
|
+ parseOpcodeAndParams($opcodes{$asmInstruction}, \@parameters, \$instructionNumber);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
@@ -76,37 +76,55 @@ sub parseAssembly
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-# TODO
|
|
|
sub parseOpcodeAndParams
|
|
|
{
|
|
|
+ # A reference to the current instruction number
|
|
|
+ # Need to assign first due to usage for opcode index
|
|
|
+ my $instructionNumber = $_[2];
|
|
|
+ # The opcode
|
|
|
my $opcode = $_[0];
|
|
|
+ # Store program index of opcode now because opcode may be modified in the parameter loop
|
|
|
+ my $opcodeIdx = $$instructionNumber++;
|
|
|
+ # Parameters for the opcode
|
|
|
my @parameters = @{ $_[1] };
|
|
|
- my $operand1 = $parameters[0];
|
|
|
- if(isImmediate($parameters[0]))
|
|
|
- {
|
|
|
- $opcode = length($opcode) == 1 ? "10$opcode" : "1$opcode";
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- $operand1 = getAddress($parameters[0])
|
|
|
- }
|
|
|
|
|
|
- my $operand2 = $parameters[1];
|
|
|
- if(isImmediate($parameters[1]))
|
|
|
+ # Store at is usually the last parameter, if there are any parameters
|
|
|
+ my $storeAt = $#parameters > 0 ? getAddress(pop(@parameters)) : -1;
|
|
|
+
|
|
|
+ # The amount of digits the opcode is expected to be when the parameter tries to add its parameter mode
|
|
|
+ my $parameterModeIdx = 2;
|
|
|
+
|
|
|
+ foreach my $param (@parameters)
|
|
|
{
|
|
|
- $opcode = length($opcode) < 3 ? "100$opcode" : "1$opcode";
|
|
|
+ if(isImmediate($param))
|
|
|
+ {
|
|
|
+ if(length($opcode) < $parameterModeIdx)
|
|
|
+ {
|
|
|
+ $opcode = "0$opcode";
|
|
|
+ }
|
|
|
+ $opcode = "1$opcode";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $param = getAddress($param);
|
|
|
+ }
|
|
|
+ $parameterModeIdx++;
|
|
|
+
|
|
|
+
|
|
|
+ $program[$$instructionNumber++] = $param;
|
|
|
+ if($$instructionNumber == 9)
|
|
|
+ {
|
|
|
+ print "$opcode, $param";
|
|
|
+ die "Overwriting memory!";
|
|
|
+ }
|
|
|
}
|
|
|
- else
|
|
|
+ # Insert opcode back where it belongs
|
|
|
+ $program[$opcodeIdx] = $opcode;
|
|
|
+ if($storeAt > -1)
|
|
|
{
|
|
|
- $operand2 = getAddress($parameters[1])
|
|
|
+ # Add the storeAt address
|
|
|
+ $program[$$instructionNumber++] = $storeAt;
|
|
|
}
|
|
|
-
|
|
|
- my $storeAt = getAddress($parameters[2]);
|
|
|
-
|
|
|
- $program[$instructionNumber++] = $opcode;
|
|
|
- $program[$instructionNumber++] = $operand1;
|
|
|
- $program[$instructionNumber++] = $operand2;
|
|
|
- $program[$instructionNumber++] = $storeAt;
|
|
|
}
|
|
|
|
|
|
# Check if a parameter is Immediate Mode or Position
|
|
@@ -114,12 +132,21 @@ sub parseOpcodeAndParams
|
|
|
# Parameter is considered Position mode if it's prefixed with "0d"
|
|
|
sub isImmediate
|
|
|
{
|
|
|
- return !(shift =~ /^0d/);
|
|
|
+ return shift =~ /^-?\d+$/;
|
|
|
}
|
|
|
|
|
|
+# Check if a parameter
|
|
|
+sub isLabel
|
|
|
+{
|
|
|
+ $_[0] =~ /(\w+?)(?:\s*+\s*\d*)?/;
|
|
|
+ print "Testing: $_[0]\n";
|
|
|
+ return !!$labels{$1};
|
|
|
+}
|
|
|
+
|
|
|
+# Get the address a value represents
|
|
|
sub getAddress
|
|
|
{
|
|
|
- return substr(shift, 2);
|
|
|
+ return (shift =~ s/^0d//r);
|
|
|
}
|
|
|
|
|
|
sub readFile
|
|
@@ -145,6 +172,4 @@ sub readFile
|
|
|
|
|
|
parseAssembly(readFile($ARGV[0]));
|
|
|
|
|
|
-print "[".join(",", @program)."]";
|
|
|
-
|
|
|
-print "\n";
|
|
|
+print "[".join(",", @program)."]\n";
|