muscle-tab.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. /* Muscle table manager for Bison.
  2. Copyright (C) 2001-2015, 2018-2021 Free Software Foundation, Inc.
  3. This file is part of Bison, the GNU Compiler Compiler.
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  14. #include <config.h>
  15. #include "system.h"
  16. #include <hash.h>
  17. #include <quote.h>
  18. #include "complain.h"
  19. #include "files.h"
  20. #include "fixits.h"
  21. #include "getargs.h"
  22. #include "muscle-tab.h"
  23. muscle_kind
  24. muscle_kind_new (char const *k)
  25. {
  26. if (STREQ (k, "code"))
  27. return muscle_code;
  28. else if (STREQ (k, "keyword"))
  29. return muscle_keyword;
  30. else if (STREQ (k, "string"))
  31. return muscle_string;
  32. abort ();
  33. }
  34. char const *
  35. muscle_kind_string (muscle_kind k)
  36. {
  37. switch (k)
  38. {
  39. case muscle_code: return "code";
  40. case muscle_keyword: return "keyword";
  41. case muscle_string: return "string";
  42. }
  43. abort ();
  44. }
  45. /* A key-value pair, along with storage that can be reclaimed when
  46. this pair is no longer needed. */
  47. typedef struct
  48. {
  49. char const *key;
  50. char const *value;
  51. char *storage;
  52. muscle_kind kind;
  53. } muscle_entry;
  54. /* The name of muscle for the %define variable VAR (corresponding to
  55. FIELD, if defined). */
  56. static uniqstr
  57. muscle_name (char const *var, char const *field)
  58. {
  59. if (field)
  60. return UNIQSTR_CONCAT ("percent_define_", field, "(", var, ")");
  61. else
  62. return UNIQSTR_CONCAT ("percent_define(", var, ")");
  63. }
  64. /* An obstack used to create some entries. */
  65. struct obstack muscle_obstack;
  66. /* Initial capacity of muscles hash table. */
  67. #define HT_INITIAL_CAPACITY 257
  68. static struct hash_table *muscle_table = NULL;
  69. static bool
  70. hash_compare_muscles (void const *x, void const *y)
  71. {
  72. muscle_entry const *m1 = x;
  73. muscle_entry const *m2 = y;
  74. return STREQ (m1->key, m2->key);
  75. }
  76. static size_t
  77. hash_muscle (const void *x, size_t tablesize)
  78. {
  79. muscle_entry const *m = x;
  80. return hash_string (m->key, tablesize);
  81. }
  82. /* Create a fresh muscle name KEY, and insert in the hash table. */
  83. static void *
  84. muscle_entry_new (char const *key)
  85. {
  86. muscle_entry *res = xmalloc (sizeof *res);
  87. res->key = key;
  88. res->value = NULL;
  89. res->storage = NULL;
  90. hash_xinsert (muscle_table, res);
  91. return res;
  92. }
  93. static void
  94. muscle_entry_free (void *entry)
  95. {
  96. muscle_entry *mentry = entry;
  97. free (mentry->storage);
  98. free (mentry);
  99. }
  100. void
  101. muscle_init (void)
  102. {
  103. /* Initialize the muscle obstack. */
  104. obstack_init (&muscle_obstack);
  105. muscle_table = hash_xinitialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
  106. hash_compare_muscles, muscle_entry_free);
  107. }
  108. void
  109. muscle_free (void)
  110. {
  111. hash_free (muscle_table);
  112. obstack_free (&muscle_obstack, NULL);
  113. }
  114. /* Look for the muscle named KEY. Return NULL if does not exist. */
  115. static muscle_entry *
  116. muscle_lookup (char const *key)
  117. {
  118. muscle_entry probe;
  119. probe.key = key;
  120. return hash_lookup (muscle_table, &probe);
  121. }
  122. void
  123. muscle_insert (char const *key, char const *value)
  124. {
  125. muscle_entry *entry = muscle_lookup (key);
  126. if (entry)
  127. free (entry->storage);
  128. else
  129. /* First insertion in the hash. */
  130. entry = muscle_entry_new (key);
  131. entry->value = value;
  132. entry->storage = NULL;
  133. }
  134. /* Append VALUE to the current value of KEY. If KEY did not already
  135. exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously
  136. associated value. Copy VALUE and SEPARATOR. If VALUE does not end
  137. with TERMINATOR, append one. */
  138. static void
  139. muscle_grow (const char *key, const char *val,
  140. const char *separator, const char *terminator)
  141. {
  142. muscle_entry *entry = muscle_lookup (key);
  143. if (entry)
  144. {
  145. obstack_sgrow (&muscle_obstack, entry->value);
  146. obstack_sgrow (&muscle_obstack, separator);
  147. free (entry->storage);
  148. }
  149. else
  150. entry = muscle_entry_new (key);
  151. obstack_sgrow (&muscle_obstack, val);
  152. size_t vals = strlen (val);
  153. size_t terms = strlen (terminator);
  154. if (terms <= vals
  155. && STRNEQ (val + vals - terms, terminator))
  156. obstack_sgrow (&muscle_obstack, terminator);
  157. {
  158. char const *new_val = obstack_finish0 (&muscle_obstack);
  159. entry->value = entry->storage = xstrdup (new_val);
  160. obstack_free (&muscle_obstack, new_val);
  161. }
  162. }
  163. /*------------------------------------------------------------------.
  164. | Using muscle_grow, append a synchronization line for the location |
  165. | LOC to the current value of KEY. |
  166. `------------------------------------------------------------------*/
  167. static void
  168. muscle_syncline_grow (char const *key, location loc)
  169. {
  170. obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
  171. obstack_quote (&muscle_obstack,
  172. quotearg_style (c_quoting_style, loc.start.file));
  173. obstack_sgrow (&muscle_obstack, ")dnl\n[");
  174. char const *extension = obstack_finish0 (&muscle_obstack);
  175. muscle_grow (key, extension, "", "");
  176. obstack_free (&muscle_obstack, extension);
  177. }
  178. /*------------------------------------------------------------------.
  179. | Append VALUE to the current value of KEY, using muscle_grow. But |
  180. | in addition, issue a synchronization line for the location LOC |
  181. | using muscle_syncline_grow. |
  182. `------------------------------------------------------------------*/
  183. void
  184. muscle_code_grow (const char *key, const char *val, location loc)
  185. {
  186. muscle_syncline_grow (key, loc);
  187. muscle_grow (key, val, "", "\n");
  188. }
  189. void
  190. muscle_pair_list_grow (const char *muscle,
  191. const char *a1, const char *a2)
  192. {
  193. obstack_sgrow (&muscle_obstack, "[");
  194. obstack_quote (&muscle_obstack, a1);
  195. obstack_sgrow (&muscle_obstack, ", ");
  196. obstack_quote (&muscle_obstack, a2);
  197. obstack_sgrow (&muscle_obstack, "]");
  198. char const *pair = obstack_finish0 (&muscle_obstack);
  199. muscle_grow (muscle, pair, ",\n", "");
  200. obstack_free (&muscle_obstack, pair);
  201. }
  202. char const *
  203. muscle_find_const (char const *key)
  204. {
  205. muscle_entry *entry = muscle_lookup (key);
  206. return entry ? entry->value : NULL;
  207. }
  208. char *
  209. muscle_find (char const *key)
  210. {
  211. muscle_entry *entry = muscle_lookup (key);
  212. if (entry)
  213. {
  214. aver (entry->value == entry->storage);
  215. return entry->storage;
  216. }
  217. return NULL;
  218. }
  219. /* In the format 'file_name:line.column', append BOUND to MUSCLE. Use
  220. digraphs for special characters in the file name. */
  221. static void
  222. muscle_boundary_grow (char const *key, boundary bound)
  223. {
  224. obstack_sgrow (&muscle_obstack, "[[");
  225. obstack_escape (&muscle_obstack, bound.file);
  226. obstack_printf (&muscle_obstack, ":%d.%d@@%d]]", bound.line, bound.column, bound.byte);
  227. char const *extension = obstack_finish0 (&muscle_obstack);
  228. muscle_grow (key, extension, "", "");
  229. obstack_free (&muscle_obstack, extension);
  230. }
  231. void
  232. muscle_location_grow (char const *key, location loc)
  233. {
  234. muscle_boundary_grow (key, loc.start);
  235. muscle_grow (key, "", ", ", "");
  236. muscle_boundary_grow (key, loc.end);
  237. }
  238. #define COMMON_DECODE(Value) \
  239. case '$': \
  240. ++(Value); aver (*(Value) == ']'); \
  241. ++(Value); aver (*(Value) == '['); \
  242. obstack_sgrow (&muscle_obstack, "$"); \
  243. break; \
  244. case '@': \
  245. switch (*++(Value)) \
  246. { \
  247. case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
  248. case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
  249. case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
  250. default: aver (false); break; \
  251. } \
  252. break; \
  253. default: \
  254. obstack_1grow (&muscle_obstack, *(Value)); \
  255. break;
  256. /* Reverse of obstack_escape. */
  257. static char *
  258. string_decode (char const *key)
  259. {
  260. char const *value = muscle_find_const (key);
  261. if (!value)
  262. return NULL;
  263. do {
  264. switch (*value)
  265. {
  266. COMMON_DECODE (value)
  267. case '[':
  268. case ']':
  269. aver (false);
  270. break;
  271. }
  272. } while (*value++);
  273. char const *value_decoded = obstack_finish (&muscle_obstack);
  274. char *res = xstrdup (value_decoded);
  275. obstack_free (&muscle_obstack, value_decoded);
  276. return res;
  277. }
  278. /* Reverse of muscle_location_grow. */
  279. static location
  280. location_decode (char const *value)
  281. {
  282. aver (value);
  283. aver (*value == '[');
  284. ++value; aver (*value == '[');
  285. location loc;
  286. while (*++value)
  287. switch (*value)
  288. {
  289. COMMON_DECODE (value)
  290. case '[':
  291. aver (false);
  292. break;
  293. case ']':
  294. ++value; aver (*value == ']');
  295. char *boundary_str = obstack_finish0 (&muscle_obstack);
  296. switch (*++value)
  297. {
  298. case ',':
  299. boundary_set_from_string (&loc.start, boundary_str);
  300. obstack_free (&muscle_obstack, boundary_str);
  301. ++value; aver (*value == ' ');
  302. ++value; aver (*value == '[');
  303. ++value; aver (*value == '[');
  304. break;
  305. case '\0':
  306. boundary_set_from_string (&loc.end, boundary_str);
  307. obstack_free (&muscle_obstack, boundary_str);
  308. return loc;
  309. break;
  310. default:
  311. aver (false);
  312. break;
  313. }
  314. break;
  315. }
  316. aver (false);
  317. return loc;
  318. }
  319. void
  320. muscle_user_name_list_grow (char const *key, char const *user_name,
  321. location loc)
  322. {
  323. muscle_grow (key, "[[[[", ",", "");
  324. muscle_grow (key, user_name, "", "");
  325. muscle_grow (key, "]], ", "", "");
  326. muscle_location_grow (key, loc);
  327. muscle_grow (key, "]]", "", "");
  328. }
  329. /** Return an allocated string that represents the %define directive
  330. that performs the assignment.
  331. @param assignment "VAR", or "VAR=VAL".
  332. @param value default value if VAL \a assignment has no '='.
  333. For instance:
  334. "foo", NULL => "%define foo"
  335. "foo", "baz" => "%define foo baz"
  336. "foo=bar", NULL => "%define foo bar"
  337. "foo=bar", "baz" => "%define foo bar"
  338. "foo=", NULL => "%define foo"
  339. "foo=", "baz" => "%define foo"
  340. */
  341. static
  342. char *
  343. define_directive (char const *assignment,
  344. muscle_kind kind,
  345. char const *value)
  346. {
  347. char *eq = strchr (assignment, '=');
  348. char const *fmt
  349. = eq || !value || !*value ? "%%define %s"
  350. : kind == muscle_code ? "%%define %s {%s}"
  351. : kind == muscle_string ? "%%define %s \"%s\""
  352. : "%%define %s %s";
  353. char *res = xmalloc (strlen (fmt) + strlen (assignment)
  354. + (value ? strlen (value) : 0));
  355. sprintf (res, fmt, assignment, value);
  356. eq = strchr (res, '=');
  357. if (eq)
  358. *eq = eq[1] ? ' ' : '\0';
  359. return res;
  360. }
  361. /** If the \a variable name is obsolete, return the name to use,
  362. * otherwise \a variable. If the \a value is obsolete, update it too.
  363. *
  364. * Allocates the returned value if needed, otherwise the returned
  365. * value is exactly \a variable. */
  366. static
  367. char const *
  368. muscle_percent_variable_update (char const *variable,
  369. muscle_kind kind,
  370. char const **value,
  371. char **old, char **upd)
  372. {
  373. typedef struct
  374. {
  375. const char *obsolete;
  376. const char *updated;
  377. muscle_kind kind;
  378. } conversion_type;
  379. const conversion_type conversion[] =
  380. {
  381. { "%error-verbose", "parse.error=verbose", muscle_keyword },
  382. { "%error_verbose", "parse.error=verbose", muscle_keyword },
  383. { "abstract", "api.parser.abstract", muscle_keyword },
  384. { "annotations", "api.parser.annotations", muscle_code },
  385. { "api.push_pull", "api.push-pull", muscle_keyword },
  386. { "api.tokens.prefix", "api.token.prefix", muscle_code },
  387. { "extends", "api.parser.extends", muscle_keyword },
  388. { "filename_type", "api.filename.type", muscle_code },
  389. { "final", "api.parser.final", muscle_keyword },
  390. { "implements", "api.parser.implements", muscle_keyword },
  391. { "lex_symbol", "api.token.constructor", -1 },
  392. { "location_type", "api.location.type", muscle_code },
  393. { "lr.default-reductions", "lr.default-reduction", muscle_keyword },
  394. { "lr.keep-unreachable-states", "lr.keep-unreachable-state", muscle_keyword },
  395. { "lr.keep_unreachable_states", "lr.keep-unreachable-state", muscle_keyword },
  396. { "namespace", "api.namespace", muscle_code },
  397. { "package", "api.package", muscle_code },
  398. { "parser_class_name", "api.parser.class", muscle_code },
  399. { "public", "api.parser.public", muscle_keyword },
  400. { "strictfp", "api.parser.strictfp", muscle_keyword },
  401. { "stype", "api.value.type", -1 },
  402. { "variant=", "api.value.type=variant", -1 },
  403. { "variant=true", "api.value.type=variant", -1 },
  404. { NULL, NULL, -1, }
  405. };
  406. for (conversion_type const *c = conversion; c->obsolete; ++c)
  407. {
  408. char const *eq = strchr (c->obsolete, '=');
  409. if (eq
  410. ? (!strncmp (c->obsolete, variable, eq - c->obsolete)
  411. && STREQ (eq + 1, *value))
  412. : STREQ (c->obsolete, variable))
  413. {
  414. /* Generate the deprecation warning. */
  415. *old = c->obsolete[0] == '%'
  416. ? xstrdup (c->obsolete)
  417. : define_directive (c->obsolete, kind, *value);
  418. *upd = define_directive (c->updated, c->kind, *value);
  419. /* Update the variable and its value. */
  420. {
  421. char *res = xstrdup (c->updated);
  422. char *eq2 = strchr (res, '=');
  423. if (eq2)
  424. {
  425. *eq2 = '\0';
  426. *value = eq2 + 1;
  427. }
  428. return res;
  429. }
  430. }
  431. }
  432. return variable;
  433. }
  434. void
  435. muscle_percent_define_insert (char const *var, location variable_loc,
  436. muscle_kind kind,
  437. char const *value,
  438. muscle_percent_define_how how)
  439. {
  440. /* Backward compatibility. */
  441. char *old = NULL;
  442. char *upd = NULL;
  443. char const *variable
  444. = muscle_percent_variable_update (var, kind,
  445. &value, &old, &upd);
  446. uniqstr name = muscle_name (variable, NULL);
  447. uniqstr loc_name = muscle_name (variable, "loc");
  448. uniqstr syncline_name = muscle_name (variable, "syncline");
  449. uniqstr how_name = muscle_name (variable, "how");
  450. uniqstr kind_name = muscle_name (variable, "kind");
  451. /* Command-line options are processed before the grammar file. */
  452. bool warned = false;
  453. if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE)
  454. {
  455. char const *current_value = muscle_find_const (name);
  456. if (current_value)
  457. {
  458. muscle_percent_define_how how_old
  459. = atoi (muscle_find_const (how_name));
  460. if (how_old == MUSCLE_PERCENT_DEFINE_F)
  461. goto end;
  462. /* If assigning the same value, make it a warning. */
  463. warnings warn = STREQ (value, current_value) ? Wother : complaint;
  464. complain (&variable_loc, warn,
  465. _("%%define variable %s redefined"),
  466. quote (variable));
  467. location loc = muscle_percent_define_get_loc (variable);
  468. subcomplain (&loc, warn, _("previous definition"));
  469. fixits_register (&variable_loc, "");
  470. warned = true;
  471. }
  472. }
  473. if (!warned && old && upd)
  474. deprecated_directive (&variable_loc, old, upd);
  475. MUSCLE_INSERT_STRING (name, value);
  476. muscle_insert (loc_name, "");
  477. muscle_location_grow (loc_name, variable_loc);
  478. muscle_insert (syncline_name, "");
  479. muscle_syncline_grow (syncline_name, variable_loc);
  480. muscle_user_name_list_grow ("percent_define_user_variables", variable,
  481. variable_loc);
  482. MUSCLE_INSERT_INT (how_name, how);
  483. MUSCLE_INSERT_STRING (kind_name, muscle_kind_string (kind));
  484. end:
  485. free (old);
  486. free (upd);
  487. if (variable != var)
  488. free ((char *) variable);
  489. }
  490. /* This is used for backward compatibility, e.g., "%define api.pure"
  491. supersedes "%pure-parser". */
  492. void
  493. muscle_percent_define_ensure (char const *variable, location loc,
  494. bool value)
  495. {
  496. uniqstr name = muscle_name (variable, NULL);
  497. char const *val = value ? "" : "false";
  498. /* Don't complain is VARIABLE is already defined, but be sure to set
  499. its value to VAL. */
  500. if (!muscle_find_const (name)
  501. || muscle_percent_define_flag_if (variable) != value)
  502. muscle_percent_define_insert (variable, loc, muscle_keyword, val,
  503. MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
  504. }
  505. /* Mark %define VARIABLE as used. */
  506. static void
  507. muscle_percent_define_use (char const *variable)
  508. {
  509. muscle_insert (muscle_name (variable, "bison_variables"), "");
  510. }
  511. /* The value of %define variable VARIABLE (corresponding to FIELD, if
  512. defined). Do not register as used, but diagnose unset variables. */
  513. static
  514. char const *
  515. muscle_percent_define_get_raw (char const *variable, char const *field)
  516. {
  517. uniqstr name = muscle_name (variable, field);
  518. char const *res = muscle_find_const (name);
  519. if (!res)
  520. complain (NULL, fatal, _("%s: undefined %%define variable %s"),
  521. "muscle_percent_define_get_raw", quote (variable));
  522. return res;
  523. }
  524. char *
  525. muscle_percent_define_get (char const *variable)
  526. {
  527. uniqstr name = muscle_name (variable, NULL);
  528. char *value = string_decode (name);
  529. if (!value)
  530. value = xstrdup ("");
  531. muscle_percent_define_use (variable);
  532. return value;
  533. }
  534. /* The kind of VARIABLE. An error if undefined. */
  535. static muscle_kind
  536. muscle_percent_define_get_kind (char const *variable)
  537. {
  538. return muscle_kind_new (muscle_percent_define_get_raw (variable, "kind"));
  539. }
  540. /* Check the kind of VARIABLE. An error if undefined. */
  541. static void
  542. muscle_percent_define_check_kind (char const *variable, muscle_kind kind)
  543. {
  544. if (muscle_percent_define_get_kind (variable) != kind)
  545. {
  546. location loc = muscle_percent_define_get_loc (variable);
  547. switch (kind)
  548. {
  549. case muscle_code:
  550. complain (&loc, Wdeprecated,
  551. _("%%define variable '%s' requires '{...}' values"),
  552. variable);
  553. break;
  554. case muscle_keyword:
  555. complain (&loc, Wdeprecated,
  556. _("%%define variable '%s' requires keyword values"),
  557. variable);
  558. break;
  559. case muscle_string:
  560. complain (&loc, Wdeprecated,
  561. _("%%define variable '%s' requires '\"...\"' values"),
  562. variable);
  563. break;
  564. }
  565. }
  566. }
  567. location
  568. muscle_percent_define_get_loc (char const *variable)
  569. {
  570. return location_decode (muscle_percent_define_get_raw (variable, "loc"));
  571. }
  572. char const *
  573. muscle_percent_define_get_syncline (char const *variable)
  574. {
  575. return muscle_percent_define_get_raw (variable, "syncline");
  576. }
  577. bool
  578. muscle_percent_define_ifdef (char const *variable)
  579. {
  580. if (muscle_find_const (muscle_name (variable, NULL)))
  581. {
  582. muscle_percent_define_use (variable);
  583. return true;
  584. }
  585. else
  586. return false;
  587. }
  588. bool
  589. muscle_percent_define_flag_if (char const *variable)
  590. {
  591. uniqstr invalid_boolean_name = muscle_name (variable, "invalid_boolean");
  592. bool res = false;
  593. if (muscle_percent_define_ifdef (variable))
  594. {
  595. char *value = muscle_percent_define_get (variable);
  596. muscle_percent_define_check_kind (variable, muscle_keyword);
  597. if (value[0] == '\0' || STREQ (value, "true"))
  598. res = true;
  599. else if (STREQ (value, "false"))
  600. res = false;
  601. else if (!muscle_find_const (invalid_boolean_name))
  602. {
  603. muscle_insert (invalid_boolean_name, "");
  604. location loc = muscle_percent_define_get_loc (variable);
  605. complain (&loc, complaint,
  606. _("invalid value for %%define Boolean variable %s"),
  607. quote (variable));
  608. }
  609. free (value);
  610. }
  611. else
  612. complain (NULL, fatal, _("%s: undefined %%define variable %s"),
  613. "muscle_percent_define_flag", quote (variable));
  614. return res;
  615. }
  616. void
  617. muscle_percent_define_default (char const *variable, char const *value)
  618. {
  619. uniqstr name = muscle_name (variable, NULL);
  620. if (!muscle_find_const (name))
  621. {
  622. MUSCLE_INSERT_STRING (name, value);
  623. MUSCLE_INSERT_STRING (muscle_name (variable, "kind"), "keyword");
  624. {
  625. uniqstr loc_name = muscle_name (variable, "loc");
  626. location loc;
  627. loc.start.file = "<default value>";
  628. loc.start.line = -1;
  629. loc.start.column = -1;
  630. loc.start.byte = -1;
  631. loc.end = loc.start;
  632. muscle_insert (loc_name, "");
  633. muscle_location_grow (loc_name, loc);
  634. }
  635. muscle_insert (muscle_name (variable, "syncline"), "");
  636. }
  637. }
  638. void
  639. muscle_percent_define_check_values (char const * const *values)
  640. {
  641. for (; *values; ++values)
  642. {
  643. char const * const *variablep = values;
  644. uniqstr name = muscle_name (*variablep, NULL);
  645. char *value = string_decode (name);
  646. muscle_percent_define_check_kind (*variablep, muscle_keyword);
  647. if (value)
  648. {
  649. for (++values; *values; ++values)
  650. if (STREQ (value, *values))
  651. break;
  652. if (!*values)
  653. {
  654. location loc = muscle_percent_define_get_loc (*variablep);
  655. complain (&loc, complaint,
  656. _("invalid value for %%define variable %s: %s"),
  657. quote (*variablep), quote_n (1, value));
  658. for (values = variablep + 1; *values; ++values)
  659. subcomplain (&loc, complaint | no_caret | silent,
  660. _("accepted value: %s"), quote (*values));
  661. }
  662. else
  663. while (*values)
  664. ++values;
  665. free (value);
  666. }
  667. else
  668. complain (NULL, fatal, _("%s: undefined %%define variable %s"),
  669. "muscle_percent_define_check_values", quote (*variablep));
  670. }
  671. }
  672. void
  673. muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
  674. char const *code, location code_loc)
  675. {
  676. char const *name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
  677. muscle_code_grow (name, code, code_loc);
  678. muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
  679. qualifier_loc);
  680. }
  681. /*------------------------------------------------.
  682. | Output the definition of ENTRY as a m4_define. |
  683. `------------------------------------------------*/
  684. static inline bool
  685. muscle_m4_output (muscle_entry *entry, FILE *out)
  686. {
  687. fprintf (out,
  688. "m4_define([b4_%s],\n"
  689. "[[%s]])\n\n\n", entry->key, entry->value);
  690. return true;
  691. }
  692. static bool
  693. muscle_m4_output_processor (void *entry, void *out)
  694. {
  695. return muscle_m4_output (entry, out);
  696. }
  697. void
  698. muscles_m4_output (FILE *out)
  699. {
  700. hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
  701. }