optc-gen.awk 18.6 KB
Newer Older
1
#  Copyright (C) 2003-2014 Free Software Foundation, Inc.
Kelley Cook committed
2 3 4 5 6
#  Contributed by Kelley Cook, June 2004.
#  Original code from Neil Booth, May 2003.
#
# This program is free software; you can redistribute it and/or modify it
# 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
Kelley Cook committed
8 9 10 11 12 13 14 15
# later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
16 17
# along with this program; see the file COPYING3.  If not see
# <http://www.gnu.org/licenses/>.
Kelley Cook committed
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
Kelley Cook committed
21 22
# C file.
#
Joseph Myers committed
23 24 25

# This program uses functions from opt-functions.awk and code from
# opt-read.awk.
Kelley Cook committed
26
#
Joseph Myers committed
27
# Usage: awk -f opt-functions.awk -f opt-read.awk -f optc-gen.awk \
Kelley Cook committed
28 29 30 31
#            [-v header_name=header.h] < inputfile > options.c

# Dump that array of options into a C file.
END {
32 33 34 35 36 37 38 39 40

# Record first EnabledBy and LangEnabledBy uses.
n_enabledby = 0;
for (i = 0; i < n_langs; i++) {
    n_enabledby_lang[i] = 0;
}
for (i = 0; i < n_opts; i++) {
    enabledby_arg = opt_args("EnabledBy", flags[i]);
    if (enabledby_arg != "") {
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
        n_enabledby_names = split(enabledby_arg, enabledby_names, " && ");
        if (n_enabledby_names > 2) {
            print "#error EnabledBy (Wfoo && Wbar && Wbaz) not currently supported"
        }
        for (j = 1; j <= n_enabledby_names; j++) {
            enabledby_name = enabledby_names[j];
            enabledby_index = opt_numbers[enabledby_name];
            if (enabledby_index == "") {
                print "#error Enabledby: " enabledby_name 
            } else {
                condition = "";
                if (n_enabledby_names == 2) {
                    opt_var_name_1 = search_var_name(enabledby_names[1], opt_numbers, opts, flags, n_opts);
                    opt_var_name_2 = search_var_name(enabledby_names[2], opt_numbers, opts, flags, n_opts);
                    if (opt_var_name_1 == "") {
                        print "#error " enabledby_names[1] " does not have a Var() flag"
                    }
                    if (opt_var_name_2 == "") {
                        print "#error " enabledby_names[2] " does not have a Var() flag"
                    }
                    condition = "opts->x_" opt_var_name_1 " && opts->x_" opt_var_name_2;
                }
                if (enables[enabledby_name] == "") {
                    enabledby[n_enabledby] = enabledby_name;
                    n_enabledby++;
                }
                enables[enabledby_name] = enables[enabledby_name] opts[i] ";";
                enablesif[enabledby_name] = enablesif[enabledby_name] condition ";";
69 70 71 72 73 74
            }
        }
    }

    enabledby_arg = opt_args("LangEnabledBy", flags[i]);
    if (enabledby_arg != "") {
75
        enabledby_langs = nth_arg(0, enabledby_arg);
76
        enabledby_name = nth_arg(1, enabledby_arg);
77 78 79
        enabledby_posarg = nth_arg(2, enabledby_arg);
	enabledby_negarg = nth_arg(3, enabledby_arg);
        lang_enabled_by(enabledby_langs, enabledby_name, enabledby_posarg, enabledby_negarg);
80 81 82 83
    }
}


84
print "/* This file is auto-generated by optc-gen.awk.  */"
Kelley Cook committed
85
print ""
86 87 88
n_headers = split(header_name, headers, " ")
for (i = 1; i <= n_headers; i++)
	print "#include " quote headers[i] quote
Kelley Cook committed
89
print "#include " quote "opts.h" quote
90
print "#include " quote "intl.h" quote
91
print "#include " quote "insn-attr-common.h" quote
Kelley Cook committed
92 93
print ""

94 95 96 97 98 99 100
if (n_extra_c_includes > 0) {
	for (i = 0; i < n_extra_c_includes; i++) {
		print "#include " quote extra_c_includes[i] quote
	}
	print ""
}

101 102 103 104 105 106 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
for (i = 0; i < n_enums; i++) {
	name = enum_names[i]
	type = enum_type[name]
	print "static const struct cl_enum_arg cl_enum_" name \
	    "_data[] = "
	print "{"
	print enum_data[name] "  { NULL, 0, 0 }"
	print "};"
	print ""
	print "static void"
	print "cl_enum_" name "_set (void *var, int value)"
	print "{"
	print "  *((" type " *) var) = (" type ") value;"
	print "}"
	print ""
	print "static int"
	print "cl_enum_" name "_get (const void *var)"
	print "{"
	print "  return (int) *((const " type " *) var);"
	print "}"
	print ""
}

print "const struct cl_enum cl_enums[] ="
print "{"
for (i = 0; i < n_enums; i++) {
	name = enum_names[i]
	ehelp = enum_help[name]
	if (ehelp == "")
		ehelp = "NULL"
	else
		ehelp = quote ehelp quote
	unknown_error = enum_unknown_error[name]
	if (unknown_error == "")
		unknown_error = "NULL"
	else
		unknown_error = quote unknown_error quote
	print "  {"
	print "    " ehelp ","
	print "    " unknown_error ","
	print "    cl_enum_" name "_data,"
	print "    sizeof (" enum_type[name] "),"
	print "    cl_enum_" name "_set,"
	print "    cl_enum_" name "_get"
	print "  },"
}
print "};"
print "const unsigned int cl_enums_count = " n_enums ";"
print ""

151
print "const struct gcc_options global_options_init =\n{"
152
for (i = 0; i < n_extra_vars; i++) {
153 154 155 156 157 158 159
	var = extra_vars[i]
	init = extra_vars[i]
	if (var ~ "=" ) {
		sub(".*= *", "", init)
	} else {
		init = "0"
	}
160 161 162 163 164 165
	sub(" *=.*", "", var)
	name = var
	sub("^.*[ *]", "", name)
	sub("\\[.*\\]$", "", name)
	var_seen[name] = 1
	print "  " init ", /* " name " */"
166
}
Kelley Cook committed
167 168 169 170 171
for (i = 0; i < n_opts; i++) {
	name = var_name(flags[i]);
	if (name == "")
		continue;

172 173 174 175 176
	init = opt_args("Init", flags[i])
	if (init != "") {
		if (name in var_init && var_init[name] != init)
			print "#error multiple initializers for " name
		var_init[name] = init
177
	}
178 179 180 181 182 183 184 185 186 187 188 189 190
}
for (i = 0; i < n_opts; i++) {
	name = var_name(flags[i]);
	if (name == "")
		continue;

	if (name in var_seen)
		continue;

	if (name in var_init)
		init = var_init[name]
	else
		init = "0"
191

192
	print "  " init ", /* " name " */"
193 194

	var_seen[name] = 1;
195
}
196 197
for (i = 0; i < n_opts; i++) {
	name = static_var(opts[i], flags[i]);
198 199 200 201
	if (name != "") {
		print "  0, /* " name " (private state) */"
		print "#undef x_" name
	}
202
}
203 204 205 206
for (i = 0; i < n_opts; i++) {
	if (flag_set_p("SetByCombined", flags[i]))
		print "  false, /* frontend_set_" var_name(flags[i]) " */"
}
207
print "};"
208
print ""
209
print "struct gcc_options global_options;"
210 211
print "struct gcc_options global_options_set;"
print ""
Kelley Cook committed
212 213 214

print "const char * const lang_names[] =\n{"
for (i = 0; i < n_langs; i++) {
215
        macros[i] = "CL_" lang_sanitized_name(langs[i])
Kelley Cook committed
216 217 218 219 220 221
	s = substr("         ", length (macros[i]))
	print "  " quote langs[i] quote ","
    }

print "  0\n};\n"
print "const unsigned int cl_options_count = N_OPTS;\n"
222 223 224
print "#if (1U << " n_langs ") > CL_MIN_OPTION_CLASS"
print "  #error the number of languages exceeds the implementation limit"
print "#endif"
225
print "const unsigned int cl_lang_count = " n_langs ";\n"
Kelley Cook committed
226 227 228

print "const struct cl_option cl_options[] =\n{"

229 230
j = 0
for (i = 0; i < n_opts; i++) {
Kelley Cook committed
231
	back_chain[i] = "N_OPTS";
232 233 234 235 236 237
	indices[opts[i]] = j;
	# Combine the flags of identical switches.  Switches
	# appear many times if they are handled by many front
	# ends, for example.
	while( i + 1 != n_opts && opts[i] == opts[i + 1] ) {
		flags[i + 1] = flags[i] " " flags[i + 1];
238 239
		if (help[i + 1] == "")
			help[i + 1] = help[i]
240
		else if (help[i] != "" && help[i + 1] != help[i])
241 242 243
			print "#error Multiple different help strings for " \
				opts[i] ":\n\t" help[i] "\n\t" help[i + 1]
				
244 245 246 247 248 249
		i++;
		back_chain[i] = "N_OPTS";
		indices[opts[i]] = j;
	}
	j++;
}
Kelley Cook committed
250

251
for (i = 0; i < n_opts; i++) {
252 253 254
	# With identical flags, pick only the last one.  The
	# earlier loop ensured that it has all flags merged,
	# and a nonempty help text if one of the texts was nonempty.
255 256 257
	while( i + 1 != n_opts && opts[i] == opts[i + 1] ) {
		i++;
	}
Kelley Cook committed
258

259
	len = length (opts[i]);
260
	enum = opt_enum(opts[i])
261 262 263 264 265 266 267 268 269 270 271

	# If this switch takes joined arguments, back-chain all
	# subsequent switches to it for which it is a prefix.  If
	# a later switch S is a longer prefix of a switch T, T
	# will be back-chained to S in a later iteration of this
	# for() loop, which is what we want.
	if (flag_set_p("Joined.*", flags[i])) {
		for (j = i + 1; j < n_opts; j++) {
			if (substr (opts[j], 1, len) != opts[i])
				break;
			back_chain[j] = enum;
Kelley Cook committed
272
		}
273
	}
Kelley Cook committed
274

275 276 277
	s = substr("                                  ", length (opts[i]))
	if (i + 1 == n_opts)
		comma = ""
Kelley Cook committed
278

279 280 281 282
	if (help[i] == "")
		hlp = "0"
	else
		hlp = quote help[i] quote;
Kelley Cook committed
283

284 285 286 287 288 289
	missing_arg_error = opt_args("MissingArgError", flags[i])
	if (missing_arg_error == "")
		missing_arg_error = "0"
	else
		missing_arg_error = quote missing_arg_error quote

290 291 292 293 294 295 296

	warn_message = opt_args("Warn", flags[i])
	if (warn_message == "")
		warn_message = "0"
	else
		warn_message = quote warn_message quote

297 298
	alias_arg = opt_args("Alias", flags[i])
	if (alias_arg == "") {
299 300 301 302
		if (flag_set_p("Ignore", flags[i]))
			alias_data = "NULL, NULL, OPT_SPECIAL_ignore"
		else
			alias_data = "NULL, NULL, N_OPTS"
303 304 305 306 307
	} else {
		alias_opt = nth_arg(0, alias_arg)
		alias_posarg = nth_arg(1, alias_arg)
		alias_negarg = nth_arg(2, alias_arg)

308
		if (var_ref(opts[i], flags[i]) != "-1")
309 310 311 312 313 314 315 316
			print "#error Alias setting variable"

		if (alias_posarg != "" && alias_negarg == "") {
			if (!flag_set_p("RejectNegative", flags[i]) \
			    && opts[i] ~ "^[Wfm]")
				print "#error Alias with single argument " \
					"allowing negative form"
		}
317 318 319 320 321
		if (alias_posarg != "" \
		    && flag_set_p("NegativeAlias", flags[i])) {
			print "#error Alias with multiple arguments " \
				"used with NegativeAlias"
		}
322 323 324 325 326 327 328 329 330 331 332 333 334

		alias_opt = opt_enum(alias_opt)
		if (alias_posarg == "")
			alias_posarg = "NULL"
		else
			alias_posarg = quote alias_posarg quote
		if (alias_negarg == "")
			alias_negarg = "NULL"
		else
			alias_negarg = quote alias_negarg quote
		alias_data = alias_posarg ", " alias_negarg ", " alias_opt
	}

335 336 337 338 339 340 341 342 343 344 345 346 347
	neg = opt_args("Negative", flags[i]);
	if (neg != "")
		idx = indices[neg]
	else {
		if (flag_set_p("RejectNegative", flags[i]))
			idx = -1;
		else {
			if (opts[i] ~ "^[Wfm]")
				idx = indices[opts[i]];
			else
				idx = -1;
		}
	}
348 349
	# Split the printf after %u to work around an ia64-hp-hpux11.23
	# awk bug.
350 351
	printf("  { %c-%s%c,\n    %s,\n    %s,\n    %s,\n    %s, %s, %u,",
	       quote, opts[i], quote, hlp, missing_arg_error, warn_message,
352
	       alias_data, back_chain[i], len)
353
	printf(" %d,\n", idx)
354 355
	condition = opt_args("Condition", flags[i])
	cl_flags = switch_flags(flags[i])
356 357
	cl_bit_fields = switch_bit_fields(flags[i])
	cl_zero_bit_fields = switch_bit_fields("")
358 359 360
	if (condition != "")
		printf("#if %s\n" \
		       "    %s,\n" \
361
		       "    0, %s,\n" \
362
		       "#else\n" \
363 364
		       "    0,\n" \
		       "    1 /* Disabled.  */, %s,\n" \
365
		       "#endif\n",
366
		       condition, cl_flags, cl_bit_fields, cl_zero_bit_fields)
367
	else
368 369 370
		printf("    %s,\n" \
		       "    0, %s,\n",
		       cl_flags, cl_bit_fields)
371 372
	printf("    %s, %s }%s\n", var_ref(opts[i], flags[i]),
	       var_set(flags[i]), comma)
Kelley Cook committed
373 374 375
}

print "};"
376

377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
print "\n\n"
print "bool                                                                  "
print "common_handle_option_auto (struct gcc_options *opts,                  "
print "                           struct gcc_options *opts_set,              "
print "                           const struct cl_decoded_option *decoded,   "
print "                           unsigned int lang_mask, int kind,          "
print "                           location_t loc,                            "
print "                           const struct cl_option_handlers *handlers, "
print "                           diagnostic_context *dc)                    "
print "{                                                                     "
print "  size_t scode = decoded->opt_index;                                  "
print "  int value = decoded->value;                                         "
print "  enum opt_code code = (enum opt_code) scode;                         "
print "                                                                      "
print "  gcc_assert (decoded->canonical_option_num_elements <= 2);           "
print "                                                                      "
print "  switch (code)                                                       "
print "    {                                                                 "
395
# Handle EnabledBy
396 397 398
for (i = 0; i < n_enabledby; i++) {
    enabledby_name = enabledby[i];
    print "    case " opt_enum(enabledby_name) ":"
399
    n_enables = split(enables[enabledby_name], thisenable, ";");
400 401 402 403
    n_enablesif = split(enablesif[enabledby_name], thisenableif, ";");
    if (n_enables != n_enablesif) {
        print "#error n_enables != n_enablesif: Something went wrong!"
    }
404 405
    for (j = 1; j < n_enables; j++) {
        opt_var_name = var_name(flags[opt_numbers[thisenable[j]]]);
406
        if (opt_var_name != "") {
407 408
            condition = "!opts_set->x_" opt_var_name
            if (thisenableif[j] != "") {
409 410 411
                value = "(" thisenableif[j] ")"
            } else {
                value = "value"
412 413
            }
            print "      if (" condition ")"
414
            print "        handle_generated_option (opts, opts_set,"
415
            print "                                 " opt_enum(thisenable[j]) ", NULL, " value ","
416 417 418 419
            print "                                 lang_mask, kind, loc, handlers, dc);"
        } else {
            print "#error " thisenable[j] " does not have a Var() flag"
        }
420 421 422 423 424 425 426 427 428
    }
    print "      break;\n"
}
print "    default:    "
print "      break;    "
print "    }           "
print "  return true;  "
print "}               "

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
# Handle LangEnabledBy
for (i = 0; i < n_langs; i++) {
    lang_name = lang_sanitized_name(langs[i]);
    mark_unused = " ATTRIBUTE_UNUSED";

    print "\n\n"
    print "bool                                                                  "
    print lang_name "_handle_option_auto (struct gcc_options *opts" mark_unused ",              "
    print "                           struct gcc_options *opts_set" mark_unused ",              "
    print "                           size_t scode" mark_unused ", const char *arg" mark_unused ", int value" mark_unused ",  "
    print "                           unsigned int lang_mask" mark_unused ", int kind" mark_unused ",          "
    print "                           location_t loc" mark_unused ",                            "
    print "                           const struct cl_option_handlers *handlers" mark_unused ", "
    print "                           diagnostic_context *dc" mark_unused ")                    "
    print "{                                                                     "
    print "  enum opt_code code = (enum opt_code) scode;                         "
    print "                                                                      "
    print "  switch (code)                                                       "
    print "    {                                                                 "
    
    for (k = 0; k < n_enabledby_lang[i]; k++) {
        enabledby_name = enabledby[lang_name,k];
        print "    case " opt_enum(enabledby_name) ":"
452 453 454 455 456 457 458 459 460 461 462 463 464
        n_thisenable = split(enables[lang_name,enabledby_name], thisenable, ";");
        for (j = 1; j < n_thisenable; j++) {
            n_thisenable_args = split(thisenable[j], thisenable_args, ",");
            if (n_thisenable_args == 1) {
                thisenable_opt = thisenable[j];
                value = "value";
            } else {
                thisenable_opt = thisenable_args[1];
                with_posarg = thisenable_args[2];
                with_negarg = thisenable_args[3];
                value = "value ? " with_posarg " : " with_negarg;
            }
            opt_var_name = var_name(flags[opt_numbers[thisenable_opt]]);
465 466 467
            if (opt_var_name != "") {
                print "      if (!opts_set->x_" opt_var_name ")"
                print "        handle_generated_option (opts, opts_set,"
468
                print "                                 " opt_enum(thisenable_opt) ", NULL, " value ","
469 470
                print "                                 lang_mask, kind, loc, handlers, dc);"
            } else {
471
                print "#error " thisenable_opt " does not have a Var() flag"
472
            }
473 474 475 476 477 478 479 480 481 482
        }
        print "      break;\n"
    }
    print "    default:    "
    print "      break;    "
    print "    }           "
    print "  return true;  "
    print "}               "
}

483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
#Handle CPP()
print "\n"
print "#include " quote "cpplib.h" quote;
print "void"
print "cpp_handle_option_auto (const struct gcc_options * opts,                   "
print "                        size_t scode, struct cpp_options * cpp_opts)"    
print "{                                                                     "
print "  enum opt_code code = (enum opt_code) scode;                         "
print "                                                                      "
print "  switch (code)                                                       "
print "    {                                                                 "
for (i = 0; i < n_opts; i++) {
    # With identical flags, pick only the last one.  The
    # earlier loop ensured that it has all flags merged,
    # and a nonempty help text if one of the texts was nonempty.
    while( i + 1 != n_opts && opts[i] == opts[i + 1] ) {
        i++;
    }

    cpp_option = nth_arg(0, opt_args("CPP", flags[i]));
503 504 505 506 507 508 509 510 511 512 513 514 515 516
    if (cpp_option != "") {
        opt_var_name = var_name(flags[i]);
        init = opt_args("Init", flags[i])
        if (opt_var_name != "" && init != "") {
            print "    case " opt_enum(opts[i]) ":"
            print "      cpp_opts->" cpp_option " = opts->x_" opt_var_name ";"
            print "      break;"
        } else if (opt_var_name == "" && init == "") {
            print "#error CPP() requires setting Init() and Var() for " opts[i]
        } else if (opt_var_name != "") {
            print "#error CPP() requires setting Init() for " opts[i]
        } else {
            print "#error CPP() requires setting Var() for " opts[i]
        }
517
    }
Kelley Cook committed
518
}
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
print "    default:    "
print "      break;    "
print "    }           "
print "}\n"
print "void"
print "init_global_opts_from_cpp(struct gcc_options * opts,                   "
print "                         const struct cpp_options * cpp_opts)"    
print "{                                                                     "
for (i = 0; i < n_opts; i++) {
    # With identical flags, pick only the last one.  The
    # earlier loop ensured that it has all flags merged,
    # and a nonempty help text if one of the texts was nonempty.
    while( i + 1 != n_opts && opts[i] == opts[i + 1] ) {
        i++;
    }
    cpp_option = nth_arg(0, opt_args("CPP", flags[i]));
    opt_var_name = var_name(flags[i]);
    if (cpp_option != "" && opt_var_name != "") {
        print "  opts->x_" opt_var_name " = cpp_opts->" cpp_option ";"
    }
}
print "}               "

}