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