Class: Spitewaste::SpitewasteParser

Inherits:
Object
  • Object
show all
Defined in:
lib/spitewaste/parsers/spitewaste.rb

Constant Summary collapse

NameError =
Class.new Exception
INSTRUCTIONS =
/(\S+):|(\b(#{OPERATORS_M2T.keys * ?|})\s+(-?\d\S*)?)/
SPECIAL_INSN =
/(call|jump|jz|jn)\s+(\S+)/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(program, **options) ⇒ SpitewasteParser

Returns a new instance of SpitewasteParser.



16
17
18
19
20
21
22
23
# File 'lib/spitewaste/parsers/spitewaste.rb', line 16

def initialize program, **options
  @src = program.dup
  @macros = {}
  @symbol_file = options['symbol_file']

  preprocess!
  eliminate_dead_code! unless options[:keep_dead_code]
end

Instance Attribute Details

#errorObject (readonly)

Returns the value of attribute error.



14
15
16
# File 'lib/spitewaste/parsers/spitewaste.rb', line 14

def error
  @error
end

#instructionsObject (readonly)

Returns the value of attribute instructions.



14
15
16
# File 'lib/spitewaste/parsers/spitewaste.rb', line 14

def instructions
  @instructions
end

#srcObject (readonly)

Returns the value of attribute src.



14
15
16
# File 'lib/spitewaste/parsers/spitewaste.rb', line 14

def src
  @src
end

#symbol_tableObject (readonly)

Returns the value of attribute symbol_table.



14
15
16
# File 'lib/spitewaste/parsers/spitewaste.rb', line 14

def symbol_table
  @symbol_table
end

Instance Method Details

#parseObject



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/spitewaste/parsers/spitewaste.rb', line 25

def parse
  @instructions = []

  # first-come, first-served mapping from label names to auto-incrementing
  # indices starting from 0; it would be nice if names could round-trip,
  # but even encoding short ones would result in unpleasantly wide code.
  @symbol_table = Hash.new { |h, k| h[k] = h.size }
  @src.scan(/(\S+):/) { @symbol_table[$1] } # populate label indices
  File.write @symbol_file, @symbol_table.to_json if @symbol_file

  special = @src.scan SPECIAL_INSN
  @src.scan INSTRUCTIONS do |label, _, operator, arg|
    next @instructions << [:label, @symbol_table[label]] if label

    if %i[call jump jz jn].include? operator = operator.to_sym
      arg = @symbol_table[special.shift[1]]
    else
      if OPERATORS_M2T.keys.index(operator) < 8 && !arg
        raise "missing arg for #{operator}"
      elsif arg
        begin
          arg = Integer arg
        rescue ArgumentError
          raise "invalid argument '#{arg}' for #{operator}"
        end
      end
    end

    @instructions << [operator, arg]
  end
end