4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
28 /* Copyright (c) 1988 AT&T */
29 /* All Rights Reserved */
33 * University Copyright- Copyright (c) 1982, 1986, 1988
34 * The Regents of the University of California
37 * University Acknowledgment- Portions of this document are derived from
38 * software developed by the University of California, Berkeley, and its
43 * *******************************************************************
45 * ********************************************************************
46 * This software is copyright (C) 1982 by Pavel Curtis *
48 * Permission is granted to reproduce and distribute *
49 * this file by any means so long as no fee is charged *
50 * above a nominal handling fee and so long as this *
51 * notice is always included in the copies. *
53 * Other rights are reserved except as explicitly granted *
54 * by written permission of the author. *
56 * Computer Science Dept. *
58 * Cornell University *
61 * Ph- (607) 256-4934 *
63 * Pavel.Cornell@Udel-Relay (ARPAnet) *
64 * decvax!cornell!pavel (UUCPnet) *
65 * ********************************************************************
69 * comp_parse.c -- The high-level (ha!) parts of the compiler,
70 * that is, the routines which drive the scanner,
73 * $Log: RCS/comp_parse.v $
74 * Revision 2.1 82/10/25 14:45:43 pavel
75 * Added Copyright Notice
77 * Revision 2.0 82/10/24 15:16:39 pavel
78 * Beta-one Test Release
80 * Revision 1.3 82/08/23 22:29:39 pavel
81 * The REAL Alpha-one Release Version
83 * Revision 1.2 82/08/19 19:09:53 pavel
84 * Alpha Test Release One
86 * Revision 1.1 82/08/12 18:37:12 pavel
92 #include <sys/types.h>
99 #include "curses_inc.h"
100 #include "compiler.h"
103 extern char check_only
;
104 extern char *progname
;
107 int next_free
; /* next free character in string_table */
108 unsigned int table_size
= 0; /* current string_table size */
109 short term_names
; /* string table offset - current terminal */
110 int part2
= 0; /* set to allow old compiled defns to be used */
111 int complete
= 0; /* 1 if entry done with no forward uses */
115 struct use_item
*fptr
, *bptr
;
119 struct use_item
*head
, *tail
;
122 struct use_header use_list
= {NULL
, NULL
};
125 void dequeue(struct use_item
*);
126 void init_structure(short Booleans
[], short Numbers
[], short Strings
[]);
127 void dump_structure(short Booleans
[], short Numbers
[], short Strings
[]);
129 void err_abort(char *fmt
, ...);
130 void syserr_abort(char *fmt
, ...);
131 void warning(char *fmt
, ...);
133 int do_entry(struct use_item
*item_ptr
);
134 int read_entry(char *filename
, struct _bool_struct
*bptr
,
135 struct _num_struct
*nptr
, struct _str_struct
*sptr
);
136 void reset_input(void);
137 int save_str(char *string
);
138 int handle_use(struct use_item
*item_ptr
, long entry_offset
, short Booleans
[],
139 short Numbers
[], short Strings
[]);
140 void panic_mode(int ch
);
141 void check_dir(char dirletter
);
142 int write_object(FILE *fp
, short Booleans
[], short Numbers
[], short Strings
[]);
145 * The use_list is a doubly-linked list with NULLs terminating the lists:
147 * use_item use_item use_item
148 * --------- --------- ---------
150 * |-------| |-------| |-------|
151 * | ----+-->| ----+-->| NULL | fptr
152 * |-------| |-------| |-------|
153 * | NULL |<--+---- |<--+---- | bptr
154 * --------- --------- ---------
156 * | ------------------ |
158 * +--+---- | ----+---+
170 * Main loop of the compiler.
173 * if curr_token != NAMES
175 * while (not at end of file)
185 struct use_item
*ptr
;
188 token_type
= get_token();
190 if (token_type
!= NAMES
)
192 "File does not start with terminal names in column one");
194 while (token_type
!= EOF
)
195 token_type
= do_entry(NULL
);
197 DEBUG(2, "Starting handling of forward USE's\n", "");
199 for (part2
= 0; part2
< 2; part2
++) {
201 DEBUG(2, "\n\nPART %d\n\n", part2
);
202 while (use_list
.head
!= NULL
&& old_use_count
!= use_count
) {
203 old_use_count
= use_count
;
204 for (ptr
= use_list
.tail
; ptr
!= NULL
;
206 fseek(stdin
, ptr
->offset
, 0);
208 if ((token_type
= get_token()) != NAMES
)
210 "Token after a seek not NAMES");
211 (void) do_entry(ptr
);
216 for (ptr
= use_list
.head
; ptr
!= NULL
;
218 fseek(stdin
, ptr
->offset
, 0);
220 if ((token_type
= get_token()) != NAMES
)
222 "Token after a seek not NAMES");
223 (void) do_entry(ptr
);
229 "Finished a pass through enqueued forward USE's\n", "");
233 if (use_list
.head
!= NULL
&& !check_only
) {
235 "\nError in following use-links. Either there is a loop in the links\n"
236 "or they reference non-existent terminals. The following is a list of\n"
237 "the entries involved:\n\n");
239 for (ptr
= use_list
.head
; ptr
!= NULL
; ptr
= ptr
->fptr
) {
240 fseek(stdin
, ptr
->offset
, 0);
241 fgets(line
, 1024, stdin
);
242 fprintf(stderr
, "%s", line
);
252 struct use_item
*ptr
;
255 fprintf(stderr
, "dump_list %s\n", str
);
256 for (ptr
= use_list
.head
; ptr
!= NULL
; ptr
= ptr
->fptr
) {
257 fseek(stdin
, ptr
->offset
, 0);
258 fgets(line
, 1024, stdin
);
259 fprintf(stderr
, "ptr %x off %d bptr %x fptr %x str %s",
260 ptr
, ptr
->offset
, ptr
->bptr
, ptr
->fptr
, line
);
262 fprintf(stderr
, "\n");
269 * Compile one entry. During the first pass, item_ptr is NULL. In pass
270 * two, item_ptr points to the current entry in the use_list.
272 * found-forward-use = FALSE
273 * re-initialise internal arrays
274 * save names in string_table
276 * while (not EOF and not NAMES)
277 * if found-forward-use
280 * if handle_use() < 0
281 * found-forward-use = TRUE
283 * check for existance and type-correctness
284 * enter cap into structure
286 * save string in string_table
288 * if ! found-forward-use
289 * dump compiled entry into filesystem
295 struct use_item
*item_ptr
;
299 struct name_table_entry
*entry_ptr
;
300 int found_forward_use
= FALSE
;
301 short Booleans
[MAXBOOLS
],
305 init_structure(Booleans
, Numbers
, Strings
);
307 term_names
= save_str(curr_token
.tk_name
);
308 DEBUG(2, "Starting '%s'\n", curr_token
.tk_name
);
309 entry_offset
= curr_file_pos
;
311 for (token_type
= get_token();
312 token_type
!= EOF
&& token_type
!= NAMES
;
313 token_type
= get_token()) {
314 /* LINTED E_NOP_IF_STMT */
315 if (found_forward_use
)
317 else if (strcmp(curr_token
.tk_name
, "use") == 0) {
318 if (handle_use(item_ptr
, entry_offset
,
319 Booleans
, Numbers
, Strings
) < 0)
320 found_forward_use
= TRUE
;
322 entry_ptr
= find_entry(curr_token
.tk_name
);
324 if (entry_ptr
== NOTFOUND
) {
325 warning("Unknown Capability - '%s'",
331 if (token_type
!= CANCEL
&&
332 entry_ptr
->nte_type
!= token_type
)
333 warning("Wrong type used for capability '%s'",
335 switch (token_type
) {
337 switch (entry_ptr
->nte_type
) {
339 Booleans
[entry_ptr
->nte_index
] = -2;
343 Numbers
[entry_ptr
->nte_index
] = -2;
347 Strings
[entry_ptr
->nte_index
] = -2;
353 if (Booleans
[entry_ptr
->nte_index
] == 0)
354 Booleans
[entry_ptr
->nte_index
] = TRUE
;
358 if (Numbers
[entry_ptr
->nte_index
] == -1)
359 Numbers
[entry_ptr
->nte_index
] =
360 curr_token
.tk_valnumber
;
364 if (Strings
[entry_ptr
->nte_index
] == -1)
365 Strings
[entry_ptr
->nte_index
] =
366 save_str(curr_token
.tk_valstring
);
370 warning("Unknown token type");
374 } /* end else cur_token.name != "use" */
376 } /* endwhile (not EOF and not NAMES) */
378 if (found_forward_use
)
381 dump_structure(Booleans
, Numbers
, Strings
);
388 * Change all cancellations to a non-entry.
389 * For booleans, @ -> false
391 * For strings, @ -> -1
393 * This only has to be done for entries which
394 * have to be compatible with the pre-Vr3 format.
396 #ifndef NOCANCELCOMPAT
398 elim_cancellations(short Booleans
[], short Numbers
[], short Strings
[])
401 for (i
= 0; i
< BoolCount
; i
++) {
402 if (Booleans
[i
] == -2)
406 for (i
= 0; i
< NumCount
; i
++) {
407 if (Numbers
[i
] == -2)
411 for (i
= 0; i
< StrCount
; i
++) {
412 if (Strings
[i
] == -2)
416 #endif /* NOCANCELCOMPAT */
418 * Change the cancellation signal from the -2 used internally to
419 * the 2 used within the binary.
422 change_cancellations(short Booleans
[])
425 for (i
= 0; i
< BoolCount
; i
++) {
426 if (Booleans
[i
] == -2)
435 * Put a record of the given offset onto the use-list.
442 struct use_item
*item
;
444 item
= (struct use_item
*)malloc(sizeof (struct use_item
));
447 syserr_abort("Not enough memory for use_list element");
449 item
->offset
= offset
;
451 if (use_list
.head
!= NULL
) {
452 item
->bptr
= use_list
.tail
;
453 use_list
.tail
->fptr
= item
;
455 use_list
.tail
= item
;
457 use_list
.tail
= use_list
.head
= item
;
458 item
->fptr
= item
->bptr
= NULL
;
467 * remove the pointed-to item from the use_list
472 dequeue(struct use_item
*ptr
)
474 if (ptr
->fptr
== NULL
)
475 use_list
.tail
= ptr
->bptr
;
477 (ptr
->fptr
)->bptr
= ptr
->bptr
;
479 if (ptr
->bptr
== NULL
)
480 use_list
.head
= ptr
->fptr
;
482 (ptr
->bptr
)->fptr
= ptr
->fptr
;
488 * invalid_term_name(name)
490 * Look for invalid characters in a term name. These include
491 * space, tab and '/'.
493 * Generate an error message if given name does not begin with a
494 * digit or letter, then exit.
496 * return TRUE if name is invalid.
501 invalid_term_name(char *name
)
504 if (! isdigit(*name
) && ! islower(*name
) && ! isupper(*name
))
507 for (; *name
; name
++)
510 else if (isspace(*name
) || (*name
== '/'))
513 fprintf(stderr
, "%s: Line %d: Illegal terminal name - '%s'\n",
514 progname
, curr_line
, name
);
516 "Terminal names must start with a letter or digit\n");
525 * Save the compiled version of a description in the filesystem.
527 * make a copy of the name-list
528 * break it up into first-name and all-but-last-name
530 * clear CANCELS out of the structure
532 * write object information to first-name
534 * for each valid name
540 dump_structure(short Booleans
[], short Numbers
[], short Strings
[])
542 struct stat64 statbuf
;
544 char name_list
[1024];
545 char *first_name
, *other_names
, *cur_name
;
546 char filename
[128 + 2 + 1];
547 char linkname
[128 + 2 + 1];
551 strcpy(name_list
, term_names
+ string_table
);
552 DEBUG(7, "Name list = '%s'\n", name_list
);
554 first_name
= name_list
;
555 /* Set othernames to 1 past first '|' in the list. */
556 /* Null out that '|' in the process. */
557 other_names
= strchr(first_name
, '|');
559 *other_names
++ = '\0';
561 if (invalid_term_name(first_name
))
562 warning("'%s': bad first term name.", first_name
);
565 DEBUG(7, "First name = '%s'\n", first_name
);
566 DEBUG(7, "Other names = '%s'\n", other_names
? other_names
: "NULL");
568 if ((len
= strlen(first_name
)) > 128)
569 warning("'%s': terminal name too long.", first_name
);
571 warning("'%s': terminal name too short.", first_name
);
573 check_dir(first_name
[0]);
575 sprintf(filename
, "%c/%s", first_name
[0], first_name
);
577 if (stat64(filename
, &statbuf
) >= 0 && statbuf
.st_mtime
>= start_time
) {
578 warning("'%s' defined in more than one entry.", first_name
);
579 fprintf(stderr
, "Entry being used is '%s'.\n",
580 (unsigned)term_names
+ string_table
);
585 fp
= fopen(filename
, "w");
588 syserr_abort("Can't open %s/%s\n", destination
,
591 DEBUG(1, "Created %s\n", filename
);
592 } else DEBUG(1, "Would have created %s\n", filename
);
594 #ifndef NOCANCELCOMPAT
595 /* eliminate cancellation markings if there is no '+' in the name */
596 if (strchr(first_name
, '+') == 0)
597 elim_cancellations(Booleans
, Numbers
, Strings
);
599 #endif /* NOCANCELCOMPAT */
600 change_cancellations(Booleans
);
603 if (write_object(fp
, Booleans
, Numbers
, Strings
) < 0) {
604 syserr_abort("Error writing %s/%s", destination
,
610 alphastart
= isalpha(first_name
[0]);
612 while (other_names
) {
613 cur_name
= other_names
;
614 other_names
= strchr(cur_name
, '|');
616 *other_names
++ = '\0';
617 if (*cur_name
== '\0')
620 if ((len
= strlen(cur_name
)) > 128) {
621 warning("'%s': terminal name too long.", cur_name
);
623 } else if (len
== 1) {
624 warning("'%s': terminal name too short.", first_name
);
628 if (invalid_term_name(cur_name
)) {
630 warning("'%s': bad term name found in list.",
635 check_dir(cur_name
[0]);
637 sprintf(linkname
, "%c/%s", cur_name
[0], cur_name
);
639 alphastart
|= isalpha(cur_name
[0]);
641 if (strcmp(first_name
, cur_name
) == 0) {
642 warning("Terminal name '%s' synonym for itself",
646 if (stat64(linkname
, &statbuf
) >= 0 &&
647 statbuf
.st_mtime
>= start_time
) {
649 "'%s' defined in more than one entry.", cur_name
);
651 "Entry being used is '%s'.\n",
652 (unsigned)term_names
+
656 if (link(filename
, linkname
) < 0)
657 syserr_abort("Can't link %s to %s",
659 DEBUG(1, "Linked %s\n", linkname
);
660 } else DEBUG(1, "Would have linked %s\n", linkname
);
665 warning("At least one synonym should begin with a letter.");
671 * write_object(fp, Booleans, Numbers, Strings)
673 * Write out the compiled entry to the given file.
674 * Return 0 if OK or -1 if not.
678 #define swap(x) (((x >> 8) & 0377) + 256 * (x & 0377))
680 #define might_swap(x) (must_swap() ? swap(x) : (x))
684 write_object(fp
, Booleans
, Numbers
, Strings
)
690 struct header header
;
695 char cBooleans
[MAXBOOLS
];
698 namelist
= term_names
+ string_table
;
699 namelen
= strlen(namelist
) + 1;
701 l_next_free
= next_free
;
702 if (l_next_free
% 256 == 255)
706 header
.magic
= swap(MAGIC
);
707 header
.name_size
= swap(namelen
);
708 header
.bool_count
= swap(BoolCount
);
709 header
.num_count
= swap(NumCount
);
710 header
.str_count
= swap(StrCount
);
711 header
.str_size
= swap(l_next_free
);
713 header
.magic
= MAGIC
;
714 header
.name_size
= namelen
;
715 header
.bool_count
= BoolCount
;
716 header
.num_count
= NumCount
;
717 header
.str_count
= StrCount
;
718 header
.str_size
= l_next_free
;
721 for (i
= 0; i
< BoolCount
; i
++)
722 cBooleans
[i
] = Booleans
[i
];
724 if (fwrite(&header
, sizeof (header
), 1, fp
) != 1 ||
725 fwrite(namelist
, sizeof (char), namelen
, fp
) != namelen
||
726 fwrite(cBooleans
, sizeof (char), BoolCount
, fp
) !=
730 if ((namelen
+BoolCount
) % 2 != 0 &&
731 fwrite(&zero
, sizeof (char), 1, fp
) != 1)
735 for (i
= 0; i
< NumCount
; i
++)
736 Numbers
[i
] = swap(Numbers
[i
]);
737 for (i
= 0; i
< StrCount
; i
++)
738 Strings
[i
] = swap(Strings
[i
]);
741 if (fwrite((char *)Numbers
, sizeof (short), NumCount
, fp
) != NumCount
||
742 fwrite((char *)Strings
, sizeof (short), StrCount
, fp
)
744 fwrite(string_table
, sizeof (char), l_next_free
, fp
)
755 * copy string into next free part of string_table, doing a realloc()
756 * if necessary. return offset of beginning of string from start of
767 /* Do not let an offset be 255. It reads as -1 in Vr2 binaries. */
768 if (next_free
% 256 == 255)
771 old_next_free
= next_free
;
773 if (table_size
== 0) {
774 if ((string_table
= malloc(1024)) == NULL
)
775 syserr_abort("Out of memory");
777 DEBUG(5, "Made initial string table allocation. Size is %u\n",
781 while (table_size
<= next_free
+ strlen(string
)) {
782 if ((string_table
= realloc(string_table
, table_size
+ 1024))
784 syserr_abort("Out of memory");
786 DEBUG(5, "Extended string table. Size now %u\n", table_size
);
789 strcpy(&string_table
[next_free
], string
);
790 DEBUG(7, "Saved string '%s' ", string
);
791 DEBUG(7, "at location %d\n", next_free
);
792 next_free
+= strlen(string
) + 1;
794 return (old_next_free
);
798 * init_structure(Booleans, Numbers, Strings)
800 * Initialise the given arrays
801 * Reset the next_free counter to zero.
806 init_structure(short Booleans
[], short Numbers
[], short Strings
[])
810 for (i
= 0; i
< BoolCount
; i
++)
813 for (i
= 0; i
< NumCount
; i
++)
816 for (i
= 0; i
< StrCount
; i
++)
824 * handle_use(item_ptr, entry_offset, Booleans, Numbers, Strings)
826 * Merge the compiled file whose name is in cur_token.valstring
827 * with the current entry.
829 * if it's a forward use-link
830 * if item_ptr == NULL
831 * queue it up for later handling
833 * ignore it (we're already going through the queue)
834 * else it's a backward use-link
835 * read in the object file for that terminal
836 * merge contents with current structure
838 * Returned value is 0 if it was a backward link and we
839 * successfully read it in, -1 if a forward link.
843 handle_use(item_ptr
, entry_offset
, Booleans
, Numbers
, Strings
)
845 struct use_item
*item_ptr
;
850 struct _bool_struct use_bools
;
851 struct _num_struct use_nums
;
852 struct _str_struct use_strs
;
853 struct stat64 statbuf
;
856 char *UB
= &use_bools
._auto_left_margin
; /* first bool */
857 short *UN
= &use_nums
._columns
; /* first num */
858 char **US
= &use_strs
.strs
._back_tab
; /* first str */
860 if (invalid_term_name(curr_token
.tk_valstring
))
861 warning("%s: bad term name", curr_token
.tk_valstring
);
863 sprintf(filename
, "%c/%s", curr_token
.tk_valstring
[0],
864 curr_token
.tk_valstring
);
866 if (stat64(filename
, &statbuf
) < 0 ||
867 (part2
== 0 && statbuf
.st_mtime
< start_time
)) {
868 DEBUG(2, "Forward USE to %s", curr_token
.tk_valstring
);
870 if (item_ptr
== NULL
) {
871 DEBUG(2, " (enqueued)\n", "");
872 enqueue(entry_offset
);
873 } else DEBUG(2, " (skipped)\n", "");
877 DEBUG(2, "Backward USE to %s\n", curr_token
.tk_valstring
);
878 if (read_entry(filename
, &use_bools
, &use_nums
, &use_strs
) < 0)
879 syserr_abort("Error in re-reading compiled file %s",
882 for (i
= 0; i
< BoolCount
; i
++) {
883 if (Booleans
[i
] == FALSE
) {
884 if (UB
[i
] == TRUE
) /* now true */
886 else if (UB
[i
] > TRUE
) /* cancelled */
891 for (i
= 0; i
< NumCount
; i
++) {
892 if (Numbers
[i
] == -1)
896 for (i
= 0; i
< StrCount
; i
++) {
897 if (Strings
[i
] == -1) {
898 if (US
[i
] == (char *)-1)
900 else if (US
[i
] != (char *)0)
901 Strings
[i
] = save_str(US
[i
]);