Class: MicroCisc::Compile::Statement

Inherits:
Object
  • Object
show all
Defined in:
lib/micro_cisc/compile/statement.rb

Constant Summary collapse

SUGAR_REGEX =
/(?<name>(\$|&)[^\s\[\]]+)\s+(?<op>as|=)\s+(?<param>.+)/
FUNCTION_REGEX =
/(?<stack>[^\s\[\]]+)\s*(\[(?<words>[0-9]+)\]){0,1}\s+<=\s+(?<label>[a-zA-Z_][a-zA-Z0-9_\-@$!%]*)\s*\(\s*(?<args>[^)]*)/
IMM_REGEX =
/ (0x){0,1}(?<imm_val>[0-9A-Fa-f])\.imm/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(label_generator, statement, sugar) ⇒ Statement

Returns a new instance of Statement.



9
10
11
12
13
14
# File 'lib/micro_cisc/compile/statement.rb', line 9

def initialize(label_generator, statement, sugar)
  @label_generator = label_generator
  @original = statement
  @minimal = filter_comments(statement)
  @sugar = sugar
end

Instance Attribute Details

#minimalObject (readonly)

Returns the value of attribute minimal.



7
8
9
# File 'lib/micro_cisc/compile/statement.rb', line 7

def minimal
  @minimal
end

#originalObject (readonly)

Returns the value of attribute original.



7
8
9
# File 'lib/micro_cisc/compile/statement.rb', line 7

def original
  @original
end

Instance Method Details

#create_variable(name, arg) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
# File 'lib/micro_cisc/compile/statement.rb', line 27

def create_variable(name, arg)
  if arg.end_with?("mem") || arg.end_with?("reg")
    name = name[1..-1]
    arg = arg[0..-4]

    @sugar["$#{name}"] = "#{arg}mem"
    @sugar["&#{name}"] = "#{arg}reg"
  else
    @sugar[name] = arg
  end
end

#filter_comments(instruction) ⇒ Object



16
17
18
19
20
21
22
23
24
25
# File 'lib/micro_cisc/compile/statement.rb', line 16

def filter_comments(instruction)
  # Remove all inline comments
  instruction = instruction.to_s.strip.gsub(/\/[^\/]*\//, '')
  # Remove all word comments
  instruction = instruction.gsub(/'[^\s]*/, '')
  # Remove all line comments
  instruction = instruction.gsub(/#.*/, '')
  # Single space
  instruction.gsub(/\s+/, ' ')
end

#parseObject



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/micro_cisc/compile/statement.rb', line 39

def parse
  if FUNCTION_REGEX =~ @minimal
    parse_function_call
  elsif SUGAR_REGEX =~ @minimal
    match = SUGAR_REGEX.match(@minimal)
    name = match['name']
    if match['op'] == 'as'
      create_variable(name, match['param'])
      []
    elsif match['op'] == '='
      @minimal = match['param']
      instruction = Instruction.new(@label_generator, minimal, original, @sugar)
      dest = instruction.dest
      if [1, 2, 3].include?(dest)
        create_variable(name, "#{dest}.mem")
      else
        dest -= 4 if dest > 4
        create_variable(name, "#{dest}.reg")
      end
      [instruction]
    else
      raise ArgumentError, "Invalid syntax declaration: #{@minimal}"
    end
  else
    [Instruction.new(@label_generator, @minimal, original, @sugar)]
  end
end

#parse_function_callObject

Raises:

  • (ArgumentError)


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/micro_cisc/compile/statement.rb', line 67

def parse_function_call
  match = FUNCTION_REGEX.match(@minimal)
  label = match['label']

  stack = match['stack']
  stack = @sugar[stack] if @sugar[stack]
  raise ArgumentError, "Invalid stack param, mem register expected: #{stack}" unless stack =~ /^[1-3]\.mem$/
  stackp = stack.sub('mem', 'reg')

  return_words = match['words'].to_i
  args = match['args'].split(',').map(&:strip)

  instructions = []
  if return_words > 0
    instruction = "copy #{stackp} -#{return_words}.imm #{stackp}"
    instructions << Instruction.new(@label_generator, instruction, "  #{instruction} # return vars - #{original}", @sugar)
  end

  instruction = "copy 0.reg #{args.size + 2}.imm #{stack} push"
  instructions << Instruction.new(@label_generator, instruction, "  #{instruction} # return addr - #{original}", @sugar)

  stack_delta = 1 + return_words
  args = args.each do |arg|
    arg = arg.split(' ').map { |a| @sugar[a] || a }.join(' ')
    is_stack = arg.start_with?(stack)
    if is_stack
      offset = stack_delta
      if arg_imm = IMM_REGEX.match(arg)
        arg_imm = arg_imm['imm_val'].to_i(16)
        arg = arg.sub(IMM_REGEX, '')
      else
        arg_imm = 0
      end
      offset_immediate = (offset + arg_imm) > 0 ? " #{(offset + arg_imm)}.imm" : ''
      arg = "#{arg}#{offset_immediate}"
    end
    instruction = "copy #{arg} #{stack} push"
    stack_delta += 1
    instructions << Instruction.new(@label_generator, instruction, "  #{instruction} # push arg - #{original}", @sugar)
  end
  instruction = "copy 0.reg #{label}.disp 0.reg"
  instructions << Instruction.new(@label_generator, instruction, "  #{instruction} # call - #{original}", @sugar)
  instructions
end