class Z80::Alloc

Alloc class is used internally by relocation mechanizm and lazy evaluation of labels' values. See Label instead.

Public Class Methods

include?(alloc, label) click to toggle source

Return true if label takes part in an alloc expression.

# File lib/z80/labels.rb, line 1120
def Alloc.include?(alloc, label)
        return true if alloc == label
        return false unless alloc.is_a?(Alloc)
        alloc.instance_exec do
                Alloc.include?(@lhs, label) || Alloc.include?(@rhs, label)
        end
end
new(lhs, oper=nil, rhs=nil, index=[]) click to toggle source
# File lib/z80/labels.rb, line 1164
def initialize(lhs, oper=nil, rhs=nil, index=[])
        raise Syntax, "lhs is not a Label or an Alloc" unless lhs.is_a?(Label) or lhs.is_a?(Alloc)
        rhs = rhs.to_alloc if rhs.is_a?(Label)
        raise Syntax, "rhs is not an Alloc or an integer" unless rhs.nil? or Integer === rhs or rhs.is_a?(Alloc)
        raise Syntax, "lhs nor rhs must not be a pointer" if lhs.pointer? or (rhs.respond_to?(:pointer?) and rhs.pointer?)
        raise Syntax, "invalid operator" unless oper.nil? or [:+,:-,:+@,:-@,:>>,:<<,:/,:%,:*,:^,:&,:|,:~,:alias].include?(oper)
        raise Syntax, "invalid operator's rhs" unless (rhs.nil? and (oper.nil? or [:+@,:-@,:~,:alias].include?(oper))) or
                                                                                                                                                                                                (!oper.nil? and !rhs.nil?)
        xalias = if oper == :alias
                oper = nil
                true
        else
                false
        end
        raise Syntax, "invalid index" unless Array === index and index.all?{|m| Integer === m || String === m || m.is_a?(Alloc) }
        raise Syntax, "index-op is only allowed on labels" unless index.empty? or oper.nil?
        unless oper.nil?
                raise Syntax, "invalid operator's lhs" unless lhs.is_a?(Alloc)
        end
        @lhs     = lhs
        @oper    = oper
        @rhs     = rhs
        @index   = index
        @pointer = false
        @alias   = xalias
        @name    = nil
end

Public Instance Methods

%(other) click to toggle source
# File lib/z80/labels.rb, line 1253
def %(other)
        Alloc.new(self, :%, other)
end
&(other) click to toggle source
# File lib/z80/labels.rb, line 1281
def &(other)
        Alloc.new(self, :&, other)
end
*(other) click to toggle source
# File lib/z80/labels.rb, line 1245
def *(other)
        Alloc.new(self, :*, other)
end
**(m) click to toggle source
# File lib/z80/labels.rb, line 1219
def **(m)
        label = self
        begin
                if label.sublabel_access_expression?
                        label.instance_eval do
                                label = @lhs
                                @index.each do |idx|
                                        label = label ** idx
                                end
                        end
                else
                        raise Syntax, "** #{m} not allowed on an expression: #{label.inspect}" if label.expression?
                        label = label.instance_variable_get('@lhs')
                end
        end until label.is_a?(Label)
        label.**(m)
end
+(other) click to toggle source
# File lib/z80/labels.rb, line 1237
def +(other)
        Alloc.new(self, :+, other)
end
+@() click to toggle source
# File lib/z80/labels.rb, line 1265
def +@
        Alloc.new(self, :+@)
end
-(other) click to toggle source
# File lib/z80/labels.rb, line 1241
def -(other)
        Alloc.new(self, :-, other)
end
-@() click to toggle source
# File lib/z80/labels.rb, line 1269
def -@
        Alloc.new(self, :-@)
end
/(other) click to toggle source
# File lib/z80/labels.rb, line 1249
def /(other)
        Alloc.new(self, :/, other)
end
<<(other) click to toggle source
# File lib/z80/labels.rb, line 1261
def <<(other)
        Alloc.new(self, :<<, other)
end
==(other) click to toggle source
# File lib/z80/labels.rb, line 1192
def ==(other)
        case other
        when Label
                !expression? && @lhs == other
        when Alloc
                %w[@lhs @oper @rhs @index @pointer].all? do |n|
                        self.instance_variable_get(n) == other.instance_variable_get(n)
                end
        else
                false
        end
end
>>(other) click to toggle source
# File lib/z80/labels.rb, line 1257
def >>(other)
        Alloc.new(self, :>>, other)
