123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- #!/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";
|