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