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