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