Class: MicroCisc::Compile::Statement
- Inherits:
-
Object
- Object
- MicroCisc::Compile::Statement
- Defined in:
- lib/micro_cisc/compile/statement.rb
Constant Summary collapse
- SUGAR_REGEX =
/(?<names>(\$|&)[^\s\[\]]+(\s*,\s*(\$|&)[^\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 =
/ (?<imm_val>-{0,1}(0x){0,1}[0-9A-Fa-f])\.imm/
Instance Attribute Summary collapse
-
#minimal ⇒ Object
readonly
Returns the value of attribute minimal.
-
#original ⇒ Object
readonly
Returns the value of attribute original.
Instance Method Summary collapse
- #create_equivalent(name, arg, delta) ⇒ Object
- #create_variable(name, arg, delta) ⇒ Object
- #filter_comments(instruction) ⇒ Object
- #get_var(name) ⇒ Object
-
#initialize(label_generator, statement, indexed_vars, equivalents) ⇒ Statement
constructor
A new instance of Statement.
- #normalize(arg, delta) ⇒ Object
- #parse ⇒ Object
- #parse_function_call ⇒ Object
- #update_variable(arg, delta) ⇒ Object
Constructor Details
#initialize(label_generator, statement, indexed_vars, equivalents) ⇒ Statement
Returns a new instance of Statement.
9 10 11 12 13 14 15 |
# File 'lib/micro_cisc/compile/statement.rb', line 9 def initialize(label_generator, statement, indexed_vars, equivalents) @label_generator = label_generator @original = statement @minimal = filter_comments(statement) @indexed_vars = indexed_vars @equivalents = equivalents end |
Instance Attribute Details
#minimal ⇒ Object (readonly)
Returns the value of attribute minimal.
7 8 9 |
# File 'lib/micro_cisc/compile/statement.rb', line 7 def minimal @minimal end |
#original ⇒ Object (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_equivalent(name, arg, delta) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/micro_cisc/compile/statement.rb', line 54 def create_equivalent(name, arg, delta) arg = normalize(arg, delta) if arg.first.include?("mem") || arg.first.include?("reg") imm_val = arg.last # remove mem/reg part arg_num = arg[0][0..-4] name = name[1..-1] mem_name = "$#{name}" ref_name = "&#{name}" @indexed_vars.delete(mem_name) @indexed_vars.delete(ref_name) imm_str = " #{imm_val}.imm" if imm_val > 0 @equivalents[mem_name] = "#{arg_num}mem#{imm_str}" @equivalents[ref_name] = "#{arg_num}reg#{imm_str}" else @indexed_vars.delete(name) @equivalents[name] = arg.first end end |
#create_variable(name, arg, delta) ⇒ Object
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/micro_cisc/compile/statement.rb', line 35 def create_variable(name, arg, delta) unless arg.include?("mem") || arg.include?("reg") raise ArgumentError, "Indexed variable reference is not allowed for non-register arguments, use 'as' instead" end arg = normalize(arg, delta) imm_val = arg.last # remove mem/reg part arg_num = arg.first[0..-4] name = name[1..-1] mem_name = "$#{name}" ref_name = "&#{name}" @equivalents.delete(mem_name) @equivalents.delete(ref_name) @indexed_vars[mem_name] = ["#{arg_num}mem", imm_val] @indexed_vars[ref_name] = ["#{arg_num}reg", imm_val] end |
#filter_comments(instruction) ⇒ Object
17 18 19 20 21 22 23 24 25 26 |
# File 'lib/micro_cisc/compile/statement.rb', line 17 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 |
#get_var(name) ⇒ Object
86 87 88 89 90 91 92 93 94 |
# File 'lib/micro_cisc/compile/statement.rb', line 86 def get_var(name) val = @equivalents[name] val ||= begin pair = @indexed_vars[name] "#{pair.first} #{pair.last}.imm" if pair end val || name end |
#normalize(arg, delta) ⇒ Object
28 29 30 31 32 33 |
# File 'lib/micro_cisc/compile/statement.rb', line 28 def normalize(arg, delta) imm_matches = arg.scan(IMM_REGEX).flatten imm_val = imm_matches.map(&:to_i).sum + delta arg = arg.gsub(IMM_REGEX, '').strip [arg, imm_val] end |
#parse ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/micro_cisc/compile/statement.rb', line 96 def parse instruction = nil names = [] op = nil if FUNCTION_REGEX =~ @minimal return parse_function_call elsif SUGAR_REGEX =~ @minimal match = SUGAR_REGEX.match(@minimal) op = match['op'] names = match['names'].split(',').map(&:strip) @minimal = match['param'] if minimal.start_with?('copy') || minimal.start_with?('compute') instruction = Instruction.new(@label_generator, @minimal, original, self) else var = match['param'] imm_match = IMM_REGEX.match(var) imm_val = imm_match ? imm_match['imm_val'].to_i : 0 var = var.to_s.gsub(IMM_REGEX, '').strip @minimal = "#{get_var(var)}#{" #{imm_val}.imm" if imm_val != 0}" end else instruction = Instruction.new(@label_generator, @minimal, original, self) end if instruction && instruction.instruction? dest = instruction.dest if instruction.inc && instruction.inc > 0 if dest > 4 # pop update_variable("#{dest - 4}.mem", -1) else # push update_variable("#{dest}.mem", 1) end end if minimal.start_with?('copy') && dest > 4 && instruction.src == dest # Manually modifying a register update_variable("#{dest - 4}.mem", -1 * instruction.immediates.first) end dest -= 4 if dest > 4 @minimal = "#{dest}.mem" end names.each_with_index do |name, index| if op == 'as' create_equivalent(name, @minimal, index) elsif op == '=' create_variable(name, @minimal, index) end end [instruction].compact end |
#parse_function_call ⇒ Object
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/micro_cisc/compile/statement.rb', line 148 def parse_function_call match = FUNCTION_REGEX.match(@minimal) label = match['label'] stack = match['stack'] stack = get_var(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}", self) end instruction = "copy 0.reg #{args.size + 2}.imm #{stack} push" instructions << Instruction.new(@label_generator, instruction, " #{instruction} # return addr - #{original}", self) stack_delta = 1 + return_words args = args.each do |arg| arg = arg.split(' ').map { |a| get_var(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}", self) end instruction = "copy 0.reg #{label}.disp 0.reg" instructions << Instruction.new(@label_generator, instruction, " #{instruction} # call - #{original}", self) if return_words > 0 update_variable(stack, return_words) end instructions end |
#update_variable(arg, delta) ⇒ Object
76 77 78 79 80 81 82 83 84 |
# File 'lib/micro_cisc/compile/statement.rb', line 76 def update_variable(arg, delta) arg = arg.sub('reg', 'mem') ['mem', 'reg'].each do |type| variable = arg.sub('mem', type) @indexed_vars.each do |name, value| value[1] += delta if value.first == variable end end end |