end
[](index = nil) click to toggle source
# File lib/z80/labels.rb, line 1484
def [](index = nil)
        if index.nil?
                if @pointer
                        dup
                else
                        raise Syntax, "pointer not allowed from a sizeof" if @oper == :+@
                        Alloc.new(self).tap { |l| l.instance_variable_set('@pointer', true) }
                end 
        else
                raise Syntax, "indexing is only allowed on a label" unless indexable?
                if @index.empty?
                        Alloc.new(self)
                else
                        dup
                end.tap do |l|
                        lix = l.instance_variable_get('@index')
                        case index
                        when String, Symbol
                                lix << index.to_s
                        when Label, Alloc
                                lix << index.to_alloc
                        when Integer
                                if Integer === lix.last
                                        lix[-1]+= index
                                else
                                        lix << index
                                end
                        else
                                raise Syntax, "invalid index"
                        end
                end
        end
end
^(other) click to toggle source
# File lib/z80/labels.rb, line 1273
def ^(other)
        Alloc.new(self, :^, other)
end
alias?() click to toggle source

This label can be the only dummy sublabel of another label and as such may exist in both members and dummies.

# File lib/z80/labels.rb, line 1207
def alias?; @alias; end
dummy?() click to toggle source
# File lib/z80/labels.rb, line 1289
def dummy?
        @lhs.dummy? || (@rhs.respond_to?(:dummy?) && @rhs.dummy?)
end
dup() click to toggle source
Calls superclass method
# File lib/z80/labels.rb, line 1157
def dup
        super.tap do |l| 
                l.instance_variable_set('@index', @index.dup)
                l.instance_variable_set('@name', nil)
        end
end
expression?() click to toggle source
# File lib/z80/labels.rb, line 1211
def expression?
        @pointer || !@oper.nil? || !@index.empty?
end
immediate?() click to toggle source
# File lib/z80/labels.rb, line 1293
def immediate?
        if @index.empty?
                @lhs.immediate? && (@rhs.respond_to?(:immediate?) ? @rhs.immediate? : true)
        else
                label = @lhs
                return false if label.dummy?
                @index.all? do |idx|
                        case idx
                        when String
                                label = label ** idx
                                label ? label.immediate? : false
                        when Alloc
                                idx.immediate?
                        else
                                label.immediate?
                        end
                end # all?
        end
end
indexable?() click to toggle source
# File lib/z80/labels.rb, line 1476
def indexable?
        if @alias
                @lhs.indexable?
        else
                !@pointer and @oper.nil? and (@lhs.is_a?(Label) or !@index.empty?)
        end
end
method_missing(m) click to toggle source
Calls superclass method
# File lib/z80/labels.rb, line 1522
def method_missing(m)
        if m == :to_ary || m == :to_a || m == :to_hash || m == :to_h
                super
        else
                self.[](m)
        end
end
name=(value) click to toggle source
# File lib/z80/labels.rb, line 1464
def name=(value)
        value = value.to_s
        raise Syntax, "Invalid label name: #{value.inspect}" if value.empty?
        raise Syntax, "Can't rename already named label: #{@name} != #{value}" if @name and @name != value
        @name = value
end
pointer?() click to toggle source
# File lib/z80/labels.rb, line 1209
def pointer?; @pointer; end
reinitialize(address, type = 1, reloc = nil, members = nil) click to toggle source
# File lib/z80/labels.rb, line 1317
def reinitialize(address, type = 1, reloc = nil, members = nil)
        return self if address == self
        raise Syntax, "Can't re-initialize" unless @oper.nil? && @index.empty? && @lhs.is_a?(Label) && @lhs.dummy? && !@pointer
        if address.is_a?(Label) || Integer === address
                @lhs.reinitialize(address, type, reloc, members)
        elsif address.is_a?(self.class)
                lhs, oper, rhs, index, pointer, xalias = %w[@lhs @oper @rhs @index @pointer @alias].
                                                                                                                                                         map {|n| address.instance_variable_get(n) }
                if lhs.is_a?(Label)
                        @lhs.reinitialize(lhs, type, reloc, members)
                else
                        @lhs   = lhs
                end
                @oper    = oper
                @rhs     = rhs
                @index   = index
                @pointer = pointer
                @alias   = xalias
        else
                raise Syntax, "invalid re-initialize address"
        end
        name = if address.respond_to?(:to_name)
                address.to_name
        elsif
                @lhs.to_name
        end
        if name and @name and @name != name and @alias
                name = nil
        end
        self.name = name unless name.nil?
        self
end
respond_to_missing?(m, include_private=false) click to toggle source
# File lib/z80/labels.rb, line 1518
def respond_to_missing?(m, include_private=false)
        m != :to_ary && m != :to_a && m != :to_hash && m != :to_h
end
sublabel?() click to toggle source
# File lib/z80/labels.rb, line 1313
def sublabel?
        false
end
sublabel_access_expression?() click to toggle source
# File lib/z80/labels.rb, line 1215
def sublabel_access_expression?
        !@pointer && @oper.nil? && !@index.empty? && @index.all? {|s| String === s }
