1 Star 0 Fork 0

艾克斯可乐棒/OriMachine

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
om1-assembler.rb 13.48 KB
一键复制 编辑 原始数据 按行查看 历史
艾克斯可乐棒 提交于 2022-03-22 15:10 +08:00 . first
#om1-assembly
class Symbol_table_extra
attr_accessor :offset, :update
def initialize(offset = -1, update = true)
@offset = offset
@update = update
end
end
class Assembler
attr_reader :machine_code, :error_list, :offset
@@GLOBAL_ARGS = {
:parse_add => 1, :parse_ld => 1, :parse_ldi => 1, :parse_st => 1, :parse_jmp => 1,
:parse_bre => 2, :parse_brn => 2, :parse_brp => 2, :parse_br_ => 2, :parse_halt => 0,
:parse_push => 0, :parse_pop => 0, :parse_jsr => 1, :parse_occu => 1, :parse_fill => 1
}
def initialize
#assembler information
@line = 1
@offset = 0
@symbol_table = {}
@error_list = []
#run-time information
@state = :parse_start
#destination file
@machine_code = []
end
#assembling ...
def assemble(code)
code.each_line do |instr|
args = 0
pre_cmt_state = nil
@state = :parse_start
instr.split(' ').each do |word|
#puts "#{@line} / #{@offset} : #{word} - #{@state}"
case word
when 'add'
if @state != :parse_start
@error_list << "#{@line} : more operations in one instruction"
@machine_code << :ei
@state = :parse_exception
else
@machine_code << 0x00
@state = :parse_add
end
when 'ld'
if @state != :parse_start
@error_list << "#{@line} : more operations in one instruction"
@machine_code << :ei
@state = :parse_exception
else
@machine_code << 0x01
@state = :parse_ld
end
when 'ldi'
if @state != :parse_start
@error_list << "#{@line} : more operations in one instruction"
@machine_code << :ei
@state = :parse_exception
else
@machine_code << 0x02
@state = :parse_ldi
end
when 'st'
if @state != :parse_start
@error_list << "#{@line} : more operations in one instruction"
@machine_code << :ei
@state = :parse_exception
else
@machine_code << 0x03
@state = :parse_st
end
when 'jmp'
if @state != :parse_start
@error_list << "#{@line} : more operations in one instruction"
@machine_code << :ei
@state = :parse_exception
else
@machine_code << 0x04
@state = :parse_jmp
end
when 'bre'
if @state != :parse_start
@error_list << "#{@line} : more operations in one instruction"
@machine_code << :ei
@state = :parse_exception
else
@machine_code << 0x05
@state = :parse_bre
end
when 'brn'
if @state != :parse_start
@error_list << "#{@line} : more operations in one instruction"
@machine_code << :ei
@state = :parse_exception
else
@machine_code << 0x06
@state = :parse_brn
end
when 'brp'
if @state != :parse_start
@error_list << "#{@line} : more operations in one instruction"
@machine_code << :ei
@state = :parse_exception
else
@machine_code << 0x07
@state = :parse_brp
end
when 'halt'
if @state != :parse_start
@error_list << "#{@line} : more operations in one instruction"
@machine_code << :ei
@state = :parse_exception
else
@machine_code << 0x08
@state = :parse_halt
end
when 'push'
if @state != :parse_start
@error_list << "#{@line} : more operations in one instruction"
@machine_code << :ei
@state = :parse_exception
else
@machine_code << 0x09
@state = :parse_push
end
when 'pop'
if @state != :parse_start
@error_list << "#{@line} : more operations in one instruction"
@machine_code << :ei
@state = :parse_exception
else
@machine_code << 0x0a
@state = :parse_pop
end
when 'jsr'
if @state != :parse_start
@error_list << "#{@line} : more operations in one instruction"
@machine_code << :ei
@state = :parse_exception
else
@machine_code << 0x0b
@state = :parse_jsr
end
when '>'
if @state != :parse_start
@error_list << "#{@line} : more operations in one instruction"
@machine_code << :ei
@state = :parse_exception
else
@state = :parse_fill
end
when '@'
if @state != :parse_start
@error_list << "#{@line} : more operations in one instruction"
@machine_code << :ei
@state = :parse_exception
else
@state = :parse_occu
end
when /;.*/
break
when /:.*/
@symbol_table[word[1..-1]] = Symbol_table_extra.new(-1, true) unless @symbol_table[word[1..-1]]
pre = @symbol_table[word[1..-1]].offset
while pre != -1
tmp = @machine_code[pre]
@machine_code[pre] = @offset
pre = tmp
end
@symbol_table[word[1..-1]].offset = @offset
@symbol_table[word[1..-1]].update = false
@offset -= 1 # pseudo instruction doesn't occupy memory space
else
#enumeric = word.to_i
case @state
when :parse_comment
# deal_with comment ...
when :parse_fill
if isEnglish(word)
@error_list << "#{@line} : fill > arg must be numeric"
@machine_code << :ef
@state = :parse_exception
else
@machine_code << (word.to_i > 0 ? word.to_i : word.to_i & 0xff)
@offset -= 1
end
when :parse_occu
if isEnglish(word)
@error_list << "#{@line} : occu @ arg must be numeric"
@machine_code << :eoa
@state = :parse_exception
else
occu_len = word.to_i
#raise "dup must more than 0" if word.to_i <= 0
if occu_len <= 0
@error_list << "#{@line} : occu @ must more than 1 space"
@machine_code << :eon
else
occu_len.times { @machine_code << 0 }
@offset += occu_len - 1
end
end
when :parse_ldi, :parse_add
if isEnglish(word)
@error_list << "#{@line} : can't use symbol in instr_add or instr_ldi"
@machine_code << :ef
@state = :parse_exception
else
@machine_code << (word.to_i > 0 ? word.to_i : word.to_i & 0xff)
end
when :parse_ld, :parse_st, :parse_jmp, :parse_br_, :parse_jsr
if isEnglish(word)
@symbol_table[word] = Symbol_table_extra.new(-1, true) unless @symbol_table[word]
@machine_code << @symbol_table[word].offset
@symbol_table[word].offset = @offset if @symbol_table[word].update
else
if word.to_i < 0
@error_list << "#{@line} : oprand can't be negtive"
@machine_code << :enn
else
@machine_code << word.to_i
end
end
when :parse_bre, :parse_brn, :parse_brp
@machine_code << (word.to_i > 0 ? word.to_i : word.to_i & 0xff)
end
@state = :parse_br_ if (@state == :parse_bre) || (@state == :parse_brn) || (@state == :parse_brp)
args += 1
end
@offset += 1
end
unless @state == :parse_start || @state == :parse_exception
@error_list << "#{@line} : much_args" if args > @@GLOBAL_ARGS[@state]
@error_list << "#{@line} : less_args" if args < @@GLOBAL_ARGS[@state]
end
@line += 1
end
@symbol_table.each { |k, v| @error_list << "can't find label <#{k}>" if v.update }
return @error_list.empty?
end
#check the token whether a numeric or a symbol
def isEnglish(word)
state = :start
word.each_char do |ch|
case state
when :start
case ch
when '-', '0'..'9'
state = :digit
else
state = :else
end
when :digit
state = ('0' <= ch && ch <= '9') ? :digit : :else
end
end
return (state == :digit) ? false : true
end
end
class Receiver
attr_reader :src_file, :des_file, :code
def initialize
@src_file = ""
@des_file = ""
@code = ""
end
def get_name_of_files
state = :rcv_start
ARGV.each do |arg|
case arg
when '-o'
state = :rcv_o
when '-s'
state = :rcv_s
else
case state
when :rcv_start
puts "invalid arguments #{arg}"
return false
when :rcv_o
@des_file = arg
when :rcv_s
if File.file? arg
@src_file = arg
else
puts "no such file #{arg}"
return false
end
end
end
end
return !(@src_file.empty? || @des_file.empty?)
end
def get_content
File.open(@src_file, "r") do |file|
file.each { |line| @code << line }
end
end
def output_file(machine_code)
machine_code.unshift(machine_code.length)
# i know where the problem there
# in c program, file-io has two way to write "\n" to file
# one way is only write "\n"
# and another is no only write "\n", and also "\r"
# yes, the "\r" is just 0x0D
# it's soooooo strange ...
# in text mode, you write "\n" as "\r\n"
# in bin mode, you write "\n" just as "\n"
IO.binwrite(@des_file, machine_code.pack('C*'))
end
end
rcv = Receiver.new ; assembler = Assembler.new
puts "+ geting source code ... "
return unless rcv.get_name_of_files ; rcv.get_content
puts "+ assembling ... "
if assembler.assemble(rcv.code)
rcv.output_file(assembler.machine_code)
puts "+ done (#{assembler.machine_code.length} bytes) ... "
print "\n+ machine_code : \n", assembler.machine_code
else
puts "\n+ assembler failure : error (#{assembler.error_list.length})"
assembler.error_list.each { |e| puts '+--> ' + e }
end
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/aikesikelebang/ori-machine.git
git@gitee.com:aikesikelebang/ori-machine.git
aikesikelebang
ori-machine
OriMachine
master

搜索帮助