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