# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
+require "config"
+
#
# Base utility types for the AST.
#
true
end
+ def immediateOperand?
+ true
+ end
+
def register?
false
end
"(#{left.dump} + #{right.dump})"
end
+ def value
+ "#{left.value} + #{right.value}"
+ end
+
def address?
false
end
true
end
+ def immediateOperand?
+ true
+ end
+
def register?
false
end
"(#{left.dump} - #{right.dump})"
end
+ def value
+ "#{left.value} - #{right.value}"
+ end
+
def address?
false
end
true
end
+ def immediateOperand?
+ true
+ end
+
def register?
false
end
true
end
+ def immediateOperand?
+ false
+ end
+
def register?
false
end
true
end
+ def immediateOperand?
+ false
+ end
+
def register?
false
end
true
end
+ def immediateOperand?
+ false
+ end
+
def register?
false
end
true
end
+ def immediateOperand?
+ false
+ end
+
def register?
false
end
true
end
+ def immediateOperand?
+ false
+ end
+
def register?
false
end
true
end
+ def immediateOperand?
+ false
+ end
+
+ def register?
+ false
+ end
+end
+
+class StringLiteral < NoChildren
+ attr_reader :value
+
+ def initialize(codeOrigin, value)
+ super(codeOrigin)
+ @value = value[1..-2]
+ raise "Bad string literal #{value.inspect} at #{codeOriginString}" unless value.is_a? String
+ end
+
+ def dump
+ "#{value}"
+ end
+
+ def ==(other)
+ other.is_a? StringLiteral and other.value == @value
+ end
+
+ def address?
+ false
+ end
+
+ def label?
+ false
+ end
+
+ def immediate?
+ false
+ end
+
+ def immediateOperand?
+ false
+ end
+
def register?
false
end
false
end
+ def immediateOperand?
+ false
+ end
+
def register?
true
end
false
end
+ def immediateOperand?
+ false
+ end
+
def register?
true
end
raise "Bad offset for address #{offset.inspect} at #{codeOriginString}" unless offset.is_a? Variable or offset.immediate?
end
+ def withOffset(extraOffset)
+ Address.new(codeOrigin, @base, Immediate.new(codeOrigin, @offset.value + extraOffset))
+ end
+
def children
[@base, @offset]
end
false
end
+ def immediateOperand?
+ true
+ end
+
def register?
false
end
end
end
+ def withOffset(extraOffset)
+ BaseIndex.new(codeOrigin, @base, @index, @scale, Immediate.new(codeOrigin, @offset.value + extraOffset))
+ end
+
def children
[@base, @index, @offset]
end
false
end
+ def immediateOperand?
+ false
+ end
+
def register?
false
end
@address = address
end
+ def withOffset(extraOffset)
+ AbsoluteAddress.new(codeOrigin, Immediate.new(codeOrigin, @address.value + extraOffset))
+ end
+
def dump
"#{address.dump}[]"
end
false
end
+ def immediateOperand?
+ true
+ end
+
def register?
false
end
end
class Instruction < Node
- attr_reader :opcode, :operands
+ attr_reader :opcode, :operands, :annotation
- def initialize(codeOrigin, opcode, operands)
+ def initialize(codeOrigin, opcode, operands, annotation=nil)
super(codeOrigin)
@opcode = opcode
@operands = operands
+ @annotation = annotation
end
def children
end
def mapChildren(&proc)
- Instruction.new(codeOrigin, @opcode, @operands.map(&proc))
+ Instruction.new(codeOrigin, @opcode, @operands.map(&proc), @annotation)
end
def dump
"\t" + opcode.to_s + " " + operands.collect{|v| v.dump}.join(", ")
end
+
+ def lowerDefault
+ case opcode
+ when "localAnnotation"
+ $asm.putLocalAnnotation
+ when "globalAnnotation"
+ $asm.putGlobalAnnotation
+ when "emit"
+ $asm.puts "#{operands[0].dump}"
+ else
+ raise "Unhandled opcode #{opcode} at #{codeOriginString}"
+ end
+ end
end
class Error < NoChildren
end
$labelMapping = {}
+$referencedExternLabels = Array.new
class Label < NoChildren
attr_reader :name
def initialize(codeOrigin, name)
super(codeOrigin)
@name = name
+ @extern = true
+ @global = false
end
- def self.forName(codeOrigin, name)
+ def self.forName(codeOrigin, name, definedInFile = false)
if $labelMapping[name]
raise "Label name collision: #{name}" unless $labelMapping[name].is_a? Label
else
$labelMapping[name] = Label.new(codeOrigin, name)
end
+ if definedInFile
+ $labelMapping[name].clearExtern()
+ end
$labelMapping[name]
end
-
+
+ def self.setAsGlobal(codeOrigin, name)
+ if $labelMapping[name]
+ label = $labelMapping[name]
+ raise "Label: #{name} declared global multiple times" unless not label.global?
+ label.setGlobal()
+ else
+ newLabel = Label.new(codeOrigin, name)
+ newLabel.setGlobal()
+ $labelMapping[name] = newLabel
+ end
+ end
+
+ def self.resetReferenced
+ $referencedExternLabels = Array.new
+ end
+
+ def self.forReferencedExtern()
+ $referencedExternLabels.each {
+ | label |
+ yield "#{label.name}"
+ }
+ end
+
+ def clearExtern
+ @extern = false
+ end
+
+ def extern?
+ @extern
+ end
+
+ def setGlobal
+ @global = true
+ end
+
+ def global?
+ @global
+ end
+
def dump
"#{name}:"
end
label.name
end
+ def extern?
+ $labelMapping[name].is_a? Label and $labelMapping[name].extern?
+ end
+
+ def used
+ if !$referencedExternLabels.include?(@label) and extern?
+ $referencedExternLabels.push(@label)
+ end
+ end
+
def dump
label.name
end
+ def value
+ asmLabel()
+ end
+
def address?
false
end
def immediate?
false
end
+
+ def immediateOperand?
+ true
+ end
end
class LocalLabelReference < NoChildren
def dump
label.name
end
+
+ def value
+ asmLabel()
+ end
def address?
false
def immediate?
false
end
+
+ def immediateOperand?
+ true
+ end
end
class Sequence < Node
end
def children
- [@left, @right]
+ [@child]
end
def mapChildren
class Macro < Node
attr_reader :name, :variables, :body
-
+
def initialize(codeOrigin, name, variables, body)
super(codeOrigin)
@name = name
end
class MacroCall < Node
- attr_reader :name, :operands
+ attr_reader :name, :operands, :annotation
- def initialize(codeOrigin, name, operands)
+ def initialize(codeOrigin, name, operands, annotation)
super(codeOrigin)
@name = name
@operands = operands
raise unless @operands
@operands.each{|v| raise unless v}
+ @annotation = annotation
end
def children
end
def mapChildren(&proc)
- MacroCall.new(codeOrigin, @name, @operands.map(&proc))
+ MacroCall.new(codeOrigin, @name, @operands.map(&proc), @annotation)
end
def dump