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 37typedef struct _open_table open_table; 38struct _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}; 48struct _table 49{ 50 open_table *current; 51}; 52 53 54static line_ref * 55current_line (open_table * file) 56{ 57 line_ref *entry = ZALLOC (line_ref); 58 *entry = file->pseudo_line; 59 return entry; 60} 61 62static table_entry * 63new_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 73static void 74set_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 81void 82table_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 172table * 173table_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 189char * 190skip_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 201char * 202back_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 212char * 213skip_digits (char *chp) 214{ 215 while (1) 216 { 217 if (*chp == '\0' || *chp == '\n' || !isdigit (*chp)) 218 return chp; 219 chp++; 220 } 221} 222 223char * 224skip_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 241static char * 242skip_to_null (char *chp) 243{ 244 return skip_to_separator (chp, ""); 245} 246 247 248static char * 249skip_to_nl (char *chp) 250{ 251 return skip_to_separator (chp, "\n"); 252} 253 254 255static void 256next_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 268extern table_entry * 269table_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 489extern void 490table_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 533void 534dump_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 551static const char * 552table_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 564void 565dump_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 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