source: libcfa/src/parseargs.cfa@ d9b7b66

Last change on this file since d9b7b66 was f02f546, checked in by Michael Brooks <mlbrooks@…>, 2 years ago

Implement new rules for array dimension expression matching.

Core changes:
src/ResolvExpr/Unify.cc: add sense of "these two expressions unify"
src/InitTweak/GenInit.cc: make hoisting happen more often
tests/array-container/*: reconfigure the array-dimension test to use non-"classic" expectation rules

Misc contributors and noise:
libcfa/src/parseargs.cfa: ,ake a parameter, that's used as a length expression, constant (example of an array user following new rules)
src/ResolvExpr/ResolveTypeof.h: make fixArrayType public
src/Validate/GenericParameter.cpp: do the array-type desugaring in both AST corners that forall-variables can be found (not just in one of them)
tests/.expect/typedefRedef-ERR1.txt: old one was "expecting" a bug, that new array rules handle correctly

  • Property mode set to 100644
File size: 10.5 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2022 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// parseargs.cfa
8// implementation of arguments parsing (argc, argv)
9//
10// Author : Thierry Delisle
11// Created On : Wed Oct 12 15:28:01 2022
12// Last Modified By :
13// Last Modified On :
14// Update Count :
15//
16
17#include "parseargs.hfa"
18
19#include <assert.h>
20#include <ctype.h>
21#include <stdint.h>
22#include <string.h>
23#include <errno.h>
24#include <unistd.h>
25
26extern "C" {
27 #include <getopt.h>
28 #include <sys/ioctl.h>
29
30 struct FILE;
31 extern FILE * stderr;
32 extern FILE * stdout;
33
34 extern int fileno(FILE *stream);
35
36 extern int fprintf ( FILE * stream, const char * format, ... );
37
38 extern long long int strtoll (const char* str, char** endptr, int base);
39 extern unsigned long long int strtoull(const char* str, char** endptr, int base);
40 extern double strtod (const char* str, char** endptr);
41}
42
43#include "common.hfa"
44#include "limits.hfa"
45
46#pragma GCC visibility push(default)
47
48extern int cfa_args_argc __attribute__((weak));
49extern char ** cfa_args_argv __attribute__((weak));
50extern char ** cfa_args_envp __attribute__((weak));
51
52forall([N])
53static void usage(char * cmd, const array( cfa_option, N ) & options, const char * usage, FILE * out) __attribute__ ((noreturn));
54//-----------------------------------------------------------------------------
55// checking
56forall([N])
57static void check_args( const array( cfa_option, N ) & options ) {
58 for(i; N) {
59 for(j; N) {
60 if(i == j) continue;
61
62 if( options[i].short_name != '\0'
63 && options[i].short_name == options[j].short_name)
64 abort("Parse Args error: two options have short name '%c' (%zu & %zu)", options[i].short_name, i, j);
65
66 if(0 == strcmp(options[i].long_name, options[j].long_name)) abort("Parse Args error: two options have long name '%s' (%zu & %zu)", options[i].long_name, i, j);
67 }
68 }
69}
70
71
72//-----------------------------------------------------------------------------
73// Parsing args
74forall([opt_count]) {
75 void parse_args( const array( cfa_option, opt_count ) & options, const char * usage, char ** & left ) {
76 if( 0p != &cfa_args_argc ) {
77 parse_args(cfa_args_argc, cfa_args_argv, options, usage, left );
78 }
79 else {
80 char * temp = "";
81 parse_args(0, &temp, options, usage, left );
82 }
83 }
84
85 void parse_args(
86 int argc,
87 char * argv[],
88 const array( cfa_option, opt_count ) & options,
89 const char * usage,
90 char ** & left
91 ) {
92 check_args(options);
93
94 int maxv = 'h';
95 char optstring[(opt_count * 3) + 2] = { '\0' };
96 {
97 int idx = 0;
98 for(i; opt_count) {
99 if (options[i].short_name) {
100 maxv = max(options[i].short_name, maxv);
101 optstring[idx] = options[i].short_name;
102 idx++;
103 if( ((intptr_t)options[i].parse) != ((intptr_t)parse_settrue)
104 && ((intptr_t)options[i].parse) != ((intptr_t)parse_setfalse) ) {
105 optstring[idx] = ':';
106 idx++;
107 }
108 }
109 }
110 optstring[idx+0] = 'h';
111 optstring[idx+1] = '\0';
112 }
113
114 struct option optarr[opt_count + 2];
115 {
116 int idx = 0;
117 for(i; opt_count) {
118 if(options[i].long_name) {
119 // we don't have the mutable keyword here, which is really what we would want
120 int & val_ref = (int &)(const int &)options[i].val;
121 val_ref = (options[i].short_name != '\0') ? ((int)options[i].short_name) : ++maxv;
122
123 optarr[idx].name = options[i].long_name;
124 optarr[idx].flag = 0p;
125 optarr[idx].val = options[i].val;
126 if( ((intptr_t)options[i].parse) == ((intptr_t)parse_settrue)
127 || ((intptr_t)options[i].parse) == ((intptr_t)parse_setfalse) ) {
128 optarr[idx].has_arg = no_argument;
129 } else {
130 optarr[idx].has_arg = required_argument;
131 }
132 idx++;
133 }
134 }
135 optarr[idx+0].[name, has_arg, flag, val] = ["help", no_argument, 0, 'h'];
136 optarr[idx+1].[name, has_arg, flag, val] = [0, no_argument, 0, 0];
137 }
138
139 FILE * out = stderr;
140 NEXT_ARG:
141 for() {
142 int idx = 0;
143 int opt = getopt_long(argc, argv, optstring, optarr, &idx);
144 switch(opt) {
145 case -1:
146 if(&left != 0p) left = argv + optind;
147 return;
148 case 'h':
149 out = stdout;
150 case '?':
151 usage(argv[0], options, usage, out);
152 default:
153 for(i; opt_count) {
154 if(opt == options[i].val) {
155 const char * arg = optarg ? optarg : "";
156 if( arg[0] == '=' ) { arg++; }
157 // work around for some weird bug
158 void * variable = options[i].variable;
159 bool (*parse_func)(const char *, void * ) = options[i].parse;
160 bool success = parse_func( arg, variable );
161 if(success) continue NEXT_ARG;
162
163 fprintf(out, "Argument '%s' for option %c could not be parsed\n\n", arg, (char)opt);
164 usage(argv[0], options, usage, out);
165 }
166 }
167 abort("Internal parse arg error\n");
168 }
169
170 }
171 }
172}
173
174static inline int next_newline(const char * str) {
175 int ret;
176 const char * ptr = strstr(str, "\n");
177 if(!ptr) return MAX;
178
179 /* paranoid */ verify( str <= ptr);
180 intptr_t low = (intptr_t)str;
181 intptr_t hi = (intptr_t)ptr;
182 ret = hi - low;
183
184 return ret;
185}
186
187//-----------------------------------------------------------------------------
188// Print usage
189static void printopt(FILE * out, int width, int max, char sn, const char * ln, const char * help) {
190 // check how wide we should be printing
191 // this includes all options and the help message
192 int hwidth = max - (11 + width);
193 if(hwidth <= 0) hwidth = max;
194
195 // check which pieces we have
196 bool has_ln = ln && strcmp("", ln);
197 bool has_help = help && strcmp("", help);
198
199 // print the small name if present
200 if(sn != '\0') fprintf(out, " -%c", sn);
201 else fprintf(out, " ");
202
203 // print a comma if we have both short and long names
204 if(sn != '\0' && has_ln) fprintf(out, ", ");
205 else fprintf(out, " ");
206
207 // print the long name if present
208 if(has_ln) fprintf(out, "--%-*s", width, ln);
209 else if(has_help) fprintf(out, " %-*s", width, "");
210
211 if(has_help) {
212 // print the help
213 // We need to wrap at the max width, and also indent newlines so everything is nice and pretty
214
215 // for each line to print
216 for() {
217 //find out if there is a newline
218 int nextnl = next_newline(help);
219 int real = min(min(strlen(help), hwidth), nextnl);
220
221 fprintf(out, " %.*s", real, help);
222 // printf("%d %d\n", real, nextnl);
223 help += real;
224 if( nextnl == real ) help++;
225 if('\0' == *help) break;
226 fprintf(out, "\n%*s", width + 8, "");
227 }
228 }
229 fprintf(out, "\n");
230}
231
232void print_args_usage(cfa_option options[], const size_t opt_count, const char * usage, bool error) __attribute__ ((noreturn)) {
233 const array( cfa_option, opt_count ) & arr = (const array( cfa_option, opt_count ) &) *options;
234 usage(cfa_args_argv[0], arr, usage, error ? stderr : stdout);
235}
236
237void print_args_usage(int , char * argv[], cfa_option options[], const size_t opt_count, const char * usage, bool error) __attribute__ ((noreturn)) {
238 const array( cfa_option, opt_count ) & arr = (const array( cfa_option, opt_count ) &) *options;
239 usage(argv[0], arr, usage, error ? stderr : stdout);
240}
241
242forall( [N] ) {
243 void print_args_usage( const array(cfa_option, N ) & options, const char * usage, bool error) {
244 usage(cfa_args_argv[0], options, usage, error ? stderr : stdout);
245 }
246
247 void print_args_usage(int argc, char * argv[], const array( cfa_option, N ) & options, const char * usage, bool error) {
248 usage(argv[0], options, usage, error ? stderr : stdout);
249 }
250}
251
252forall([N])
253static void usage(char * cmd, const array( cfa_option, N ) & options, const char * help, FILE * out) __attribute__((noreturn)) {
254 int width = 0;
255 {
256 for(i; N) {
257 if(options[i].long_name) {
258 int w = strlen(options[i].long_name);
259 if(w > width) width = w;
260 }
261 }
262 }
263
264 int max_width = 1_000_000;
265 int outfd = fileno(out);
266 if(isatty(outfd)) {
267 struct winsize size;
268 int ret = ioctl(outfd, TIOCGWINSZ, &size);
269 if(ret < 0) abort( "ioctl error: (%d) %s\n", (int)errno, strerror(errno) );
270 max_width = size.ws_col;
271 }
272
273 fprintf(out, "Usage:\n %s %s\n", cmd, help);
274
275 for(i; N) {
276 printopt(out, width, max_width, options[i].short_name, options[i].long_name, options[i].help);
277 }
278 fprintf(out, " -%c, --%-*s %s\n", 'h', width, "help", "print this help message");
279 exit(out == stdout ? 0 : 1);
280}
281
282//-----------------------------------------------------------------------------
283// Typed argument parsing
284bool parse_yesno(const char * arg, bool & value ) {
285 if(strcmp(arg, "yes") == 0) {
286 value = true;
287 return true;
288 }
289
290 if(strcmp(arg, "Y") == 0) {
291 value = true;
292 return true;
293 }
294
295 if(strcmp(arg, "y") == 0) {
296 value = true;
297 return true;
298 }
299
300 if(strcmp(arg, "no") == 0) {
301 value = false;
302 return true;
303 }
304
305 if(strcmp(arg, "N") == 0) {
306 value = false;
307 return true;
308 }
309
310 if(strcmp(arg, "n") == 0) {
311 value = false;
312 return true;
313 }
314
315 return false;
316}
317
318bool parse_truefalse(const char * arg, bool & value) {
319 if(strcmp(arg, "true") == 0) {
320 value = true;
321 return true;
322 }
323
324 if(strcmp(arg, "false") == 0) {
325 value = false;
326 return true;
327 }
328
329 return false;
330}
331
332bool parse_settrue (const char *, bool & value ) {
333 value = true;
334 return true;
335}
336
337bool parse_setfalse(const char *, bool & value ) {
338 value = false;
339 return true;
340}
341
342bool parse(const char * arg, const char * & value ) {
343 value = arg;
344 return true;
345}
346
347bool parse(const char * arg, int & value) {
348 char * end;
349
350 errno = 0;
351 long long int r = strtoll(arg, &end, 0);
352 if(errno) return false;
353 if(*end != '\0') return false;
354 if(r > (int)MAX) return false;
355 if(r < (int)MIN) return false;
356
357 value = r;
358 return true;
359}
360
361static unsigned long long int strict_strtoull( const char * arg, int base) {
362 errno = 0;
363 {
364 const char * in = arg;
365 for() {
366 if('\0' == *in) {
367 errno = EINVAL;
368 return 0;
369 }
370 if(!isspace(*in)) break;
371 in++;
372 }
373 if(!isdigit(*in)) {
374 errno = EINVAL;
375 return 0;
376 }
377 }
378
379 *char end;
380 unsigned long long int r = strtoull(arg, &end, base);
381 if(*end != '\0') errno = EINVAL;
382 if(errno) return 0;
383 return r;
384}
385
386bool parse(const char * arg, unsigned & value) {
387 unsigned long long int r = strict_strtoull(arg, 0);
388 if(errno) return false;
389 if(r > (unsigned)MAX) return false;
390
391 value = r;
392 return true;
393}
394
395bool parse(const char * arg, unsigned long & value) {
396 unsigned long long int r = strict_strtoull(arg, 0);
397 if(errno) return false;
398 if(r > (unsigned long)MAX) return false;
399
400 value = r;
401 return true;
402}
403
404bool parse(const char * arg, unsigned long long & value) {
405 unsigned long long int r = strict_strtoull(arg, 0);
406 if(errno) return false;
407 if(r > (unsigned long long)MAX) return false;
408
409 value = r;
410 return true;
411}
412
413bool parse(const char * arg, double & value) {
414 char * end;
415 double r = strtod(arg, &end);
416 if(*end != '\0') return false;
417
418 value = r;
419 return true;
420}
Note: See TracBrowser for help on using the repository browser.