]>
Commit | Line | Data |
---|---|---|
10692477 | 1 | /* MD reader for GCC. |
818ab71a | 2 | Copyright (C) 1987-2016 Free Software Foundation, Inc. |
10692477 RS |
3 | |
4 | This file is part of GCC. | |
5 | ||
6 | GCC is free software; you can redistribute it and/or modify it under | |
7 | the terms of the GNU General Public License as published by the Free | |
8 | Software Foundation; either version 3, or (at your option) any later | |
9 | version. | |
10 | ||
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GCC; see the file COPYING3. If not see | |
18 | <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | #include "bconfig.h" | |
21 | #include "system.h" | |
22 | #include "coretypes.h" | |
bb933490 | 23 | #include "errors.h" |
10692477 RS |
24 | #include "read-md.h" |
25 | ||
26 | /* Associates PTR (which can be a string, etc.) with the file location | |
27 | specified by FILENAME and LINENO. */ | |
28 | struct ptr_loc { | |
29 | const void *ptr; | |
30 | const char *filename; | |
31 | int lineno; | |
32 | }; | |
33 | ||
600ab3fc RS |
34 | /* A singly-linked list of filenames. */ |
35 | struct file_name_list { | |
36 | struct file_name_list *next; | |
37 | const char *fname; | |
38 | }; | |
39 | ||
d2a3ce4e | 40 | /* Obstack used for allocating MD strings. */ |
10692477 RS |
41 | struct obstack string_obstack; |
42 | ||
43 | /* A table of ptr_locs, hashed on the PTR field. */ | |
44 | static htab_t ptr_locs; | |
45 | ||
46 | /* An obstack for the above. Plain xmalloc is a bit heavyweight for a | |
47 | small structure like ptr_loc. */ | |
48 | static struct obstack ptr_loc_obstack; | |
49 | ||
50 | /* A hash table of triples (A, B, C), where each of A, B and C is a condition | |
51 | and A is equivalent to "B && C". This is used to keep track of the source | |
d2a3ce4e | 52 | of conditions that are made up of separate MD strings (such as the split |
10692477 RS |
53 | condition of a define_insn_and_split). */ |
54 | static htab_t joined_conditions; | |
55 | ||
56 | /* An obstack for allocating joined_conditions entries. */ | |
57 | static struct obstack joined_conditions_obstack; | |
58 | ||
c5e88b39 RS |
59 | /* The file we are reading. */ |
60 | FILE *read_md_file; | |
10692477 | 61 | |
c5e88b39 RS |
62 | /* The filename of READ_MD_FILE. */ |
63 | const char *read_md_filename; | |
64 | ||
65 | /* The current line number in READ_MD_FILE. */ | |
66 | int read_md_lineno; | |
10692477 | 67 | |
600ab3fc RS |
68 | /* The name of the toplevel file that indirectly included READ_MD_FILE. */ |
69 | const char *in_fname; | |
70 | ||
71 | /* The directory part of IN_FNAME. NULL if IN_FNAME is a bare filename. */ | |
72 | static char *base_dir; | |
73 | ||
74 | /* The first directory to search. */ | |
75 | static struct file_name_list *first_dir_md_include; | |
76 | ||
77 | /* A pointer to the null terminator of the md include chain. */ | |
78 | static struct file_name_list **last_dir_md_include_ptr = &first_dir_md_include; | |
79 | ||
80 | /* This callback will be invoked whenever an md include directive is | |
81 | processed. To be used for creation of the dependency file. */ | |
82 | void (*include_callback) (const char *); | |
83 | ||
84 | /* The current maximum length of directory names in the search path | |
85 | for include files. (Altered as we get more of them.) */ | |
86 | static size_t max_include_len; | |
87 | ||
9f418533 RS |
88 | /* A table of md_constant structures, hashed by name. Null if no |
89 | constant expansion should occur. */ | |
90 | static htab_t md_constants; | |
91 | ||
24609606 RS |
92 | /* A table of enum_type structures, hashed by name. */ |
93 | static htab_t enum_types; | |
94 | ||
600ab3fc RS |
95 | static void handle_file (directive_handler_t); |
96 | ||
9f418533 RS |
97 | /* Given an object that starts with a char * name field, return a hash |
98 | code for its name. */ | |
99 | ||
100 | hashval_t | |
101 | leading_string_hash (const void *def) | |
102 | { | |
103 | return htab_hash_string (*(const char *const *) def); | |
104 | } | |
105 | ||
106 | /* Given two objects that start with char * name fields, return true if | |
107 | they have the same name. */ | |
108 | ||
109 | int | |
110 | leading_string_eq_p (const void *def1, const void *def2) | |
111 | { | |
112 | return strcmp (*(const char *const *) def1, | |
113 | *(const char *const *) def2) == 0; | |
114 | } | |
115 | ||
10692477 RS |
116 | /* Return a hash value for the pointer pointed to by DEF. */ |
117 | ||
118 | static hashval_t | |
119 | leading_ptr_hash (const void *def) | |
120 | { | |
121 | return htab_hash_pointer (*(const void *const *) def); | |
122 | } | |
123 | ||
124 | /* Return true if DEF1 and DEF2 are pointers to the same pointer. */ | |
125 | ||
126 | static int | |
127 | leading_ptr_eq_p (const void *def1, const void *def2) | |
128 | { | |
129 | return *(const void *const *) def1 == *(const void *const *) def2; | |
130 | } | |
131 | ||
132 | /* Associate PTR with the file position given by FILENAME and LINENO. */ | |
133 | ||
134 | static void | |
d2a3ce4e | 135 | set_md_ptr_loc (const void *ptr, const char *filename, int lineno) |
10692477 RS |
136 | { |
137 | struct ptr_loc *loc; | |
138 | ||
139 | loc = (struct ptr_loc *) obstack_alloc (&ptr_loc_obstack, | |
140 | sizeof (struct ptr_loc)); | |
141 | loc->ptr = ptr; | |
142 | loc->filename = filename; | |
143 | loc->lineno = lineno; | |
144 | *htab_find_slot (ptr_locs, loc, INSERT) = loc; | |
145 | } | |
146 | ||
147 | /* Return the position associated with pointer PTR. Return null if no | |
148 | position was set. */ | |
149 | ||
150 | static const struct ptr_loc * | |
d2a3ce4e | 151 | get_md_ptr_loc (const void *ptr) |
10692477 RS |
152 | { |
153 | return (const struct ptr_loc *) htab_find (ptr_locs, &ptr); | |
154 | } | |
155 | ||
156 | /* Associate NEW_PTR with the same file position as OLD_PTR. */ | |
157 | ||
158 | void | |
d2a3ce4e | 159 | copy_md_ptr_loc (const void *new_ptr, const void *old_ptr) |
10692477 | 160 | { |
d2a3ce4e | 161 | const struct ptr_loc *loc = get_md_ptr_loc (old_ptr); |
10692477 | 162 | if (loc != 0) |
d2a3ce4e | 163 | set_md_ptr_loc (new_ptr, loc->filename, loc->lineno); |
10692477 RS |
164 | } |
165 | ||
166 | /* If PTR is associated with a known file position, print a #line | |
41723253 | 167 | directive for it to OUTF. */ |
10692477 RS |
168 | |
169 | void | |
41723253 | 170 | fprint_md_ptr_loc (FILE *outf, const void *ptr) |
10692477 | 171 | { |
d2a3ce4e | 172 | const struct ptr_loc *loc = get_md_ptr_loc (ptr); |
10692477 | 173 | if (loc != 0) |
41723253 SB |
174 | fprintf (outf, "#line %d \"%s\"\n", loc->lineno, loc->filename); |
175 | } | |
176 | ||
177 | /* Special fprint_md_ptr_loc for writing to STDOUT. */ | |
178 | void | |
179 | print_md_ptr_loc (const void *ptr) | |
180 | { | |
181 | fprint_md_ptr_loc (stdout, ptr); | |
10692477 RS |
182 | } |
183 | ||
184 | /* Return a condition that satisfies both COND1 and COND2. Either string | |
185 | may be null or empty. */ | |
186 | ||
187 | const char * | |
188 | join_c_conditions (const char *cond1, const char *cond2) | |
189 | { | |
190 | char *result; | |
191 | const void **entry; | |
192 | ||
193 | if (cond1 == 0 || cond1[0] == 0) | |
194 | return cond2; | |
195 | ||
196 | if (cond2 == 0 || cond2[0] == 0) | |
197 | return cond1; | |
198 | ||
199 | if (strcmp (cond1, cond2) == 0) | |
200 | return cond1; | |
201 | ||
202 | result = concat ("(", cond1, ") && (", cond2, ")", NULL); | |
203 | obstack_ptr_grow (&joined_conditions_obstack, result); | |
204 | obstack_ptr_grow (&joined_conditions_obstack, cond1); | |
205 | obstack_ptr_grow (&joined_conditions_obstack, cond2); | |
206 | entry = XOBFINISH (&joined_conditions_obstack, const void **); | |
207 | *htab_find_slot (joined_conditions, entry, INSERT) = entry; | |
208 | return result; | |
209 | } | |
210 | ||
41723253 SB |
211 | /* Print condition COND to OUTF, wrapped in brackets. If COND was created |
212 | by join_c_conditions, recursively invoke this function for the original | |
10692477 RS |
213 | conditions and join the result with "&&". Otherwise print a #line |
214 | directive for COND if its original file position is known. */ | |
215 | ||
216 | void | |
41723253 | 217 | fprint_c_condition (FILE *outf, const char *cond) |
10692477 RS |
218 | { |
219 | const char **halves = (const char **) htab_find (joined_conditions, &cond); | |
220 | if (halves != 0) | |
221 | { | |
41723253 SB |
222 | fprintf (outf, "("); |
223 | fprint_c_condition (outf, halves[1]); | |
224 | fprintf (outf, " && "); | |
225 | fprint_c_condition (outf, halves[2]); | |
226 | fprintf (outf, ")"); | |
10692477 RS |
227 | } |
228 | else | |
229 | { | |
41723253 SB |
230 | fputc ('\n', outf); |
231 | fprint_md_ptr_loc (outf, cond); | |
232 | fprintf (outf, "(%s)", cond); | |
10692477 RS |
233 | } |
234 | } | |
235 | ||
41723253 SB |
236 | /* Special fprint_c_condition for writing to STDOUT. */ |
237 | ||
238 | void | |
239 | print_c_condition (const char *cond) | |
240 | { | |
241 | fprint_c_condition (stdout, cond); | |
242 | } | |
243 | ||
bb933490 RS |
244 | /* A vfprintf-like function for reporting an error against line LINENO |
245 | of the current MD file. */ | |
246 | ||
247 | static void ATTRIBUTE_PRINTF(2,0) | |
cc472607 | 248 | message_at_1 (file_location loc, const char *msg, va_list ap) |
bb933490 | 249 | { |
cc472607 | 250 | fprintf (stderr, "%s:%d: ", loc.filename, loc.lineno); |
bb933490 RS |
251 | vfprintf (stderr, msg, ap); |
252 | fputc ('\n', stderr); | |
253 | } | |
254 | ||
cc472607 RS |
255 | /* A printf-like function for reporting a message against location LOC. */ |
256 | ||
257 | void | |
258 | message_at (file_location loc, const char *msg, ...) | |
259 | { | |
260 | va_list ap; | |
261 | ||
262 | va_start (ap, msg); | |
263 | message_at_1 (loc, msg, ap); | |
264 | va_end (ap); | |
265 | } | |
266 | ||
267 | /* Like message_at, but treat the condition as an error. */ | |
268 | ||
269 | void | |
270 | error_at (file_location loc, const char *msg, ...) | |
271 | { | |
272 | va_list ap; | |
273 | ||
274 | va_start (ap, msg); | |
275 | message_at_1 (loc, msg, ap); | |
276 | va_end (ap); | |
277 | have_error = 1; | |
278 | } | |
279 | ||
8f246310 RS |
280 | /* Like message_at, but treat the condition as a fatal error. */ |
281 | ||
282 | void | |
283 | fatal_at (file_location loc, const char *msg, ...) | |
284 | { | |
285 | va_list ap; | |
286 | ||
287 | va_start (ap, msg); | |
288 | message_at_1 (loc, msg, ap); | |
289 | va_end (ap); | |
290 | exit (1); | |
291 | } | |
292 | ||
10692477 | 293 | /* A printf-like function for reporting an error against the current |
c5e88b39 | 294 | position in the MD file. */ |
10692477 RS |
295 | |
296 | void | |
c5e88b39 | 297 | fatal_with_file_and_line (const char *msg, ...) |
10692477 RS |
298 | { |
299 | char context[64]; | |
300 | size_t i; | |
301 | int c; | |
302 | va_list ap; | |
303 | ||
304 | va_start (ap, msg); | |
305 | ||
d2a3ce4e | 306 | fprintf (stderr, "%s:%d: ", read_md_filename, read_md_lineno); |
10692477 RS |
307 | vfprintf (stderr, msg, ap); |
308 | putc ('\n', stderr); | |
309 | ||
310 | /* Gather some following context. */ | |
311 | for (i = 0; i < sizeof (context)-1; ++i) | |
312 | { | |
c5e88b39 | 313 | c = read_char (); |
10692477 RS |
314 | if (c == EOF) |
315 | break; | |
316 | if (c == '\r' || c == '\n') | |
7f7c467f RS |
317 | { |
318 | unread_char (c); | |
319 | break; | |
320 | } | |
10692477 RS |
321 | context[i] = c; |
322 | } | |
323 | context[i] = '\0'; | |
324 | ||
325 | fprintf (stderr, "%s:%d: following context is `%s'\n", | |
d2a3ce4e | 326 | read_md_filename, read_md_lineno, context); |
10692477 RS |
327 | |
328 | va_end (ap); | |
329 | exit (1); | |
330 | } | |
331 | ||
332 | /* Report that we found character ACTUAL when we expected to find | |
c5e88b39 | 333 | character EXPECTED. */ |
10692477 RS |
334 | |
335 | void | |
c5e88b39 | 336 | fatal_expected_char (int expected, int actual) |
10692477 RS |
337 | { |
338 | if (actual == EOF) | |
c5e88b39 | 339 | fatal_with_file_and_line ("expected character `%c', found EOF", |
10692477 RS |
340 | expected); |
341 | else | |
c5e88b39 | 342 | fatal_with_file_and_line ("expected character `%c', found `%c'", |
10692477 RS |
343 | expected, actual); |
344 | } | |
345 | ||
c5e88b39 | 346 | /* Read chars from the MD file until a non-whitespace char and return that. |
10692477 RS |
347 | Comments, both Lisp style and C style, are treated as whitespace. */ |
348 | ||
349 | int | |
c5e88b39 | 350 | read_skip_spaces (void) |
10692477 RS |
351 | { |
352 | int c; | |
353 | ||
354 | while (1) | |
355 | { | |
c5e88b39 | 356 | c = read_char (); |
10692477 RS |
357 | switch (c) |
358 | { | |
7f7c467f | 359 | case ' ': case '\t': case '\f': case '\r': case '\n': |
10692477 RS |
360 | break; |
361 | ||
362 | case ';': | |
363 | do | |
c5e88b39 | 364 | c = read_char (); |
10692477 | 365 | while (c != '\n' && c != EOF); |
10692477 RS |
366 | break; |
367 | ||
368 | case '/': | |
369 | { | |
370 | int prevc; | |
c5e88b39 | 371 | c = read_char (); |
10692477 | 372 | if (c != '*') |
7f7c467f RS |
373 | { |
374 | unread_char (c); | |
375 | fatal_with_file_and_line ("stray '/' in file"); | |
376 | } | |
10692477 RS |
377 | |
378 | prevc = 0; | |
c5e88b39 | 379 | while ((c = read_char ()) && c != EOF) |
10692477 | 380 | { |
7f7c467f | 381 | if (prevc == '*' && c == '/') |
10692477 RS |
382 | break; |
383 | prevc = c; | |
384 | } | |
385 | } | |
386 | break; | |
387 | ||
388 | default: | |
389 | return c; | |
390 | } | |
391 | } | |
392 | } | |
393 | ||
601070fc DM |
394 | /* Consume any whitespace, then consume the next non-whitespace |
395 | character, issuing a fatal error if it is not EXPECTED. */ | |
396 | ||
397 | void | |
398 | require_char_ws (char expected) | |
399 | { | |
400 | int ch = read_skip_spaces (); | |
401 | if (ch != expected) | |
402 | fatal_expected_char (expected, ch); | |
403 | } | |
404 | ||
9f418533 RS |
405 | /* Read an rtx code name into NAME. It is terminated by any of the |
406 | punctuation chars of rtx printed syntax. */ | |
407 | ||
408 | void | |
409 | read_name (struct md_name *name) | |
410 | { | |
411 | int c; | |
412 | size_t i; | |
4fe017f6 | 413 | int angle_bracket_depth; |
9f418533 RS |
414 | |
415 | c = read_skip_spaces (); | |
416 | ||
417 | i = 0; | |
4fe017f6 | 418 | angle_bracket_depth = 0; |
9f418533 RS |
419 | while (1) |
420 | { | |
4fe017f6 MC |
421 | if (c == '<') |
422 | angle_bracket_depth++; | |
423 | ||
424 | if ((c == '>') && (angle_bracket_depth > 0)) | |
425 | angle_bracket_depth--; | |
426 | ||
9f418533 RS |
427 | if (c == ' ' || c == '\n' || c == '\t' || c == '\f' || c == '\r' |
428 | || c == EOF) | |
429 | break; | |
4fe017f6 | 430 | if (angle_bracket_depth == 0) |
9f418533 | 431 | { |
4fe017f6 MC |
432 | if (c == ':' || c == ')' || c == ']' |
433 | || c == '"' || c == '/' || c == '(' || c == '[') | |
434 | { | |
435 | unread_char (c); | |
436 | break; | |
437 | } | |
9f418533 RS |
438 | } |
439 | ||
440 | if (i == sizeof (name->buffer) - 1) | |
441 | fatal_with_file_and_line ("name too long"); | |
442 | name->buffer[i++] = c; | |
443 | ||
444 | c = read_char (); | |
445 | } | |
446 | ||
447 | if (i == 0) | |
448 | fatal_with_file_and_line ("missing name or number"); | |
9f418533 RS |
449 | |
450 | name->buffer[i] = 0; | |
451 | name->string = name->buffer; | |
452 | ||
453 | if (md_constants) | |
454 | { | |
455 | /* Do constant expansion. */ | |
456 | struct md_constant *def; | |
457 | ||
458 | do | |
459 | { | |
460 | struct md_constant tmp_def; | |
461 | ||
462 | tmp_def.name = name->string; | |
463 | def = (struct md_constant *) htab_find (md_constants, &tmp_def); | |
464 | if (def) | |
465 | name->string = def->value; | |
466 | } | |
467 | while (def); | |
468 | } | |
469 | } | |
470 | ||
10692477 RS |
471 | /* Subroutine of the string readers. Handles backslash escapes. |
472 | Caller has read the backslash, but not placed it into the obstack. */ | |
473 | ||
474 | static void | |
c5e88b39 | 475 | read_escape (void) |
10692477 | 476 | { |
c5e88b39 | 477 | int c = read_char (); |
10692477 RS |
478 | |
479 | switch (c) | |
480 | { | |
481 | /* Backslash-newline is replaced by nothing, as in C. */ | |
482 | case '\n': | |
10692477 RS |
483 | return; |
484 | ||
485 | /* \" \' \\ are replaced by the second character. */ | |
486 | case '\\': | |
487 | case '"': | |
488 | case '\'': | |
489 | break; | |
490 | ||
491 | /* Standard C string escapes: | |
492 | \a \b \f \n \r \t \v | |
493 | \[0-7] \x | |
494 | all are passed through to the output string unmolested. | |
495 | In normal use these wind up in a string constant processed | |
496 | by the C compiler, which will translate them appropriately. | |
497 | We do not bother checking that \[0-7] are followed by up to | |
498 | two octal digits, or that \x is followed by N hex digits. | |
499 | \? \u \U are left out because they are not in traditional C. */ | |
500 | case 'a': case 'b': case 'f': case 'n': case 'r': case 't': case 'v': | |
501 | case '0': case '1': case '2': case '3': case '4': case '5': case '6': | |
502 | case '7': case 'x': | |
503 | obstack_1grow (&string_obstack, '\\'); | |
504 | break; | |
505 | ||
506 | /* \; makes stuff for a C string constant containing | |
507 | newline and tab. */ | |
508 | case ';': | |
509 | obstack_grow (&string_obstack, "\\n\\t", 4); | |
510 | return; | |
511 | ||
512 | /* pass anything else through, but issue a warning. */ | |
513 | default: | |
514 | fprintf (stderr, "%s:%d: warning: unrecognized escape \\%c\n", | |
d2a3ce4e | 515 | read_md_filename, read_md_lineno, c); |
10692477 RS |
516 | obstack_1grow (&string_obstack, '\\'); |
517 | break; | |
518 | } | |
519 | ||
520 | obstack_1grow (&string_obstack, c); | |
521 | } | |
522 | ||
523 | /* Read a double-quoted string onto the obstack. Caller has scanned | |
524 | the leading quote. */ | |
525 | ||
526 | char * | |
c5e88b39 | 527 | read_quoted_string (void) |
10692477 RS |
528 | { |
529 | int c; | |
530 | ||
531 | while (1) | |
532 | { | |
c5e88b39 | 533 | c = read_char (); /* Read the string */ |
7f7c467f | 534 | if (c == '\\') |
10692477 | 535 | { |
c5e88b39 | 536 | read_escape (); |
10692477 RS |
537 | continue; |
538 | } | |
539 | else if (c == '"' || c == EOF) | |
540 | break; | |
541 | ||
542 | obstack_1grow (&string_obstack, c); | |
543 | } | |
544 | ||
545 | obstack_1grow (&string_obstack, 0); | |
546 | return XOBFINISH (&string_obstack, char *); | |
547 | } | |
548 | ||
549 | /* Read a braced string (a la Tcl) onto the string obstack. Caller | |
550 | has scanned the leading brace. Note that unlike quoted strings, | |
551 | the outermost braces _are_ included in the string constant. */ | |
552 | ||
553 | static char * | |
c5e88b39 | 554 | read_braced_string (void) |
10692477 RS |
555 | { |
556 | int c; | |
557 | int brace_depth = 1; /* caller-processed */ | |
d2a3ce4e | 558 | unsigned long starting_read_md_lineno = read_md_lineno; |
10692477 RS |
559 | |
560 | obstack_1grow (&string_obstack, '{'); | |
561 | while (brace_depth) | |
562 | { | |
c5e88b39 | 563 | c = read_char (); /* Read the string */ |
10692477 | 564 | |
7f7c467f | 565 | if (c == '{') |
10692477 RS |
566 | brace_depth++; |
567 | else if (c == '}') | |
568 | brace_depth--; | |
569 | else if (c == '\\') | |
570 | { | |
c5e88b39 | 571 | read_escape (); |
10692477 RS |
572 | continue; |
573 | } | |
574 | else if (c == EOF) | |
575 | fatal_with_file_and_line | |
c5e88b39 | 576 | ("missing closing } for opening brace on line %lu", |
d2a3ce4e | 577 | starting_read_md_lineno); |
10692477 RS |
578 | |
579 | obstack_1grow (&string_obstack, c); | |
580 | } | |
581 | ||
582 | obstack_1grow (&string_obstack, 0); | |
583 | return XOBFINISH (&string_obstack, char *); | |
584 | } | |
585 | ||
586 | /* Read some kind of string constant. This is the high-level routine | |
587 | used by read_rtx. It handles surrounding parentheses, leading star, | |
588 | and dispatch to the appropriate string constant reader. */ | |
589 | ||
590 | char * | |
c5e88b39 | 591 | read_string (int star_if_braced) |
10692477 RS |
592 | { |
593 | char *stringbuf; | |
594 | int saw_paren = 0; | |
595 | int c, old_lineno; | |
596 | ||
c5e88b39 | 597 | c = read_skip_spaces (); |
10692477 RS |
598 | if (c == '(') |
599 | { | |
600 | saw_paren = 1; | |
c5e88b39 | 601 | c = read_skip_spaces (); |
10692477 RS |
602 | } |
603 | ||
d2a3ce4e | 604 | old_lineno = read_md_lineno; |
10692477 | 605 | if (c == '"') |
c5e88b39 | 606 | stringbuf = read_quoted_string (); |
10692477 RS |
607 | else if (c == '{') |
608 | { | |
609 | if (star_if_braced) | |
610 | obstack_1grow (&string_obstack, '*'); | |
c5e88b39 | 611 | stringbuf = read_braced_string (); |
10692477 RS |
612 | } |
613 | else | |
c5e88b39 | 614 | fatal_with_file_and_line ("expected `\"' or `{', found `%c'", c); |
10692477 RS |
615 | |
616 | if (saw_paren) | |
601070fc | 617 | require_char_ws (')'); |
10692477 | 618 | |
d2a3ce4e | 619 | set_md_ptr_loc (stringbuf, read_md_filename, old_lineno); |
10692477 RS |
620 | return stringbuf; |
621 | } | |
622 | ||
9b68b6ea RS |
623 | /* Skip the rest of a construct that started at line LINENO and that |
624 | is currently nested by DEPTH levels of parentheses. */ | |
625 | ||
cc472607 RS |
626 | static void |
627 | read_skip_construct (int depth, file_location loc) | |
9b68b6ea RS |
628 | { |
629 | struct md_name name; | |
630 | int c; | |
631 | ||
632 | do | |
633 | { | |
634 | c = read_skip_spaces (); | |
635 | if (c == EOF) | |
636 | { | |
cc472607 | 637 | error_at (loc, "unterminated construct"); |
9b68b6ea RS |
638 | exit (1); |
639 | } | |
640 | switch (c) | |
641 | { | |
642 | case '(': | |
643 | depth++; | |
644 | break; | |
645 | ||
646 | case ')': | |
647 | depth--; | |
648 | break; | |
649 | ||
650 | case ':': | |
651 | case '[': | |
652 | case ']': | |
653 | case '/': | |
654 | break; | |
655 | ||
656 | case '\"': | |
657 | case '{': | |
658 | unread_char (c); | |
659 | read_string (false); | |
660 | break; | |
661 | ||
662 | default: | |
663 | unread_char (c); | |
664 | read_name (&name); | |
665 | break; | |
666 | } | |
667 | } | |
668 | while (depth > 0); | |
669 | unread_char (c); | |
670 | } | |
671 | ||
10692477 RS |
672 | /* Given a string, return the number of comma-separated elements in it. |
673 | Return 0 for the null string. */ | |
674 | ||
675 | int | |
676 | n_comma_elts (const char *s) | |
677 | { | |
678 | int n; | |
679 | ||
680 | if (*s == '\0') | |
681 | return 0; | |
682 | ||
683 | for (n = 1; *s; s++) | |
684 | if (*s == ',') | |
685 | n++; | |
686 | ||
687 | return n; | |
688 | } | |
689 | ||
690 | /* Given a pointer to a (char *), return a pointer to the beginning of the | |
691 | next comma-separated element in the string. Advance the pointer given | |
692 | to the end of that element. Return NULL if at end of string. Caller | |
693 | is responsible for copying the string if necessary. White space between | |
694 | a comma and an element is ignored. */ | |
695 | ||
696 | const char * | |
697 | scan_comma_elt (const char **pstr) | |
698 | { | |
699 | const char *start; | |
700 | const char *p = *pstr; | |
701 | ||
702 | if (*p == ',') | |
703 | p++; | |
c3284718 | 704 | while (ISSPACE (*p)) |
10692477 RS |
705 | p++; |
706 | ||
707 | if (*p == '\0') | |
708 | return NULL; | |
709 | ||
710 | start = p; | |
711 | ||
712 | while (*p != ',' && *p != '\0') | |
713 | p++; | |
714 | ||
715 | *pstr = p; | |
716 | return start; | |
717 | } | |
718 | ||
24609606 RS |
719 | /* Convert STRING to uppercase. */ |
720 | ||
721 | void | |
722 | upcase_string (char *string) | |
723 | { | |
724 | int i; | |
725 | ||
726 | for (i = 0; string[i]; i++) | |
727 | string[i] = TOUPPER (string[i]); | |
728 | } | |
729 | ||
730 | /* Add a NAME = VALUE definition to md_constants-style hash table DEFS, | |
731 | where both NAME and VALUE are malloc()ed strings. PARENT_ENUM is the | |
732 | enum to which NAME belongs, or null if NAME is a stand-alone constant. */ | |
733 | ||
734 | static struct md_constant * | |
735 | add_constant (htab_t defs, char *name, char *value, | |
736 | struct enum_type *parent_enum) | |
737 | { | |
738 | struct md_constant *def, tmp_def; | |
739 | void **entry_ptr; | |
740 | ||
741 | tmp_def.name = name; | |
742 | entry_ptr = htab_find_slot (defs, &tmp_def, INSERT); | |
743 | if (*entry_ptr) | |
744 | { | |
745 | def = (struct md_constant *) *entry_ptr; | |
746 | if (strcmp (def->value, value) != 0) | |
747 | fatal_with_file_and_line ("redefinition of `%s', was `%s', now `%s'", | |
748 | def->name, def->value, value); | |
749 | else if (parent_enum || def->parent_enum) | |
750 | fatal_with_file_and_line ("redefinition of `%s'", def->name); | |
751 | free (name); | |
752 | free (value); | |
753 | } | |
754 | else | |
755 | { | |
756 | def = XNEW (struct md_constant); | |
757 | def->name = name; | |
758 | def->value = value; | |
759 | def->parent_enum = parent_enum; | |
760 | *entry_ptr = def; | |
761 | } | |
762 | return def; | |
763 | } | |
764 | ||
9f418533 RS |
765 | /* Process a define_constants directive, starting with the optional space |
766 | after the "define_constants". */ | |
767 | ||
600ab3fc RS |
768 | static void |
769 | handle_constants (void) | |
9f418533 RS |
770 | { |
771 | int c; | |
772 | htab_t defs; | |
773 | ||
601070fc | 774 | require_char_ws ('['); |
9f418533 RS |
775 | |
776 | /* Disable constant expansion during definition processing. */ | |
24609606 | 777 | defs = md_constants; |
9f418533 RS |
778 | md_constants = 0; |
779 | while ( (c = read_skip_spaces ()) != ']') | |
780 | { | |
781 | struct md_name name, value; | |
9f418533 RS |
782 | |
783 | if (c != '(') | |
784 | fatal_expected_char ('(', c); | |
785 | ||
786 | read_name (&name); | |
787 | read_name (&value); | |
24609606 | 788 | add_constant (defs, xstrdup (name.string), xstrdup (value.string), 0); |
9f418533 | 789 | |
601070fc | 790 | require_char_ws (')'); |
9f418533 RS |
791 | } |
792 | md_constants = defs; | |
9f418533 RS |
793 | } |
794 | ||
795 | /* For every constant definition, call CALLBACK with two arguments: | |
796 | a pointer a pointer to the constant definition and INFO. | |
797 | Stop when CALLBACK returns zero. */ | |
798 | ||
799 | void | |
800 | traverse_md_constants (htab_trav callback, void *info) | |
801 | { | |
24609606 RS |
802 | htab_traverse (md_constants, callback, info); |
803 | } | |
804 | ||
805 | /* Return a malloc()ed decimal string that represents number NUMBER. */ | |
806 | ||
807 | static char * | |
09e9c1e0 | 808 | md_decimal_string (int number) |
24609606 RS |
809 | { |
810 | /* A safe overestimate. +1 for sign, +1 for null terminator. */ | |
811 | char buffer[sizeof (int) * CHAR_BIT + 1 + 1]; | |
812 | ||
813 | sprintf (buffer, "%d", number); | |
814 | return xstrdup (buffer); | |
815 | } | |
816 | ||
817 | /* Process a define_enum or define_c_enum directive, starting with | |
818 | the optional space after the "define_enum". LINENO is the line | |
819 | number on which the directive started and MD_P is true if the | |
820 | directive is a define_enum rather than a define_c_enum. */ | |
821 | ||
822 | static void | |
cc472607 | 823 | handle_enum (file_location loc, bool md_p) |
24609606 RS |
824 | { |
825 | char *enum_name, *value_name; | |
826 | struct md_name name; | |
827 | struct enum_type *def; | |
828 | struct enum_value *ev; | |
829 | void **slot; | |
830 | int c; | |
831 | ||
832 | enum_name = read_string (false); | |
833 | slot = htab_find_slot (enum_types, &enum_name, INSERT); | |
834 | if (*slot) | |
835 | { | |
836 | def = (struct enum_type *) *slot; | |
837 | if (def->md_p != md_p) | |
cc472607 RS |
838 | error_at (loc, "redefining `%s' as a different type of enum", |
839 | enum_name); | |
24609606 RS |
840 | } |
841 | else | |
842 | { | |
843 | def = XNEW (struct enum_type); | |
844 | def->name = enum_name; | |
845 | def->md_p = md_p; | |
846 | def->values = 0; | |
847 | def->tail_ptr = &def->values; | |
848 | def->num_values = 0; | |
849 | *slot = def; | |
850 | } | |
851 | ||
601070fc | 852 | require_char_ws ('['); |
24609606 RS |
853 | |
854 | while ((c = read_skip_spaces ()) != ']') | |
855 | { | |
856 | if (c == EOF) | |
857 | { | |
cc472607 | 858 | error_at (loc, "unterminated construct"); |
24609606 RS |
859 | exit (1); |
860 | } | |
861 | unread_char (c); | |
862 | read_name (&name); | |
863 | ||
864 | ev = XNEW (struct enum_value); | |
865 | ev->next = 0; | |
866 | if (md_p) | |
867 | { | |
868 | value_name = concat (def->name, "_", name.string, NULL); | |
869 | upcase_string (value_name); | |
870 | ev->name = xstrdup (name.string); | |
871 | } | |
872 | else | |
873 | { | |
874 | value_name = xstrdup (name.string); | |
875 | ev->name = value_name; | |
876 | } | |
877 | ev->def = add_constant (md_constants, value_name, | |
09e9c1e0 | 878 | md_decimal_string (def->num_values), def); |
24609606 RS |
879 | |
880 | *def->tail_ptr = ev; | |
881 | def->tail_ptr = &ev->next; | |
882 | def->num_values++; | |
883 | } | |
884 | } | |
885 | ||
8f4fe86c RS |
886 | /* Try to find the definition of the given enum. Return null on failure. */ |
887 | ||
888 | struct enum_type * | |
889 | lookup_enum_type (const char *name) | |
890 | { | |
891 | return (struct enum_type *) htab_find (enum_types, &name); | |
892 | } | |
893 | ||
24609606 RS |
894 | /* For every enum definition, call CALLBACK with two arguments: |
895 | a pointer to the constant definition and INFO. Stop when CALLBACK | |
896 | returns zero. */ | |
897 | ||
898 | void | |
899 | traverse_enum_types (htab_trav callback, void *info) | |
900 | { | |
901 | htab_traverse (enum_types, callback, info); | |
9f418533 RS |
902 | } |
903 | ||
600ab3fc RS |
904 | /* Process an "include" directive, starting with the optional space |
905 | after the "include". Read in the file and use HANDLE_DIRECTIVE | |
906 | to process each unknown directive. LINENO is the line number on | |
1aa95df7 | 907 | which the "include" occurred. */ |
10692477 | 908 | |
600ab3fc | 909 | static void |
cc472607 | 910 | handle_include (file_location loc, directive_handler_t handle_directive) |
10692477 | 911 | { |
600ab3fc RS |
912 | const char *filename; |
913 | const char *old_filename; | |
914 | int old_lineno; | |
915 | char *pathname; | |
916 | FILE *input_file, *old_file; | |
917 | ||
918 | filename = read_string (false); | |
919 | input_file = NULL; | |
920 | ||
921 | /* If the specified file name is absolute, skip the include stack. */ | |
922 | if (!IS_ABSOLUTE_PATH (filename)) | |
923 | { | |
924 | struct file_name_list *stackp; | |
925 | ||
926 | /* Search the directory path, trying to open the file. */ | |
927 | for (stackp = first_dir_md_include; stackp; stackp = stackp->next) | |
928 | { | |
929 | static const char sep[2] = { DIR_SEPARATOR, '\0' }; | |
930 | ||
931 | pathname = concat (stackp->fname, sep, filename, NULL); | |
932 | input_file = fopen (pathname, "r"); | |
933 | if (input_file != NULL) | |
934 | break; | |
935 | free (pathname); | |
936 | } | |
937 | } | |
938 | ||
939 | /* If we haven't managed to open the file yet, try combining the | |
940 | filename with BASE_DIR. */ | |
941 | if (input_file == NULL) | |
942 | { | |
943 | if (base_dir) | |
944 | pathname = concat (base_dir, filename, NULL); | |
945 | else | |
946 | pathname = xstrdup (filename); | |
947 | input_file = fopen (pathname, "r"); | |
948 | } | |
949 | ||
950 | if (input_file == NULL) | |
951 | { | |
952 | free (pathname); | |
cc472607 | 953 | error_at (loc, "include file `%s' not found", filename); |
600ab3fc RS |
954 | return; |
955 | } | |
956 | ||
957 | /* Save the old cursor. Note that the LINENO argument to this | |
958 | function is the beginning of the include statement, while | |
959 | read_md_lineno has already been advanced. */ | |
960 | old_file = read_md_file; | |
961 | old_filename = read_md_filename; | |
962 | old_lineno = read_md_lineno; | |
963 | ||
964 | if (include_callback) | |
965 | include_callback (pathname); | |
966 | ||
967 | read_md_file = input_file; | |
968 | read_md_filename = pathname; | |
969 | handle_file (handle_directive); | |
970 | ||
971 | /* Restore the old cursor. */ | |
972 | read_md_file = old_file; | |
973 | read_md_filename = old_filename; | |
974 | read_md_lineno = old_lineno; | |
975 | ||
976 | /* Do not free the pathname. It is attached to the various rtx | |
977 | queue elements. */ | |
978 | } | |
979 | ||
980 | /* Process the current file, assuming that read_md_file and | |
981 | read_md_filename are valid. Use HANDLE_DIRECTIVE to handle | |
982 | unknown directives. */ | |
983 | ||
984 | static void | |
985 | handle_file (directive_handler_t handle_directive) | |
986 | { | |
987 | struct md_name directive; | |
cc472607 | 988 | int c; |
600ab3fc RS |
989 | |
990 | read_md_lineno = 1; | |
991 | while ((c = read_skip_spaces ()) != EOF) | |
992 | { | |
cc472607 | 993 | file_location loc (read_md_filename, read_md_lineno); |
600ab3fc RS |
994 | if (c != '(') |
995 | fatal_expected_char ('(', c); | |
996 | ||
997 | read_name (&directive); | |
998 | if (strcmp (directive.string, "define_constants") == 0) | |
999 | handle_constants (); | |
24609606 | 1000 | else if (strcmp (directive.string, "define_enum") == 0) |
cc472607 | 1001 | handle_enum (loc, true); |
24609606 | 1002 | else if (strcmp (directive.string, "define_c_enum") == 0) |
cc472607 | 1003 | handle_enum (loc, false); |
600ab3fc | 1004 | else if (strcmp (directive.string, "include") == 0) |
cc472607 | 1005 | handle_include (loc, handle_directive); |
9b68b6ea | 1006 | else if (handle_directive) |
cc472607 | 1007 | handle_directive (loc, directive.string); |
9b68b6ea | 1008 | else |
cc472607 | 1009 | read_skip_construct (1, loc); |
600ab3fc | 1010 | |
601070fc | 1011 | require_char_ws (')'); |
600ab3fc RS |
1012 | } |
1013 | fclose (read_md_file); | |
1014 | } | |
1015 | ||
1016 | /* Like handle_file, but for top-level files. Set up in_fname and | |
1017 | base_dir accordingly. */ | |
1018 | ||
1019 | static void | |
1020 | handle_toplevel_file (directive_handler_t handle_directive) | |
1021 | { | |
ba78087b | 1022 | const char *base; |
600ab3fc RS |
1023 | |
1024 | in_fname = read_md_filename; | |
ba78087b KT |
1025 | base = lbasename (in_fname); |
1026 | if (base == in_fname) | |
600ab3fc | 1027 | base_dir = NULL; |
ba78087b KT |
1028 | else |
1029 | base_dir = xstrndup (in_fname, base - in_fname); | |
600ab3fc RS |
1030 | |
1031 | handle_file (handle_directive); | |
1032 | } | |
1033 | ||
1034 | /* Parse a -I option with argument ARG. */ | |
1035 | ||
1036 | static void | |
1037 | parse_include (const char *arg) | |
1038 | { | |
1039 | struct file_name_list *dirtmp; | |
1040 | ||
1041 | dirtmp = XNEW (struct file_name_list); | |
1042 | dirtmp->next = 0; | |
1043 | dirtmp->fname = arg; | |
1044 | *last_dir_md_include_ptr = dirtmp; | |
1045 | last_dir_md_include_ptr = &dirtmp->next; | |
1046 | if (strlen (dirtmp->fname) > max_include_len) | |
1047 | max_include_len = strlen (dirtmp->fname); | |
1048 | } | |
1049 | ||
1050 | /* The main routine for reading .md files. Try to process all the .md | |
1aa95df7 | 1051 | files specified on the command line and return true if no error occurred. |
600ab3fc RS |
1052 | |
1053 | ARGC and ARGV are the arguments to main. | |
1054 | ||
1055 | PARSE_OPT, if nonnull, is passed all unknown command-line arguments. | |
1056 | It should return true if it recognizes the argument or false if a | |
1057 | generic error should be reported. | |
1058 | ||
9b68b6ea RS |
1059 | If HANDLE_DIRECTIVE is nonnull, the parser calls it for each |
1060 | unknown directive, otherwise it just skips such directives. | |
600ab3fc RS |
1061 | See the comment above the directive_handler_t definition for |
1062 | details about the callback's interface. */ | |
1063 | ||
1064 | bool | |
66b0fe8f | 1065 | read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *), |
600ab3fc RS |
1066 | directive_handler_t handle_directive) |
1067 | { | |
1068 | int i; | |
1069 | bool no_more_options; | |
1070 | bool already_read_stdin; | |
1071 | int num_files; | |
1072 | ||
1073 | /* Initialize global data. */ | |
10692477 RS |
1074 | obstack_init (&string_obstack); |
1075 | ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0); | |
1076 | obstack_init (&ptr_loc_obstack); | |
1077 | joined_conditions = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0); | |
1078 | obstack_init (&joined_conditions_obstack); | |
24609606 RS |
1079 | md_constants = htab_create (31, leading_string_hash, |
1080 | leading_string_eq_p, (htab_del) 0); | |
1081 | enum_types = htab_create (31, leading_string_hash, | |
1082 | leading_string_eq_p, (htab_del) 0); | |
600ab3fc RS |
1083 | |
1084 | /* Unlock the stdio streams. */ | |
1085 | unlock_std_streams (); | |
1086 | ||
1087 | /* First we loop over all the options. */ | |
1088 | for (i = 1; i < argc; i++) | |
1089 | if (argv[i][0] == '-') | |
1090 | { | |
1091 | /* An argument consisting of exactly one dash is a request to | |
1092 | read stdin. This will be handled in the second loop. */ | |
1093 | if (argv[i][1] == '\0') | |
1094 | continue; | |
1095 | ||
1096 | /* An argument consisting of just two dashes causes option | |
1097 | parsing to cease. */ | |
1098 | if (argv[i][1] == '-' && argv[i][2] == '\0') | |
1099 | break; | |
1100 | ||
1101 | if (argv[i][1] == 'I') | |
1102 | { | |
1103 | if (argv[i][2] != '\0') | |
1104 | parse_include (argv[i] + 2); | |
1105 | else if (++i < argc) | |
1106 | parse_include (argv[i]); | |
1107 | else | |
1108 | fatal ("directory name missing after -I option"); | |
1109 | continue; | |
1110 | } | |
1111 | ||
1112 | /* The program may have provided a callback so it can | |
1113 | accept its own options. */ | |
1114 | if (parse_opt && parse_opt (argv[i])) | |
1115 | continue; | |
1116 | ||
1117 | fatal ("invalid option `%s'", argv[i]); | |
1118 | } | |
1119 | ||
1120 | /* Now loop over all input files. */ | |
1121 | num_files = 0; | |
1122 | no_more_options = false; | |
1123 | already_read_stdin = false; | |
1124 | for (i = 1; i < argc; i++) | |
1125 | { | |
1126 | if (argv[i][0] == '-') | |
1127 | { | |
1128 | if (argv[i][1] == '\0') | |
1129 | { | |
1130 | /* Read stdin. */ | |
1131 | if (already_read_stdin) | |
1132 | fatal ("cannot read standard input twice"); | |
1133 | ||
1134 | read_md_file = stdin; | |
1135 | read_md_filename = "<stdin>"; | |
1136 | handle_toplevel_file (handle_directive); | |
1137 | already_read_stdin = true; | |
1138 | continue; | |
1139 | } | |
1140 | else if (argv[i][1] == '-' && argv[i][2] == '\0') | |
1141 | { | |
1142 | /* No further arguments are to be treated as options. */ | |
1143 | no_more_options = true; | |
1144 | continue; | |
1145 | } | |
1146 | else if (!no_more_options) | |
1147 | continue; | |
1148 | } | |
1149 | ||
1150 | /* If we get here we are looking at a non-option argument, i.e. | |
1151 | a file to be processed. */ | |
1152 | read_md_filename = argv[i]; | |
1153 | read_md_file = fopen (read_md_filename, "r"); | |
1154 | if (read_md_file == 0) | |
1155 | { | |
1156 | perror (read_md_filename); | |
1157 | return false; | |
1158 | } | |
1159 | handle_toplevel_file (handle_directive); | |
1160 | num_files++; | |
1161 | } | |
1162 | ||
1163 | /* If we get to this point without having seen any files to process, | |
1164 | read the standard input now. */ | |
1165 | if (num_files == 0 && !already_read_stdin) | |
1166 | { | |
1167 | read_md_file = stdin; | |
1168 | read_md_filename = "<stdin>"; | |
1169 | handle_toplevel_file (handle_directive); | |
1170 | } | |
1171 | ||
1172 | return !have_error; | |
10692477 | 1173 | } |