yaict.pl 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #!/bin/perl
  2. use warnings;
  3. use strict;
  4. use Data::Dumper;
  5. my $VERSION = 0.01;
  6. # The array of intcodes making up the program
  7. my @program;
  8. # Opcodes that may be encounted and their corresponding ints
  9. my %opcodes = (
  10. "add" => "01",
  11. "mult" => "02",
  12. "in" => "03",
  13. "out" => "04",
  14. "jpt" => "05",
  15. "jpf" => "06",
  16. "lt" => "07",
  17. "eq" => "08",
  18. "mrb" => "09",
  19. "hlt" => "99",
  20. );
  21. # Additional instructions that don't correspond to opcodes but need to be processed
  22. # my %instructions = (
  23. # # Load
  24. # "ld" => \&load,
  25. # );
  26. # Load a value into a memory address
  27. sub load
  28. {
  29. my $loadAddress = shift;
  30. my $valueToLoad = shift;
  31. $program[$loadAddress] = $valueToLoad;
  32. }
  33. # Parse the assembly to IntCode
  34. sub parseAssembly
  35. {
  36. my @assembly = @_;
  37. # A hash of labels and their corresponding starting line number
  38. my %labels;
  39. # The current instruction number
  40. my $instructionNumber = 0;
  41. foreach my $line (@assembly)
  42. {
  43. $line =~ /^(\w+?:?)(?: (.+))?$/;
  44. my $asmInstruction = $1;
  45. my @parameters = split(/,\s?/, $2 || "");
  46. # Store labels by the address of their next instruction
  47. if($asmInstruction =~ /:$/)
  48. {
  49. $labels{substr($asmInstruction, 0, -1)} = ++$instructionNumber;
  50. next;
  51. }
  52. if($asmInstruction eq "ld")
  53. {
  54. my $storeAt = getAddress(shift @parameters);
  55. my $value = shift @parameters;
  56. load($storeAt, $value);
  57. }
  58. elsif($opcodes{$asmInstruction})
  59. {
  60. parseOpcodeAndParams($opcodes{$asmInstruction}, \@parameters);
  61. }
  62. else
  63. {
  64. die "Failed to find matching ASM instruction for: $asmInstruction";
  65. }
  66. }
  67. }
  68. # TODO
  69. sub parseOpcodeAndParams
  70. {
  71. my $opcode = $_[0];
  72. my @parameters = @{ $_[1] };
  73. my $operand1 = $parameters[0];
  74. if(isImmediate($parameters[0]))
  75. {
  76. $opcode = length($opcode) == 1 ? "10$opcode" : "1$opcode";
  77. }
  78. else
  79. {
  80. $operand1 = getAddress($parameters[0])
  81. }
  82. my $operand2 = $parameters[1];
  83. if(isImmediate($parameters[1]))
  84. {
  85. $opcode = length($opcode) < 3 ? "100$opcode" : "1$opcode";
  86. }
  87. else
  88. {
  89. $operand2 = getAddress($parameters[1])
  90. }
  91. my $storeAt = getAddress($parameters[2]);
  92. $program[$instructionNumber++] = $opcode;
  93. $program[$instructionNumber++] = $operand1;
  94. $program[$instructionNumber++] = $operand2;
  95. $program[$instructionNumber++] = $storeAt;
  96. }
  97. # Check if a parameter is Immediate Mode or Position
  98. #
  99. # Parameter is considered Position mode if it's prefixed with "0d"
  100. sub isImmediate
  101. {
  102. return !(shift =~ /^0d/);
  103. }
  104. sub getAddress
  105. {
  106. return (shift =~ s/^0d//r);
  107. }
  108. sub readFile
  109. {
  110. my @assembly;
  111. my $filePath = shift;
  112. open(my $fh, "<", $filePath) or die "Failed to open file";
  113. while(my $line = <$fh>)
  114. {
  115. chomp $line;
  116. # Remove comments from the line
  117. $line =~ s/\/\/.+$//;
  118. # Remove trailing whitespace
  119. $line =~ s/\s+$//;
  120. if ($line ne "") {
  121. push(@assembly, $line);
  122. }
  123. }
  124. return @assembly;
  125. }
  126. parseAssembly(readFile($ARGV[0]));
  127. print "[".join(",", @program)."]\n";