1/* The IGEN simulator generator for GDB, the GNU Debugger. 2 3 Copyright 2002-2020 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 43typedef struct _open_table open_table; 44struct _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}; 54struct _table 55{ 56 open_table *current; 57}; 58 59 60static line_ref * 61current_line (open_table * file) 62{ 63 line_ref *entry = ZALLOC (line_ref); 64 *entry = file->pseudo_line; 65 return entry; 66} 67 68static table_entry * 69new_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 79static void 80set_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 87void 88table_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 176table * 177table_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 193char * 194skip_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 205char * 206back_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 216char * 217skip_digits (char *chp) 218{ 219 while (1) 220 { 221 if (*chp == '\0' || *chp == '\n' || !isdigit (*chp)) 222 return chp; 223 chp++; 224 } 225} 226 227char * 228skip_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 245static char * 246skip_to_null (char *chp) 247{ 248 return skip_to_separator (chp, ""); 249} 250 251 252static char * 253skip_to_nl (char *chp) 254{ 255 return skip_to_separator (chp, "\n"); 256} 257 258 259static void 260next_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 272extern table_entry * 273table_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 493extern void 494table_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 538void 539dump_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 553static const char * 554table_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 566void 567dump_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 591int 592main (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