1 /* PSPP - a program for statistical analysis. 2 Copyright (C) 1997-9, 2000, 2008, 2010, 2011 Free Software Foundation, Inc. 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17 #include <assert.h> 18 #include <ctype.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <stdarg.h> 22 #include <stdbool.h> 23 #include <string.h> 24 #include <errno.h> 25 #include <unistd.h> 26 27 /* GNU C allows the programmer to declare that certain functions take 28 printf-like arguments, never return, etc. Conditionalize these 29 declarations on whether gcc is in use. */ 30 #if __GNUC__ > 1 31 #define ATTRIBUTE(X) __attribute__ (X) 32 #else 33 #define ATTRIBUTE(X) 34 #endif 35 36 /* Marks a function argument as possibly not used. */ 37 #define UNUSED ATTRIBUTE ((unused)) 38 39 /* Marks a function that will never return. */ 40 #define NO_RETURN ATTRIBUTE ((noreturn)) 41 42 /* Mark a function as taking a printf- or scanf-like format 43 string as its FMT'th argument and that the FIRST'th argument 44 is the first one to be checked against the format string. */ 45 #define PRINTF_FORMAT(FMT, FIRST) ATTRIBUTE ((format (__printf__, FMT, FIRST))) 46 47 /* Max length of an input line. */ 48 #define MAX_LINE_LEN 1024 49 50 /* Max token length. */ 51 #define MAX_TOK_LEN 1024 52 53 /* argv[0]. */ 54 static char *program_name; 55 56 /* Have the input and output files been opened yet? */ 57 static bool is_open; 58 59 /* Input, output files. */ 60 static FILE *in, *out; 61 62 /* Input, output file names. */ 63 static char *ifn, *ofn; 64 65 /* Input, output file line number. */ 66 static int ln, oln = 1; 67 68 /* Input line buffer, current position. */ 69 static char *buf, *cp; 70 71 /* Token types. */ 72 enum 73 { 74 T_STRING = 256, /* String literal. */ 75 T_ID = 257 /* Identifier. */ 76 }; 77 78 /* Current token: either one of the above, or a single character. */ 79 static int token; 80 81 /* Token string value. */ 82 static char *tokstr; 83 84 /* Utility functions. */ 85 86 /* Close all open files and delete the output file, on failure. */ 87 static void 88 finish_up (void) 89 { 90 if (!is_open) 91 return; 92 is_open = false; 93 fclose (in); 94 fclose (out); 95 if (remove (ofn) == -1) 96 fprintf (stderr, "%s: %s: remove: %s\n", program_name, ofn, strerror (errno)); 97 } 98 99 void hcf (void) NO_RETURN; 100 101 /* Terminate unsuccessfully. */ 102 void 103 hcf (void) 104 { 105 finish_up (); 106 exit (EXIT_FAILURE); 107 } 108 109 int fail (const char *, ...) PRINTF_FORMAT (1, 2) NO_RETURN; 110 int error (const char *, ...) PRINTF_FORMAT (1, 2) NO_RETURN; 111 112 /* Output an error message and terminate unsuccessfully. */ 113 int 114 fail (const char *format, ...) 115 { 116 va_list args; 117 118 va_start (args, format); 119 fprintf (stderr, "%s: ", program_name); 120 vfprintf (stderr, format, args); 121 fprintf (stderr, "\n"); 122 va_end (args); 123 124 hcf (); 125 } 126 127 /* Output a context-dependent error message and terminate 128 unsuccessfully. */ 129 int 130 error (const char *format,...) 131 { 132 va_list args; 133 134 va_start (args, format); 135 fprintf (stderr, "%s:%d: (column %d) ", ifn, ln, (int) (cp - buf)); 136 vfprintf (stderr, format, args); 137 fprintf (stderr, "\n"); 138 va_end (args); 139 140 hcf (); 141 } 142 143 #define VME "virtual memory exhausted" 144 145 /* Allocate a block of SIZE bytes and return a pointer to its 146 beginning. */ 147 static void * 148 xmalloc (size_t size) 149 { 150 void *vp; 151 152 if (size == 0) 153 return NULL; 154 155 vp = malloc (size); 156 if (!vp) 157 fail ("xmalloc(%lu): %s", (unsigned long) size, VME); 158 159 return vp; 160 } 161 162 /* Make a dynamically allocated copy of string S and return a pointer 163 to the first character. */ 164 static char * 165 xstrdup (const char *s) 166 { 167 size_t size; 168 char *t; 169 170 assert (s != NULL); 171 size = strlen (s) + 1; 172 173 t = malloc (size); 174 if (!t) 175 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME); 176 177 memcpy (t, s, size); 178 return t; 179 } 180 181 /* Returns a pointer to one of 8 static buffers. The buffers are used 182 in rotation. */ 183 static char * 184 get_buffer (void) 185 { 186 static char b[8][256]; 187 static int cb; 188 189 if (++cb >= 8) 190 cb = 0; 191 192 return b[cb]; 193 } 194 195 /* Copies a string to a static buffer, converting it to lowercase in 196 the process, and returns a pointer to the static buffer. */ 197 static char * 198 st_lower (const char *s) 199 { 200 char *p, *cp; 201 202 p = cp = get_buffer (); 203 while (*s) 204 *cp++ = tolower ((unsigned char) (*s++)); 205 *cp++ = '\0'; 206 207 return p; 208 } 209 210 /* Copies a string to a static buffer, converting it to uppercase in 211 the process, and returns a pointer to the static buffer. */ 212 static char * 213 st_upper (const char *s) 214 { 215 char *p, *cp; 216 217 p = cp = get_buffer (); 218 while (*s) 219 *cp++ = toupper ((unsigned char) (*s++)); 220 *cp++ = '\0'; 221 222 return p; 223 } 224 225 /* Returns the address of the first non-whitespace character in S, or 226 the address of the null terminator if none. */ 227 static char * 228 skip_ws (char *s) 229 { 230 while (isspace ((unsigned char) *s)) 231 s++; 232 return s; 233 } 234 235 /* Read one line from the input file into buf. Lines having special 236 formats are handled specially. */ 237 static bool 238 get_line (void) 239 { 240 ln++; 241 if (0 == fgets (buf, MAX_LINE_LEN, in)) 242 { 243 if (ferror (in)) 244 fail ("%s: fgets: %s", ifn, strerror (errno)); 245 return false; 246 } 247 248 cp = strchr (buf, '\n'); 249 if (cp != NULL) 250 *cp = '\0'; 251 252 cp = buf; 253 return true; 254 } 255 256 /* Symbol table manager. */ 257 258 /* Symbol table entry. */ 259 typedef struct symbol symbol; 260 struct symbol 261 { 262 symbol *next; /* Next symbol in symbol table. */ 263 char *name; /* Symbol name. */ 264 int unique; /* 1=Name must be unique in this file. */ 265 int ln; /* Line number of definition. */ 266 int value; /* Symbol value. */ 267 }; 268 269 /* Symbol table. */ 270 symbol *symtab; 271 272 /* Add a symbol to the symbol table having name NAME, uniqueness 273 UNIQUE, and value VALUE. If a symbol having the same name is found 274 in the symbol table, its sequence number is returned and the symbol 275 table is not modified. Otherwise, the symbol is added and the next 276 available sequence number is returned. */ 277 static int 278 add_symbol (const char *name, int unique, int value) 279 { 280 symbol *iter, *sym; 281 int x; 282 283 sym = xmalloc (sizeof *sym); 284 sym->name = xstrdup (name); 285 sym->unique = unique; 286 sym->value = value; 287 sym->next = NULL; 288 sym->ln = ln; 289 if (!symtab) 290 { 291 symtab = sym; 292 return 1; 293 } 294 iter = symtab; 295 x = 1; 296 for (;;) 297 { 298 if (!strcmp (iter->name, name)) 299 { 300 if (iter->unique) 301 { 302 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn, 303 ln, name); 304 fprintf (stderr, "%s:%d: location of previous definition\n", ifn, 305 iter->ln); 306 hcf (); 307 } 308 free (sym->name); 309 free (sym); 310 return x; 311 } 312 if (!iter->next) 313 break; 314 iter = iter->next; 315 x++; 316 } 317 iter->next = sym; 318 return ++x; 319 } 320 321 /* Finds the symbol having given sequence number X within the symbol 322 table, and returns the associated symbol structure. */ 323 static symbol * 324 find_symbol (int x) 325 { 326 symbol *iter; 327 328 iter = symtab; 329 while (x > 1 && iter) 330 { 331 iter = iter->next; 332 x--; 333 } 334 assert (iter); 335 return iter; 336 } 337 338 #if DUMP_TOKENS 339 /* Writes a printable representation of the current token to 340 stdout. */ 341 static void 342 dump_token (void) 343 { 344 switch (token) 345 { 346 case T_STRING: 347 printf ("STRING\t\"%s\"\n", tokstr); 348 break; 349 case T_ID: 350 printf ("ID\t%s\n", tokstr); 351 break; 352 default: 353 printf ("PUNCT\t%c\n", token); 354 } 355 } 356 #endif /* DUMP_TOKENS */ 357 358 359 const char hyphen_proxy = '_'; 360 361 static void 362 id_cpy (char **cp) 363 { 364 char *dest = tokstr; 365 char *src = *cp; 366 367 while (*src == '_' || *src == '-' || isalnum ((unsigned char) *src)) 368 { 369 *dest++ = *src == '-' ? hyphen_proxy :toupper ((unsigned char) (*src)); 370 src++; 371 } 372 373 *cp = src; 374 *dest++ = '\0'; 375 } 376 377 static char * 378 unmunge (const char *s) 379 { 380 char *dest = xmalloc (strlen (s) + 1); 381 char *d = dest; 382 383 while (*s) 384 { 385 if (*s == hyphen_proxy) 386 *d = '-'; 387 else 388 *d = *s; 389 s++; 390 d++; 391 } 392 *d = '\0'; 393 394 return dest; 395 } 396 397 /* Reads a token from the input file. */ 398 static int 399 lex_get (void) 400 { 401 /* Skip whitespace and check for end of file. */ 402 for (;;) 403 { 404 cp = skip_ws (cp); 405 if (*cp != '\0') 406 break; 407 408 if (!get_line ()) 409 fail ("%s: Unexpected end of file.", ifn); 410 } 411 412 if (*cp == '"') 413 { 414 char *dest = tokstr; 415 token = T_STRING; 416 cp++; 417 while (*cp != '"' && *cp) 418 { 419 if (*cp == '\\') 420 { 421 cp++; 422 if (!*cp) 423 error ("Unterminated string literal."); 424 *dest++ = *cp++; 425 } 426 else 427 *dest++ = *cp++; 428 } 429 *dest++ = 0; 430 if (!*cp) 431 error ("Unterminated string literal."); 432 cp++; 433 } 434 else if (*cp == '_' || isalnum ((unsigned char) *cp)) 435 { 436 char *dest = tokstr; 437 token = T_ID; 438 439 id_cpy (&cp); 440 } 441 else 442 token = *cp++; 443 444 #if DUMP_TOKENS 445 dump_token (); 446 #endif 447 448 return token; 449 } 450 451 /* Force the current token to be an identifier token. */ 452 static void 453 force_id (void) 454 { 455 if (token != T_ID) 456 error ("Identifier expected."); 457 } 458 459 /* Force the current token to be a string token. */ 460 static void 461 force_string (void) 462 { 463 if (token != T_STRING) 464 error ("String expected."); 465 } 466 467 /* Checks whether the current token is the identifier S; if so, skips 468 the token and returns true; otherwise, returns false. */ 469 static bool 470 match_id (const char *s) 471 { 472 if (token == T_ID && !strcmp (tokstr, s)) 473 { 474 lex_get (); 475 return true; 476 } 477 return false; 478 } 479 480 /* Checks whether the current token is T. If so, skips the token and 481 returns true; otherwise, returns false. */ 482 static bool 483 match_token (int t) 484 { 485 if (token == t) 486 { 487 lex_get (); 488 return true; 489 } 490 return false; 491 } 492 493 /* Force the current token to be T, and skip it. */ 494 static void 495 skip_token (int t) 496 { 497 if (token != t) 498 error ("`%c' expected.", t); 499 lex_get (); 500 } 501 502 /* Structures. */ 503 504 /* Some specifiers have associated values. */ 505 enum 506 { 507 VAL_NONE, /* No value. */ 508 VAL_INT, /* Integer value. */ 509 VAL_DBL, /* Floating point value. */ 510 VAL_STRING /* String value. */ 511 }; 512 513 /* For those specifiers with values, the syntax of those values. */ 514 enum 515 { 516 VT_PLAIN, /* Unadorned value. */ 517 VT_PAREN /* Value must be enclosed in parentheses. */ 518 }; 519 520 /* Forward definition. */ 521 typedef struct specifier specifier; 522 523 /* A single setting. */ 524 typedef struct setting setting; 525 struct setting 526 { 527 specifier *parent; /* Owning specifier. */ 528 setting *next; /* Next in the chain. */ 529 char *specname; /* Name of the setting. */ 530 int con; /* Sequence number. */ 531 532 /* Values. */ 533 int valtype; /* One of VT_*. */ 534 int value; /* One of VAL_*. */ 535 int optvalue; /* 1=value is optional, 0=value is required. */ 536 char *valname; /* Variable name for the value. */ 537 char *restriction; /* !=NULL: expression specifying valid values. */ 538 }; 539 540 /* A single specifier. */ 541 struct specifier 542 { 543 specifier *next; /* Next in the chain. */ 544 char *varname; /* Variable name. */ 545 setting *s; /* Associated settings. */ 546 547 setting *def; /* Default setting. */ 548 setting *omit_kw; /* Setting for which the keyword can be omitted. */ 549 550 int index; /* Next array index. */ 551 }; 552 553 /* Subcommand types. */ 554 typedef enum 555 { 556 SBC_PLAIN, /* The usual case. */ 557 SBC_VARLIST, /* Variable list. */ 558 SBC_INT, /* Integer value. */ 559 SBC_PINT, /* Integer inside parentheses. */ 560 SBC_DBL, /* Floating point value. */ 561 SBC_INT_LIST, /* List of integers (?). */ 562 SBC_DBL_LIST, /* List of floating points (?). */ 563 SBC_CUSTOM, /* Custom. */ 564 SBC_ARRAY, /* Array of boolean values. */ 565 SBC_STRING, /* String value. */ 566 SBC_VAR /* Single variable name. */ 567 } 568 subcommand_type; 569 570 typedef enum 571 { 572 ARITY_ONCE_EXACTLY, /* must occur exactly once */ 573 ARITY_ONCE_ONLY, /* zero or once */ 574 ARITY_MANY /* 0, 1, ... , inf */ 575 }subcommand_arity; 576 577 /* A single subcommand. */ 578 typedef struct subcommand subcommand; 579 struct subcommand 580 { 581 subcommand *next; /* Next in the chain. */ 582 char *name; /* Subcommand name. */ 583 subcommand_type type; /* One of SBC_*. */ 584 subcommand_arity arity; /* How many times should the subcommand occur*/ 585 int narray; /* Index of next array element. */ 586 const char *prefix; /* Prefix for variable and constant names. */ 587 specifier *spec; /* Array of specifiers. */ 588 char *pv_options; /* PV_* options for SBC_VARLIST. */ 589 }; 590 591 /* Name of the command; i.e., DESCRIPTIVES. */ 592 char *cmdname; 593 594 /* Short prefix for the command; i.e., `dsc_'. */ 595 char *prefix; 596 597 /* List of subcommands. */ 598 subcommand *subcommands; 599 600 /* Default subcommand if any, or NULL. */ 601 subcommand *def; 602 603 /* Parsing. */ 604 605 void parse_subcommands (void); 606 607 /* Parse an entire specification. */ 608 static void 609 parse (void) 610 { 611 /* Get the command name and prefix. */ 612 if (token != T_STRING && token != T_ID) 613 error ("Command name expected."); 614 cmdname = xstrdup (tokstr); 615 lex_get (); 616 skip_token ('('); 617 force_id (); 618 prefix = xstrdup (tokstr); 619 lex_get (); 620 skip_token (')'); 621 skip_token (':'); 622 623 /* Read all the subcommands. */ 624 subcommands = NULL; 625 def = NULL; 626 parse_subcommands (); 627 } 628 629 /* Parses a single setting into S, given subcommand information SBC 630 and specifier information SPEC. */ 631 static void 632 parse_setting (setting *s, specifier *spec) 633 { 634 s->parent = spec; 635 636 if (match_token ('*')) 637 { 638 if (spec->omit_kw) 639 error ("Cannot have two settings with omittable keywords."); 640 else 641 spec->omit_kw = s; 642 } 643 644 if (match_token ('!')) 645 { 646 if (spec->def) 647 error ("Cannot have two default settings."); 648 else 649 spec->def = s; 650 } 651 652 force_id (); 653 s->specname = xstrdup (tokstr); 654 s->con = add_symbol (s->specname, 0, 0); 655 s->value = VAL_NONE; 656 657 lex_get (); 658 659 /* Parse setting value info if necessary. */ 660 if (token != '/' && token != ';' && token != '.' && token != ',') 661 { 662 if (token == '(') 663 { 664 s->valtype = VT_PAREN; 665 lex_get (); 666 } 667 else 668 s->valtype = VT_PLAIN; 669 670 s->optvalue = match_token ('*'); 671 672 if (match_id ("N")) 673 s->value = VAL_INT; 674 else if (match_id ("D")) 675 s->value = VAL_DBL; 676 else if (match_id ("S")) 677 s->value = VAL_STRING; 678 else 679 error ("`n', `d', or `s' expected."); 680 681 skip_token (':'); 682 683 force_id (); 684 s->valname = xstrdup (tokstr); 685 lex_get (); 686 687 if (token == ',') 688 { 689 lex_get (); 690 force_string (); 691 s->restriction = xstrdup (tokstr); 692 lex_get (); 693 } 694 else 695 s->restriction = NULL; 696 697 if (s->valtype == VT_PAREN) 698 skip_token (')'); 699 } 700 } 701 702 /* Parse a single specifier into SPEC, given subcommand information 703 SBC. */ 704 static void 705 parse_specifier (specifier *spec, subcommand *sbc) 706 { 707 spec->index = 0; 708 spec->s = NULL; 709 spec->def = NULL; 710 spec->omit_kw = NULL; 711 spec->varname = NULL; 712 713 if (token == T_ID) 714 { 715 spec->varname = xstrdup (st_lower (tokstr)); 716 lex_get (); 717 } 718 719 /* Handle array elements. */ 720 if (token != ':') 721 { 722 spec->index = sbc->narray; 723 if (sbc->type == SBC_ARRAY) 724 { 725 if (token == '|') 726 token = ','; 727 else 728 sbc->narray++; 729 } 730 spec->s = NULL; 731 return; 732 } 733 skip_token (':'); 734 735 if (sbc->type == SBC_ARRAY && token == T_ID) 736 { 737 spec->varname = xstrdup (st_lower (tokstr)); 738 spec->index = sbc->narray; 739 sbc->narray++; 740 } 741 742 743 744 /* Parse all the settings. */ 745 { 746 setting **s = &spec->s; 747 748 for (;;) 749 { 750 *s = xmalloc (sizeof **s); 751 parse_setting (*s, spec); 752 if (token == ',' || token == ';' || token == '.') 753 break; 754 skip_token ('/'); 755 s = &(*s)->next; 756 } 757 (*s)->next = NULL; 758 } 759 } 760 761 /* Parse a list of specifiers for subcommand SBC. */ 762 static void 763 parse_specifiers (subcommand *sbc) 764 { 765 specifier **spec = &sbc->spec; 766 767 if (token == ';' || token == '.') 768 { 769 *spec = NULL; 770 return; 771 } 772 773 for (;;) 774 { 775 *spec = xmalloc (sizeof **spec); 776 parse_specifier (*spec, sbc); 777 if (token == ';' || token == '.') 778 break; 779 skip_token (','); 780 spec = &(*spec)->next; 781 } 782 (*spec)->next = NULL; 783 } 784 785 /* Parse a subcommand into SBC. */ 786 static void 787 parse_subcommand (subcommand *sbc) 788 { 789 if (match_token ('*')) 790 { 791 if (def) 792 error ("Multiple default subcommands."); 793 def = sbc; 794 } 795 796 sbc->arity = ARITY_ONCE_ONLY; 797 if (match_token('+')) 798 sbc->arity = ARITY_MANY; 799 else if (match_token('^')) 800 sbc->arity = ARITY_ONCE_EXACTLY ; 801 802 803 force_id (); 804 sbc->name = xstrdup (tokstr); 805 lex_get (); 806 807 sbc->narray = 0; 808 sbc->type = SBC_PLAIN; 809 sbc->spec = NULL; 810 811 if (match_token ('[')) 812 { 813 force_id (); 814 sbc->prefix = xstrdup (st_lower (tokstr)); 815 lex_get (); 816 817 skip_token (']'); 818 skip_token ('='); 819 820 sbc->type = SBC_ARRAY; 821 parse_specifiers (sbc); 822 823 } 824 else 825 { 826 if (match_token ('(')) 827 { 828 force_id (); 829 sbc->prefix = xstrdup (st_lower (tokstr)); 830 lex_get (); 831 832 skip_token (')'); 833 } 834 else 835 sbc->prefix = ""; 836 837 skip_token ('='); 838 839 if (match_id ("VAR")) 840 sbc->type = SBC_VAR; 841 if (match_id ("VARLIST")) 842 { 843 if (match_token ('(')) 844 { 845 force_string (); 846 sbc->pv_options = xstrdup (tokstr); 847 lex_get(); 848 849 skip_token (')'); 850 } 851 else 852 sbc->pv_options = NULL; 853 854 sbc->type = SBC_VARLIST; 855 } 856 else if (match_id ("INTEGER")) 857 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT; 858 else if (match_id ("PINT")) 859 sbc->type = SBC_PINT; 860 else if (match_id ("DOUBLE")) 861 { 862 if (match_id ("LIST")) 863 sbc->type = SBC_DBL_LIST; 864 else 865 sbc->type = SBC_DBL; 866 } 867 else if (match_id ("STRING")) 868 sbc->type = SBC_STRING; 869 else if (match_id ("CUSTOM")) 870 sbc->type = SBC_CUSTOM; 871 else 872 parse_specifiers (sbc); 873 } 874 } 875 876 /* Parse all the subcommands. */ 877 void 878 parse_subcommands (void) 879 { 880 subcommand **sbc = &subcommands; 881 882 for (;;) 883 { 884 *sbc = xmalloc (sizeof **sbc); 885 (*sbc)->next = NULL; 886 887 parse_subcommand (*sbc); 888 889 if (token == '.') 890 return; 891 892 skip_token (';'); 893 sbc = &(*sbc)->next; 894 } 895 } 896 897 /* Output. */ 898 899 #define BASE_INDENT 2 /* Starting indent. */ 900 #define INC_INDENT 2 /* Indent increment. */ 901 902 /* Increment the indent. */ 903 #define indent() indent += INC_INDENT 904 #define outdent() indent -= INC_INDENT 905 906 /* Size of the indent from the left margin. */ 907 int indent; 908 909 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3); 910 911 /* Write line FORMAT to the output file, formatted as with printf, 912 indented `indent' characters from the left margin. If INDENTION is 913 greater than 0, indents BASE_INDENT * INDENTION characters after 914 writing the line; if INDENTION is less than 0, dedents BASE_INDENT 915 * INDENTION characters _before_ writing the line. */ 916 void 917 dump (int indention, const char *format, ...) 918 { 919 va_list args; 920 int i; 921 922 if (indention < 0) 923 indent += BASE_INDENT * indention; 924 925 oln++; 926 va_start (args, format); 927 for (i = 0; i < indent; i++) 928 putc (' ', out); 929 vfprintf (out, format, args); 930 putc ('\n', out); 931 va_end (args); 932 933 if (indention > 0) 934 indent += BASE_INDENT * indention; 935 } 936 937 /* Writes a blank line to the output file and adjusts 'indent' by BASE_INDENT 938 * INDENTION characters. 939 940 (This is only useful because GCC complains about using "" as a format 941 string, for whatever reason.) */ 942 static void 943 dump_blank_line (int indention) 944 { 945 oln++; 946 indent += BASE_INDENT * indention; 947 putc ('\n', out); 948 } 949 950 /* Write the structure members for specifier SPEC to the output file. 951 SBC is the including subcommand. */ 952 static void 953 dump_specifier_vars (const specifier *spec, const subcommand *sbc) 954 { 955 if (spec->varname) 956 dump (0, "long %s%s;", sbc->prefix, spec->varname); 957 958 { 959 setting *s; 960 961 for (s = spec->s; s; s = s->next) 962 { 963 if (s->value != VAL_NONE) 964 { 965 const char *typename; 966 967 assert (s->value == VAL_INT || s->value == VAL_DBL 968 || s->value == VAL_STRING); 969 typename = (s->value == VAL_INT ? "long" 970 : s->value == VAL_DBL ? "double" 971 : "char *"); 972 973 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname)); 974 } 975 } 976 } 977 } 978 979 /* Returns true if string T is a PSPP keyword, false otherwise. */ 980 static bool 981 is_keyword (const char *t) 982 { 983 static const char *kw[] = 984 { 985 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT", 986 "NE", "ALL", "BY", "TO", "WITH", 0, 987 }; 988 const char **cp; 989 990 for (cp = kw; *cp; cp++) 991 if (!strcmp (t, *cp)) 992 return true; 993 return false; 994 } 995 996 /* Transforms a string NAME into a valid C identifier: makes 997 everything lowercase and maps nonalphabetic characters to 998 underscores. Returns a pointer to a static buffer. */ 999 static char * 1000 make_identifier (const char *name) 1001 { 1002 char *p = get_buffer (); 1003 char *cp; 1004 1005 for (cp = p; *name; name++) 1006 if (isalpha ((unsigned char) *name)) 1007 *cp++ = tolower ((unsigned char) (*name)); 1008 else 1009 *cp++ = '_'; 1010 *cp = '\0'; 1011 1012 return p; 1013 } 1014 1015 /* Writes the struct and enum declarations for the parser. */ 1016 static void 1017 dump_declarations (void) 1018 { 1019 indent = 0; 1020 1021 dump (0, "struct dataset;"); 1022 1023 /* Write out enums for all the identifiers in the symbol table. */ 1024 { 1025 int f, k; 1026 symbol *sym; 1027 char *buf = NULL; 1028 1029 /* Note the squirmings necessary to make sure that the last enum 1030 is not followed by a comma, as mandated by ANSI C89. */ 1031 for (sym = symtab, f = k = 0; sym; sym = sym->next) 1032 if (!sym->unique && !is_keyword (sym->name)) 1033 { 1034 if (!f) 1035 { 1036 dump (0, "/* Settings for subcommand specifiers. */"); 1037 dump (1, "enum"); 1038 dump (1, "{"); 1039 f = 1; 1040 } 1041 1042 if (buf == NULL) 1043 buf = xmalloc (1024); 1044 else 1045 dump (0, "%s", buf); 1046 1047 if (k) 1048 sprintf (buf, "%s%s,", st_upper (prefix), sym->name); 1049 else 1050 { 1051 k = 1; 1052 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name); 1053 } 1054 } 1055 if (buf) 1056 { 1057 buf[strlen (buf) - 1] = 0; 1058 dump (0, "%s", buf); 1059 free (buf); 1060 } 1061 if (f) 1062 { 1063 dump (-1, "};"); 1064 dump_blank_line (-1); 1065 } 1066 } 1067 1068 /* Write out some type definitions */ 1069 { 1070 dump (0, "#define MAXLISTS 10"); 1071 } 1072 1073 1074 /* For every array subcommand, write out the associated enumerated 1075 values. */ 1076 { 1077 subcommand *sbc; 1078 1079 for (sbc = subcommands; sbc; sbc = sbc->next) 1080 if (sbc->type == SBC_ARRAY && sbc->narray) 1081 { 1082 dump (0, "/* Array indices for %s subcommand. */", sbc->name); 1083 1084 dump (1, "enum"); 1085 dump (1, "{"); 1086 1087 { 1088 specifier *spec; 1089 1090 for (spec = sbc->spec; spec; spec = spec->next) 1091 dump (0, "%s%s%s = %d,", 1092 st_upper (prefix), st_upper (sbc->prefix), 1093 st_upper (spec->varname), spec->index); 1094 1095 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix)); 1096 1097 dump (-1, "};"); 1098 dump_blank_line (-1); 1099 } 1100 } 1101 } 1102 1103 /* Write out structure declaration. */ 1104 { 1105 subcommand *sbc; 1106 1107 dump (0, "/* %s structure. */", cmdname); 1108 dump (1, "struct cmd_%s", make_identifier (cmdname)); 1109 dump (1, "{"); 1110 for (sbc = subcommands; sbc; sbc = sbc->next) 1111 { 1112 int f = 0; 1113 1114 if (sbc != subcommands) 1115 dump_blank_line (0); 1116 1117 dump (0, "/* %s subcommand. */", sbc->name); 1118 dump (0, "int sbc_%s;", st_lower (sbc->name)); 1119 1120 switch (sbc->type) 1121 { 1122 case SBC_ARRAY: 1123 case SBC_PLAIN: 1124 { 1125 specifier *spec; 1126 1127 for (spec = sbc->spec; spec; spec = spec->next) 1128 { 1129 if (spec->s == 0) 1130 { 1131 if (sbc->type == SBC_PLAIN) 1132 dump (0, "long int %s%s;", st_lower (sbc->prefix), 1133 spec->varname); 1134 else if (f == 0) 1135 { 1136 dump (0, "int a_%s[%s%scount];", 1137 st_lower (sbc->name), 1138 st_upper (prefix), 1139 st_upper (sbc->prefix) 1140 ); 1141 1142 f = 1; 1143 } 1144 } 1145 else 1146 dump_specifier_vars (spec, sbc); 1147 } 1148 } 1149 break; 1150 1151 case SBC_VARLIST: 1152 dump (0, "size_t %sn_%s;", st_lower (sbc->prefix), 1153 st_lower (sbc->name)); 1154 dump (0, "const struct variable **%sv_%s;", st_lower (sbc->prefix), 1155 st_lower (sbc->name)); 1156 break; 1157 1158 case SBC_VAR: 1159 dump (0, "const struct variable *%sv_%s;", st_lower (sbc->prefix), 1160 st_lower (sbc->name)); 1161 break; 1162 1163 case SBC_STRING: 1164 dump (0, "char *s_%s;", st_lower (sbc->name)); 1165 break; 1166 1167 case SBC_INT: 1168 case SBC_PINT: 1169 dump (0, "long n_%s[MAXLISTS];", st_lower (sbc->name)); 1170 break; 1171 1172 case SBC_DBL: 1173 dump (0, "double n_%s[MAXLISTS];", st_lower (sbc->name)); 1174 break; 1175 1176 case SBC_DBL_LIST: 1177 dump (0, "subc_list_double dl_%s[MAXLISTS];", 1178 st_lower(sbc->name)); 1179 break; 1180 1181 case SBC_INT_LIST: 1182 dump (0, "subc_list_int il_%s[MAXLISTS];", 1183 st_lower(sbc->name)); 1184 break; 1185 1186 1187 default:; 1188 /* nothing */ 1189 } 1190 } 1191 1192 dump (-1, "};"); 1193 dump_blank_line (-1); 1194 } 1195 1196 /* Write out prototypes for custom_*() functions as necessary. */ 1197 { 1198 bool seen = false; 1199 subcommand *sbc; 1200 1201 for (sbc = subcommands; sbc; sbc = sbc->next) 1202 if (sbc->type == SBC_CUSTOM) 1203 { 1204 if (!seen) 1205 { 1206 seen = true; 1207 dump (0, "/* Prototype for custom subcommands of %s. */", 1208 cmdname); 1209 } 1210 dump (0, "static int %scustom_%s (struct lexer *, struct dataset *, struct cmd_%s *, void *);", 1211 st_lower (prefix), st_lower (sbc->name), 1212 make_identifier (cmdname)); 1213 } 1214 1215 if (seen) 1216 dump_blank_line (0); 1217 } 1218 1219 /* Prototypes for parsing and freeing functions. */ 1220 { 1221 dump (0, "/* Command parsing functions. */"); 1222 dump (0, "static int parse_%s (struct lexer *, struct dataset *, struct cmd_%s *, void *);", 1223 make_identifier (cmdname), make_identifier (cmdname)); 1224 dump (0, "static void free_%s (struct cmd_%s *);", 1225 make_identifier (cmdname), make_identifier (cmdname)); 1226 dump_blank_line (0); 1227 } 1228 } 1229 1230 /* Writes out code to initialize all the variables that need 1231 initialization for particular specifier SPEC inside subcommand SBC. */ 1232 static void 1233 dump_specifier_init (const specifier *spec, const subcommand *sbc) 1234 { 1235 if (spec->varname) 1236 { 1237 char s[256]; 1238 1239 if (spec->def) 1240 sprintf (s, "%s%s", 1241 st_upper (prefix), find_symbol (spec->def->con)->name); 1242 else 1243 strcpy (s, "-1"); 1244 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s); 1245 } 1246 1247 { 1248 setting *s; 1249 1250 for (s = spec->s; s; s = s->next) 1251 { 1252 if (s->value != VAL_NONE) 1253 { 1254 const char *init; 1255 1256 assert (s->value == VAL_INT || s->value == VAL_DBL 1257 || s->value == VAL_STRING); 1258 init = (s->value == VAL_INT ? "LONG_MIN" 1259 : s->value == VAL_DBL ? "SYSMIS" 1260 : "NULL"); 1261 1262 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init); 1263 } 1264 } 1265 } 1266 } 1267 1268 /* Write code to initialize all variables. */ 1269 static void 1270 dump_vars_init (int persistent) 1271 { 1272 /* Loop through all the subcommands. */ 1273 { 1274 subcommand *sbc; 1275 1276 for (sbc = subcommands; sbc; sbc = sbc->next) 1277 { 1278 int f = 0; 1279 1280 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name)); 1281 if (! persistent) 1282 { 1283 switch (sbc->type) 1284 { 1285 case SBC_INT_LIST: 1286 case SBC_DBL_LIST: 1287 dump (1, "{"); 1288 dump (0, "int i;"); 1289 dump (1, "for (i = 0; i < MAXLISTS; ++i)"); 1290 dump (0, "subc_list_%s_create(&p->%cl_%s[i]) ;", 1291 sbc->type == SBC_INT_LIST ? "int" : "double", 1292 sbc->type == SBC_INT_LIST ? 'i' : 'd', 1293 st_lower (sbc->name) 1294 ); 1295 dump (-2, "}"); 1296 break; 1297 1298 case SBC_DBL: 1299 dump (1, "{"); 1300 dump (0, "int i;"); 1301 dump (1, "for (i = 0; i < MAXLISTS; ++i)"); 1302 dump (0, "p->n_%s[i] = SYSMIS;", st_lower (sbc->name)); 1303 dump (-2, "}"); 1304 break; 1305 1306 case SBC_CUSTOM: 1307 /* nothing */ 1308 break; 1309 1310 case SBC_PLAIN: 1311 case SBC_ARRAY: 1312 { 1313 specifier *spec; 1314 1315 for (spec = sbc->spec; spec; spec = spec->next) 1316 if (spec->s == NULL) 1317 { 1318 if (sbc->type == SBC_PLAIN) 1319 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname); 1320 else if (f == 0) 1321 { 1322 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);", 1323 st_lower (sbc->name), st_lower (sbc->name)); 1324 f = 1; 1325 } 1326 } 1327 else 1328 dump_specifier_init (spec, sbc); 1329 } 1330 break; 1331 1332 case SBC_VARLIST: 1333 dump (0, "p->%sn_%s = 0;", 1334 st_lower (sbc->prefix), st_lower (sbc->name)); 1335 dump (0, "p->%sv_%s = NULL;", 1336 st_lower (sbc->prefix), st_lower (sbc->name)); 1337 break; 1338 1339 case SBC_VAR: 1340 dump (0, "p->%sv_%s = NULL;", 1341 st_lower (sbc->prefix), st_lower (sbc->name)); 1342 break; 1343 1344 case SBC_STRING: 1345 dump (0, "p->s_%s = NULL;", st_lower (sbc->name)); 1346 break; 1347 1348 case SBC_INT: 1349 case SBC_PINT: 1350 dump (1, "{"); 1351 dump (0, "int i;"); 1352 dump (1, "for (i = 0; i < MAXLISTS; ++i)"); 1353 dump (0, "p->n_%s[i] = LONG_MIN;", st_lower (sbc->name)); 1354 dump (-2, "}"); 1355 break; 1356 1357 default: 1358 abort (); 1359 } 1360 } 1361 } 1362 } 1363 } 1364 1365 /* Return a pointer to a static buffer containing an expression that 1366 will match token T. */ 1367 static char * 1368 make_match (const char *t) 1369 { 1370 char *s; 1371 1372 s = get_buffer (); 1373 1374 while (*t == '_') 1375 t++; 1376 1377 if (is_keyword (t)) 1378 sprintf (s, "lex_match (lexer, T_%s)", t); 1379 else if (!strcmp (t, "ON") || !strcmp (t, "YES")) 1380 strcpy (s, "(lex_match_id (lexer, \"ON\") || lex_match_id (lexer, \"YES\") " 1381 "|| lex_match_id (lexer, \"TRUE\"))"); 1382 else if (!strcmp (t, "OFF") || !strcmp (t, "NO")) 1383 strcpy (s, "(lex_match_id (lexer, \"OFF\") || lex_match_id (lexer, \"NO\") " 1384 "|| lex_match_id (lexer, \"FALSE\"))"); 1385 else if (isdigit ((unsigned char) t[0])) 1386 sprintf (s, "lex_match_int (lexer, %s)", t); 1387 else if (strchr (t, hyphen_proxy)) 1388 { 1389 char *c = unmunge (t); 1390 sprintf (s, "lex_match_phrase (lexer, \"%s\")", c); 1391 free (c); 1392 } 1393 else 1394 sprintf (s, "lex_match_id (lexer, \"%s\")", t); 1395 1396 return s; 1397 } 1398 1399 /* Write out the parsing code for specifier SPEC within subcommand 1400 SBC. */ 1401 static void 1402 dump_specifier_parse (const specifier *spec, const subcommand *sbc) 1403 { 1404 setting *s; 1405 1406 if (spec->omit_kw && spec->omit_kw->next) 1407 error ("Omittable setting is not last setting in `%s' specifier.", 1408 spec->varname); 1409 if (spec->omit_kw && spec->omit_kw->parent->next) 1410 error ("Default specifier is not in last specifier in `%s' " 1411 "subcommand.", sbc->name); 1412 1413 for (s = spec->s; s; s = s->next) 1414 { 1415 int first = spec == sbc->spec && s == spec->s; 1416 1417 /* Match the setting's keyword. */ 1418 if (spec->omit_kw == s) 1419 { 1420 if (!first) 1421 { 1422 dump (1, "else"); 1423 dump (1, "{"); 1424 } 1425 dump (1, "%s;", make_match (s->specname)); 1426 } 1427 else 1428 dump (1, "%sif (%s)", first ? "" : "else ", 1429 make_match (s->specname)); 1430 1431 1432 /* Handle values. */ 1433 if (s->value == VAL_NONE) 1434 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname, 1435 st_upper (prefix), find_symbol (s->con)->name); 1436 else 1437 { 1438 if (spec->omit_kw != s) 1439 dump (1, "{"); 1440 1441 if (spec->varname) 1442 { 1443 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname, 1444 st_upper (prefix), find_symbol (s->con)->name); 1445 1446 if (sbc->type == SBC_ARRAY) 1447 dump (0, "p->a_%s[%s%s%s] = 1;", 1448 st_lower (sbc->name), 1449 st_upper (prefix), st_upper (sbc->prefix), 1450 st_upper (spec->varname)); 1451 } 1452 1453 1454 if (s->valtype == VT_PAREN) 1455 { 1456 if (s->optvalue) 1457 { 1458 dump (1, "if (lex_match (lexer, T_LPAREN))"); 1459 dump (1, "{"); 1460 } 1461 else 1462 { 1463 dump (1, "if (!lex_match (lexer, T_LPAREN))"); 1464 dump (1, "{"); 1465 dump (0, "lex_error_expecting (lexer, \"`('\");"); 1466 dump (0, "goto lossage;"); 1467 dump (-1, "}"); 1468 outdent (); 1469 } 1470 } 1471 1472 if (s->value == VAL_INT) 1473 { 1474 dump (1, "if (!lex_force_int (lexer))"); 1475 dump (0, "goto lossage;"); 1476 dump (-1, "p->%s%s = lex_integer (lexer);", 1477 sbc->prefix, st_lower (s->valname)); 1478 } 1479 else if (s->value == VAL_DBL) 1480 { 1481 dump (1, "if (!lex_force_num (lexer))"); 1482 dump (0, "goto lossage;"); 1483 dump (-1, "p->%s%s = lex_tokval (lexer);", sbc->prefix, 1484 st_lower (s->valname)); 1485 } 1486 else if (s->value == VAL_STRING) 1487 { 1488 dump (1, "if (!lex_force_string_or_id (lexer))"); 1489 dump (0, "goto lossage;"); 1490 dump (-1, "free (p->%s%s);", sbc->prefix, st_lower (s->valname)); 1491 dump (0, "p->%s%s = ss_xstrdup (ss_tokss (lexer));", 1492 sbc->prefix, st_lower (s->valname)); 1493 } 1494 else 1495 abort (); 1496 1497 if (s->restriction) 1498 { 1499 { 1500 char *str, *str2; 1501 str = xmalloc (MAX_TOK_LEN); 1502 str2 = xmalloc (MAX_TOK_LEN); 1503 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname)); 1504 sprintf (str, s->restriction, str2, str2, str2, str2, 1505 str2, str2, str2, str2); 1506 dump (1, "if (!(%s))", str); 1507 free (str); 1508 free (str2); 1509 } 1510 1511 dump (1, "{"); 1512 dump (0, "lex_error (lexer, NULL);"); 1513 dump (0, "goto lossage;"); 1514 dump (-1, "}"); 1515 outdent (); 1516 } 1517 1518 dump (0, "lex_get (lexer);"); 1519 1520 if (s->valtype == VT_PAREN) 1521 { 1522 dump (1, "if (!lex_force_match (lexer, T_RPAREN))"); 1523 dump (0, "goto lossage;"); 1524 outdent (); 1525 if (s->optvalue) 1526 { 1527 dump (-1, "}"); 1528 outdent (); 1529 } 1530 } 1531 1532 if (s != spec->omit_kw) 1533 dump (-1, "}"); 1534 } 1535 1536 if (s == spec->omit_kw) 1537 { 1538 dump (-1, "}"); 1539 outdent (); 1540 } 1541 outdent (); 1542 } 1543 } 1544 1545 /* Write out the code to parse subcommand SBC. */ 1546 static void 1547 dump_subcommand (const subcommand *sbc) 1548 { 1549 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY) 1550 { 1551 int count; 1552 1553 dump (1, "while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)"); 1554 dump (1, "{"); 1555 1556 { 1557 specifier *spec; 1558 1559 for (count = 0, spec = sbc->spec; spec; spec = spec->next) 1560 { 1561 if (spec->s) 1562 dump_specifier_parse (spec, sbc); 1563 else 1564 { 1565 count++; 1566 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "", 1567 make_match (st_upper (spec->varname))); 1568 if (sbc->type == SBC_PLAIN) 1569 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix), 1570 spec->varname); 1571 else 1572 dump (0, "p->a_%s[%s%s%s] = 1;", 1573 st_lower (sbc->name), 1574 st_upper (prefix), st_upper (sbc->prefix), 1575 st_upper (spec->varname)); 1576 outdent (); 1577 } 1578 } 1579 } 1580 1581 { 1582 specifier *spec; 1583 setting *s; 1584 1585 /* This code first finds the last specifier in sbc. Then it 1586 finds the last setting within that last specifier. Either 1587 or both might be NULL. */ 1588 spec = sbc->spec; 1589 s = NULL; 1590 if (spec) 1591 { 1592 while (spec->next) 1593 spec = spec->next; 1594 s = spec->s; 1595 if (s) 1596 while (s->next) 1597 s = s->next; 1598 } 1599 1600 if (spec && (!spec->s || !spec->omit_kw)) 1601 { 1602 dump (1, "else"); 1603 dump (1, "{"); 1604 dump (0, "lex_error (lexer, NULL);"); 1605 dump (0, "goto lossage;"); 1606 dump (-1, "}"); 1607 outdent (); 1608 } 1609 } 1610 1611 dump (0, "lex_match (lexer, T_COMMA);"); 1612 dump (-1, "}"); 1613 outdent (); 1614 } 1615 else if (sbc->type == SBC_VARLIST) 1616 { 1617 dump (1, "if (!parse_variables_const (lexer, dataset_dict (ds), &p->%sv_%s, &p->%sn_%s, " 1618 "PV_APPEND%s%s))", 1619 st_lower (sbc->prefix), st_lower (sbc->name), 1620 st_lower (sbc->prefix), st_lower (sbc->name), 1621 sbc->pv_options ? " |" : "", 1622 sbc->pv_options ? sbc->pv_options : ""); 1623 dump (0, "goto lossage;"); 1624 outdent (); 1625 } 1626 else if (sbc->type == SBC_VAR) 1627 { 1628 dump (0, "p->%sv_%s = parse_variable (lexer, dataset_dict (ds));", 1629 st_lower (sbc->prefix), st_lower (sbc->name)); 1630 dump (1, "if (!p->%sv_%s)", 1631 st_lower (sbc->prefix), st_lower (sbc->name)); 1632 dump (0, "goto lossage;"); 1633 outdent (); 1634 } 1635 else if (sbc->type == SBC_STRING) 1636 { 1637 dump (1, "if (!lex_force_string (lexer))"); 1638 dump (0, "return false;"); 1639 outdent (); 1640 dump (0, "free(p->s_%s);", st_lower(sbc->name)); 1641 dump (0, "p->s_%s = ss_xstrdup (lex_tokss (lexer));", 1642 st_lower (sbc->name)); 1643 dump (0, "lex_get (lexer);"); 1644 } 1645 else if (sbc->type == SBC_DBL) 1646 { 1647 dump (1, "if (!lex_force_num (lexer))"); 1648 dump (0, "goto lossage;"); 1649 dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number (lexer);", 1650 st_lower (sbc->name), st_lower (sbc->name)); 1651 dump (0, "lex_get(lexer);"); 1652 } 1653 else if (sbc->type == SBC_INT) 1654 { 1655 dump(1, "{"); 1656 dump(0, "int x;"); 1657 dump (1, "if (!lex_force_int (lexer))"); 1658 dump (0, "goto lossage;"); 1659 dump (-1, "x = lex_integer (lexer);"); 1660 dump (0, "lex_get(lexer);"); 1661 dump (0, "p->n_%s[p->sbc_%s - 1] = x;", st_lower (sbc->name), st_lower(sbc->name)); 1662 dump (-1,"}"); 1663 } 1664 else if (sbc->type == SBC_PINT) 1665 { 1666 dump (0, "lex_match (lexer, T_LPAREN);"); 1667 dump (1, "if (!lex_force_int (lexer))"); 1668 dump (0, "goto lossage;"); 1669 dump (-1, "p->n_%s = lex_integer (lexer);", st_lower (sbc->name)); 1670 dump (0, "lex_match (lexer, T_RPAREN);"); 1671 } 1672 else if (sbc->type == SBC_DBL_LIST || sbc->type == SBC_INT_LIST) 1673 { 1674 dump (0, "if (p->sbc_%s > MAXLISTS)",st_lower(sbc->name)); 1675 dump (1, "{"); 1676 dump (0, "subc_list_error (lexer, \"%s\", MAXLISTS);", 1677 st_lower(sbc->name)); 1678 dump (0, "goto lossage;"); 1679 dump (-1,"}"); 1680 1681 dump (1, "while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)"); 1682 dump (1, "{"); 1683 dump (0, "lex_match (lexer, T_COMMA);"); 1684 dump (0, "if (!lex_force_num (lexer))"); 1685 dump (1, "{"); 1686 dump (0, "goto lossage;"); 1687 dump (-1,"}"); 1688 1689 dump (0, "subc_list_%s_push (&p->%cl_%s[p->sbc_%s-1], lex_number (lexer));", 1690 sbc->type == SBC_INT_LIST ? "int" : "double", 1691 sbc->type == SBC_INT_LIST ? 'i' : 'd', 1692 st_lower (sbc->name), st_lower (sbc->name)); 1693 1694 dump (0, "lex_get (lexer);"); 1695 dump (-1,"}"); 1696 1697 } 1698 else if (sbc->type == SBC_CUSTOM) 1699 { 1700 dump (1, "switch (%scustom_%s (lexer, ds, p, aux))", 1701 st_lower (prefix), st_lower (sbc->name)); 1702 dump (0, "{"); 1703 dump (1, "case 0:"); 1704 dump (0, "goto lossage;"); 1705 dump (-1, "case 1:"); 1706 indent (); 1707 dump (0, "break;"); 1708 dump (-1, "case 2:"); 1709 indent (); 1710 dump (0, "lex_error (lexer, NULL);"); 1711 dump (0, "goto lossage;"); 1712 dump (-1, "default:"); 1713 indent (); 1714 dump (0, "NOT_REACHED ();"); 1715 dump (-1, "}"); 1716 outdent (); 1717 } 1718 } 1719 1720 /* Write out entire parser. */ 1721 static void 1722 dump_parser (int persistent) 1723 { 1724 int f; 1725 1726 indent = 0; 1727 1728 dump (0, "static int"); 1729 dump (0, "parse_%s (struct lexer *lexer, struct dataset *ds%s, struct cmd_%s *p, void *aux UNUSED)", 1730 make_identifier (cmdname), 1731 (def && (def->type == SBC_VARLIST || def->type == SBC_CUSTOM))?"":" UNUSED", 1732 make_identifier (cmdname)); 1733 dump (1, "{"); 1734 1735 dump_vars_init (persistent); 1736 1737 dump (1, "for (;;)"); 1738 dump (1, "{"); 1739 1740 f = 0; 1741 if (def && (def->type == SBC_VARLIST)) 1742 { 1743 if (def->type == SBC_VARLIST) 1744 dump (1, "if (lex_token (lexer) == T_ID " 1745 "&& dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)) != NULL " 1746 "&& lex_next_token (lexer, 1) != T_EQUALS)"); 1747 else 1748 { 1749 dump (0, "if ((lex_token (lexer) == T_ID " 1750 "&& dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)) " 1751 "&& lex_next_token (lexer, 1) != T_EQUALS)"); 1752 dump (1, " || token == T_ALL)"); 1753 } 1754 dump (1, "{"); 1755 dump (0, "p->sbc_%s++;", st_lower (def->name)); 1756 dump (1, "if (!parse_variables_const (lexer, dataset_dict (ds), &p->%sv_%s, &p->%sn_%s, " 1757 "PV_APPEND))", 1758 st_lower (def->prefix), st_lower (def->name), 1759 st_lower (def->prefix), st_lower (def->name)); 1760 dump (0, "goto lossage;"); 1761 dump (-2, "}"); 1762 outdent (); 1763 f = 1; 1764 } 1765 else if (def && def->type == SBC_CUSTOM) 1766 { 1767 dump (1, "switch (%scustom_%s (lexer, ds, p, aux))", 1768 st_lower (prefix), st_lower (def->name)); 1769 dump (0, "{"); 1770 dump (1, "case 0:"); 1771 dump (0, "goto lossage;"); 1772 dump (-1, "case 1:"); 1773 indent (); 1774 dump (0, "p->sbc_%s++;", st_lower (def->name)); 1775 dump (0, "continue;"); 1776 dump (-1, "case 2:"); 1777 indent (); 1778 dump (0, "break;"); 1779 dump (-1, "default:"); 1780 indent (); 1781 dump (0, "NOT_REACHED ();"); 1782 dump (-1, "}"); 1783 outdent (); 1784 } 1785 1786 { 1787 subcommand *sbc; 1788 1789 for (sbc = subcommands; sbc; sbc = sbc->next) 1790 { 1791 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name)); 1792 f = 1; 1793 dump (1, "{"); 1794 1795 dump (0, "lex_match (lexer, T_EQUALS);"); 1796 dump (0, "p->sbc_%s++;", st_lower (sbc->name)); 1797 if (sbc->arity != ARITY_MANY) 1798 { 1799 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name)); 1800 dump (1, "{"); 1801 dump (0, "lex_sbc_only_once (\"%s\");", sbc->name); 1802 dump (0, "goto lossage;"); 1803 dump (-1, "}"); 1804 outdent (); 1805 } 1806 dump_subcommand (sbc); 1807 dump (-1, "}"); 1808 outdent (); 1809 } 1810 } 1811 1812 1813 /* Now deal with the /ALGORITHM subcommand implicit to all commands */ 1814 dump(1,"else if (settings_get_syntax () != COMPATIBLE && lex_match_id(lexer, \"ALGORITHM\"))"); 1815 dump(1,"{"); 1816 1817 dump (0, "lex_match (lexer, T_EQUALS);"); 1818 1819 dump(1,"if (lex_match_id(lexer, \"COMPATIBLE\"))"); 1820 dump(0,"settings_set_cmd_algorithm (COMPATIBLE);"); 1821 outdent(); 1822 dump(1,"else if (lex_match_id(lexer, \"ENHANCED\"))"); 1823 dump(0,"settings_set_cmd_algorithm (ENHANCED);"); 1824 1825 dump (-1, "}"); 1826 outdent (); 1827 1828 1829 1830 dump (1, "if (!lex_match (lexer, T_SLASH))"); 1831 dump (0, "break;"); 1832 dump (-2, "}"); 1833 outdent (); 1834 dump_blank_line (0); 1835 dump (1, "if (lex_token (lexer) != T_ENDCMD)"); 1836 dump (1, "{"); 1837 dump (0, "lex_error (lexer, _(\"expecting end of command\"));"); 1838 dump (0, "goto lossage;"); 1839 dump (-1, "}"); 1840 dump_blank_line (0); 1841 1842 outdent (); 1843 1844 { 1845 /* Check that mandatory subcommands have been specified */ 1846 subcommand *sbc; 1847 1848 for (sbc = subcommands; sbc; sbc = sbc->next) 1849 { 1850 1851 if (sbc->arity == ARITY_ONCE_EXACTLY) 1852 { 1853 dump (0, "if (0 == p->sbc_%s)", st_lower (sbc->name)); 1854 dump (1, "{"); 1855 dump (0, "lex_sbc_missing (\"%s\");", sbc->name); 1856 dump (0, "goto lossage;"); 1857 dump (-1, "}"); 1858 dump_blank_line (0); 1859 } 1860 } 1861 } 1862 1863 dump (-1, "return true;"); 1864 dump_blank_line (0); 1865 dump (-1, "lossage:"); 1866 indent (); 1867 dump (0, "free_%s (p);", make_identifier (cmdname)); 1868 dump (0, "return false;"); 1869 dump (-1, "}"); 1870 dump_blank_line (0); 1871 } 1872 1873 1874 /* Write the output file header. */ 1875 static void 1876 dump_header (void) 1877 { 1878 indent = 0; 1879 dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn); 1880 dump_blank_line (0); 1881 dump (0, " Generated by q2c from %s.", ifn); 1882 dump (0, " Do not modify!"); 1883 dump (0, " */"); 1884 } 1885 1886 /* Write out commands to free variable state. */ 1887 static void 1888 dump_free (int persistent) 1889 { 1890 subcommand *sbc; 1891 int used; 1892 1893 indent = 0; 1894 1895 used = 0; 1896 if (! persistent) 1897 { 1898 for (sbc = subcommands; sbc; sbc = sbc->next) 1899 used = (sbc->type == SBC_STRING 1900 || sbc->type == SBC_DBL_LIST 1901 || sbc->type == SBC_INT_LIST); 1902 } 1903 1904 dump (0, "static void"); 1905 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname), 1906 make_identifier (cmdname), used ? "" : " UNUSED"); 1907 dump (1, "{"); 1908 1909 if (! persistent) 1910 { 1911 1912 for (sbc = subcommands; sbc; sbc = sbc->next) 1913 { 1914 switch (sbc->type) 1915 { 1916 case SBC_VARLIST: 1917 dump (0, "free (p->v_%s);", st_lower (sbc->name)); 1918 break; 1919 case SBC_STRING: 1920 dump (0, "free (p->s_%s);", st_lower (sbc->name)); 1921 break; 1922 case SBC_DBL_LIST: 1923 case SBC_INT_LIST: 1924 dump (0, "{"); 1925 dump (1, "int i;"); 1926 dump (2, "for(i = 0; i < MAXLISTS ; ++i)"); 1927 dump (1, "subc_list_%s_destroy(&p->%cl_%s[i]);", 1928 sbc->type == SBC_INT_LIST ? "int" : "double", 1929 sbc->type == SBC_INT_LIST ? 'i' : 'd', 1930 st_lower (sbc->name)); 1931 dump (0, "}"); 1932 outdent(); 1933 break; 1934 case SBC_PLAIN: 1935 { 1936 specifier *spec; 1937 setting *s; 1938 1939 for (spec = sbc->spec; spec; spec = spec->next) 1940 for (s = spec->s; s; s = s->next) 1941 if (s->value == VAL_STRING) 1942 dump (0, "free (p->%s%s);", 1943 sbc->prefix, st_lower (s->valname)); 1944 } 1945 default: 1946 break; 1947 } 1948 } 1949 } 1950 1951 dump (-1, "}"); 1952 1953 } 1954 1955 1956 1957 /* Returns the name of a directive found on the current input line, if 1958 any, or a null pointer if none found. */ 1959 static const char * 1960 recognize_directive (void) 1961 { 1962 static char directive[16]; 1963 char *sp, *ep; 1964 1965 sp = skip_ws (buf); 1966 if (strncmp (sp, "/*", 2)) 1967 return NULL; 1968 sp = skip_ws (sp + 2); 1969 if (*sp != '(') 1970 return NULL; 1971 sp++; 1972 1973 ep = strchr (sp, ')'); 1974 if (ep == NULL) 1975 return NULL; 1976 1977 if (ep - sp > 15) 1978 ep = sp + 15; 1979 memcpy (directive, sp, ep - sp); 1980 directive[ep - sp] = '\0'; 1981 return directive; 1982 } 1983 1984 int 1985 main (int argc, char *argv[]) 1986 { 1987 program_name = argv[0]; 1988 if (argc != 3) 1989 fail ("Syntax: q2c input.q output.c"); 1990 1991 ifn = argv[1]; 1992 in = fopen (ifn, "r"); 1993 if (!in) 1994 fail ("%s: open: %s.", ifn, strerror (errno)); 1995 1996 ofn = argv[2]; 1997 out = fopen (ofn, "w"); 1998 if (!out) 1999 fail ("%s: open: %s.", ofn, strerror (errno)); 2000 2001 is_open = true; 2002 buf = xmalloc (MAX_LINE_LEN); 2003 tokstr = xmalloc (MAX_TOK_LEN); 2004 2005 dump_header (); 2006 2007 2008 indent = 0; 2009 dump (0, "#line %d \"%s\"", ln + 1, ifn); 2010 while (get_line ()) 2011 { 2012 const char *directive = recognize_directive (); 2013 if (directive == NULL) 2014 { 2015 dump (0, "%s", buf); 2016 continue; 2017 } 2018 2019 dump (0, "#line %d \"%s\"", oln + 1, ofn); 2020 if (!strcmp (directive, "specification")) 2021 { 2022 /* Skip leading slash-star line. */ 2023 get_line (); 2024 lex_get (); 2025 2026 parse (); 2027 2028 /* Skip trailing star-slash line. */ 2029 get_line (); 2030 } 2031 else if (!strcmp (directive, "headers")) 2032 { 2033 indent = 0; 2034 2035 dump (0, "#include <stdlib.h>"); 2036 dump_blank_line (0); 2037 2038 dump (0, "#include \"data/settings.h\""); 2039 dump (0, "#include \"data/variable.h\""); 2040 dump (0, "#include \"language/lexer/lexer.h\""); 2041 dump (0, "#include \"language/lexer/subcommand-list.h\""); 2042 dump (0, "#include \"language/lexer/variable-parser.h\""); 2043 dump (0, "#include \"libpspp/assertion.h\""); 2044 dump (0, "#include \"libpspp/cast.h\""); 2045 dump (0, "#include \"libpspp/message.h\""); 2046 dump (0, "#include \"libpspp/str.h\""); 2047 dump_blank_line (0); 2048 2049 dump (0, "#include \"gl/xalloc.h\""); 2050 dump_blank_line (0); 2051 } 2052 else if (!strcmp (directive, "declarations")) 2053 dump_declarations (); 2054 else if (!strcmp (directive, "functions")) 2055 { 2056 dump_parser (0); 2057 dump_free (0); 2058 } 2059 else if (!strcmp (directive, "_functions")) 2060 { 2061 dump_parser (1); 2062 dump_free (1); 2063 } 2064 else 2065 error ("unknown directive `%s'", directive); 2066 indent = 0; 2067 dump (0, "#line %d \"%s\"", ln + 1, ifn); 2068 } 2069 2070 return EXIT_SUCCESS; 2071 } 2072