https://github.com/akkartik/mu/blob/master/subx/001help.cc
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 #include <map>
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 "\n"
80 "== Debugging aids\n"
81 "- Add '--trace' to any of these commands to print a trace to stderr\n"
82 " for debugging purposes.\n"
83 "- Add '--debug' to add information to traces. 'subx --debug translate' will\n"
84 " save various mappings to files that 'subx --debug --trace run'\n"
85 " can use to make traces more informative.\n"
86 "\n"
87 "Options starting with '--' must always come before any other arguments.\n"
88 "\n"
89 "To start learning how to write SubX programs, see Readme.md (particularly\n"
90 "the section on the x86 instruction set) and then run:\n"
91 " subx help\n"
92 );
93
94 }
95
96 :(code)
97 bool is_equal(char* s, const char* lit) {
98 return strncmp(s, lit, strlen(lit)) == 0;
99 }
100
101 bool starts_with(const string& s, const string& pat) {
102 string::const_iterator a=s.begin(), b=pat.begin();
103 for (; a!=s.end() && b!=pat.end(); ++a, ++b)
104 if (*a != *b) return false;
105 return b == pat.end();
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
157
158
159
160
161
162
163
164 :(before "End Includes")
165 #define SIZE(X) (assert((X).size() < (1LL<<(sizeof(int)*8-2))), static_cast<int>((X).size()))
166
167
168
169
170 :(before "atexit(reset)")
171 initialize_signal_handlers();
172
173
174 :(code)
175
176 void initialize_signal_handlers() {
177 struct sigaction action;
178 bzero(&action, sizeof(action));
179 action.sa_sigaction = dump_and_exit;
180 sigemptyset(&action.sa_mask);
181 sigaction(SIGABRT, &action, NULL);
182 sigaction(SIGILL, &action, NULL);
183 }
184 void dump_and_exit(int sig, siginfo_t* , void* ) {
185 switch (sig) {
186 case SIGABRT:
187 #ifndef __APPLE__
188 cerr << "SIGABRT: might be an integer overflow if it wasn't an assert() failure\n";
189 _Exit(1);
190 #endif
191 break;
192 case SIGILL:
193 #ifdef __APPLE__
194 cerr << "SIGILL: most likely caused by integer overflow\n";
195 _Exit(1);
196 #endif
197 break;
198 default:
199 break;
200 }
201 }
202 :(before "End Includes")
203 #include <signal.h>
204
205
206 :(before "atexit(reset)")
207 feenableexcept(FE_OVERFLOW | FE_UNDERFLOW);
208
209
210
211
212
213
214 :(before "End Includes")
215 #include <fenv.h>
216 :(code)
217 #ifdef __APPLE__
218
219
220 int feenableexcept(unsigned int excepts) {
221 static fenv_t fenv;
222 unsigned int new_excepts = excepts & FE_ALL_EXCEPT;
223 unsigned int old_excepts;
224 if (fegetenv(&fenv)) return -1;
225 old_excepts = fenv.__control & FE_ALL_EXCEPT;
226 fenv.__control &= ~new_excepts;
227 fenv.__mxcsr &= ~(new_excepts << 7);
228 return fesetenv(&fenv) ? -1 : old_excepts;
229 }
230 #endif
231
232
233 :(before "Globals")
234
235 template<typename T> typename T::mapped_type& get(T& map, typename T::key_type const& key) {
236 typename T::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& get(const T& map, typename T::key_type const& key) {
244 typename T::const_iterator iter(map.find(key));
245 if (iter == map.end()) {
246 cerr << "get couldn't find key '" << key << "'\n";
247 assert(iter != map.end());
248 }
249 return iter->second;
250 }
251 template<typename T> typename T::mapped_type const& put(T& map, typename T::key_type const& key, typename T::mapped_type const& value) {
252 map[key] = value;
253 return map[key];
254 }
255 template<typename T> bool contains_key(T& map, typename T::key_type const& key) {
256 return map.find(key) != map.end();
257 }
258 template<typename T> typename T::mapped_type& get_or_insert(T& map, typename T::key_type const& key) {
259 return map[key];
260 }
261 template<typename T> typename T::mapped_type const& put_new(T& map, typename T::key_type const& key, typename T::mapped_type const& value) {
262 assert(map.find(key) == map.end());
263 map[key] = value;
264 return map[key];
265 }
266
267
268
269
270
271
272 :(code)
273 bool has_data(istream& in) {
274 return in && !in.eof();
275 }
276
277 :(before "End Includes")
278 #include <assert.h>
279
280 #include <iostream>
281 using std::istream;
282 using std::ostream;
283 using std::iostream;
284 using std::cin;
285 using std::cout;
286 using std::cerr;
287 #include <iomanip>
288
289 #include <string.h>
290 #include <string>
291 using std::string;
292
293 #include <algorithm>
294 using std::min;
295 using std::max;