OSDN Git Service

105b3bcd17d139db85aaf5013a1b66548b4240df
[pf3gnuchains/gcc-fork.git] / gcc / read-md.c
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"
26 #include "read-md.h"
27
28 /* Associates PTR (which can be a string, etc.) with the file location
29    specified by FILENAME and LINENO.  */
30 struct ptr_loc {
31   const void *ptr;
32   const char *filename;
33   int lineno;
34 };
35
36 /* Obstack used for allocating MD strings.  */
37 struct obstack string_obstack;
38
39 /* A table of ptr_locs, hashed on the PTR field.  */
40 static htab_t ptr_locs;
41
42 /* An obstack for the above.  Plain xmalloc is a bit heavyweight for a
43    small structure like ptr_loc.  */
44 static struct obstack ptr_loc_obstack;
45
46 /* A hash table of triples (A, B, C), where each of A, B and C is a condition
47    and A is equivalent to "B && C".  This is used to keep track of the source
48    of conditions that are made up of separate MD strings (such as the split
49    condition of a define_insn_and_split).  */
50 static htab_t joined_conditions;
51
52 /* An obstack for allocating joined_conditions entries.  */
53 static struct obstack joined_conditions_obstack;
54
55 /* The current line number for the file.  */
56 int read_md_lineno = 1;
57
58 /* The filename for error reporting.  */
59 const char *read_md_filename = "<unknown>";
60
61 /* Return a hash value for the pointer pointed to by DEF.  */
62
63 static hashval_t
64 leading_ptr_hash (const void *def)
65 {
66   return htab_hash_pointer (*(const void *const *) def);
67 }
68
69 /* Return true if DEF1 and DEF2 are pointers to the same pointer.  */
70
71 static int
72 leading_ptr_eq_p (const void *def1, const void *def2)
73 {
74   return *(const void *const *) def1 == *(const void *const *) def2;
75 }
76
77 /* Associate PTR with the file position given by FILENAME and LINENO.  */
78
79 static void
80 set_md_ptr_loc (const void *ptr, const char *filename, int lineno)
81 {
82   struct ptr_loc *loc;
83
84   loc = (struct ptr_loc *) obstack_alloc (&ptr_loc_obstack,
85                                           sizeof (struct ptr_loc));
86   loc->ptr = ptr;
87   loc->filename = filename;
88   loc->lineno = lineno;
89   *htab_find_slot (ptr_locs, loc, INSERT) = loc;
90 }
91
92 /* Return the position associated with pointer PTR.  Return null if no
93    position was set.  */
94
95 static const struct ptr_loc *
96 get_md_ptr_loc (const void *ptr)
97 {
98   return (const struct ptr_loc *) htab_find (ptr_locs, &ptr);
99 }
100
101 /* Associate NEW_PTR with the same file position as OLD_PTR.  */
102
103 void
104 copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
105 {
106   const struct ptr_loc *loc = get_md_ptr_loc (old_ptr);
107   if (loc != 0)
108     set_md_ptr_loc (new_ptr, loc->filename, loc->lineno);
109 }
110
111 /* If PTR is associated with a known file position, print a #line
112    directive for it.  */
113
114 void
115 print_md_ptr_loc (const void *ptr)
116 {
117   const struct ptr_loc *loc = get_md_ptr_loc (ptr);
118   if (loc != 0)
119     printf ("#line %d \"%s\"\n", loc->lineno, loc->filename);
120 }
121
122 /* Return a condition that satisfies both COND1 and COND2.  Either string
123    may be null or empty.  */
124
125 const char *
126 join_c_conditions (const char *cond1, const char *cond2)
127 {
128   char *result;
129   const void **entry;
130
131   if (cond1 == 0 || cond1[0] == 0)
132     return cond2;
133
134   if (cond2 == 0 || cond2[0] == 0)
135     return cond1;
136
137   if (strcmp (cond1, cond2) == 0)
138     return cond1;
139
140   result = concat ("(", cond1, ") && (", cond2, ")", NULL);
141   obstack_ptr_grow (&joined_conditions_obstack, result);
142   obstack_ptr_grow (&joined_conditions_obstack, cond1);
143   obstack_ptr_grow (&joined_conditions_obstack, cond2);
144   entry = XOBFINISH (&joined_conditions_obstack, const void **);
145   *htab_find_slot (joined_conditions, entry, INSERT) = entry;
146   return result;
147 }
148
149 /* Print condition COND, wrapped in brackets.  If COND was created by
150    join_c_conditions, recursively invoke this function for the original
151    conditions and join the result with "&&".  Otherwise print a #line
152    directive for COND if its original file position is known.  */
153
154 void
155 print_c_condition (const char *cond)
156 {
157   const char **halves = (const char **) htab_find (joined_conditions, &cond);
158   if (halves != 0)
159     {
160       printf ("(");
161       print_c_condition (halves[1]);
162       printf (" && ");
163       print_c_condition (halves[2]);
164       printf (")");
165     }
166   else
167     {
168       putc ('\n', stdout);
169       print_md_ptr_loc (cond);
170       printf ("(%s)", cond);
171     }
172 }
173
174 /* A printf-like function for reporting an error against line LINENO
175    in the current MD file.  */
176
177 void
178 message_with_line (int lineno, const char *msg, ...)
179 {
180   va_list ap;
181
182   va_start (ap, msg);
183
184   fprintf (stderr, "%s:%d: ", read_md_filename, lineno);
185   vfprintf (stderr, msg, ap);
186   fputc ('\n', stderr);
187
188   va_end (ap);
189 }
190
191 /* A printf-like function for reporting an error against the current
192    position in the MD file, which is associated with INFILE.  */
193
194 void
195 fatal_with_file_and_line (FILE *infile, const char *msg, ...)
196 {
197   char context[64];
198   size_t i;
199   int c;
200   va_list ap;
201
202   va_start (ap, msg);
203
204   fprintf (stderr, "%s:%d: ", read_md_filename, read_md_lineno);
205   vfprintf (stderr, msg, ap);
206   putc ('\n', stderr);
207
208   /* Gather some following context.  */
209   for (i = 0; i < sizeof (context)-1; ++i)
210     {
211       c = getc (infile);
212       if (c == EOF)
213         break;
214       if (c == '\r' || c == '\n')
215         break;
216       context[i] = c;
217     }
218   context[i] = '\0';
219
220   fprintf (stderr, "%s:%d: following context is `%s'\n",
221            read_md_filename, read_md_lineno, context);
222
223   va_end (ap);
224   exit (1);
225 }
226
227 /* Report that we found character ACTUAL when we expected to find
228    character EXPECTED.  INFILE is the file handle associated
229    with the current file.  */
230
231 void
232 fatal_expected_char (FILE *infile, int expected, int actual)
233 {
234   if (actual == EOF)
235     fatal_with_file_and_line (infile, "expected character `%c', found EOF",
236                               expected);
237   else
238     fatal_with_file_and_line (infile, "expected character `%c', found `%c'",
239                               expected, actual);
240 }
241
242 /* Read chars from INFILE until a non-whitespace char and return that.
243    Comments, both Lisp style and C style, are treated as whitespace.  */
244
245 int
246 read_skip_spaces (FILE *infile)
247 {
248   int c;
249
250   while (1)
251     {
252       c = getc (infile);
253       switch (c)
254         {
255         case '\n':
256           read_md_lineno++;
257           break;
258
259         case ' ': case '\t': case '\f': case '\r':
260           break;
261
262         case ';':
263           do
264             c = getc (infile);
265           while (c != '\n' && c != EOF);
266           read_md_lineno++;
267           break;
268
269         case '/':
270           {
271             int prevc;
272             c = getc (infile);
273             if (c != '*')
274               fatal_expected_char (infile, '*', c);
275
276             prevc = 0;
277             while ((c = getc (infile)) && c != EOF)
278               {
279                 if (c == '\n')
280                    read_md_lineno++;
281                 else if (prevc == '*' && c == '/')
282                   break;
283                 prevc = c;
284               }
285           }
286           break;
287
288         default:
289           return c;
290         }
291     }
292 }
293
294 /* Subroutine of the string readers.  Handles backslash escapes.
295    Caller has read the backslash, but not placed it into the obstack.  */
296
297 static void
298 read_escape (FILE *infile)
299 {
300   int c = getc (infile);
301
302   switch (c)
303     {
304       /* Backslash-newline is replaced by nothing, as in C.  */
305     case '\n':
306       read_md_lineno++;
307       return;
308
309       /* \" \' \\ are replaced by the second character.  */
310     case '\\':
311     case '"':
312     case '\'':
313       break;
314
315       /* Standard C string escapes:
316          \a \b \f \n \r \t \v
317          \[0-7] \x
318          all are passed through to the output string unmolested.
319          In normal use these wind up in a string constant processed
320          by the C compiler, which will translate them appropriately.
321          We do not bother checking that \[0-7] are followed by up to
322          two octal digits, or that \x is followed by N hex digits.
323          \? \u \U are left out because they are not in traditional C.  */
324     case 'a': case 'b': case 'f': case 'n': case 'r': case 't': case 'v':
325     case '0': case '1': case '2': case '3': case '4': case '5': case '6':
326     case '7': case 'x':
327       obstack_1grow (&string_obstack, '\\');
328       break;
329
330       /* \; makes stuff for a C string constant containing
331          newline and tab.  */
332     case ';':
333       obstack_grow (&string_obstack, "\\n\\t", 4);
334       return;
335
336       /* pass anything else through, but issue a warning.  */
337     default:
338       fprintf (stderr, "%s:%d: warning: unrecognized escape \\%c\n",
339                read_md_filename, read_md_lineno, c);
340       obstack_1grow (&string_obstack, '\\');
341       break;
342     }
343
344   obstack_1grow (&string_obstack, c);
345 }
346
347 /* Read a double-quoted string onto the obstack.  Caller has scanned
348    the leading quote.  */
349
350 char *
351 read_quoted_string (FILE *infile)
352 {
353   int c;
354
355   while (1)
356     {
357       c = getc (infile); /* Read the string  */
358       if (c == '\n')
359         read_md_lineno++;
360       else if (c == '\\')
361         {
362           read_escape (infile);
363           continue;
364         }
365       else if (c == '"' || c == EOF)
366         break;
367
368       obstack_1grow (&string_obstack, c);
369     }
370
371   obstack_1grow (&string_obstack, 0);
372   return XOBFINISH (&string_obstack, char *);
373 }
374
375 /* Read a braced string (a la Tcl) onto the string obstack.  Caller
376    has scanned the leading brace.  Note that unlike quoted strings,
377    the outermost braces _are_ included in the string constant.  */
378
379 static char *
380 read_braced_string (FILE *infile)
381 {
382   int c;
383   int brace_depth = 1;  /* caller-processed */
384   unsigned long starting_read_md_lineno = read_md_lineno;
385
386   obstack_1grow (&string_obstack, '{');
387   while (brace_depth)
388     {
389       c = getc (infile); /* Read the string  */
390
391       if (c == '\n')
392         read_md_lineno++;
393       else if (c == '{')
394         brace_depth++;
395       else if (c == '}')
396         brace_depth--;
397       else if (c == '\\')
398         {
399           read_escape (infile);
400           continue;
401         }
402       else if (c == EOF)
403         fatal_with_file_and_line
404           (infile, "missing closing } for opening brace on line %lu",
405            starting_read_md_lineno);
406
407       obstack_1grow (&string_obstack, c);
408     }
409
410   obstack_1grow (&string_obstack, 0);
411   return XOBFINISH (&string_obstack, char *);
412 }
413
414 /* Read some kind of string constant.  This is the high-level routine
415    used by read_rtx.  It handles surrounding parentheses, leading star,
416    and dispatch to the appropriate string constant reader.  */
417
418 char *
419 read_string (FILE *infile, int star_if_braced)
420 {
421   char *stringbuf;
422   int saw_paren = 0;
423   int c, old_lineno;
424
425   c = read_skip_spaces (infile);
426   if (c == '(')
427     {
428       saw_paren = 1;
429       c = read_skip_spaces (infile);
430     }
431
432   old_lineno = read_md_lineno;
433   if (c == '"')
434     stringbuf = read_quoted_string (infile);
435   else if (c == '{')
436     {
437       if (star_if_braced)
438         obstack_1grow (&string_obstack, '*');
439       stringbuf = read_braced_string (infile);
440     }
441   else
442     fatal_with_file_and_line (infile, "expected `\"' or `{', found `%c'", c);
443
444   if (saw_paren)
445     {
446       c = read_skip_spaces (infile);
447       if (c != ')')
448         fatal_expected_char (infile, ')', c);
449     }
450
451   set_md_ptr_loc (stringbuf, read_md_filename, old_lineno);
452   return stringbuf;
453 }
454
455 /* Given a string, return the number of comma-separated elements in it.
456    Return 0 for the null string.  */
457
458 int
459 n_comma_elts (const char *s)
460 {
461   int n;
462
463   if (*s == '\0')
464     return 0;
465
466   for (n = 1; *s; s++)
467     if (*s == ',')
468       n++;
469
470   return n;
471 }
472
473 /* Given a pointer to a (char *), return a pointer to the beginning of the
474    next comma-separated element in the string.  Advance the pointer given
475    to the end of that element.  Return NULL if at end of string.  Caller
476    is responsible for copying the string if necessary.  White space between
477    a comma and an element is ignored.  */
478
479 const char *
480 scan_comma_elt (const char **pstr)
481 {
482   const char *start;
483   const char *p = *pstr;
484
485   if (*p == ',')
486     p++;
487   while (ISSPACE(*p))
488     p++;
489
490   if (*p == '\0')
491     return NULL;
492
493   start = p;
494
495   while (*p != ',' && *p != '\0')
496     p++;
497
498   *pstr = p;
499   return start;
500 }
501
502 /* Initialize this file's static data.  */
503
504 void
505 init_md_reader (void)
506 {
507   obstack_init (&string_obstack);
508   ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
509   obstack_init (&ptr_loc_obstack);
510   joined_conditions = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
511   obstack_init (&joined_conditions_obstack);
512 }