1
2
3
4 :(before "End Commandline Parsing")
5 if (argc <= 1 || is_equal(argv[1], "--help")) {
6
7
8 cerr << get(Help, "usage");
9 return 0;
10 }
11
12
13
14
15 char** arg = &argv[1];
16 while (argc > 1 && starts_with(*arg, "--")) {
17 if (false)
18 ;
19
20 else
21 cerr << "skipping unknown option " << *arg << '\n';
22 --argc; ++argv; ++arg;
23 }
24
25 if (is_equal(argv[1], "help")) {
26 if (argc == 2) {
27 cerr << "help on what?\n";
28 help_contents();
29 return 0;
30 }
31 string key(argv[2]);
32
33 if (contains_key(Help, key)) {
34 cerr << get(Help, key);
35 return 0;
36 }
37 else {
38 cerr << "No help found for '" << key << "'\n";
39 help_contents();
40 cerr << "Please check your command for typos.\n";
41 return 1;
42 }
43 }
44
45 :(code)
46 void help_contents() {
47 cerr << "Available top-level topics:\n";
48 cerr << " usage\n";
49
50 }
51
52 :(before "End Globals")
53 map<string, string> Help;
54 :(before "End Includes")
55
56 using std::map;
57 :(before "End One-time Setup")
58 init_help();
59 :(code)
60 void init_help() {
61 put(Help, "usage",
62 "Welcome to SubX, a better way to program in machine code.\n"
63 "SubX uses a subset of the x86 instruction set. SubX programs will run\n"
64 "without modification on Linux computers.\n"
65 "It provides a better experience and better error messages than\n"
66 "programming directly in machine code, but you have to stick to the\n"
67 "instructions it supports.\n"
68 "\n"
69 "== Ways to invoke subx\n"
70 "- Run tests:\n"
71 " subx test\n"
72 "- See this message:\n"
73 " subx --help\n"
74 "- Convert a textual SubX program into a standard ELF binary that you can\n"
75 " run on your computer:\n"
76 " subx translate input1.subx intput2.subx ... -o <output ELF binary>\n"
77 "- Run a SubX binary using SubX itself (for better error messages):\n"
78 " subx run <ELF binary>\n"
79 "Add '--trace' to any of these commands to also emit a trace, for debugging purposes.\n"
80 "However, options starting with '--' must always come before any other arguments.\n"
81 "\n"
82 "To start learning how to write SubX programs, run:\n"
83 " subx help\n"
84 );
85
86 }
87
88 :(code)
89 bool is_equal(char* s, const char* lit) {
90 return strncmp(s, lit, strlen(lit)) == 0;
91 }
92
93 bool starts_with(const string& s, const string& pat) {
94 string::const_iterator a=s.begin(), b=pat.begin();
95 for (; a!=s.end() && b!=pat.end(); ++a, ++b)
96 if (*a != *b) return false;
97 return b == pat.end();
98 }
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 :(before "End Includes")
157
158
159
160
161
162 :(before "atexit(reset)")
163 initialize_signal_handlers();
164
165
166 :(code)
167
168 void initialize_signal_handlers() {
169 struct sigaction action;
170 bzero(&action, sizeof(action));
171 action.sa_sigaction = dump_and_exit;
172 sigemptyset(&action.sa_mask);
173 sigaction(SIGABRT, &action, NULL);
174 sigaction(SIGILL, &action, NULL);
175 }
176 void dump_and_exit(int sig, siginfo_t* , void* ) {
177 switch (sig) {
178 case SIGABRT:
179
180 cerr << "SIGABRT: might be an integer overflow if it wasn't an assert() failure\n";
181 _Exit(1);
182
183 break;
184 case SIGILL:
185
186 cerr << "SIGILL: most likely caused by integer overflow\n";
187 _Exit(1);
188
189 break;
190 default:
191 break;
192 }
193 }
194 :(before "End Includes")
195
196
197
198 :(before "atexit(reset)")
199 feenableexcept(FE_OVERFLOW | FE_UNDERFLOW);
200
201
202
203
204
205
206 :(before "End Includes")
207
208 :(code)
209
210
211
212 int feenableexcept(unsigned int excepts) {
213 static fenv_t fenv;
214 unsigned int new_excepts = excepts & FE_ALL_EXCEPT;
215 unsigned int old_excepts;
216 if (fegetenv(&fenv)) return -1;
217 old_excepts = fenv.__control & FE_ALL_EXCEPT;
218 fenv.__control &= ~new_excepts;
219 fenv.__mxcsr &= ~(new_excepts << 7);
220 return fesetenv(&fenv) ? -1 : old_excepts;
221 }
222
223
224
225 :(before "Globals")
226
227 template<typename T> typename T::mapped_type& get(T& map, typename T::key_type const& key) {
228 typename T::iterator iter(map.find(key));
229 if (iter == map.end()) {
230 cerr << "get couldn't find key '" << key << "'\n";
231 assert(iter != map.end());
232 }
233 return iter->second;
234 }
235 template<typename T> typename T::mapped_type const& get(const T& map, typename T::key_type const& key) {
236 typename T::const_iterator iter(map.find(key));
237 if (iter == map.end()) {
238 cerr << "get couldn't find key '" << key << "'\n";
239 assert(iter != map.end());
240 }
241 return iter->second;
242 }
243 template<typename T> typename T::mapped_type const& put(T& map, typename T::key_type const& key, typename T::mapped_type const& value) {
244 map[key] = value;
245 return map[key];
246 }
247 template<typename T> bool contains_key(T& map, typename T::key_type const& key) {
248 return map.find(key) != map.end();
249 }
250 template<typename T> typename T::mapped_type& get_or_insert(T& map, typename T::key_type const& key) {
251 return map[key];
252 }
253 template<typename T> typename T::mapped_type const& put_new(T& map, typename T::key_type const& key, typename T::mapped_type const& value) {
254 assert(map.find(key) == map.end());
255 map[key] = value;
256 return map[key];
257 }
258
259
260
261
262
263
264 :(code)
265 bool has_data(istream& in) {
266 return in && !in.eof();
267 }
268
269 :(before "End Includes")
270
271
272
273 using std::istream;
274 using std::ostream;
275 using std::iostream;
276 using std::cin;
277 using std::cout;
278 using std::cerr;
279
280
281
282
283 using std::string;
284
285
286 using std::min;
287 using std::max;