1#  Copyright (C) 2003-2015 Free Software Foundation, Inc.
2#  Contributed by Kelley Cook, June 2004.
3#  Original code from Neil Booth, May 2003.
4#
5# This program is free software; you can redistribute it and/or modify it
6# under the terms of the GNU General Public License as published by the
7# Free Software Foundation; either version 3, or (at your option) any
8# later version.
9# 
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14# 
15# You should have received a copy of the GNU General Public License
16# along with this program; see the file COPYING3.  If not see
17# <http://www.gnu.org/licenses/>.
18
19# This Awk script reads in the option records generated from 
20# opt-gather.awk, combines the flags of duplicate options and generates a
21# C file.
22#
23
24# This program uses functions from opt-functions.awk and code from
25# opt-read.awk.
26#
27# Usage: awk -f opt-functions.awk -f opt-read.awk -f optc-gen.awk \
28#            [-v header_name=header.h] < inputfile > options.c
29
30# Dump that array of options into a C file.
31END {
32
33# Record first EnabledBy and LangEnabledBy uses.
34n_enabledby = 0;
35for (i = 0; i < n_langs; i++) {
36    n_enabledby_lang[i] = 0;
37}
38for (i = 0; i < n_opts; i++) {
39    enabledby_arg = opt_args("EnabledBy", flags[i]);
40    if (enabledby_arg != "") {
41        logical_and = index(enabledby_arg, " && ");
42        if (logical_and != 0) {
43            # EnabledBy(arg1 && arg2)
44            split_sep = " && ";
45        } else {
46            # EnabledBy(arg) or EnabledBy(arg1 || arg2 || arg3)
47            split_sep = " \\|\\| ";
48        }
49        n_enabledby_names = split(enabledby_arg, enabledby_names, split_sep);
50        if (logical_and != 0 && n_enabledby_names > 2) {
51            print "#error EnabledBy (Wfoo && Wbar && Wbaz) not currently supported"
52        }
53        for (j = 1; j <= n_enabledby_names; j++) {
54            enabledby_name = enabledby_names[j];
55            enabledby_index = opt_numbers[enabledby_name];
56            if (enabledby_index == "") {
57                print "#error Enabledby: " enabledby_name 
58            } else {
59                condition = "";
60                if (logical_and != 0) {
61                    opt_var_name_1 = search_var_name(enabledby_names[1], opt_numbers, opts, flags, n_opts);
62                    opt_var_name_2 = search_var_name(enabledby_names[2], opt_numbers, opts, flags, n_opts);
63                    if (opt_var_name_1 == "") {
64                        print "#error " enabledby_names[1] " does not have a Var() flag"
65                    }
66                    if (opt_var_name_2 == "") {
67                        print "#error " enabledby_names[2] " does not have a Var() flag"
68                    }
69                    condition = "opts->x_" opt_var_name_1 " && opts->x_" opt_var_name_2;
70                }
71                if (enables[enabledby_name] == "") {
72                    enabledby[n_enabledby] = enabledby_name;
73                    n_enabledby++;
74                }
75                enables[enabledby_name] = enables[enabledby_name] opts[i] ";";
76                enablesif[enabledby_name] = enablesif[enabledby_name] condition ";";
77            }
78        }
79    }
80
81    enabledby_arg = opt_args("LangEnabledBy", flags[i]);
82    if (enabledby_arg != "") {
83        enabledby_langs = nth_arg(0, enabledby_arg);
84        enabledby_name = nth_arg(1, enabledby_arg);
85        enabledby_posarg = nth_arg(2, enabledby_arg);
86	enabledby_negarg = nth_arg(3, enabledby_arg);
87        lang_enabled_by(enabledby_langs, enabledby_name, enabledby_posarg, enabledby_negarg);
88    }
89}
90
91
92print "/* This file is auto-generated by optc-gen.awk.  */"
93print ""
94n_headers = split(header_name, headers, " ")
95for (i = 1; i <= n_headers; i++)
96	print "#include " quote headers[i] quote
97print "#include " quote "opts.h" quote
98print "#include " quote "intl.h" quote
99print "#include " quote "insn-attr-common.h" quote
100print ""
101
102if (n_extra_c_includes > 0) {
103	for (i = 0; i < n_extra_c_includes; i++) {
104		print "#include " quote extra_c_includes[i] quote
105	}
106	print ""
107}
108
109for (i = 0; i < n_enums; i++) {
110	name = enum_names[i]
111	type = enum_type[name]
112	print "static const struct cl_enum_arg cl_enum_" name \
113	    "_data[] = "
114	print "{"
115	print enum_data[name] "  { NULL, 0, 0 }"
116	print "};"
117	print ""
118	print "static void"
119	print "cl_enum_" name "_set (void *var, int value)"
120	print "{"
121	print "  *((" type " *) var) = (" type ") value;"
122	print "}"
123	print ""
124	print "static int"
125	print "cl_enum_" name "_get (const void *var)"
126	print "{"
127	print "  return (int) *((const " type " *) var);"
128	print "}"
129	print ""
130}
131
132print "const struct cl_enum cl_enums[] ="
133print "{"
134for (i = 0; i < n_enums; i++) {
135	name = enum_names[i]
136	ehelp = enum_help[name]
137	if (ehelp == "")
138		ehelp = "NULL"
139	else
140		ehelp = quote ehelp quote
141	unknown_error = enum_unknown_error[name]
142	if (unknown_error == "")
143		unknown_error = "NULL"
144	else
145		unknown_error = quote unknown_error quote
146	print "  {"
147	print "    " ehelp ","
148	print "    " unknown_error ","
149	print "    cl_enum_" name "_data,"
150	print "    sizeof (" enum_type[name] "),"
151	print "    cl_enum_" name "_set,"
152	print "    cl_enum_" name "_get"
153	print "  },"
154}
155print "};"
156print "const unsigned int cl_enums_count = " n_enums ";"
157print ""
158
159print "const struct gcc_options global_options_init =\n{"
160for (i = 0; i < n_extra_vars; i++) {
161	var = extra_vars[i]
162	init = extra_vars[i]
163	if (var ~ "=" ) {
164		sub(".*= *", "", init)
165	} else {
166		init = "0"
167	}
168	sub(" *=.*", "", var)
169	name = var
170	sub("^.*[ *]", "", name)
171	sub("\\[.*\\]$", "", name)
172	var_seen[name] = 1
173	print "  " init ", /* " name " */"
174}
175for (i = 0; i < n_opts; i++) {
176	name = var_name(flags[i]);
177	if (name == "")
178		continue;
179
180	init = opt_args("Init", flags[i])
181	if (init != "") {
182		if (name in var_init && var_init[name] != init)
183			print "#error multiple initializers for " name
184		var_init[name] = init
185	}
186}
187for (i = 0; i < n_opts; i++) {
188	name = var_name(flags[i]);
189	if (name == "")
190		continue;
191
192	if (name in var_seen)
193		continue;
194
195	if (name in var_init)
196		init = var_init[name]
197	else
198		init = "0"
199
200	print "  " init ", /* " name " */"
201
202	var_seen[name] = 1;
203}
204for (i = 0; i < n_opts; i++) {
205	name = static_var(opts[i], flags[i]);
206	if (name != "") {
207		print "  0, /* " name " (private state) */"
208		print "#undef x_" name
209	}
210}
211for (i = 0; i < n_opts; i++) {
212	if (flag_set_p("SetByCombined", flags[i]))
213		print "  false, /* frontend_set_" var_name(flags[i]) " */"
214}
215print "};"
216print ""
217print "struct gcc_options global_options;"
218print "struct gcc_options global_options_set;"
219print ""
220
221print "const char * const lang_names[] =\n{"
222for (i = 0; i < n_langs; i++) {
223        macros[i] = "CL_" lang_sanitized_name(langs[i])
224	s = substr("         ", length (macros[i]))
225	print "  " quote langs[i] quote ","
226    }
227
228print "  0\n};\n"
229print "const unsigned int cl_options_count = N_OPTS;\n"
230print "#if (1U << " n_langs ") > CL_MIN_OPTION_CLASS"
231print "  #error the number of languages exceeds the implementation limit"
232print "#endif"
233print "const unsigned int cl_lang_count = " n_langs ";\n"
234
235print "const struct cl_option cl_options[] =\n{"
236
237j = 0
238for (i = 0; i < n_opts; i++) {
239	back_chain[i] = "N_OPTS";
240	indices[opts[i]] = j;
241	# Combine the flags of identical switches.  Switches
242	# appear many times if they are handled by many front
243	# ends, for example.
244	while( i + 1 != n_opts && opts[i] == opts[i + 1] ) {
245		flags[i + 1] = flags[i] " " flags[i + 1];
246		if (help[i + 1] == "")
247			help[i + 1] = help[i]
248		else if (help[i] != "" && help[i + 1] != help[i])
249			print "#error Multiple different help strings for " \
250				opts[i] ":\n\t" help[i] "\n\t" help[i + 1]
251				
252		i++;
253		back_chain[i] = "N_OPTS";
254		indices[opts[i]] = j;
255	}
256	j++;
257}
258
259for (i = 0; i < n_opts; i++) {
260	# With identical flags, pick only the last one.  The
261	# earlier loop ensured that it has all flags merged,
262	# and a nonempty help text if one of the texts was nonempty.
263	while( i + 1 != n_opts && opts[i] == opts[i + 1] ) {
264		i++;
265	}
266
267	len = length (opts[i]);
268	enum = opt_enum(opts[i])
269
270	# If this switch takes joined arguments, back-chain all
271	# subsequent switches to it for which it is a prefix.  If
272	# a later switch S is a longer prefix of a switch T, T
273	# will be back-chained to S in a later iteration of this
274	# for() loop, which is what we want.
275	if (flag_set_p("Joined.*", flags[i])) {
276		for (j = i + 1; j < n_opts; j++) {
277			if (substr (opts[j], 1, len) != opts[i])
278				break;
279			back_chain[j] = enum;
280		}
281	}
282
283	s = substr("                                  ", length (opts[i]))
284	if (i + 1 == n_opts)
285		comma = ""
286
287	if (help[i] == "")
288		hlp = "0"
289	else
290		hlp = quote help[i] quote;
291
292	missing_arg_error = opt_args("MissingArgError", flags[i])
293	if (missing_arg_error == "")
294		missing_arg_error = "0"
295	else
296		missing_arg_error = quote missing_arg_error quote
297
298
299	warn_message = opt_args("Warn", flags[i])
300	if (warn_message == "")
301		warn_message = "0"
302	else
303		warn_message = quote warn_message quote
304
305	alias_arg = opt_args("Alias", flags[i])
306	if (alias_arg == "") {
307		if (flag_set_p("Ignore", flags[i]))
308			alias_data = "NULL, NULL, OPT_SPECIAL_ignore"
309		else
310			alias_data = "NULL, NULL, N_OPTS"
311	} else {
312		alias_opt = nth_arg(0, alias_arg)
313		alias_posarg = nth_arg(1, alias_arg)
314		alias_negarg = nth_arg(2, alias_arg)
315
316		if (var_ref(opts[i], flags[i]) != "-1")
317			print "#error Alias setting variable"
318
319		if (alias_posarg != "" && alias_negarg == "") {
320			if (!flag_set_p("RejectNegative", flags[i]) \
321			    && opts[i] ~ "^[Wfm]")
322				print "#error Alias with single argument " \
323					"allowing negative form"
324		}
325		if (alias_posarg != "" \
326		    && flag_set_p("NegativeAlias", flags[i])) {
327			print "#error Alias with multiple arguments " \
328				"used with NegativeAlias"
329		}
330
331		alias_opt = opt_enum(alias_opt)
332		if (alias_posarg == "")
333			alias_posarg = "NULL"
334		else
335			alias_posarg = quote alias_posarg quote
336		if (alias_negarg == "")
337			alias_negarg = "NULL"
338		else
339			alias_negarg = quote alias_negarg quote
340		alias_data = alias_posarg ", " alias_negarg ", " alias_opt
341	}
342
343	neg = opt_args("Negative", flags[i]);
344	if (neg != "")
345		idx = indices[neg]
346	else {
347		if (flag_set_p("RejectNegative", flags[i]))
348			idx = -1;
349		else {
350			if (opts[i] ~ "^[Wfm]")
351				idx = indices[opts[i]];
352			else
353				idx = -1;
354		}
355	}
356	# Split the printf after %u to work around an ia64-hp-hpux11.23
357	# awk bug.
358	printf("  { %c-%s%c,\n    %s,\n    %s,\n    %s,\n    %s, %s, %u,",
359	       quote, opts[i], quote, hlp, missing_arg_error, warn_message,
360	       alias_data, back_chain[i], len)
361	printf(" %d,\n", idx)
362	condition = opt_args("Condition", flags[i])
363	cl_flags = switch_flags(flags[i])
364	cl_bit_fields = switch_bit_fields(flags[i])
365	cl_zero_bit_fields = switch_bit_fields("")
366	if (condition != "")
367		printf("#if %s\n" \
368		       "    %s,\n" \
369		       "    0, %s,\n" \
370		       "#else\n" \
371		       "    0,\n" \
372		       "    1 /* Disabled.  */, %s,\n" \
373		       "#endif\n",
374		       condition, cl_flags, cl_bit_fields, cl_zero_bit_fields)
375	else
376		printf("    %s,\n" \
377		       "    0, %s,\n",
378		       cl_flags, cl_bit_fields)
379	printf("    %s, %s }%s\n", var_ref(opts[i], flags[i]),
380	       var_set(flags[i]), comma)
381}
382
383print "};"
384
385print "\n\n"
386print "bool                                                                  "
387print "common_handle_option_auto (struct gcc_options *opts,                  "
388print "                           struct gcc_options *opts_set,              "
389print "                           const struct cl_decoded_option *decoded,   "
390print "                           unsigned int lang_mask, int kind,          "
391print "                           location_t loc,                            "
392print "                           const struct cl_option_handlers *handlers, "
393print "                           diagnostic_context *dc)                    "
394print "{                                                                     "
395print "  size_t scode = decoded->opt_index;                                  "
396print "  int value = decoded->value;                                         "
397print "  enum opt_code code = (enum opt_code) scode;                         "
398print "                                                                      "
399print "  gcc_assert (decoded->canonical_option_num_elements <= 2);           "
400print "                                                                      "
401print "  switch (code)                                                       "
402print "    {                                                                 "
403# Handle EnabledBy
404for (i = 0; i < n_enabledby; i++) {
405    enabledby_name = enabledby[i];
406    print "    case " opt_enum(enabledby_name) ":"
407    n_enables = split(enables[enabledby_name], thisenable, ";");
408    n_enablesif = split(enablesif[enabledby_name], thisenableif, ";");
409    if (n_enables != n_enablesif) {
410        print "#error n_enables != n_enablesif: Something went wrong!"
411    }
412    for (j = 1; j < n_enables; j++) {
413        opt_var_name = var_name(flags[opt_numbers[thisenable[j]]]);
414        if (opt_var_name != "") {
415            condition = "!opts_set->x_" opt_var_name
416            if (thisenableif[j] != "") {
417                value = "(" thisenableif[j] ")"
418            } else {
419                value = "value"
420            }
421            print "      if (" condition ")"
422            print "        handle_generated_option (opts, opts_set,"
423            print "                                 " opt_enum(thisenable[j]) ", NULL, " value ","
424            print "                                 lang_mask, kind, loc, handlers, dc);"
425        } else {
426            print "#error " thisenable[j] " does not have a Var() flag"
427        }
428    }
429    print "      break;\n"
430}
431print "    default:    "
432print "      break;    "
433print "    }           "
434print "  return true;  "
435print "}               "
436
437# Handle LangEnabledBy
438for (i = 0; i < n_langs; i++) {
439    lang_name = lang_sanitized_name(langs[i]);
440    mark_unused = " ATTRIBUTE_UNUSED";
441
442    print "\n\n"
443    print "bool                                                                  "
444    print lang_name "_handle_option_auto (struct gcc_options *opts" mark_unused ",              "
445    print "                           struct gcc_options *opts_set" mark_unused ",              "
446    print "                           size_t scode" mark_unused ", const char *arg" mark_unused ", int value" mark_unused ",  "
447    print "                           unsigned int lang_mask" mark_unused ", int kind" mark_unused ",          "
448    print "                           location_t loc" mark_unused ",                            "
449    print "                           const struct cl_option_handlers *handlers" mark_unused ", "
450    print "                           diagnostic_context *dc" mark_unused ")                    "
451    print "{                                                                     "
452    print "  enum opt_code code = (enum opt_code) scode;                         "
453    print "                                                                      "
454    print "  switch (code)                                                       "
455    print "    {                                                                 "
456    
457    for (k = 0; k < n_enabledby_lang[i]; k++) {
458        enabledby_name = enabledby[lang_name,k];
459        print "    case " opt_enum(enabledby_name) ":"
460        n_thisenable = split(enables[lang_name,enabledby_name], thisenable, ";");
461        for (j = 1; j < n_thisenable; j++) {
462            n_thisenable_args = split(thisenable[j], thisenable_args, ",");
463            if (n_thisenable_args == 1) {
464                thisenable_opt = thisenable[j];
465                value = "value";
466            } else {
467                thisenable_opt = thisenable_args[1];
468                with_posarg = thisenable_args[2];
469                with_negarg = thisenable_args[3];
470                value = "value ? " with_posarg " : " with_negarg;
471            }
472            opt_var_name = var_name(flags[opt_numbers[thisenable_opt]]);
473            if (opt_var_name != "") {
474                print "      if (!opts_set->x_" opt_var_name ")"
475                print "        handle_generated_option (opts, opts_set,"
476                print "                                 " opt_enum(thisenable_opt) ", NULL, " value ","
477                print "                                 lang_mask, kind, loc, handlers, dc);"
478            } else {
479                print "#error " thisenable_opt " does not have a Var() flag"
480            }
481        }
482        print "      break;\n"
483    }
484    print "    default:    "
485    print "      break;    "
486    print "    }           "
487    print "  return true;  "
488    print "}               "
489}
490
491#Handle CPP()
492print "\n"
493print "#include " quote "cpplib.h" quote;
494print "void"
495print "cpp_handle_option_auto (const struct gcc_options * opts,                   "
496print "                        size_t scode, struct cpp_options * cpp_opts)"    
497print "{                                                                     "
498print "  enum opt_code code = (enum opt_code) scode;                         "
499print "                                                                      "
500print "  switch (code)                                                       "
501print "    {                                                                 "
502for (i = 0; i < n_opts; i++) {
503    # With identical flags, pick only the last one.  The
504    # earlier loop ensured that it has all flags merged,
505    # and a nonempty help text if one of the texts was nonempty.
506    while( i + 1 != n_opts && opts[i] == opts[i + 1] ) {
507        i++;
508    }
509
510    cpp_option = nth_arg(0, opt_args("CPP", flags[i]));
511    if (cpp_option != "") {
512        opt_var_name = var_name(flags[i]);
513        init = opt_args("Init", flags[i])
514        if (opt_var_name != "" && init != "") {
515            print "    case " opt_enum(opts[i]) ":"
516            print "      cpp_opts->" cpp_option " = opts->x_" opt_var_name ";"
517            print "      break;"
518        } else if (opt_var_name == "" && init == "") {
519            print "#error CPP() requires setting Init() and Var() for " opts[i]
520        } else if (opt_var_name != "") {
521            print "#error CPP() requires setting Init() for " opts[i]
522        } else {
523            print "#error CPP() requires setting Var() for " opts[i]
524        }
525    }
526}
527print "    default:    "
528print "      break;    "
529print "    }           "
530print "}\n"
531print "void"
532print "init_global_opts_from_cpp(struct gcc_options * opts,                   "
533print "                         const struct cpp_options * cpp_opts)"    
534print "{                                                                     "
535for (i = 0; i < n_opts; i++) {
536    # With identical flags, pick only the last one.  The
537    # earlier loop ensured that it has all flags merged,
538    # and a nonempty help text if one of the texts was nonempty.
539    while( i + 1 != n_opts && opts[i] == opts[i + 1] ) {
540        i++;
541    }
542    cpp_option = nth_arg(0, opt_args("CPP", flags[i]));
543    opt_var_name = var_name(flags[i]);
544    if (cpp_option != "" && opt_var_name != "") {
545        print "  opts->x_" opt_var_name " = cpp_opts->" cpp_option ";"
546    }
547}
548print "}               "
549
550}
551
552