|
|
1.1 root 1: /*********************************************************************
2: * COPYRIGHT NOTICE *
3: **********************************************************************
4: * This software is copyright (C) 1982 by Pavel Curtis *
5: * *
6: * Permission is granted to reproduce and distribute *
7: * this file by any means so long as no fee is charged *
8: * above a nominal handling fee and so long as this *
9: * notice is always included in the copies. *
10: * *
11: * Other rights are reserved except as explicitly granted *
12: * by written permission of the author. *
13: * Pavel Curtis *
14: * Computer Science Dept. *
15: * 405 Upson Hall *
16: * Cornell University *
17: * Ithaca, NY 14853 *
18: * *
19: * Ph- (607) 256-4934 *
20: * *
21: * Pavel.Cornell@Udel-Relay (ARPAnet) *
22: * decvax!cornell!pavel (UUCPnet) *
23: *********************************************************************/
24:
25: /*
26: * comp_parse.c -- The high-level (ha!) parts of the compiler,
27: * that is, the routines which drive the scanner,
28: * etc.
29: *
30: * $Log: comp_parse.c,v $
31: * Revision 1.11 93/04/12 14:13:03 bin
32: * Udo: third color update
33: *
34: * Revision 1.5 92/06/02 12:04:31 bin
35: * *** empty log message ***
36: *
37: * Revision 1.2 92/04/13 14:36:22 bin
38: * update by vlad
39: *
40: * Revision 3.2 91/07/28 13:59:10 munk
41: * Made all the large arrays static
42: *
43: * Revision 3.1 84/12/13 11:19:32 john
44: * Revisions by Mark Horton
45: *
46: * Revision 2.1 82/10/25 14:45:43 pavel
47: * Added Copyright Notice
48: *
49: * Revision 2.0 82/10/24 15:16:39 pavel
50: * Beta-one Test Release
51: *
52: * Revision 1.3 82/08/23 22:29:39 pavel
53: * The REAL Alpha-one Release Version
54: *
55: * Revision 1.2 82/08/19 19:09:53 pavel
56: * Alpha Test Release One
57: *
58: * Revision 1.1 82/08/12 18:37:12 pavel
59: * Initial revision
60: *
61: *
62: */
63:
64: #ifdef RCSHDR
65: static char RCSid[] =
66: "$Header: /src386/usr/lib/ncurses/RCS/comp_parse.c,v 1.11 93/04/12 14:13:03 bin Exp Locker: bin $";
67: #endif
68:
69: #include <sys/types.h>
70: #include <sys/stat.h>
71: #include <stdio.h>
72: #include <ctype.h>
73: #include "compiler.h"
74: #include "term.h"
75: #include "object.h"
76:
77: char *string_table;
78: int next_free; /* next free character in string_table */
79: int table_size = 0; /* current string_table size */
80: short term_names; /* string table offset - current terminal */
81: int part2 = 0; /* set to allow old compiled defns to be used */
82: int complete = 0; /* 1 if entry done with no forward uses */
83:
84: struct use_item
85: {
86: long offset;
87: struct use_item *fptr, *bptr;
88: };
89:
90: struct use_header
91: {
92: struct use_item *head, *tail;
93: };
94:
95: struct use_header use_list = {NULL, NULL};
96: int use_count = 0;
97:
98: /*
99: * The use_list is a doubly-linked list with NULLs terminating the lists:
100: *
101: * use_item use_item use_item
102: * --------- --------- ---------
103: * | | | | | | offset
104: * |-------| |-------| |-------|
105: * | ----+-->| ----+-->| NULL | fptr
106: * |-------| |-------| |-------|
107: * | NULL |<--+---- |<--+---- | bptr
108: * --------- --------- ---------
109: * ^ ^
110: * | ------------------ |
111: * | | | | |
112: * +--+---- | ----+---+
113: * | | |
114: * ------------------
115: * head tail
116: * use_list
117: *
118: */
119:
120:
121: /*
122: * compile()
123: *
124: * Main loop of the compiler.
125: *
126: * get_token()
127: * if curr_token != NAMES
128: * err_abort()
129: * while (not at end of file)
130: * do an entry
131: *
132: */
133:
134: compile()
135: {
136: static char line[1024];
137: int token_type;
138: struct use_item *ptr;
139: int old_use_count;
140:
141: token_type = get_token();
142:
143: if (token_type != NAMES)
144: err_abort("File does not start with terminal names in column one");
145:
146: while (token_type != EOF)
147: token_type = do_entry((struct use_item *) 0);
148:
149: DEBUG(2, "Starting handling of forward USE's\n", "");
150:
151: for (part2=0; part2<2; part2++) {
152: old_use_count = -1;
153: DEBUG(2, "\n\nPART %d\n\n", part2);
154: while (use_list.head != NULL && old_use_count != use_count)
155: {
156: old_use_count = use_count;
157: for (ptr = use_list.tail; ptr != NULL; ptr = ptr->bptr)
158: {
159: fseek(stdin, ptr->offset, 0);
160: reset_input();
161: if ((token_type = get_token()) != NAMES)
162: syserr_abort("Token after a seek not NAMES");
163: (void) do_entry(ptr);
164: if (complete)
165: dequeue(ptr);
166: }
167:
168: for (ptr = use_list.head; ptr != NULL; ptr = ptr->fptr)
169: {
170: fseek(stdin, ptr->offset, 0);
171: reset_input();
172: if ((token_type = get_token()) != NAMES)
173: syserr_abort("Token after a seek not NAMES");
174: (void) do_entry(ptr);
175: if (complete)
176: dequeue(ptr);
177: }
178:
179: DEBUG(2, "Finished a pass through enqueued forward USE's\n", "");
180: }
181: }
182:
183: if (use_list.head != NULL)
184: {
185: fprintf(stderr, "\nError in following up use-links. Either there is\n");
186: fprintf(stderr, "a loop in the links or they reference non-existant\n");
187: fprintf(stderr, "terminals. The following is a list of the entries\n");
188: fprintf(stderr, "involved:\n\n");
189:
190: for (ptr = use_list.head; ptr != NULL; ptr = ptr->fptr)
191: {
192: fseek(stdin, ptr->offset, 0);
193: fgets(line, 1024, stdin);
194: fprintf(stderr, "%s", line);
195: }
196:
197: exit(1);
198: }
199: }
200:
201:
202: dump_list(str)
203: char *str;
204: {
205: struct use_item *ptr;
206: static char line[512];
207:
208: fprintf(stderr, "dump_list %s\n", str);
209: for (ptr = use_list.head; ptr != NULL; ptr = ptr->fptr)
210: {
211: fseek(stdin, ptr->offset, 0);
212: fgets(line, 1024, stdin);
213: fprintf(stderr, "ptr %x off %d bptr %x fptr %x str %s",
214: ptr, ptr->offset, ptr->bptr, ptr->fptr, line);
215: }
216: fprintf(stderr, "\n");
217: }
218:
219:
220: /*
221: * int
222: * do_entry(item_ptr)
223: *
224: * Compile one entry. During the first pass, item_ptr is NULL. In pass
225: * two, item_ptr points to the current entry in the use_list.
226: *
227: * found-forward-use = FALSE
228: * re-initialise internal arrays
229: * save names in string_table
230: * get_token()
231: * while (not EOF and not NAMES)
232: * if found-forward-use
233: * do nothing
234: * else if 'use'
235: * if handle_use() < 0
236: * found-forward-use = TRUE
237: * else
238: * check for existance and type-correctness
239: * enter cap into structure
240: * if STRING
241: * save string in string_table
242: * get_token()
243: * if ! found-forward-use
244: * clear CANCELS out of the structure
245: * dump compiled entry into filesystem
246: *
247: */
248:
249: int
250: do_entry(item_ptr)
251: struct use_item *item_ptr;
252: {
253: long entry_offset;
254: int i;
255: register int token_type;
256: register struct name_table_entry *entry_ptr;
257: int found_forward_use = FALSE;
258: static char Booleans[BOOLCOUNT];
259: static short Numbers[NUMCOUNT],
260: Strings[STRCOUNT];
261:
262: init_structure(Booleans, Numbers, Strings);
263: complete = 0;
264: term_names = save_str(curr_token.tk_name);
265: DEBUG(2, "Starting '%s'\n", curr_token.tk_name);
266: entry_offset = curr_file_pos;
267:
268: for (token_type = get_token();
269: token_type != EOF && token_type != NAMES;
270: token_type = get_token())
271: {
272: if (found_forward_use)
273: /* do nothing */ ;
274: else if (strcmp(curr_token.tk_name, "use") == 0)
275: {
276: if (handle_use(item_ptr, entry_offset,
277: Booleans, Numbers, Strings) < 0)
278: found_forward_use = TRUE;
279: }
280: else
281: {
282: entry_ptr = find_entry(curr_token.tk_name);
283:
284: if (entry_ptr == NOTFOUND) {
285: warning("Unknown Capability - '%s'",
286: curr_token.tk_name);
287: continue;
288: }
289:
290:
291: if (token_type != CANCEL
292: && entry_ptr->nte_type != token_type)
293: warning("Wrong type used for capability '%s'",
294: curr_token.tk_name);
295: switch (token_type)
296: {
297: case CANCEL:
298: switch (entry_ptr->nte_type)
299: {
300: case BOOLEAN:
301: Booleans[entry_ptr->nte_index] = -2;
302: break;
303:
304: case NUMBER:
305: Numbers[entry_ptr->nte_index] = -2;
306: break;
307:
308: case STRING:
309: Strings[entry_ptr->nte_index] = -2;
310: break;
311: }
312: break;
313:
314: case BOOLEAN:
315: Booleans[entry_ptr->nte_index] = TRUE;
316: break;
317:
318: case NUMBER:
319: Numbers[entry_ptr->nte_index] =
320: curr_token.tk_valnumber;
321: break;
322:
323: case STRING:
324: Strings[entry_ptr->nte_index] =
325: save_str(curr_token.tk_valstring);
326: break;
327:
328: default:
329: warning("Unknown token type");
330: panic_mode(',');
331: continue;
332: }
333: } /* end else cur_token.name != "use" */
334:
335: } /* endwhile (not EOF and not NAMES) */
336:
337: if (found_forward_use)
338: return(token_type);
339:
340: for (i=0; i < BOOLCOUNT; i++)
341: {
342: if (Booleans[i] == -2)
343: Booleans[i] = FALSE;
344: }
345:
346: for (i=0; i < NUMCOUNT; i++)
347: {
348: if (Numbers[i] == -2)
349: Numbers[i] = -1;
350: }
351:
352: for (i=0; i < STRCOUNT; i++)
353: {
354: if (Strings[i] == -2)
355: Strings[i] = -1;
356: }
357:
358: dump_structure(term_names, Booleans, Numbers, Strings);
359:
360: complete = 1;
361: return(token_type);
362: }
363:
364:
365: /*
366: * enqueue(offset)
367: *
368: * Put a record of the given offset onto the use-list.
369: *
370: */
371:
372: enqueue(offset)
373: long offset;
374: {
375: struct use_item *item;
376: char *malloc();
377:
378: item = (struct use_item *) malloc(sizeof(struct use_item));
379:
380: if (item == NULL)
381: syserr_abort("Not enough memory for use_list element");
382:
383: item->offset = offset;
384:
385: if (use_list.head != NULL)
386: {
387: item->bptr = use_list.tail;
388: use_list.tail->fptr = item;
389: item->fptr = NULL;
390: use_list.tail = item;
391: }
392: else
393: {
394: use_list.tail = use_list.head = item;
395: item->fptr = item->bptr = NULL;
396: }
397:
398: use_count ++;
399: }
400:
401:
402: /*
403: * dequeue(ptr)
404: *
405: * remove the pointed-to item from the use_list
406: *
407: */
408:
409: dequeue(ptr)
410: struct use_item *ptr;
411: {
412: if (ptr->fptr == NULL)
413: use_list.tail = ptr->bptr;
414: else
415: (ptr->fptr)->bptr = ptr->bptr;
416:
417: if (ptr->bptr == NULL)
418: use_list.head = ptr->fptr;
419: else
420: (ptr->bptr)->fptr = ptr->fptr;
421:
422: use_count --;
423: }
424:
425:
426: /*
427: * dump_structure()
428: *
429: * Save the compiled version of a description in the filesystem.
430: *
431: * make a copy of the name-list
432: * break it up into first-name and all-but-last-name
433: * creat(first-name)
434: * write object information to first-name
435: * close(first-name)
436: * for each name in all-but-last-name
437: * link to first-name
438: *
439: */
440:
441: dump_structure(term_names, Booleans, Numbers, Strings)
442: short term_names;
443: char Booleans[];
444: short Numbers[];
445: short Strings[];
446: {
447: char *strcpy();
448: struct stat statbuf;
449: FILE *fp;
450: static char name_list[1024];
451: register char *first_name, *other_names;
452: register char *ptr;
453: static char filename[50];
454: static char linkname[50];
455: extern char check_only;
456:
457: strcpy(name_list, term_names + string_table);
458: DEBUG(7, "Name list = '%s'\n", name_list);
459:
460: first_name = name_list;
461:
462: ptr = &name_list[strlen(name_list) - 1];
463: other_names = ptr + 1;
464:
465: while (ptr > name_list && *ptr != '|')
466: ptr--;
467:
468: if (ptr != name_list)
469: {
470: *ptr = '\0';
471:
472: for (ptr = name_list; *ptr != '\0' && *ptr != '|'; ptr++)
473: ;
474:
475: if (*ptr == '\0')
476: other_names = ptr;
477: else
478: {
479: *ptr = '\0';
480: other_names = ptr + 1;
481: }
482: }
483:
484: if (check_only) {
485: DEBUG(1, "Checked %s\n", first_name);
486: return;
487: }
488:
489: DEBUG(7, "First name = '%s'\n", first_name);
490: DEBUG(7, "Other names = '%s'\n", other_names);
491:
492: if (strlen(first_name) > 100)
493: warning("'%s': terminal name too long.", first_name);
494:
495: check_name(first_name);
496:
497: sprintf(filename, "%c/%s", first_name[0], first_name);
498:
499: if (stat(filename, &statbuf) >= 0 && statbuf.st_mtime >= start_time)
500: {
501: warning("'%s' defined in more than one entry.", first_name);
502: fprintf(stderr, "Entry being used is '%s'.\n",
503: (unsigned) term_names + string_table);
504: }
505:
506: unlink(filename);
507: fp = fopen(filename, "w");
508: if (fp == NULL)
509: {
510: perror(filename);
511: syserr_abort("Can't open %s/%s\n", destination, filename);
512: }
513: DEBUG(1, "Created %s\n", filename);
514:
515: if (write_object(fp, term_names, Booleans, Numbers, Strings) < 0)
516: {
517: syserr_abort("Error in writing %s/%s", destination, filename);
518: }
519: fclose(fp);
520:
521: while (*other_names != '\0')
522: {
523: ptr = other_names++;
524: while (*other_names != '|' && *other_names != '\0')
525: other_names++;
526:
527: if (*other_names != '\0')
528: *(other_names++) = '\0';
529:
530: if (strlen(ptr) > 100)
531: {
532: warning("'%s': terminal name too long.", ptr);
533: continue;
534: }
535:
536: sprintf(linkname, "%c/%s", ptr[0], ptr);
537:
538: if (strcmp(filename, linkname) == 0)
539: {
540: warning("Terminal name '%s' synonym for itself", first_name);
541: }
542: else if (stat(linkname, &statbuf) >= 0 &&
543: statbuf.st_mtime >= start_time)
544: {
545: warning("'%s' defined in more than one entry.", ptr);
546: fprintf(stderr, "Entry being used is '%s'.\n",
547: (unsigned) term_names + string_table);
548: }
549: else
550: {
551: unlink(linkname);
552: if (link(filename, linkname) < 0)
553: syserr_abort("Can't link %s to %s", filename, linkname);
554: DEBUG(1, "Linked %s\n", linkname);
555: }
556: }
557: }
558:
559:
560: /*
561: * int
562: * write_object(fp, term_names, Booleans, Numbers, Strings)
563: *
564: * Write out the compiled entry to the given file.
565: * Return 0 if OK or -1 if not.
566: *
567: */
568:
569: #define swap(x) (((x >> 8) & 0377) + 256 * (x & 0377))
570:
571: #define might_swap(x) (must_swap() ? swap(x) : (x))
572:
573:
574: int
575: write_object(fp, term_names, Booleans, Numbers, Strings)
576: FILE *fp;
577: short term_names;
578: char Booleans[];
579: short Numbers[];
580: short Strings[];
581: {
582: struct header header;
583: char *namelist;
584: short namelen;
585: char zero = '\0';
586: int i;
587:
588: namelist = term_names + string_table;
589: namelen = strlen(namelist) + 1;
590:
591: if (must_swap())
592: {
593: header.magic = swap(MAGIC);
594: header.name_size = swap(namelen);
595: header.bool_count = swap(BOOLCOUNT);
596: header.num_count = swap(NUMCOUNT);
597: header.str_count = swap(STRCOUNT);
598: header.str_size = swap(next_free);
599: }
600: else
601: {
602: header.magic = MAGIC;
603: header.name_size = namelen;
604: header.bool_count = BOOLCOUNT;
605: header.num_count = NUMCOUNT;
606: header.str_count = STRCOUNT;
607: header.str_size = next_free;
608: }
609:
610: if (fwrite(&header, sizeof(header), 1, fp) != 1
611: || fwrite(namelist, sizeof(char), namelen, fp) != namelen
612: || fwrite(Booleans, sizeof(char), BOOLCOUNT, fp) != BOOLCOUNT)
613: return(-1);
614:
615: if ((namelen+BOOLCOUNT) % 2 != 0 && fwrite(&zero, sizeof(char), 1, fp) != 1)
616: return(-1);
617:
618: if (must_swap())
619: {
620: for (i=0; i < NUMCOUNT; i++)
621: Numbers[i] = swap(Numbers[i]);
622: for (i=0; i < STRCOUNT; i++)
623: Strings[i] = swap(Strings[i]);
624: }
625:
626: if (fwrite((char *) Numbers, sizeof(short), NUMCOUNT, fp) != NUMCOUNT
627: || fwrite((char *) Strings, sizeof(short), STRCOUNT, fp) != STRCOUNT
628: || fwrite((char *) string_table, sizeof(char), next_free, fp)
629: != next_free)
630: return(-1);
631:
632: return(0);
633: }
634:
635:
636: /*
637: * check_name(name)
638: *
639: * Generate an error message if given name does not begin with a
640: * digit or letter (should be lower-case letter, but SV likes capital)
641: * Vlad 3-11-92
642: */
643:
644: check_name(name)
645: char *name;
646: {
647: if (!isalnum(name[0]))
648: {
649: fprintf(stderr, "tic: Line %d: Illegal terminal name - '%s'\n",
650: curr_line, name);
651: fprintf(stderr,
652: "Terminal names must start with letter or digit\n");
653: exit(1);
654: }
655: }
656:
657:
658: /*
659: * int
660: * save_str(string)
661: *
662: * copy string into next free part of string_table, doing a realloc()
663: * if necessary. return offset of beginning of string from start of
664: * string_table.
665: *
666: */
667:
668: int
669: save_str(string)
670: char *string;
671: {
672: char *malloc(), *realloc(), *strcpy();
673: int old_next_free = next_free;
674:
675: if (table_size == 0)
676: {
677: if ((string_table = malloc(1024)) == NULL)
678: syserr_abort("Out of memory");
679: table_size = 1024;
680: DEBUG(5, "Made initial string table allocation. Size is %d\n",
681: table_size);
682: }
683:
684: while (table_size < next_free + strlen(string))
685: {
686: if ((string_table = realloc(string_table, table_size + 1024))
687: == NULL)
688: syserr_abort("Out of memory");
689: table_size += 1024;
690: DEBUG(5, "Extended string table. Size now %d\n", table_size);
691: }
692:
693: strcpy(&string_table[next_free], string);
694: DEBUG(7, "Saved string '%s' ", string);
695: DEBUG(7, "at location %d\n", next_free);
696: next_free += strlen(string) + 1;
697:
698: return(old_next_free);
699: }
700:
701:
702: /*
703: * init_structure(Booleans, Numbers, Strings)
704: *
705: * Initialise the given arrays
706: * Reset the next_free counter to zero.
707: *
708: */
709:
710: init_structure(Booleans, Numbers, Strings)
711: char Booleans[];
712: short Numbers[], Strings[];
713: {
714: int i;
715:
716: for (i=0; i < BOOLCOUNT; i++)
717: Booleans[i] = FALSE;
718:
719: for (i=0; i < NUMCOUNT; i++)
720: Numbers[i] = -1;
721:
722: for (i=0; i < STRCOUNT; i++)
723: Strings[i] = -1;
724:
725: next_free = 0;
726: }
727:
728:
729: /*
730: ** int
731: ** handle_use(item_ptr, entry_offset, Booleans, Numbers, Strings)
732: **
733: ** Merge the compiled file whose name is in cur_token.valstring
734: ** with the current entry.
735: **
736: ** if it's a forward use-link
737: ** if item_ptr == NULL
738: ** queue it up for later handling
739: ** else
740: ** ignore it (we're already going through the queue)
741: ** else it's a backward use-link
742: ** read in the object file for that terminal
743: ** merge contents with current structure
744: **
745: ** Returned value is 0 if it was a backward link and we
746: ** successfully read it in, -1 if a forward link.
747: */
748:
749: int
750: handle_use(item_ptr, entry_offset, Booleans, Numbers, Strings)
751: long entry_offset;
752: struct use_item *item_ptr;
753: char Booleans[];
754: short Numbers[];
755: short Strings[];
756: {
757: struct term use_term;
758: struct stat statbuf;
759: static char filename[50];
760: int i;
761:
762: check_name(curr_token.tk_valstring);
763:
764: sprintf(filename, "%c/%s", curr_token.tk_valstring[0],
765: curr_token.tk_valstring);
766:
767: if (stat(filename, &statbuf) < 0 || part2==0 && statbuf.st_mtime < start_time)
768: {
769: DEBUG(2, "Forward USE to %s", curr_token.tk_valstring);
770:
771: if (item_ptr == NULL)
772: {
773: DEBUG(2, " (enqueued)\n", "");
774: enqueue(entry_offset);
775: }
776: else
777: DEBUG(2, " (skipped)\n", "");
778:
779: return(-1);
780: }
781: else
782: {
783: DEBUG(2, "Backward USE to %s\n", curr_token.tk_valstring);
784: if (read_entry(filename, &use_term) < 0)
785: syserr_abort("Error in re-reading compiled file %s", filename);
786:
787: for (i=0; i < BOOLCOUNT; i++)
788: {
789: if (Booleans[i] == FALSE && use_term.Booleans[i] == TRUE)
790: Booleans[i] = TRUE;
791: }
792:
793: for (i=0; i < NUMCOUNT; i++)
794: {
795: if (Numbers[i] == -1 && use_term.Numbers[i] != -1)
796: Numbers[i] = use_term.Numbers[i];
797: }
798:
799: for (i=0; i < STRCOUNT; i++)
800: {
801: if (Strings[i] == -1 && use_term.Strings[i] != (char *) 0)
802: Strings[i] = save_str(use_term.Strings[i]);
803: }
804:
805: }
806: return(0);
807: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.