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