xref: /netbsd-src/external/gpl3/gdb/dist/sim/igen/table.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /* The IGEN simulator generator for GDB, the GNU Debugger.
2 
3    Copyright 2002-2014 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
622