$: << File.dirname(__FILE__)
+require "config"
require "backends"
require "digest/sha1"
require "offsets"
@state = :cpp
@commentState = :none
@comment = nil
+ @internalComment = nil
+ @annotation = nil
+ @codeOrigin = nil
+ @numLocalLabels = 0
+ @numGlobalLabels = 0
+
+ @newlineSpacerState = :none
+ @lastlabel = ""
end
-
+
def enterAsm
- @outp.puts "asm ("
+ @outp.puts "OFFLINE_ASM_BEGIN" if !$emitWinAsm
@state = :asm
end
def leaveAsm
+ putsProcEndIfNeeded if $emitWinAsm
putsLastComment
- @outp.puts ");"
+ @outp.puts "OFFLINE_ASM_END" if !$emitWinAsm
@state = :cpp
end
leaveAsm
end
+ # Concatenates all the various components of the comment to dump.
def lastComment
- if @comment
- result = "// #{@comment}"
- else
- result = ""
+ separator = " "
+ result = ""
+ result = "#{@comment}" if @comment
+ if @annotation and $enableInstrAnnotations
+ result += separator if result != ""
+ result += "#{@annotation}"
end
+ if @internalComment
+ result += separator if result != ""
+ result += "#{@internalComment}"
+ end
+ if @codeOrigin and $enableCodeOriginComments
+ result += separator if result != ""
+ result += "#{@codeOrigin}"
+ end
+ if result != ""
+ result = $commentPrefix + " " + result
+ end
+
+ # Reset all the components that we've just sent to be dumped.
@commentState = :none
@comment = nil
+ @annotation = nil
+ @codeOrigin = nil
+ @internalComment = nil
result
end
+ # Puts a C Statement in the output stream.
+ def putc(*line)
+ raise unless @state == :asm
+ @outp.puts(formatDump(" " + line.join(''), lastComment))
+ end
+
+ def formatDump(dumpStr, comment, commentColumns=$preferredCommentStartColumn)
+ if comment.length > 0
+ "%-#{commentColumns}s %s" % [dumpStr, comment]
+ else
+ dumpStr
+ end
+ end
+
+ # private method for internal use only.
+ def putAnnotation(text)
+ raise unless @state == :asm
+ if $enableInstrAnnotations
+ @outp.puts text
+ @annotation = nil
+ end
+ end
+
+ def putLocalAnnotation()
+ putAnnotation " // #{@annotation}" if @annotation
+ end
+
+ def putGlobalAnnotation()
+ putsNewlineSpacerIfAppropriate(:annotation)
+ putAnnotation "// #{@annotation}" if @annotation
+ end
+
def putsLastComment
comment = lastComment
unless comment.empty?
def puts(*line)
raise unless @state == :asm
- @outp.puts("\"\\t" + line.join('') + "\\n\" #{lastComment}")
+ if !$emitWinAsm
+ @outp.puts(formatDump(" \"\\t" + line.join('') + "\\n\"", lastComment))
+ else
+ @outp.puts(formatDump(" " + line.join(''), lastComment))
+ end
end
def print(line)
@outp.print("\"" + line + "\"")
end
- def putsLabel(labelName)
+ def putsNewlineSpacerIfAppropriate(state)
+ if @newlineSpacerState != state
+ @outp.puts("\n")
+ @newlineSpacerState = state
+ end
+ end
+
+ def putsProc(label, comment)
+ raise unless $emitWinAsm
+ @outp.puts(formatDump("#{label} PROC PUBLIC", comment))
+ @lastlabel = label
+ end
+
+ def putsProcEndIfNeeded
+ raise unless $emitWinAsm
+ if @lastlabel != ""
+ @outp.puts("#{@lastlabel} ENDP")
+ end
+ @lastlabel = ""
+ end
+
+ def putsLabel(labelName, isGlobal)
raise unless @state == :asm
- @outp.puts("OFFLINE_ASM_GLOBAL_LABEL(#{labelName}) #{lastComment}")
+ @numGlobalLabels += 1
+ putsProcEndIfNeeded if $emitWinAsm and isGlobal
+ putsNewlineSpacerIfAppropriate(:global)
+ @internalComment = $enableLabelCountComments ? "Global Label #{@numGlobalLabels}" : nil
+ if isGlobal
+ if !$emitWinAsm
+ @outp.puts(formatDump("OFFLINE_ASM_GLOBAL_LABEL(#{labelName})", lastComment))
+ else
+ putsProc(labelName, lastComment)
+ end
+ elsif /\Allint_op_/.match(labelName)
+ if !$emitWinAsm
+ @outp.puts(formatDump("OFFLINE_ASM_OPCODE_LABEL(op_#{$~.post_match})", lastComment))
+ else
+ label = "llint_" + "op_#{$~.post_match}"
+ @outp.puts(formatDump(" _#{label}:", lastComment))
+ end
+ else
+ if !$emitWinAsm
+ @outp.puts(formatDump("OFFLINE_ASM_GLUE_LABEL(#{labelName})", lastComment))
+ else
+ @outp.puts(formatDump(" _#{labelName}:", lastComment))
+ end
+ end
+ @newlineSpacerState = :none # After a global label, we can use another spacer.
end
def putsLocalLabel(labelName)
raise unless @state == :asm
- @outp.puts("LOCAL_LABEL_STRING(#{labelName}) \":\\n\" #{lastComment}")
+ @numLocalLabels += 1
+ @outp.puts("\n")
+ @internalComment = $enableLabelCountComments ? "Local Label #{@numLocalLabels}" : nil
+ if !$emitWinAsm
+ @outp.puts(formatDump(" OFFLINE_ASM_LOCAL_LABEL(#{labelName})", lastComment))
+ else
+ @outp.puts(formatDump(" #{labelName}:", lastComment))
+ end
end
-
+
+ def self.externLabelReference(labelName)
+ if !$emitWinAsm
+ "\" LOCAL_REFERENCE(#{labelName}) \""
+ else
+ "#{labelName}"
+ end
+ end
+
def self.labelReference(labelName)
- "\" SYMBOL_STRING(#{labelName}) \""
+ if !$emitWinAsm
+ "\" LOCAL_LABEL_STRING(#{labelName}) \""
+ else
+ "_#{labelName}"
+ end
end
def self.localLabelReference(labelName)
- "\" LOCAL_LABEL_STRING(#{labelName}) \""
+ if !$emitWinAsm
+ "\" LOCAL_LABEL_STRING(#{labelName}) \""
+ else
+ "#{labelName}"
+ end
end
- def comment(text)
+ def self.cLabelReference(labelName)
+ if /\Allint_op_/.match(labelName)
+ "op_#{$~.post_match}" # strip opcodes of their llint_ prefix.
+ else
+ "#{labelName}"
+ end
+ end
+
+ def self.cLocalLabelReference(labelName)
+ "#{labelName}"
+ end
+
+ def codeOrigin(text)
case @commentState
when :none
- @comment = text
+ @codeOrigin = text
@commentState = :one
when :one
- @outp.puts "// #{@comment}"
- @outp.puts "// #{text}"
- @comment = nil
+ if $enableCodeOriginComments
+ @outp.puts " " + $commentPrefix + " #{@codeOrigin}"
+ @outp.puts " " + $commentPrefix + " #{text}"
+ end
+ @codeOrigin = nil
@commentState = :many
when :many
- @outp.puts "// #{text}"
+ @outp.puts $commentPrefix + " #{text}" if $enableCodeOriginComments
else
raise
end
end
+
+ def comment(text)
+ @comment = text
+ end
+ def annotation(text)
+ @annotation = text
+ end
end
+IncludeFile.processIncludeOptions()
+
asmFile = ARGV.shift
offsetsFile = ARGV.shift
outputFlnm = ARGV.shift
begin
configurationList = offsetsAndConfigurationIndex(offsetsFile)
rescue MissingMagicValuesException
- $stderr.puts "offlineasm: No magic values found. Skipping assembly file generation assuming the classic interpreter is enabled."
+ $stderr.puts "offlineasm: No magic values found. Skipping assembly file generation."
exit 0
end
+$emitWinAsm = isMSVC ? outputFlnm.index(".asm") != nil : false
+$commentPrefix = $emitWinAsm ? ";" : "//"
+
inputHash =
- "// offlineasm input hash: " + parseHash(asmFile) +
+ $commentPrefix + " offlineasm input hash: " + parseHash(asmFile) +
" " + Digest::SHA1.hexdigest(configurationList.map{|v| (v[0] + [v[1]]).join(' ')}.join(' ')) +
" " + selfHash
| outp |
$output = outp
$output.puts inputHash
-
+
$asm = Assembler.new($output)
ast = parse(asmFile)
-
+
configurationList.each {
| configuration |
offsetsList = configuration[0]