end
to_aliased_name(start) click to toggle source
# File lib/z80/labels.rb, line 1354
def to_aliased_name(start)
        raise CompileError, "not an alias" unless alias?
        if @lhs.alias? or @lhs.is_a?(Label)
                @lhs.to_aliased_name(start)
        else
                @lhs.to_str
        end
end
to_alloc() click to toggle source
# File lib/z80/labels.rb, line 1350
def to_alloc; self; end
to_i(start = 0, rel_to = nil, override:nil, prefix:''.freeze, size_of:false) click to toggle source

rel_to: an absolute address or :self used by ix/iy offset addressing

# File lib/z80/labels.rb, line 1387
def to_i(start = 0, rel_to = nil, override:nil, prefix:''.freeze, size_of:false)
        rel_to_label = rel_to == :self ? :self : nil

        arg_to_i = ->(arg, rel_to) do
                case arg
                when Integer
                        arg.to_i
                when Alloc, Label
                        arg.to_alloc.to_i(start, rel_to, override:override)
                else
                        raise CompileError, "Invalid argument: #{arg.inspect}"
                end
        end

        if !size_of and @name and rel_to_label.nil?
                if (override_value = override && override[prefix + @name])
                        return override_value - rel_to.to_i
                end
        end

        val = if @oper.nil?
                label = @lhs
                raise CompileError, "can't calculate an address of a directly addressed sublabel: #{label}" if label.sublabel?
                addr = label.to_i(start, rel_to_label, override:override, prefix:prefix)
                # allow overrides of simple nested sublabels that only exist when overridden
                if !size_of and rel_to_label.nil? and !@index.empty? and label.to_name and
                         @index.all?{|idx| idx.is_a?(String)} and
                         (override_value = override && override[prefix + label.to_name + '.'.freeze + @index.join('.'.freeze)])
                         override_value - rel_to.to_i
                else
                        @index.each do |idx|
                                case idx
                                when String
                                        raise CompileError, "Unknown member: #{idx} of label #{label}." unless sublabel = label ** idx
                                        subprefix = prefix + label.to_name + '.'.freeze
                                        # a member of struct
                                        if sublabel.sublabel?
                                                addr += sublabel.to_i
                                        elsif label.sublabel?
                                                raise CompileError, "Non struct member as a member of a struct label: #{subprefix}#{sublabel.to_name}"
                                        # a label
                                        else
                                                if label.immediate? and !sublabel.immediate?
                                                        raise CompileError, "Relative member #{subprefix}#{sublabel.to_name} of an absolute label #{label}!"
                                                end
                                                addr = sublabel.to_i(start, rel_to_label, override:override, prefix:subprefix)
                                        end
                                        prefix = subprefix
                                        label = sublabel
                                else
                                        addr+= arg_to_i.call(idx, nil) * label.to_i(size_of:true)
                                end
                        end
                        if size_of
                                label.to_i(size_of:true)
                        else
                                addr
                        end
                end
        else
                raise CompileError, "Can't get a size from an expression: #{self.inspect}" if size_of
                case @oper
                when :+@ then return @lhs.to_i(start, rel_to, override:override, size_of:true)
                when :-@ then -arg_to_i.call(@lhs, rel_to_label)
                when :~ then ~arg_to_i.call(@lhs, rel_to_label)
                else
                        arg_to_i[@lhs, rel_to_label].send(@oper, arg_to_i[@rhs, rel_to_label])
                end
        end

        if Integer === rel_to
                val - rel_to
        else
                val
        end
end
to_label(_) click to toggle source
# File lib/z80/labels.rb, line 1352
def to_label(_); self; end
to_name(info=false) click to toggle source
# File lib/z80/labels.rb, line 1471
def to_name(info=false)
        return @name if @name
        return @lhs.to_name(info) if !expression?
end
to_s()
Alias for: to_str
to_str() click to toggle source
# File lib/z80/labels.rb, line 1363
def to_str
        return @name if @name
        return @lhs.to_str if @pointer
        case @oper
        when nil
                @lhs.to_name(true).to_s + @index.map {|idx|
                        case idx
                        when String
                                '.' + idx
                        else
                                "[#{idx}]"
                        end
                }.join
        when :+@
                "(+#{@lhs})"
        when :~, :-@
                "#{@oper.to_s[0]}(#{@lhs})"
        else
                "(#{@lhs}#{@oper}#{@rhs})"
        end
end
Also aliased as: to_s
|(other) click to toggle source
# File lib/z80/labels.rb, line 1277
def |(other)
        Alloc.new(self, :|, other)
end
~() click to toggle source
# File lib/z80/labels.rb, line 1285
def ~
        Alloc.new(self, :~)
end