Change profiling so that it is enabled by default. Re-generate everything.
[external/binutils.git] / sim / igen / table.c
1 /*  This file is part of the program psim.
2
3     Copyright (C) 1994-1995,1997 Andrew Cagney <cagney@highland.com.au>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14  
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  
19     */
20
21
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <stdio.h>
25 #include <fcntl.h>
26 #include <ctype.h>
27
28 #include "config.h"
29 #include "misc.h"
30 #include "lf.h"
31 #include "table.h"
32
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36
37 #ifdef HAVE_STDLIB_H
38 #include <stdlib.h>
39 #endif
40
41 typedef struct _open_table open_table;
42 struct _open_table {
43   size_t size;
44   char *buffer;
45   char *pos;
46   line_ref pseudo_line;
47   line_ref real_line;
48   open_table *parent;
49   table *root;
50 };
51 struct _table {
52   open_table *current;
53 };
54
55
56 static line_ref *
57 current_line (open_table *file)
58 {
59   line_ref *entry = ZALLOC (line_ref);
60   *entry = file->pseudo_line;
61   return entry;
62 }
63
64 static table_entry *
65 new_table_entry (open_table *file,
66                  table_entry_type type)
67 {
68   table_entry *entry;
69   entry = ZALLOC (table_entry);
70   entry->file = file->root;
71   entry->line = current_line (file);
72   entry->type = type;
73   return entry;
74 }
75
76 static void
77 set_nr_table_entry_fields (table_entry *entry,
78                            int nr_fields)
79 {
80   entry->field = NZALLOC (char*, nr_fields + 1);
81   entry->nr_fields = nr_fields;
82 }
83
84
85 void
86 table_push (table *root,
87             line_ref *line,
88             table_include *includes,
89             const char *file_name)
90 {
91   FILE *ff;
92   open_table *file;
93   table_include dummy;
94   table_include *include = &dummy;
95
96   /* dummy up a search of this directory */
97   dummy.next = includes;
98   dummy.dir = "";
99
100   /* create a file descriptor */
101   file = ZALLOC (open_table);
102   if (file == NULL)
103     {
104       perror (file_name);
105       exit (1);
106     }
107   file->root = root;
108   file->parent = root->current;
109   root->current = file;
110
111   while (1)
112     {
113       /* save the file name */
114       char *dup_name = NZALLOC (char, strlen (include->dir) + strlen (file_name) + 2);
115       if (dup_name == NULL)
116         {
117           perror (file_name);
118           exit (1);
119         }
120       if (include->dir[0] != '\0')
121         {
122           strcat (dup_name, include->dir);
123           strcat (dup_name, "/");
124         }
125       strcat (dup_name, file_name);
126       file->real_line.file_name = dup_name;
127       file->pseudo_line.file_name = dup_name;
128       /* open the file */
129
130       ff = fopen (dup_name, "rb");
131       if (ff)
132         break;
133       /* zfree (dup_name); */
134       if (include->next == NULL)
135         {
136           if (line != NULL)
137             error (line, "Problem opening file `%s'\n", file_name);
138           perror (file_name);
139           exit (1);
140         }
141       include = include->next;
142   }
143
144
145   /* determine the size */
146   fseek (ff, 0, SEEK_END);
147   file->size = ftell (ff);
148   fseek (ff, 0, SEEK_SET);
149
150   /* allocate this much memory */
151   file->buffer = (char*) zalloc (file->size + 1);
152   if (file->buffer == NULL)
153     {
154       perror (file_name);
155       exit (1);
156     }
157   file->pos = file->buffer;
158
159   /* read it all in */
160   if (fread (file->buffer, 1, file->size, ff) < file->size) {
161     perror (file_name);
162     exit (1);
163   }
164   file->buffer[file->size] = '\0';
165
166   /* set the initial line numbering */
167   file->real_line.line_nr = 1; /* specifies current line */
168   file->pseudo_line.line_nr = 1; /* specifies current line */
169
170   /* done */
171   fclose (ff);
172 }
173
174 table *
175 table_open (const char *file_name)
176 {
177   table *root;
178
179   /* create a file descriptor */
180   root = ZALLOC (table);
181   if (root == NULL)
182     {
183       perror (file_name);
184       exit (1);
185     }
186
187   table_push (root, NULL, NULL, file_name);
188   return root;
189 }
190
191 char *
192 skip_spaces (char *chp)
193 {
194   while (1)
195     {
196       if (*chp == '\0'
197           || *chp == '\n'
198           || !isspace (*chp))
199         return chp;
200       chp++;
201     }
202 }
203
204
205 char *
206 back_spaces (char *start, char *chp)
207 {
208   while (1)
209     {
210       if (chp <= start
211           || !isspace (chp[-1]))
212         return chp;
213       chp--;
214     }
215 }
216
217 char *
218 skip_digits (char *chp)
219 {
220   while (1)
221     {
222       if (*chp == '\0'
223           || *chp == '\n'
224           || !isdigit (*chp))
225         return chp;
226       chp++;
227     }
228 }
229
230 char *
231 skip_to_separator (char *chp,
232                    char *separators)
233 {
234   while (1)
235     {
236       char *sep = separators;
237       while (1)
238         {
239           if (*chp == *sep)
240             return chp;
241           if (*sep == '\0')
242             break;
243           sep++;
244         }
245       chp++;
246     }
247 }
248
249 static char *
250 skip_to_null (char *chp)
251 {
252   return skip_to_separator (chp, "");
253 }
254
255
256 static char *
257 skip_to_nl (char * chp)
258 {
259   return skip_to_separator (chp, "\n");
260 }
261
262
263 static void
264 next_line (open_table *file)
265 {
266   file->pos = skip_to_nl (file->pos);
267   if (*file->pos == '0')
268     error (&file->pseudo_line, "Missing <nl> at end of line\n");
269   *file->pos = '\0';
270   file->pos += 1;
271   file->real_line.line_nr += 1;
272   file->pseudo_line.line_nr += 1;
273 }
274
275
276 extern table_entry *
277 table_read (table *root)
278 {
279   open_table *file = root->current;
280   table_entry *entry = NULL;
281   while(1)
282     {
283
284       /* end-of-file? */
285       while (*file->pos == '\0')
286         {
287           if (file->parent != NULL)
288             {
289               file = file->parent;
290               root->current = file;
291             }
292           else
293             return NULL;
294         }
295
296       /* code_block? */
297       if (*file->pos == '{')
298         {
299           char *chp;
300           next_line (file); /* discard leading brace */
301           entry = new_table_entry (file, table_code_entry);
302           chp = file->pos;
303           /* determine how many lines are involved - look for <nl> "}" */
304           {
305             int nr_lines = 0;
306             while (*file->pos != '}')
307               {
308                 next_line (file);
309                 nr_lines++;
310               }
311             set_nr_table_entry_fields (entry, nr_lines);
312           }
313           /* now enter each line */
314           {
315             int line_nr;
316             for (line_nr = 0; line_nr < entry->nr_fields; line_nr++)
317               {
318                 if (strncmp (chp, "  ", 2) == 0)
319                   entry->field[line_nr] = chp + 2;
320                 else
321                   entry->field[line_nr] = chp;
322                 chp = skip_to_null (chp) + 1;
323               }
324             /* skip trailing brace */
325             ASSERT (*file->pos == '}');
326             next_line (file);
327           }
328           break;
329         }
330
331       /* tab block? */
332       if (*file->pos == '\t')
333         {
334           char *chp = file->pos;
335           entry = new_table_entry (file, table_code_entry);
336           /* determine how many lines are involved - look for <nl> !<tab> */
337           {
338             int nr_lines = 0;
339             int nr_blank_lines = 0;
340             while (1)
341               {
342                 if (*file->pos == '\t')
343                   {
344                     nr_lines = nr_lines + nr_blank_lines + 1;
345                     nr_blank_lines = 0;
346                     next_line (file);
347                   }
348                 else
349                   {
350                     file->pos = skip_spaces (file->pos);
351                     if (*file->pos != '\n')
352                       break;
353                     nr_blank_lines++;
354                     next_line (file);
355                   }
356               }
357             set_nr_table_entry_fields (entry, nr_lines);
358           }
359           /* now enter each line */
360           {
361             int line_nr;
362             for (line_nr = 0; line_nr < entry->nr_fields; line_nr++)
363               {
364                 if (*chp == '\t')
365                   entry->field[line_nr] = chp + 1;
366                 else
367                   entry->field[line_nr] = ""; /* blank */
368                 chp = skip_to_null (chp) + 1;
369               }
370           }
371           break;
372         }
373
374       /* cpp directive? */
375       if (file->pos[0] == '#')
376         {
377           char *chp = skip_spaces (file->pos + 1);
378
379           /* cpp line-nr directive - # <line-nr> "<file>" */
380           if (isdigit (*chp)
381               && *skip_digits (chp) == ' '
382               && *skip_spaces (skip_digits (chp)) == '"')
383             {
384               int line_nr;
385               char *file_name;
386               file->pos = chp;
387               /* parse the number */
388               line_nr = atoi(file->pos) - 1;
389               /* skip to the file name */
390               while (file->pos[0] != '0'
391                      && file->pos[0] != '"'
392                      && file->pos[0] != '\0')
393                 file->pos++;
394               if (file->pos[0] != '"')
395                 error (&file->real_line, "Missing opening quote in cpp directive\n");
396               /* parse the file name */
397               file->pos++;
398               file_name = file->pos;
399               while (file->pos[0] != '"'
400                      && file->pos[0] != '\0')
401                 file->pos++;
402               if (file->pos[0] != '"')
403                 error (&file->real_line, "Missing closing quote in cpp directive\n");
404               file->pos[0] = '\0';
405               file->pos++;
406               file->pos = skip_to_nl (file->pos);
407               if (file->pos[0] != '\n')
408                 error (&file->real_line, "Missing newline in cpp directive\n");
409               file->pseudo_line.file_name = file_name;
410               file->pseudo_line.line_nr = line_nr;
411               next_line (file);
412               continue;
413             }
414
415           /* #define and #undef - not implemented yet */
416
417           /* Old style # comment */
418           next_line (file);
419           continue;
420         }
421
422       /* blank line or end-of-file? */
423       file->pos = skip_spaces (file->pos);
424       if (*file->pos == '\0')
425         error (&file->pseudo_line, "Missing <nl> at end of file\n");
426       if (*file->pos == '\n')
427         {
428           next_line (file);
429           continue;
430         }
431
432       /* comment - leading // or # - skip */
433       if ((file->pos[0] == '/' && file->pos[1] == '/')
434           || (file->pos[0] == '#'))
435         {
436           next_line (file);
437           continue;
438         }
439
440       /* colon field */
441       {
442         char *chp = file->pos;
443         entry = new_table_entry (file, table_colon_entry);
444         next_line (file);
445         /* figure out how many fields */
446         {
447           int nr_fields = 1;
448           char *tmpch = chp;
449           while (1)
450             {
451               tmpch = skip_to_separator (tmpch, "\\:");
452               if (*tmpch == '\\')
453                 {
454                   /* eat the escaped character */
455                   char *cp = tmpch;
456                   while (cp[1] != '\0')
457                     {
458                       cp[0] = cp[1];
459                       cp++;
460                     }
461                   cp[0] = '\0';
462                   tmpch++;
463                 }
464               else if (*tmpch != ':')
465                 break;
466               else
467                 {
468                   *tmpch = '\0';
469                   tmpch++;
470                   nr_fields++;
471                 }
472             }
473           set_nr_table_entry_fields (entry, nr_fields);
474         }
475         /* now parse them */
476         {
477           int field_nr;
478           for (field_nr = 0; field_nr < entry->nr_fields; field_nr++)
479             {
480               chp = skip_spaces (chp);
481               entry->field[field_nr] = chp;
482               chp = skip_to_null (chp);
483               *back_spaces (entry->field[field_nr], chp) = '\0';
484               chp++;
485             }
486         }
487         break;
488       }
489
490     }
491
492   ASSERT (entry == NULL || entry->field[entry->nr_fields] == NULL);
493   return entry;
494 }
495
496 extern void
497 table_print_code (lf *file,
498                   table_entry *entry)
499 {
500   int field_nr;
501   int nr = 0;
502   for (field_nr = 0;
503        field_nr < entry->nr_fields;
504        field_nr++)
505     {
506       char *chp = entry->field[field_nr];
507       int in_bit_field = 0;
508       if (*chp == '#')
509         lf_indent_suppress(file);
510       while (*chp != '\0') 
511         {
512           if (chp[0] == '{'
513               && !isspace(chp[1])
514               && chp[1] != '\0')
515             {
516               in_bit_field = 1;
517               nr += lf_putchr(file, '_');
518             }
519           else if (in_bit_field && chp[0] == ':')
520             {
521               nr += lf_putchr(file, '_');
522             }
523           else if (in_bit_field && *chp == '}')
524             {
525               nr += lf_putchr(file, '_');
526               in_bit_field = 0;
527             }
528           else 
529             {
530               nr += lf_putchr(file, *chp);
531             }
532           chp++;
533         }
534       if (in_bit_field)
535         {
536           line_ref line = *entry->line;
537           line.line_nr += field_nr;
538           error (&line, "Bit field brace miss match\n");
539         }
540       nr += lf_putchr(file, '\n');
541     }
542 }
543
544
545
546 void
547 dump_line_ref (lf *file,
548                  char *prefix,
549                  const line_ref *line,
550                  char *suffix)
551 {
552   lf_printf (file, "%s(line_ref*) 0x%lx", prefix, (long) line);
553   if (line != NULL)
554     {
555       lf_indent (file, +1);
556       lf_printf (file, "\n(line_nr %d)", line->line_nr);
557       lf_printf (file, "\n(file_name %s)", line->file_name);
558       lf_indent (file, -1);
559     }
560   lf_printf (file, "%s", suffix);
561 }
562
563
564 static const char *
565 table_entry_type_to_str (table_entry_type type)
566 {
567   switch (type)
568     {
569     case table_code_entry: return "code-entry";
570     case table_colon_entry: return "colon-entry";
571     }
572   return "*invalid*";
573 }
574
575 void
576 dump_table_entry(lf *file,
577                  char *prefix,
578                  const table_entry *entry,
579                  char *suffix)
580 {
581   lf_printf (file, "%s(table_entry*) 0x%lx", prefix, (long) entry);
582   if (entry != NULL)
583     {
584       int field;
585       lf_indent (file, +1);
586       dump_line_ref (file, "\n(line ", entry->line, ")");
587       lf_printf (file, "\n(type %s)", table_entry_type_to_str (entry->type));
588       lf_printf (file, "\n(nr_fields %d)", entry->nr_fields);
589       lf_printf (file, "\n(fields");
590       lf_indent (file, +1);
591       for (field = 0; field < entry->nr_fields; field++)
592         lf_printf (file, "\n\"%s\"", entry->field[field]);
593       lf_indent (file, -1);
594       lf_printf (file, ")");
595       lf_indent (file, -1);
596     }
597   lf_printf (file, "%s", suffix);
598 }
599
600
601 #ifdef MAIN
602 int
603 main(int argc, char **argv)
604 {
605   table *t;
606   table_entry *entry;
607   lf *l;
608   int line_nr;
609
610   if (argc != 2)
611     {
612       printf("Usage: table <file>\n");
613       exit (1);
614     }
615
616   t = table_open (argv[1]);
617   l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-table");
618
619   line_nr = 0;
620   do
621     {
622       char line[10];
623       entry = table_read (t);
624       line_nr ++;
625       sprintf (line, "(%d ", line_nr);
626       dump_table_entry (l, line, entry, ")\n");
627     }
628   while (entry != NULL);
629
630   return 0;
631 }
632 #endif