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