]>
Commit | Line | Data |
---|---|---|
6fe7ccc8 A |
1 | #!/usr/bin/env ruby |
2 | ||
3 | # Copyright (C) 2011 Apple Inc. All rights reserved. | |
4 | # | |
5 | # Redistribution and use in source and binary forms, with or without | |
6 | # modification, are permitted provided that the following conditions | |
7 | # are met: | |
8 | # 1. Redistributions of source code must retain the above copyright | |
9 | # notice, this list of conditions and the following disclaimer. | |
10 | # 2. Redistributions in binary form must reproduce the above copyright | |
11 | # notice, this list of conditions and the following disclaimer in the | |
12 | # documentation and/or other materials provided with the distribution. | |
13 | # | |
14 | # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | |
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
16 | # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
17 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | |
18 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
19 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
20 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
21 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
22 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
23 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
24 | # THE POSSIBILITY OF SUCH DAMAGE. | |
25 | ||
26 | $: << File.dirname(__FILE__) | |
27 | ||
28 | require "backends" | |
29 | require "digest/sha1" | |
30 | require "offsets" | |
31 | require "parser" | |
32 | require "self_hash" | |
33 | require "settings" | |
34 | require "transform" | |
35 | ||
36 | class Assembler | |
37 | def initialize(outp) | |
38 | @outp = outp | |
39 | @state = :cpp | |
40 | @commentState = :none | |
41 | @comment = nil | |
42 | end | |
43 | ||
44 | def enterAsm | |
45 | @outp.puts "asm (" | |
46 | @state = :asm | |
47 | end | |
48 | ||
49 | def leaveAsm | |
50 | putsLastComment | |
51 | @outp.puts ");" | |
52 | @state = :cpp | |
53 | end | |
54 | ||
55 | def inAsm | |
56 | enterAsm | |
57 | yield | |
58 | leaveAsm | |
59 | end | |
60 | ||
61 | def lastComment | |
62 | if @comment | |
63 | result = "// #{@comment}" | |
64 | else | |
65 | result = "" | |
66 | end | |
67 | @commentState = :none | |
68 | @comment = nil | |
69 | result | |
70 | end | |
71 | ||
72 | def putsLastComment | |
73 | comment = lastComment | |
74 | unless comment.empty? | |
75 | @outp.puts comment | |
76 | end | |
77 | end | |
78 | ||
79 | def puts(*line) | |
80 | raise unless @state == :asm | |
81 | @outp.puts("\"\\t" + line.join('') + "\\n\" #{lastComment}") | |
82 | end | |
83 | ||
84 | def print(line) | |
85 | raise unless @state == :asm | |
86 | @outp.print("\"" + line + "\"") | |
87 | end | |
88 | ||
89 | def putsLabel(labelName) | |
90 | raise unless @state == :asm | |
91 | @outp.puts("OFFLINE_ASM_GLOBAL_LABEL(#{labelName}) #{lastComment}") | |
92 | end | |
93 | ||
94 | def putsLocalLabel(labelName) | |
95 | raise unless @state == :asm | |
96 | @outp.puts("LOCAL_LABEL_STRING(#{labelName}) \":\\n\" #{lastComment}") | |
97 | end | |
98 | ||
99 | def self.labelReference(labelName) | |
100 | "\" SYMBOL_STRING(#{labelName}) \"" | |
101 | end | |
102 | ||
103 | def self.localLabelReference(labelName) | |
104 | "\" LOCAL_LABEL_STRING(#{labelName}) \"" | |
105 | end | |
106 | ||
107 | def comment(text) | |
108 | case @commentState | |
109 | when :none | |
110 | @comment = text | |
111 | @commentState = :one | |
112 | when :one | |
113 | @outp.puts "// #{@comment}" | |
114 | @outp.puts "// #{text}" | |
115 | @comment = nil | |
116 | @commentState = :many | |
117 | when :many | |
118 | @outp.puts "// #{text}" | |
119 | else | |
120 | raise | |
121 | end | |
122 | end | |
123 | end | |
124 | ||
125 | asmFile = ARGV.shift | |
126 | offsetsFile = ARGV.shift | |
127 | outputFlnm = ARGV.shift | |
128 | ||
129 | $stderr.puts "offlineasm: Parsing #{asmFile} and #{offsetsFile} and creating assembly file #{outputFlnm}." | |
130 | ||
131 | begin | |
132 | configurationList = offsetsAndConfigurationIndex(offsetsFile) | |
133 | rescue MissingMagicValuesException | |
134 | $stderr.puts "offlineasm: No magic values found. Skipping assembly file generation assuming the classic interpreter is enabled." | |
135 | exit 0 | |
136 | end | |
137 | ||
138 | inputHash = | |
139 | "// offlineasm input hash: " + parseHash(asmFile) + | |
140 | " " + Digest::SHA1.hexdigest(configurationList.map{|v| (v[0] + [v[1]]).join(' ')}.join(' ')) + | |
141 | " " + selfHash | |
142 | ||
143 | if FileTest.exist? outputFlnm | |
144 | File.open(outputFlnm, "r") { | |
145 | | inp | | |
146 | firstLine = inp.gets | |
147 | if firstLine and firstLine.chomp == inputHash | |
148 | $stderr.puts "offlineasm: Nothing changed." | |
149 | exit 0 | |
150 | end | |
151 | } | |
152 | end | |
153 | ||
154 | File.open(outputFlnm, "w") { | |
155 | | outp | | |
156 | $output = outp | |
157 | $output.puts inputHash | |
158 | ||
159 | $asm = Assembler.new($output) | |
160 | ||
161 | ast = parse(asmFile) | |
162 | ||
163 | configurationList.each { | |
164 | | configuration | | |
165 | offsetsList = configuration[0] | |
166 | configIndex = configuration[1] | |
167 | forSettings(computeSettingsCombinations(ast)[configIndex], ast) { | |
168 | | concreteSettings, lowLevelAST, backend | | |
169 | lowLevelAST = lowLevelAST.resolve(*buildOffsetsMap(lowLevelAST, offsetsList)) | |
170 | lowLevelAST.validate | |
171 | emitCodeInConfiguration(concreteSettings, lowLevelAST, backend) { | |
172 | $asm.inAsm { | |
173 | lowLevelAST.lower(backend) | |
174 | } | |
175 | } | |
176 | } | |
177 | } | |
178 | } | |
179 | ||
180 | $stderr.puts "offlineasm: Assembly file #{outputFlnm} successfully generated." | |
181 |