#!/bin/perl use warnings; use strict; use Data::Dumper; my $VERSION = 0.01; # The array of intcodes making up the program my @program; # Opcodes that may be encounted and their corresponding ints my %opcodes = ( "add" => "01", "mult" => "02", "in" => "03", "out" => "04", "jpt" => "05", "jpf" => "06", "lt" => "07", "eq" => "08", "mrb" => "09", "hlt" => "99", ); # Additional instructions that don't correspond to opcodes but need to be processed # my %instructions = ( # # Load # "ld" => \&load, # ); # Load a value into a memory address sub load { my $loadAddress = shift; my $valueToLoad = shift; $program[$loadAddress] = $valueToLoad; } # Parse the assembly to IntCode sub parseAssembly { my @assembly = @_; # A hash of labels and their corresponding starting line number my %labels; # The current instruction number my $instructionNumber = 0; foreach my $line (@assembly) { $line =~ /^(\w+?:?)(?: (.+))?$/; my $asmInstruction = $1; my @parameters = split(/,\s?/, $2 || ""); # Store labels by the address of their next instruction if($asmInstruction =~ /:$/) { $labels{substr($asmInstruction, 0, -1)} = ++$instructionNumber; next; } if($asmInstruction eq "ld") { my $storeAt = getAddress(shift @parameters); my $value = shift @parameters; load($storeAt, $value); } elsif($opcodes{$asmInstruction}) { parseOpcodeAndParams($opcodes{$asmInstruction}, \@parameters); } else { die "Failed to find matching ASM instruction for: $asmInstruction"; } } } # TODO sub parseOpcodeAndParams { my $opcode = $_[0]; 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])) { $opcode = length($opcode) < 3 ? "100$opcode" : "1$opcode"; } else { $operand2 = getAddress($parameters[1]) } 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 # # Parameter is considered Position mode if it's prefixed with "0d" sub isImmediate { return !(shift =~ /^0d/); } sub getAddress { return (shift =~ s/^0d//r); } sub readFile { my @assembly; my $filePath = shift; open(my $fh, "<", $filePath) or die "Failed to open file"; while(my $line = <$fh>) { chomp $line; # Remove comments from the line $line =~ s/\/\/.+$//; # Remove trailing whitespace $line =~ s/\s+$//; if ($line ne "") { push(@assembly, $line); } } return @assembly; } parseAssembly(readFile($ARGV[0])); print "[".join(",", @program)."]\n";