mirror of
https://github.com/safiire/n65.git
synced 2025-03-03 01:30:07 +00:00
Added the ability to do arithmetic on symbolic names :)
This commit is contained in:
parent
21af1f0bf6
commit
6b387e20df
@ -46,7 +46,7 @@ module N65
|
|||||||
|
|
||||||
|
|
||||||
####
|
####
|
||||||
## Initialize with filename
|
## Initialize with a byte array
|
||||||
def initialize(bytes_array)
|
def initialize(bytes_array)
|
||||||
@bytes_array = bytes_array
|
@bytes_array = bytes_array
|
||||||
end
|
end
|
||||||
@ -62,7 +62,7 @@ module N65
|
|||||||
when Fixnum
|
when Fixnum
|
||||||
byte
|
byte
|
||||||
when String
|
when String
|
||||||
value = saved_assembler.symbol_table.resolve_symbol(byte)
|
saved_assembler.symbol_table.resolve_symbol(byte)
|
||||||
else
|
else
|
||||||
fail(InvalidByteValue, byte)
|
fail(InvalidByteValue, byte)
|
||||||
end
|
end
|
||||||
|
@ -6,28 +6,28 @@ module N65
|
|||||||
## All the regexes used to parse in one module
|
## All the regexes used to parse in one module
|
||||||
module Regexes
|
module Regexes
|
||||||
## Mnemonics
|
## Mnemonics
|
||||||
Mnemonic = '([A-Za-z]{3})'
|
Mnemonic = '([A-Za-z]{3})'
|
||||||
Branches = '(BPL|BMI|BVC|BVS|BCC|BCS|BNE|BEQ|bpl|bmi|bvc|bvs|bcc|bcs|bne|beq)'
|
Branches = '(BPL|BMI|BVC|BVS|BCC|BCS|BNE|BEQ|bpl|bmi|bvc|bvs|bcc|bcs|bne|beq)'
|
||||||
|
|
||||||
## Numeric Literals
|
## Numeric Literals
|
||||||
Hex8 = '\$([A-Fa-f0-9]{1,2})'
|
Hex8 = '\$([A-Fa-f0-9]{1,2})'
|
||||||
Hex16 = '\$([A-Fa-f0-9]{3,4})'
|
Hex16 = '\$([A-Fa-f0-9]{3,4})'
|
||||||
|
|
||||||
Bin8 = '%([01]{1,8})'
|
Bin8 = '%([01]{1,8})'
|
||||||
Bin16 = '%([01]{9,16})'
|
Bin16 = '%([01]{9,16})'
|
||||||
|
|
||||||
Num8 = Regexp.union(Regexp.new(Hex8), Regexp.new(Bin8)).to_s
|
Num8 = Regexp.union(Regexp.new(Hex8), Regexp.new(Bin8)).to_s
|
||||||
Num16 = Regexp.union(Regexp.new(Hex16),Regexp.new(Bin16)).to_s
|
Num16 = Regexp.union(Regexp.new(Hex16),Regexp.new(Bin16)).to_s
|
||||||
|
|
||||||
Immediate = "\##{Num8}"
|
Immediate = "\##{Num8}"
|
||||||
|
|
||||||
## Symbols, must begin with a letter, and supports dot syntax
|
## Symbols, must begin with a letter, and supports dot syntax
|
||||||
Sym = '([a-zA-Z][a-zA-Z\d_\.]*)'
|
Sym = '([a-zA-Z][a-zA-Z\d_\.]*(?:[\+\-\*\/]\d+)*)'
|
||||||
|
|
||||||
|
|
||||||
## The X or Y register
|
## The X or Y register
|
||||||
XReg = '[Xx]'
|
XReg = '[Xx]'
|
||||||
YReg = '[Yy]'
|
YReg = '[Yy]'
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -56,10 +56,30 @@ module N65
|
|||||||
|
|
||||||
|
|
||||||
####
|
####
|
||||||
##
|
## Separate arithmetic from scope name
|
||||||
|
def find_arithmetic(name)
|
||||||
|
last_name = name.split('.').last
|
||||||
|
md = last_name.match(/([\+\-\*\/])(\d+)$/)
|
||||||
|
f = lambda{|v| v}
|
||||||
|
|
||||||
|
unless md.nil?
|
||||||
|
full_match, operator, argument = md.to_a
|
||||||
|
name.gsub!(full_match, '')
|
||||||
|
f = lambda {|value| value.send(operator.to_sym, argument.to_i) }
|
||||||
|
end
|
||||||
|
|
||||||
|
[name, f]
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
####
|
||||||
|
## Resolve a symbol to its value
|
||||||
def resolve_symbol(name)
|
def resolve_symbol(name)
|
||||||
|
name, arithmetic = find_arithmetic(name)
|
||||||
|
|
||||||
method = name.include?('.') ? :resolve_symbol_dot_syntax : :resolve_symbol_scoped
|
method = name.include?('.') ? :resolve_symbol_dot_syntax : :resolve_symbol_scoped
|
||||||
value = self.send(method, name)
|
value = self.send(method, name)
|
||||||
|
value = arithmetic.call(value)
|
||||||
|
|
||||||
fail(UndefinedSymbol, name) if value.nil?
|
fail(UndefinedSymbol, name) if value.nil?
|
||||||
value
|
value
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
module N65
|
module N65
|
||||||
VERSION ||= "1.1.0"
|
VERSION ||= "1.5.0"
|
||||||
end
|
end
|
||||||
|
78
test/test_arithmetic_symbols.rb
Normal file
78
test/test_arithmetic_symbols.rb
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
gem 'minitest'
|
||||||
|
require 'minitest/autorun'
|
||||||
|
require 'minitest/unit'
|
||||||
|
|
||||||
|
require_relative '../lib/n65.rb'
|
||||||
|
|
||||||
|
|
||||||
|
class TestArithmeticSymbols < MiniTest::Test
|
||||||
|
include N65
|
||||||
|
|
||||||
|
|
||||||
|
def test_identify_plain_symbol
|
||||||
|
re = Regexp.new(Regexes::Sym)
|
||||||
|
assert_match(re, 'dog')
|
||||||
|
assert_match(re, 'animal.dog')
|
||||||
|
assert_match(re, 'global.animal.dog')
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def test_symbol_values
|
||||||
|
st = SymbolTable.new
|
||||||
|
st.define_symbol('variable', 0xff)
|
||||||
|
assert_equal(0xff, st.resolve_symbol('variable'))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def test_perform_symbolic_arithmetic
|
||||||
|
st = SymbolTable.new
|
||||||
|
st.define_symbol('variable', 0x20)
|
||||||
|
assert_equal(0x21, st.resolve_symbol('variable+1'))
|
||||||
|
assert_equal(0x40, st.resolve_symbol('variable*2'))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def test_symbol_addition
|
||||||
|
program = <<-ASM
|
||||||
|
.ines {"prog": 1, "char": 0, "mapper": 0, "mirror": 0}
|
||||||
|
|
||||||
|
.org $0020
|
||||||
|
.scope struct
|
||||||
|
.space a 1
|
||||||
|
.space b 1
|
||||||
|
.
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
.scope main
|
||||||
|
sei
|
||||||
|
cld
|
||||||
|
lda struct+1 zp
|
||||||
|
lda struct*2 zp
|
||||||
|
rts
|
||||||
|
.
|
||||||
|
ASM
|
||||||
|
|
||||||
|
assembler = Assembler.new
|
||||||
|
program.split(/\n/).each do |line|
|
||||||
|
assembler.assemble_one_line(line)
|
||||||
|
end
|
||||||
|
assembler.fulfill_promises
|
||||||
|
|
||||||
|
binary = assembler.emit_binary_rom[16...23].split(//).map(&:ord)
|
||||||
|
|
||||||
|
## So yay, arithmetic on symbols works now :)
|
||||||
|
correct = [
|
||||||
|
0x78, # sei
|
||||||
|
0xd8, # cld
|
||||||
|
0xa5, # lda
|
||||||
|
0x21, # $20 + 1
|
||||||
|
0xa5, # lda
|
||||||
|
0x40, # $20 * 2
|
||||||
|
0x60 # rts
|
||||||
|
]
|
||||||
|
assert_equal(binary, correct)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
@ -74,7 +74,7 @@ class TestSymbolTable < MiniTest::Test
|
|||||||
|
|
||||||
####
|
####
|
||||||
## Test exiting a sub scope, and being able to access a symbol through a full path
|
## Test exiting a sub scope, and being able to access a symbol through a full path
|
||||||
def test_exit_scope
|
def test_exit_scope_full_path
|
||||||
st = SymbolTable.new
|
st = SymbolTable.new
|
||||||
st.enter_scope('animals')
|
st.enter_scope('animals')
|
||||||
st.define_symbol('dog', 'woof')
|
st.define_symbol('dog', 'woof')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user