lift the nodes out of the parser

This commit is contained in:
Torsten Ruger 2014-04-16 12:03:39 +03:00
parent 1564f9b439
commit 69b0f7a0e3
8 changed files with 103 additions and 89 deletions

View File

@ -50,7 +50,7 @@ module Asm
# Build representation for source value # Build representation for source value
def build_operand(arg) def build_operand(arg)
if (arg.is_a?(Asm::Parser::NumLiteralArgNode)) if (arg.is_a?(Asm::NumLiteralArgNode))
if (arg.value.fits_u8?) if (arg.value.fits_u8?)
# no shifting needed # no shifting needed
@operand = arg.value @operand = arg.value
@ -61,10 +61,10 @@ module Asm
else else
raise Asm::AssemblyError.new(Asm::ERRSTR_NUMERIC_TOO_LARGE, arg) raise Asm::AssemblyError.new(Asm::ERRSTR_NUMERIC_TOO_LARGE, arg)
end end
elsif (arg.is_a?(Asm::Parser::RegisterArgNode)) elsif (arg.is_a?(Asm::RegisterArgNode))
@operand = reg_ref(arg) @operand = reg_ref(arg)
@i = 0 @i = 0
elsif (arg.is_a?(Asm::Parser::ShiftNode)) elsif (arg.is_a?(Asm::ShiftNode))
rm_ref = reg_ref(arg.argument) rm_ref = reg_ref(arg.argument)
@i = 0 @i = 0
shift_op = {'lsl' => 0b000, 'lsr' => 0b010, 'asr' => 0b100, shift_op = {'lsl' => 0b000, 'lsr' => 0b010, 'asr' => 0b100,
@ -75,12 +75,12 @@ module Asm
end end
arg1 = arg.value arg1 = arg.value
if (arg1.is_a?(Asm::Parser::NumLiteralArgNode)) if (arg1.is_a?(Asm::NumLiteralArgNode))
if (arg1.value >= 32) if (arg1.value >= 32)
raise Asm::AssemblyError.new('cannot shift by more than 31', arg1) raise Asm::AssemblyError.new('cannot shift by more than 31', arg1)
end end
shift_imm = arg1.value shift_imm = arg1.value
elsif (arg1.is_a?(Asm::Parser::RegisterArgNode)) elsif (arg1.is_a?(Asm::RegisterArgNode))
shift_op |= 0x1; shift_op |= 0x1;
shift_imm = reg_ref(arg1) << 1 shift_imm = reg_ref(arg1) << 1
elsif (arg.type == 'rrx') elsif (arg.type == 'rrx')

View File

@ -31,13 +31,13 @@ module Asm
a a
end end
class MathReferenceArgNode < Asm::Parser::ReferenceArgNode class MathReferenceArgNode < Asm::ReferenceArgNode
attr_accessor :op, :right attr_accessor :op, :right
end end
def simplify_reference(arg) def simplify_reference(arg)
node = MathReferenceArgNode.new node = MathReferenceArgNode.new
if (arg.is_a?(Asm::Parser::MathNode)) if (arg.is_a?(Asm::MathNode))
node.argument = arg.left node.argument = arg.left
node.op = arg.op node.op = arg.op
node.right = arg.right node.right = arg.right
@ -50,17 +50,17 @@ module Asm
# Build representation for target address # Build representation for target address
def build_operand(arg1) def build_operand(arg1)
if (arg1.is_a?(Asm::Parser::ReferenceArgNode)) if (arg1.is_a?(Asm::ReferenceArgNode))
argr = simplify_reference(arg1.argument) argr = simplify_reference(arg1.argument)
arg = argr.argument arg = argr.argument
if (arg.is_a?(Asm::Parser::RegisterArgNode)) if (arg.is_a?(Asm::RegisterArgNode))
@i = 0 @i = 0
@pre_post_index = 1 @pre_post_index = 1
@w = 0 @w = 0
@rn = reg_ref(arg) @rn = reg_ref(arg)
@operand = 0 @operand = 0
if (argr.op and argr.right.is_a?(Asm::Parser::NumLiteralArgNode)) if (argr.op and argr.right.is_a?(Asm::NumLiteralArgNode))
val = argr.right.value val = argr.right.value
if (val < 0) if (val < 0)
@add_offset = 0 @add_offset = 0
@ -78,7 +78,7 @@ module Asm
else else
raise Asm::AssemblyError.new(Asm::ERRSTR_INVALID_ARG, arg) raise Asm::AssemblyError.new(Asm::ERRSTR_INVALID_ARG, arg)
end end
elsif (arg1.is_a?(Asm::Parser::LabelEquivAddrArgNode) or arg1.is_a?(Asm::Parser::NumEquivAddrArgNode)) elsif (arg1.is_a?(Asm::LabelEquivAddrArgNode) or arg1.is_a?(Asm::NumEquivAddrArgNode))
@i = 0 @i = 0
@pre_post_index = 1 @pre_post_index = 1
@w = 0 @w = 0
@ -99,10 +99,10 @@ module Asm
(inst_class << 12+4+4+1+1+1+1+1+1) | (cond << 12+4+4+1+1+1+1+1+1+2) (inst_class << 12+4+4+1+1+1+1+1+1) | (cond << 12+4+4+1+1+1+1+1+1+2)
if (@use_addrtable_reloc) if (@use_addrtable_reloc)
closest_addrtable = Asm::Arm.closest_addrtable(as) closest_addrtable = Asm::Arm.closest_addrtable(as)
if (@addrtable_reloc_target.is_a?(Asm::Parser::LabelEquivAddrArgNode)) if (@addrtable_reloc_target.is_a?(Asm::LabelEquivAddrArgNode))
obj = ast_asm.object_for_label(@addrtable_reloc_target.label, inst) obj = ast_asm.object_for_label(@addrtable_reloc_target.label, inst)
ref_label = closest_addrtable.add_label(obj) ref_label = closest_addrtable.add_label(obj)
elsif (@addrtable_reloc_target.is_a?(Asm::Parser::NumEquivAddrArgNode)) elsif (@addrtable_reloc_target.is_a?(Asm::NumEquivAddrArgNode))
ref_label = closest_addrtable.add_const(@addrtable_reloc_target.value) ref_label = closest_addrtable.add_const(@addrtable_reloc_target.value)
end end
as.add_relocation io.tell, ref_label, Asm::Arm::R_ARM_PC12, as.add_relocation io.tell, ref_label, Asm::Arm::R_ARM_PC12,

View File

@ -29,7 +29,7 @@ module Asm
# Build representation for source value # Build representation for source value
def build_operand(arg) def build_operand(arg)
if (arg.is_a?(Asm::Parser::RegisterListArgNode)) if (arg.is_a?(Asm::RegisterListArgNode))
@operand = 0 @operand = 0
arg.registers.each do |reg_node| arg.registers.each do |reg_node|
reg = reg_ref(reg_node) reg = reg_ref(reg_node)

View File

@ -121,14 +121,14 @@ module Asm
a.write io, as a.write io, as
when :b, :bl when :b, :bl
arg = args[0] arg = args[0]
if (arg.is_a?(Asm::Parser::NumLiteralArgNode)) if (arg.is_a?(Asm::NumLiteralArgNode))
jmp_val = arg.value >> 2 jmp_val = arg.value >> 2
packed = [jmp_val].pack('l') packed = [jmp_val].pack('l')
# signed 32-bit, condense to 24-bit # signed 32-bit, condense to 24-bit
# TODO add check that the value fits into 24 bits # TODO add check that the value fits into 24 bits
io << packed[0,3] io << packed[0,3]
elsif (arg.is_a?(Asm::LabelObject) or arg.is_a?(Asm::Parser::LabelRefArgNode)) elsif (arg.is_a?(Asm::LabelObject) or arg.is_a?(Asm::LabelRefArgNode))
arg = @ast_asm.object_for_label(arg.label, self) if arg.is_a?(Asm::Parser::LabelRefArgNode) arg = @ast_asm.object_for_label(arg.label, self) if arg.is_a?(Asm::LabelRefArgNode)
as.add_relocation(io.tell, arg, Asm::Arm::R_ARM_PC24, RelocHandler) as.add_relocation(io.tell, arg, Asm::Arm::R_ARM_PC24, RelocHandler)
io << "\x00\x00\x00" io << "\x00\x00\x00"
end end
@ -139,7 +139,7 @@ module Asm
(COND_BITS[@cond] << 16+4+8) (COND_BITS[@cond] << 16+4+8)
when :swi when :swi
arg = args[0] arg = args[0]
if (arg.is_a?(Asm::Parser::NumLiteralArgNode)) if (arg.is_a?(Asm::NumLiteralArgNode))
packed = [arg.value].pack('L')[0,3] packed = [arg.value].pack('L')[0,3]
io << packed io << packed
io.write_uint8 0b1111 | (COND_BITS[@cond] << 4) io.write_uint8 0b1111 | (COND_BITS[@cond] << 4)

View File

@ -2,7 +2,7 @@ module Asm
module Arm module Arm
module Asm::Arm::InstructionTools module Asm::Arm::InstructionTools
def reg_ref(arg) def reg_ref(arg)
if (not arg.is_a?(Asm::Parser::RegisterArgNode)) if (not arg.is_a?(Asm::RegisterArgNode))
raise Asm::AssemblyError.new('argument must be a register', arg) raise Asm::AssemblyError.new('argument must be a register', arg)
end end

View File

@ -16,17 +16,17 @@ module Asm
def load_ast(ast) def load_ast(ast)
label_breadcrumb = [] label_breadcrumb = []
ast.children.each do |cmd| ast.children.each do |cmd|
if (cmd.is_a?(Asm::Parser::LabelNode)) if (cmd.is_a?(Asm::LabelNode))
m = /^\/+/.match(cmd.name) m = /^\/+/.match(cmd.name)
count = m ? m[0].length : 0 count = m ? m[0].length : 0
label_breadcrumb = label_breadcrumb[0,count] label_breadcrumb = label_breadcrumb[0,count]
label_breadcrumb << cmd.name[count..-1] label_breadcrumb << cmd.name[count..-1]
@asm.add_object object_for_label(label_breadcrumb.join('/')) @asm.add_object object_for_label(label_breadcrumb.join('/'))
elsif (cmd.is_a?(Asm::Parser::InstructionNode)) elsif (cmd.is_a?(Asm::InstructionNode))
inst = @asm_arch::Instruction.new(cmd, self) inst = @asm_arch::Instruction.new(cmd, self)
@asm.add_object inst @asm.add_object inst
@inst_label_context[inst] = label_breadcrumb @inst_label_context[inst] = label_breadcrumb
elsif (cmd.is_a?(Asm::Parser::DirectiveNode)) elsif (cmd.is_a?(Asm::DirectiveNode))
if (cmd.name == 'global') if (cmd.name == 'global')
symbol_for_label(cmd.value)[:linkage] = Elf::Constants::STB_GLOBAL symbol_for_label(cmd.value)[:linkage] = Elf::Constants::STB_GLOBAL
elsif (cmd.name == 'extern') elsif (cmd.name == 'extern')

80
lib/asm/nodes.rb Normal file
View File

@ -0,0 +1,80 @@
module Asm
class Node
def initialize(s = nil)
if (s)
@line = s.prev_line
@column = s.prev_column
else
@line = 0
@column = 0
end
yield self if block_given?
end
attr_reader :line, :column
end
class ToplevelNode < Node
attr_accessor :children
end
class DirectiveNode < Node
attr_accessor :name, :value
end
class LabelNode < Node
attr_accessor :name
end
class InstructionNode < Node
attr_accessor :opcode, :args
end
class ArgNode < Node
end
class ShiftNode < Node
attr_accessor :type, :value, :argument
end
class MathNode < Node
attr_accessor :left, :right, :op
alias_method :argument, :left
alias_method :argument=, :left=
end
class RegisterArgNode < ArgNode
attr_accessor :name
end
class RegisterListArgNode < ArgNode
attr_accessor :registers
end
class NumLiteralArgNode < ArgNode
attr_accessor :value
end
class NumEquivAddrArgNode < NumLiteralArgNode
end
class LabelRefArgNode < ArgNode
attr_accessor :label, :label_object
end
class LabelEquivAddrArgNode < LabelRefArgNode
end
class ReferenceArgNode < ArgNode
attr_accessor :argument
end
class ParseError < StandardError
def initialize(message, s)
super(message)
@line = s.line
@column = s.column
end
attr_reader :line, :column
end
end

View File

@ -1,16 +1,7 @@
require_relative 'str_scanner' require_relative 'str_scanner'
require_relative 'nodes'
module Asm module Asm
class ParseError < StandardError
def initialize(message, s)
super(message)
@line = s.line
@column = s.column
end
attr_reader :line, :column
end
class Parser class Parser
def initialize(str) def initialize(str)
scanner = Asm::Scanner.new(str) scanner = Asm::Scanner.new(str)
@ -23,24 +14,6 @@ module Asm
new(str).ast new(str).ast
end end
class Node
def initialize(s = nil)
if (s)
@line = s.prev_line
@column = s.prev_column
else
@line = 0
@column = 0
end
yield self if block_given?
end
attr_reader :line, :column
end
class ToplevelNode < Node
attr_accessor :children
end
def parse_toplevel(s) def parse_toplevel(s)
node = ToplevelNode.new(s) node = ToplevelNode.new(s)
node.children = [] node.children = []
@ -63,16 +36,12 @@ module Asm
node node
end end
class CommentNode < Node; end
def parse_comment(s) def parse_comment(s)
if (s.scan(/;.*?$/)) if (s.scan(/;.*?$/))
CommentNode.new(s) CommentNode.new(s)
end end
end end
class DirectiveNode < Node
attr_accessor :name, :value
end
def parse_directive(s) def parse_directive(s)
if (m = s.scan(/\.(\w+)(?:(?!$)\s+(.+)\s*?$)?/)) if (m = s.scan(/\.(\w+)(?:(?!$)\s+(.+)\s*?$)?/))
DirectiveNode.new(s) { |n| DirectiveNode.new(s) { |n|
@ -82,9 +51,6 @@ module Asm
end end
end end
class LabelNode < Node
attr_accessor :name
end
def parse_label(s) def parse_label(s)
if (m = s.scan(/(\/*\w+):/)) if (m = s.scan(/(\/*\w+):/))
LabelNode.new(s) { |n| LabelNode.new(s) { |n|
@ -93,9 +59,6 @@ module Asm
end end
end end
class InstructionNode < Node
attr_accessor :opcode, :args
end
def parse_instruction(s) def parse_instruction(s)
if (m = s.scan(/(\w+)/)) if (m = s.scan(/(\w+)/))
node = InstructionNode.new(s) { |n| node = InstructionNode.new(s) { |n|
@ -113,8 +76,6 @@ module Asm
end end
end end
class ArgNode < Node
end
def parse_arg(s) def parse_arg(s)
s.scan /\s*/ s.scan /\s*/
node = nil node = nil
@ -146,9 +107,6 @@ module Asm
node node
end end
class ShiftNode < Node
attr_accessor :type, :value, :argument
end
def parse_shift(s) def parse_shift(s)
if (m = s.scan(/(lsl|lsr|asr|ror|rrx)\s+/i)) if (m = s.scan(/(lsl|lsr|asr|ror|rrx)\s+/i))
op = m[0].downcase op = m[0].downcase
@ -163,11 +121,6 @@ module Asm
end end
end end
class MathNode < Node
attr_accessor :left, :right, :op
alias_method :argument, :left
alias_method :argument=, :left=
end
def parse_math(s) def parse_math(s)
if (m = s.scan_str(/[\+\-]/)) if (m = s.scan_str(/[\+\-]/))
if (arg1 = parse_arg(s)) if (arg1 = parse_arg(s))
@ -185,9 +138,6 @@ module Asm
r13 r14 r15 a1 a2 a3 a4 v1 v2 v3 v4 v5 v6 r13 r14 r15 a1 a2 a3 a4 v1 v2 v3 v4 v5 v6
rfp sl fp ip sp lr pc rfp sl fp ip sp lr pc
)) ))
class RegisterArgNode < ArgNode
attr_accessor :name
end
def parse_register(s) def parse_register(s)
if (m = s.scan_str(REGISTER_REGEXP)) if (m = s.scan_str(REGISTER_REGEXP))
RegisterArgNode.new(s) { |n| RegisterArgNode.new(s) { |n|
@ -196,9 +146,6 @@ module Asm
end end
end end
class RegisterListArgNode < ArgNode
attr_accessor :registers
end
def parse_register_list(s) def parse_register_list(s)
if (m = s.scan(/\{/)) if (m = s.scan(/\{/))
node = RegisterListArgNode.new(s) do |n| node = RegisterListArgNode.new(s) do |n|
@ -222,11 +169,6 @@ module Asm
end end
end end
class NumLiteralArgNode < ArgNode
attr_accessor :value
end
class NumEquivAddrArgNode < NumLiteralArgNode
end
def parse_num_literal(s) def parse_num_literal(s)
if (m = s.scan(/(=?)#(-?(?:0x)?[0-9A-Fa-f]+)/)) if (m = s.scan(/(=?)#(-?(?:0x)?[0-9A-Fa-f]+)/))
(m[0] == '=' ? NumEquivAddrArgNode : NumLiteralArgNode).new(s) { |n| (m[0] == '=' ? NumEquivAddrArgNode : NumLiteralArgNode).new(s) { |n|
@ -235,11 +177,6 @@ module Asm
end end
end end
class LabelRefArgNode < ArgNode
attr_accessor :label, :label_object
end
class LabelEquivAddrArgNode < LabelRefArgNode
end
def parse_label_ref(s) def parse_label_ref(s)
if (m = s.scan(/(=?)(\/*\w+)/)) if (m = s.scan(/(=?)(\/*\w+)/))
(m[0] == '=' ? LabelEquivAddrArgNode : LabelRefArgNode).new(s) { |n| (m[0] == '=' ? LabelEquivAddrArgNode : LabelRefArgNode).new(s) { |n|
@ -248,9 +185,6 @@ module Asm
end end
end end
class ReferenceArgNode < ArgNode
attr_accessor :argument
end
def parse_reference(s) def parse_reference(s)
if (m = s.scan(/\[/)) if (m = s.scan(/\[/))
arg = parse_arg(s) arg = parse_arg(s)