History

tcc options: document behavior and clashes (no-op)

The tcc options behavior is non trivial, and it's also susceptible to ambiguities - which do exist (but currently are not painful). - Add a script 'optclash' which detects clashes/ambiguities. - Document the parsing behaviour and current clashes/resolutions as comments in libtcc.c .

Avi Halachmi (:avih) committed 1 year ago

Commit 234e2dd1 parent 01d1b7b2 files · +83 −0Browse files

Unified · Split

2 files
  1. libtcc.c +45 −0
  2. optclash +38 −0
libtcc.c+45−0
@@ -1571,6 +1571,30 @@ enum { · 1570 unmodified lines
15711571 #define TCC_OPTION_HAS_ARG 0x0001
15721572 #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
15731573
1574+/*
1575+ * in tcc_options, if opt-string A is a prefix of opt-string B,
1576+ * it's un-ambiguous if and only if option A is without TCC_OPTION_HAS_ARG.
1577+ * otherwise (A with HAS_ARG), if, for instance, A is FOO and B is FOOBAR,
1578+ * then "-FOOBAR" is either A with arg BAR, or B (-FOOBARX too, if B HAS_ARG).
1579+ *
1580+ * tcc_parse_args searches tcc_options in order, so if ambiguous:
1581+ * - if the shorter (A) is earlier: the longer (B) is completely unreachable.
1582+ * - else B wins, and A can't be used with adjacent arg if it also matches B.
1583+ *
1584+ * there are few clashes currently, and the longer is always earlier/reachable.
1585+ * when it's ambiguous, shorter-concat-arg is not useful currently.
1586+ * the sh(1) script 'optclash' can identifiy clashes (tcc root dir, try "-h").
1587+ * at the time of writing, running './optclash' prints this:
1588+
1589+ -Wl,... (1642) overrides -W... (1644)
1590+ -Wp,... (1643) overrides -W... (1644)
1591+ -dumpmachine (1630) overrides -d... (1632)
1592+ -dumpversion (1631) overrides -d... (1632)
1593+ -dynamiclib (1623) overrides -d... (1632)
1594+ -flat_namespace (1624) overrides -f... (1650)
1595+ -mfloat-abi... (1647) overrides -m... (1649)
1596+
1597+ */
15741598 static const TCCOption tcc_options[] = {
15751599 { "h", TCC_OPTION_HELP, 0 },
15761600 { "-help", TCC_OPTION_HELP, 0 },
@@ -1808,6 +1832,27 @@ static void args_parser_add_file(TCCState *s, const char* filename, int filetype · 231 unmodified lines
18081832 ++s->nb_libraries;
18091833 }
18101834
1835+/* parsing is between getopt(3) and getopt_long(3), and permuting-like:
1836+ * - an option is 1 or more chars.
1837+ * - at most 1 option per arg in argv.
1838+ * - an option in argv is "-OPT[...]" (few are --OPT, if OPT is "-...").
1839+ * - optarg is next arg, or adjacent non-empty (no '='. -std=.. is arg "=..").
1840+ * - supports also adjacent-only optarg (typically optional).
1841+ * - supports mixed options and operands ("--" is ignored, except with -run).
1842+ * - -OPT[...] can be ambiguous, which is resolved using tcc_options's order.
1843+ * (see tcc_options for details)
1844+ *
1845+ * specifically, per arg of argv, in order:
1846+ * - if arg begins with '@' and is not exactly "@": process as @listfile.
1847+ * - elif arg is exactly "-" or doesn't begin with '-': process as input file.
1848+ * - if -run... is already set: also stop, arg... become argv of run_main.
1849+ * - elif arg is "--":
1850+ * - if -run... is already set: stop, arg... become argv of run_main.
1851+ * - else ignore it.
1852+ * - else ("-STRING") try to apply it as option, maybe with next (opt)arg.
1853+ *
1854+ * after all args, if -run... but no "stop": run_main gets our argv (tcc ...)
1855+ */
18111856 /* using * to argc/argv to let "tcc -ar" benefit from @listfile expansion */
18121857 PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
18131858 {
optclash+38−0
@@ -0,0 +1,38 @@
1+#!/bin/sh
2+
3+export LC_ALL=C
4+
5+defname=libtcc.c
6+
7+# $1 is the line number, $2... is the actual source line
8+extract_opts() { awk '/tcc_options\[\]/ {x=1}; x; x && $2~/^}/ {exit}'; }
9+
10+case $1 in -h|--help)
11+ echo "Usage: $0 [INFILE]"
12+ echo "Detect tcc_options[] clashes in $defname-like INFILE."
13+ echo "If INFILE is missing, use $defname at the same dir as this script."
14+ echo "Clashes are reported as longer-overrides, or longer-unreachable."
15+ exit
16+esac
17+
18+f=${1-$(dirname "$0")/$defname}
19+[ -r "$f" ] || { >&2 echo "$0: can't read -- $f"; exit 1; }
20+
21+nl -b a <"$f" | extract_opts | tr \" ' ' | awk '$2=="{"' | sort -b -k 3 |
22+# "<line-num> { <unquoted-opt> <rest-of-line>" sorted-up by opt
23+# unavoidable O(N^2). the sort simplifies the awk code - only test prior opts.
24+awk '
25+ {
26+ n=$1; opt=$3; h=/HAS_ARG/
27+ for (pn in prevs) { # pn: line-num
28+ po = prevs[pn] # po: opt-with-has-arg
29+ if (index(opt,po) == 1) {
30+ clash=1
31+ printf("-%s%s (%d) %s -%s... (%s)\n", opt,h?"...":"",n,
32+ n>pn? "is not reachable! by":"overrides", po,pn)
33+ }
34+ }
35+ }
36+ h {prevs[n] = opt}
37+ END {if (clash) exit 1; print "no clashes"}
38+'

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t