Regenerate configure
[platform/upstream/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   int fd;
92   struct stat stat_buf;
93   open_table *file;
94   table_include dummy;
95   table_include *include = &dummy;
96
97   /* dummy up a search of this directory */
98   dummy.next = includes;
99   dummy.dir = "";
100
101   /* create a file descriptor */
102   file = ZALLOC (open_table);
103   if (file == NULL)
104     {
105       perror (file_name);
106       exit (1);
107     }
108   file->root = root;
109   file->parent = root->current;
110   root->current = file;
111
112   while (1)
113     {
114       /* save the file name */
115       char *dup_name = 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 printf ("Trying `%s'\n", dup_name);
130       /* open the file */
131       fd = open (dup_name, O_RDONLY, 0);
132       if (fd >= 0)
133         break;
134       /* zfree (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   if (fstat (fd, &stat_buf) < 0) {
148     perror (file_name);
149     exit (1);
150   }
151   file->size = stat_buf.st_size;
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 (read (fd, file->buffer, file->size) < file->size) {
164     perror (file_name);
165     exit (1);
166   }
167   file->buffer[file->size] = '\0';
168
169   /* set the initial line numbering */
170   file->real_line.line_nr = 1; /* specifies current line */
171   file->pseudo_line.line_nr = 1; /* specifies current line */
172
173   /* done */
174   close (fd);
175 }
176
177 table *
178 table_open (const char *file_name)
179 {
180   table *root;
181
182   /* create a file descriptor */
183   root = ZALLOC (table);
184   if (root == NULL)
185     {
186       perror (file_name);
187       exit (1);
188     }
189
190   table_push (root, NULL, NULL, file_name);
191   return root;
192 }
193
194 char *
195 skip_spaces (char *chp)
196 {
197   while (1)
198     {
199       if (*chp == '\0'
200           || *chp == '\n'
201           || !isspace (*chp))
202         return chp;
203       chp++;
204     }
205 }
206
207
208 char *
209 back_spaces (char *start, char *chp)
210 {
211   while (1)
212     {
213       if (chp <= start
214           || !isspace (chp[-1]))
215         return chp;
216       chp--;
217     }
218 }
219
220 char *
221 skip_digits (char *chp)
222 {
223   while (1)
224     {
225       if (*chp == '\0'
226           || *chp == '\n'
227           || !isdigit (*chp))
228         return chp;
229       chp++;
230     }
231 }
232
233 char *
234 skip_to_separator (char *chp,
235                    char *separators)
236 {
237   while (1)
238     {
239       char *sep = separators;
240       while (1)
241         {
242           if (*chp == *sep)
243             return chp;
244           if (*sep == '\0')
245             break;
246           sep++;
247         }
248       chp++;
249     }
250 }
251
252 static char *
253 skip_to_null (char *chp)
254 {
255   return skip_to_separator (chp, "");
256 }
257
258
259 static char *
260 skip_to_nl (char * chp)
261 {
262   return skip_to_separator (chp, "\n");
263 }
264
265
266 static void
267 next_line (open_table *file)
268 {
269   file->pos = skip_to_nl (file->pos);
270   if (*file->pos == '0')
271     error (&file->pseudo_line, "Missing <nl> at end of line\n");
272   *file->pos = '\0';
273   file->pos += 1;
274   file->real_line.line_nr += 1;
275   file->pseudo_line.line_nr += 1;
276 }
277
278
279 extern table_entry *
280 table_read (table *root)
281 {
282   open_table *file = root->current;
283   table_entry *entry = NULL;
284   while(1)
285     {
286
287       /* end-of-file? */
288       while (*file->pos == '\0')
289         {
290           if (file->parent != NULL)
291             {
292               file = file->parent;
293               root->current = file;
294             }
295           else
296             return NULL;
297         }
298
299       /* code_block? */
300       if (*file->pos == '{')
301         {
302           char *chp;
303           next_line (file); /* discard leading brace */
304           entry = new_table_entry (file, table_code_entry);
305           chp = file->pos;
306           /* determine how many lines are involved - look for <nl> "}" */
307           {
308             int nr_lines = 0;
309             while (*file->pos != '}')
310               {
311                 next_line (file);
312                 nr_lines++;
313               }
314             set_nr_table_entry_fields (entry, nr_lines);
315           }
316           /* now enter each line */
317           {
318             int line_nr;
319             for (line_nr = 0; line_nr < entry->nr_fields; line_nr++)
320               {
321                 if (strncmp (chp, "  ", 2) == 0)
322                   entry->field[line_nr] = chp + 2;
323                 else
324                   entry->field[line_nr] = chp;
325                 chp = skip_to_null (chp) + 1;
326               }
327             /* skip trailing brace */
328             ASSERT (*file->pos == '}');
329             next_line (file);
330           }
331           break;
332         }
333
334       /* tab block? */
335       if (*file->pos == '\t')
336         {
337           char *chp = file->pos;
338           entry = new_table_entry (file, table_code_entry);
339           /* determine how many lines are involved - look for <nl> !<tab> */
340           {
341             int nr_lines = 0;
342             int nr_blank_lines = 0;
343             while (1)
344               {
345                 if (*file->pos == '\t')
346                   {
347                     nr_lines = nr_lines + nr_blank_lines + 1;
348                     nr_blank_lines = 0;
349                     next_line (file);
350                   }
351                 else
352                   {
353                     file->pos = skip_spaces (file->pos);
354                     if (*file->pos != '\n')
355                       break;
356                     nr_blank_lines++;
357                     next_line (file);
358                   }
359               }
360             set_nr_table_entry_fields (entry, nr_lines);
361           }
362           /* now enter each line */
363           {
364             int line_nr;
365             for (line_nr = 0; line_nr < entry->nr_fields; line_nr++)
366               {
367                 if (*chp == '\t')
368                   entry->field[line_nr] = chp + 1;
369                 else
370                   entry->field[line_nr] = ""; /* blank */
371                 chp = skip_to_null (chp) + 1;
372               }
373           }
374           break;
375         }
376
377       /* cpp directive? */
378       if (file->pos[0] == '#')
379         {
380           char *chp = skip_spaces (file->pos + 1);
381
382           /* cpp line-nr directive - # <line-nr> "<file>" */
383           if (isdigit (*chp)
384               && *skip_digits (chp) == ' '
385               && *skip_spaces (skip_digits (chp)) == '"')
386             {
387               int line_nr;
388               char *file_name;
389               file->pos = chp;
390               /* parse the number */
391               line_nr = atoi(file->pos) - 1;
392               /* skip to the file name */
393               while (file->pos[0] != '0'
394                      && file->pos[0] != '"'
395                      && file->pos[0] != '\0')
396                 file->pos++;
397               if (file->pos[0] != '"')
398                 error (&file->real_line, "Missing opening quote in cpp directive\n");
399               /* parse the file name */
400               file->pos++;
401               file_name = file->pos;
402               while (file->pos[0] != '"'
403                      && file->pos[0] != '\0')
404                 file->pos++;
405               if (file->pos[0] != '"')
406                 error (&file->real_line, "Missing closing quote in cpp directive\n");
407               file->pos[0] = '\0';
408               file->pos++;
409               file->pos = skip_to_nl (file->pos);
410               if (file->pos[0] != '\n')
411                 error (&file->real_line, "Missing newline in cpp directive\n");
412               file->pseudo_line.file_name = file_name;
413               file->pseudo_line.line_nr = line_nr;
414               next_line (file);
415               continue;
416             }
417
418           /* #define and #undef - not implemented yet */
419
420           /* Old style # comment */
421           next_line (file);
422           continue;
423         }
424
425       /* blank line or end-of-file? */
426       file->pos = skip_spaces (file->pos);
427       if (*file->pos == '\0')
428         error (&file->pseudo_line, "Missing <nl> at end of file\n");
429       if (*file->pos == '\n')
430         {
431           next_line (file);
432           continue;
433         }
434
435       /* comment - leading // or # - skip */
436       if ((file->pos[0] == '/' && file->pos[1] == '/')
437           || (file->pos[0] == '#'))
438         {
439           next_line (file);
440           continue;
441         }
442
443       /* colon field */
444       {
445         char *chp = file->pos;
446         entry = new_table_entry (file, table_colon_entry);
447         next_line (file);
448         /* figure out how many fields */
449         {
450           int nr_fields = 1;
451           char *tmpch = chp;
452           while (1)
453             {
454               tmpch = skip_to_separator (tmpch, "\\:");
455               if (*tmpch == '\\')
456                 {
457                   /* eat the escaped character */
458                   char *cp = tmpch;
459                   while (cp[1] != '\0')
460                     {
461                       cp[0] = cp[1];
462                       cp++;
463                     }
464                   cp[0] = '\0';
465                   tmpch++;
466                 }
467               else if (*tmpch != ':')
468                 break;
469               else
470                 {
471                   *tmpch = '\0';
472                   tmpch++;
473                   nr_fields++;
474                 }
475             }
476           set_nr_table_entry_fields (entry, nr_fields);
477         }
478         /* now parse them */
479         {
480           int field_nr;
481           for (field_nr = 0; field_nr < entry->nr_fields; field_nr++)
482             {
483               chp = skip_spaces (chp);
484               entry->field[field_nr] = chp;
485               chp = skip_to_null (chp);
486               *back_spaces (entry->field[field_nr], chp) = '\0';
487               chp++;
488             }
489         }
490         break;
491       }
492
493     }
494
495   ASSERT (entry == NULL || entry->field[entry->nr_fields] == NULL);
496   return entry;
497 }
498
499 extern void
500 table_print_code (lf *file,
501                   table_entry *entry)
502 {
503   int field_nr;
504   int nr = 0;
505   for (field_nr = 0;
506        field_nr < entry->nr_fields;
507        field_nr++)
508     {
509       char *chp = entry->field[field_nr];
510       int in_bit_field = 0;
511       if (*chp == '#')
512         lf_indent_suppress(file);
513       while (*chp != '\0') 
514         {
515           if (chp[0] == '{'
516               && !isspace(chp[1])
517               && chp[1] != '\0')
518             {
519               in_bit_field = 1;
520               nr += lf_putchr(file, '_');
521             }
522           else if (in_bit_field && chp[0] == ':')
523             {
524               nr += lf_putchr(file, '_');
525             }
526           else if (in_bit_field && *chp == '}')
527             {
528               nr += lf_putchr(file, '_');
529               in_bit_field = 0;
530             }
531           else 
532             {
533               nr += lf_putchr(file, *chp);
534             }
535           chp++;
536         }
537       if (in_bit_field)
538         {
539           line_ref line = *entry->line;
540           line.line_nr += field_nr;
541           error (&line, "Bit field brace miss match\n");
542         }
543       nr += lf_putchr(file, '\n');
544     }
545 }
546
547
548
549 void
550 dump_line_ref (lf *file,
551                  char *prefix,
552                  const line_ref *line,
553                  char *suffix)
554 {
555   lf_printf (file, "%s(line_ref*) 0x%lx", prefix, (long) line);
556   if (line != NULL)
557     {
558       lf_indent (file, +1);
559       lf_printf (file, "\n(line_nr %d)", line->line_nr);
560       lf_printf (file, "\n(file_name %s)", line->file_name);
561       lf_indent (file, -1);
562     }
563   lf_printf (file, "%s", suffix);
564 }
565
566
567 static const char *
568 table_entry_type_to_str (table_entry_type type)
569 {
570   switch (type)
571     {
572     case table_code_entry: return "code-entry";
573     case table_colon_entry: return "colon-entry";
574     }
575   return "*invalid*";
576 }
577
578 void
579 dump_table_entry(lf *file,
580                  char *prefix,
581                  const table_entry *entry,
582                  char *suffix)
583 {
584   lf_printf (file, "%s(table_entry*) 0x%lx", prefix, (long) entry);
585   if (entry != NULL)
586     {
587       int field;
588       lf_indent (file, +1);
589       dump_line_ref (file, "\n(line ", entry->line, ")");
590       lf_printf (file, "\n(type %s)", table_entry_type_to_str (entry->type));
591       lf_printf (file, "\n(nr_fields %d)", entry->nr_fields);
592       lf_printf (file, "\n(fields");
593       lf_indent (file, +1);
594       for (field = 0; field < entry->nr_fields; field++)
595         lf_printf (file, "\n\"%s\"", entry->field[field]);
596       lf_indent (file, -1);
597       lf_printf (file, ")");
598       lf_indent (file, -1);
599     }
600   lf_printf (file, "%s", suffix);
601 }
602
603
604 #ifdef MAIN
605 int
606 main(int argc, char **argv)
607 {
608   table *t;
609   table_entry *entry;
610   lf *l;
611   int line_nr;
612
613   if (argc != 2)
614     {
615       printf("Usage: table <file>\n");
616       exit (1);
617     }
618
619   t = table_open (argv[1]);
620   l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-table");
621
622   line_nr = 0;
623   do
624     {
625       char line[10];
626       entry = table_read (t);
627       line_nr ++;
628       sprintf (line, "(%d ", line_nr);
629       dump_table_entry (l, line, entry, ")\n");
630     }
631   while (entry != NULL);
632
633   return 0;
634 }
635 #endif