]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/igen/table.c
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / sim / igen / table.c
1 /* The IGEN simulator generator for GDB, the GNU Debugger.
2
3 Copyright 2002-2023 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 int nr = 0;
494 for (field_nr = 0; field_nr < entry->nr_fields; field_nr++)
495 {
496 char *chp = entry->field[field_nr];
497 int in_bit_field = 0;
498 if (*chp == '#')
499 lf_indent_suppress (file);
500 while (*chp != '\0')
501 {
502 if (chp[0] == '{' && !isspace (chp[1]) && chp[1] != '\0')
503 {
504 in_bit_field = 1;
505 nr += lf_putchr (file, '_');
506 }
507 else if (in_bit_field && chp[0] == ':')
508 {
509 nr += lf_putchr (file, '_');
510 }
511 else if (in_bit_field && *chp == '}')
512 {
513 nr += lf_putchr (file, '_');
514 in_bit_field = 0;
515 }
516 else
517 {
518 nr += lf_putchr (file, *chp);
519 }
520 chp++;
521 }
522 if (in_bit_field)
523 {
524 line_ref line = *entry->line;
525 line.line_nr += field_nr;
526 error (&line, "Bit field brace miss match\n");
527 }
528 nr += lf_putchr (file, '\n');
529 }
530 }
531
532
533 void
534 dump_line_ref (lf *file,
535 const char *prefix,
536 const line_ref *line,
537 const char *suffix)
538 {
539 lf_printf (file, "%s(line_ref*) %p", prefix, line);
540 if (line != NULL)
541 {
542 lf_indent (file, +1);
543 lf_printf (file, "\n(line_nr %d)", line->line_nr);
544 lf_printf (file, "\n(file_name %s)", line->file_name);
545 lf_indent (file, -1);
546 }
547 lf_printf (file, "%s", suffix);
548 }
549
550
551 static const char *
552 table_entry_type_to_str (table_entry_type type)
553 {
554 switch (type)
555 {
556 case table_code_entry:
557 return "code-entry";
558 case table_colon_entry:
559 return "colon-entry";
560 }
561 return "*invalid*";
562 }
563
564 void
565 dump_table_entry (lf *file,
566 const char *prefix,
567 const table_entry *entry,
568 const char *suffix)
569 {
570 lf_printf (file, "%s(table_entry*) %p", prefix, 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