Files

82 lines
2.1 KiB
Ruby

# dump machine code
require_relative "ast-def"
require_relative "machine"
def dump_seq(seq)
seq.each_cons(2) do |insn1, insn2|
if insn1.is_a?(IPush) && insn2.is_a?(IPush)
p insn1, insn2
raise "consecutive push"
end
end
seq.map do |insn|
case insn
when IRead then (REGISTER_READ + insn.var.ord - ?a.ord).chr if insn.var
when IWrite then (REGISTER_WRITE + insn.var.ord - ?a.ord).chr if insn.var
when IInc then MNEMONIC[:Inc] + (REGISTER_READ + insn.var.ord - ?a.ord).chr
when IDec then MNEMONIC[:Dec] + (REGISTER_READ + insn.var.ord - ?a.ord).chr
when IPush then encode_number(insn.num)
when IBranch
MNEMONIC[:BranchS] + dump_seq(insn.s1) +
MNEMONIC[:BranchM] + dump_seq(insn.s2) +
MNEMONIC[:BranchE]
when ILoop
MNEMONIC[:LoopS] + dump_seq(insn.s1) +
MNEMONIC[:LoopM] + dump_seq(insn.s2) +
MNEMONIC[:LoopE]
when IBinary then MNEMONIC[insn.op]
when ITest then MNEMONIC[:Test]
when IARef then MNEMONIC[:ARef]
when IOut then MNEMONIC[:Out]
when IExit then MNEMONIC[:Exit]
when IASet then MNEMONIC[:ASet]
end
end.join
end
def check_opt_inc_dec(seq, i)
return unless seq[i].is_a?(IRead)
return unless seq[i + 1] == IPush[1]
return unless seq[i + 2] == IBinary[:+] || seq[i + 2] == IBinary[:-]
return unless seq[i + 3] == IWrite[seq[i].var]
insn = (seq[i + 2].op == :+ ? IInc : IDec)[seq[i].var]
flag = seq[i + 4].is_a?(IRead) && seq[i + 4].var == seq[i].var
[insn, seq[i].var, flag]
end
def opt_inc_dec(seq)
while true
modified = false
(seq.size - 3).times do |i|
new_insn, var, flag = check_opt_inc_dec(seq, i)
if new_insn
if flag
seq[i, 5] = [new_insn]
else
seq[i, 4] = [new_insn, IWrite[var]]
end
modified = true
end
end
break if !modified
end
seq.each do |insn|
case insn
when IBranch, ILoop
opt_inc_dec(insn.s1)
opt_inc_dec(insn.s2)
end
end
end
if ARGV.size != 2
puts "usage: #$0 <seq3.txt> <raw.txt>"
else
seq = eval(File.read(ARGV[0]))
opt_inc_dec(seq)
File.write(ARGV[1], dump_seq(seq))
end