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