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