1
2
3
4
5
6 :(scenario transform_literal_string)
7 == code
8 b8/copy "test"/imm32
9 == data
10 +transform: -- move literal strings to data segment
11 +transform: adding global variable '__subx_global_1' containing "test"
12 +transform: instruction after transform: 'b8 __subx_global_1'
13
14
15
16
17 :(after "Begin Transforms")
18
19 Transform.push_back(transform_literal_strings);
20
21
22 :(before "End Globals")
23 int Next_auto_global = 1;
24 :(code)
25 void transform_literal_strings(program& p) {
26 trace(99, "transform") << "-- move literal strings to data segment" << end();
27 if (p.segments.empty()) return;
28 segment& code = p.segments.at(0);
29 segment data;
30 for (int i = 0; i < SIZE(code.lines); ++i) {
31 line& inst = code.lines.at(i);
32 for (int j = 0; j < SIZE(inst.words); ++j) {
33 word& curr = inst.words.at(j);
34 if (curr.data.at(0) != '"') continue;
35 ostringstream global_name;
36 global_name << "__subx_global_" << Next_auto_global;
37 ++Next_auto_global;
38 add_global_to_data_segment(global_name.str(), curr, data);
39 curr.data = global_name.str();
40 }
41 trace(99, "transform") << "instruction after transform: '" << data_to_string(inst) << "'" << end();
42 }
43 if (data.lines.empty()) return;
44 if (SIZE(p.segments) < 2) {
45 p.segments.resize(2);
46 p.segments.at(1).lines.swap(data.lines);
47 }
48 vector<line>& existing_data = p.segments.at(1).lines;
49 existing_data.insert(existing_data.end(), data.lines.begin(), data.lines.end());
50 }
51
52 void add_global_to_data_segment(const string& name, const word& value, segment& data) {
53 trace(99, "transform") << "adding global variable '" << name << "' containing " << value.data << end();
54
55 data.lines.push_back(label(name));
56
57 data.lines.push_back(line());
58 emit_hex_bytes(data.lines.back(), SIZE(value.data)-2, 4);
59
60 data.lines.push_back(line());
61 line& curr = data.lines.back();
62 for (int i = 1; i < SIZE(value.data)-1; ++i) {
63 char c = value.data.at(i);
64 curr.words.push_back(word());
65 curr.words.back().data = hex_byte_to_string(c);
66 curr.words.back().metadata.push_back(string(1, c));
67 }
68 }
69
70 line label(string s) {
71 line result;
72 result.words.push_back(word());
73 result.words.back().data = (s+":");
74 return result;
75 }
76
77
78
79
80 :(scenarios parse_instruction_character_by_character)
81 :(scenario instruction_with_string_literal)
82 a "abc def" z
83 +parse2: word: a
84 +parse2: word: "abc def"
85 +parse2: word: z
86
87 $parse2: 3
88
89 :(before "End Line Parsing Special-cases(line_data -> l)")
90 if (line_data.find('"') != string::npos) {
91 parse_instruction_character_by_character(line_data, l);
92 continue;
93 }
94
95 :(code)
96 void parse_instruction_character_by_character(const string& line_data, vector<line>& out) {
97
98 istringstream in(line_data);
99 in >> std::noskipws;
100 line result;
101
102 while (has_data(in)) {
103 skip_whitespace(in);
104 if (!has_data(in)) break;
105 char c = in.get();
106 if (c == '#') break;
107 if (c == ':') break;
108 if (c == '.') {
109 if (!has_data(in)) break;
110 if (isspace(in.peek()))
111 continue;
112 }
113 ostringstream w;
114 w << c;
115 if (c == '"') {
116
117 while (has_data(in)) {
118 in >> c;
119 w << c;
120 if (c == '"') break;
121 }
122 }
123
124 while (!isspace(in.peek()) && has_data(in)) {
125 in >> c;
126 w << c;
127 }
128 result.words.push_back(word());
129 parse_word(w.str(), result.words.back());
130 trace(99, "parse2") << "word: " << to_string(result.words.back()) << end();
131 }
132 if (!result.words.empty())
133 out.push_back(result);
134 }
135
136 void skip_whitespace(istream& in) {
137 while (true) {
138 if (has_data(in) && isspace(in.peek())) in.get();
139 else break;
140 }
141 }
142
143 void skip_comment(istream& in) {
144 if (has_data(in) && in.peek() == '#') {
145 in.get();
146 while (has_data(in) && in.peek() != '\n') in.get();
147 }
148 }
149
150
151 void parse_instruction_character_by_character(const string& line_data) {
152 vector<line> out;
153 parse_instruction_character_by_character(line_data, out);
154 }
155
156 :(scenario parse2_comment_token_in_middle)
157 a . z
158 +parse2: word: a
159 +parse2: word: z
160 -parse2: word: .
161
162 $parse2: 2
163
164 :(scenario parse2_word_starting_with_dot)
165 a .b c
166 +parse2: word: a
167 +parse2: word: .b
168 +parse2: word: c
169
170 :(scenario parse2_comment_token_at_start)
171 . a b
172 +parse2: word: a
173 +parse2: word: b
174 -parse2: word: .
175
176 :(scenario parse2_comment_token_at_end)
177 a b .
178 +parse2: word: a
179 +parse2: word: b
180 -parse2: word: .
181
182 :(scenario parse2_word_starting_with_dot_at_start)
183 .a b c
184 +parse2: word: .a
185 +parse2: word: b
186 +parse2: word: c
187
188 :(scenario parse2_metadata)
189 .a b/c d
190 +parse2: word: .a
191 +parse2: word: b /c
192 +parse2: word: d
193
194 :(scenario parse2_string_with_metadata)
195 a "bc def"/disp32 g
196 +parse2: word: a
197 +parse2: word: "bc def" /disp32
198 +parse2: word: g
199
200 :(scenario parse2_string_with_metadata_at_end)
201 a "bc def"/disp32
202 +parse2: word: a
203 +parse2: word: "bc def" /disp32
204
205 :(code)
206 void test_parse2_string_with_metadata_at_end_of_line_without_newline() {
207 parse_instruction_character_by_character(
208 "68/push \"test\"/f"
209 );
210 CHECK_TRACE_CONTENTS(
211 "parse2: word: 68 /push^D"
212 "parse2: word: \"test\" /f^D"
213 );
214 }