GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/yacc/reader.c Lines: 748 1116 67.0 %
Date: 2016-12-06 Branches: 389 817 47.6 %

Line Branch Exec Source
1
/* $OpenBSD: reader.c,v 1.33 2016/03/22 18:24:34 mmcc Exp $	 */
2
/* $NetBSD: reader.c,v 1.5 1996/03/19 03:21:43 jtc Exp $	 */
3
4
/*
5
 * Copyright (c) 1989 The Regents of the University of California.
6
 * All rights reserved.
7
 *
8
 * This code is derived from software contributed to Berkeley by
9
 * Robert Paul Corbett.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 * 1. Redistributions of source code must retain the above copyright
15
 *    notice, this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright
17
 *    notice, this list of conditions and the following disclaimer in the
18
 *    documentation and/or other materials provided with the distribution.
19
 * 3. Neither the name of the University nor the names of its contributors
20
 *    may be used to endorse or promote products derived from this software
21
 *    without specific prior written permission.
22
 *
23
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
 * SUCH DAMAGE.
34
 */
35
36
#include <limits.h>
37
#include "defs.h"
38
39
/* The line size must be a positive integer.  One hundred was chosen	 */
40
/* because few lines in Yacc input grammars exceed 100 characters.	 */
41
/* Note that if a line exceeds LINESIZE characters, the line buffer	 */
42
/* will be expanded to accommodate it.					 */
43
44
#define LINESIZE 100
45
46
char *cache;
47
int cinc, cache_size;
48
49
int ntags, tagmax;
50
char **tag_table;
51
52
char saw_eof, unionized;
53
char *cptr, *line;
54
int linesize;
55
56
bucket *goal;
57
int prec;
58
int gensym;
59
char last_was_action;
60
61
int maxitems;
62
bucket **pitem;
63
64
int maxrules;
65
bucket **plhs;
66
67
int name_pool_size;
68
char *name_pool;
69
70
void cachec(int);
71
void get_line(void);
72
char *dup_line(void);
73
void skip_comment(void);
74
int nextc(void);
75
int keyword(void);
76
void copy_ident(void);
77
void copy_text(void);
78
void copy_union(void);
79
bucket *get_literal(void);
80
int is_reserved(char *);
81
bucket *get_name(void);
82
int get_number(void);
83
char *get_tag(void);
84
void declare_tokens(int);
85
void declare_types(void);
86
void declare_start(void);
87
void handle_expect(void);
88
void read_declarations(void);
89
void initialize_grammar(void);
90
void expand_items(void);
91
void expand_rules(void);
92
void advance_to_start(void);
93
void start_rule(bucket *, int);
94
void end_rule(void);
95
void insert_empty_rule(void);
96
void add_symbol(void);
97
void copy_action(void);
98
int mark_symbol(void);
99
void read_grammar(void);
100
void free_tags(void);
101
void pack_names(void);
102
void check_symbols(void);
103
void pack_symbols(void);
104
void pack_grammar(void);
105
void print_grammar(void);
106
107
char line_format[] = "#line %d \"%s\"\n";
108
109
void
110
cachec(int c)
111
58992
{
112
58992
	assert(cinc >= 0);
113
58992
	if (cinc >= cache_size) {
114
		cache_size += 256;
115
		cache = realloc(cache, cache_size);
116
		if (cache == NULL)
117
			no_space();
118
	}
119
58992
	cache[cinc] = c;
120
58992
	++cinc;
121
58992
}
122
123
124
void
125
get_line(void)
126
15945
{
127
15945
	FILE *f = input_file;
128
	int c, i;
129
130


15945
	if (saw_eof || (c = getc(f)) == EOF) {
131
		if (line) {
132
			free(line);
133
			line = 0;
134
		}
135
		cptr = 0;
136
		saw_eof = 1;
137
		return;
138
	}
139

15945
	if (line == NULL || linesize != (LINESIZE + 1)) {
140
24
		free(line);
141
24
		linesize = LINESIZE + 1;
142
24
		line = malloc(linesize);
143
24
		if (line == NULL)
144
			no_space();
145
	}
146
15945
	i = 0;
147
15945
	++lineno;
148
	for (;;) {
149
382140
		line[i] = c;
150
382140
		if (c == '\n') {
151
15945
			cptr = line;
152
15945
			return;
153
		}
154
366195
		if (++i >= linesize) {
155
3
			linesize += LINESIZE;
156
3
			line = realloc(line, linesize);
157
3
			if (line == NULL)
158
				no_space();
159
		}
160

366195
		c = getc(f);
161
366195
		if (c == EOF) {
162
			line[i] = '\n';
163
			saw_eof = 1;
164
			cptr = line;
165
			return;
166
		}
167
	}
168
}
169
170
171
char *
172
dup_line(void)
173
3873
{
174
	char *p, *s, *t;
175
176
3873
	if (line == NULL)
177
		return (0);
178
3873
	s = line;
179
136638
	while (*s != '\n')
180
128892
		++s;
181
3873
	p = malloc(s - line + 1);
182
3873
	if (p == NULL)
183
		no_space();
184
185
3873
	s = line;
186
3873
	t = p;
187
132765
	while ((*t++ = *s++) != '\n')
188
		continue;
189
3873
	return (p);
190
}
191
192
193
void
194
skip_comment(void)
195
268
{
196
	char *s;
197
268
	int st_lineno = lineno;
198
268
	char *st_line = dup_line();
199
268
	char *st_cptr = st_line + (cptr - line);
200
201
268
	s = cptr + 2;
202
	for (;;) {
203

23763
		if (*s == '*' && s[1] == '/') {
204
268
			cptr = s + 2;
205
268
			free(st_line);
206
			return;
207
		}
208
23495
		if (*s == '\n') {
209
377
			get_line();
210
377
			if (line == NULL)
211
				unterminated_comment(st_lineno, st_line, st_cptr);
212
377
			s = cptr;
213
		} else
214
23118
			++s;
215
	}
216
}
217
218
219
int
220
nextc(void)
221
16349
{
222
	char *s;
223
224
16349
	if (line == NULL) {
225
21
		get_line();
226
21
		if (line == NULL)
227
			return (EOF);
228
	}
229
16349
	s = cptr;
230
	for (;;) {
231

37188
		switch (*s) {
232
		case '\n':
233
4591
			get_line();
234
4591
			if (line == NULL)
235
				return (EOF);
236
4591
			s = cptr;
237
4591
			break;
238
239
		case ' ':
240
		case '\t':
241
		case '\f':
242
		case '\r':
243
		case '\v':
244
		case ',':
245
		case ';':
246
15980
			++s;
247
15980
			break;
248
249
		case '\\':
250
			cptr = s;
251
			return ('%');
252
253
		case '/':
254
268
			if (s[1] == '*') {
255
268
				cptr = s;
256
268
				skip_comment();
257
268
				s = cptr;
258
268
				break;
259
			} else if (s[1] == '/') {
260
				get_line();
261
				if (line == NULL)
262
					return (EOF);
263
				s = cptr;
264
				break;
265
			}
266
			/* fall through */
267
268
		default:
269
16349
			cptr = s;
270
16349
			return ((unsigned char) *s);
271
		}
272
	}
273
}
274
275
276
int
277
keyword(void)
278
453
{
279
	int c;
280
453
	char *t_cptr = cptr;
281
282
453
	c = (unsigned char) *++cptr;
283
453
	if (isalpha(c)) {
284
411
		cinc = 0;
285
		for (;;) {
286
2317
			if (isalpha(c)) {
287
1906
				if (isupper(c))
288
					c = tolower(c);
289
1906
				cachec(c);
290

411
			} else if (isdigit(c) || c == '_' || c == '.' || c == '$')
291
				cachec(c);
292
			else
293
				break;
294
1906
			c = (unsigned char) *++cptr;
295
1906
		}
296
411
		cachec(NUL);
297
298

411
		if (strcmp(cache, "token") == 0 || strcmp(cache, "term") == 0)
299
257
			return (TOKEN);
300
154
		if (strcmp(cache, "type") == 0)
301
145
			return (TYPE);
302
9
		if (strcmp(cache, "left") == 0)
303
4
			return (LEFT);
304
5
		if (strcmp(cache, "right") == 0)
305
			return (RIGHT);
306

5
		if (strcmp(cache, "nonassoc") == 0 || strcmp(cache, "binary") == 0)
307
			return (NONASSOC);
308
5
		if (strcmp(cache, "start") == 0)
309
1
			return (START);
310
4
		if (strcmp(cache, "union") == 0)
311
4
			return (UNION);
312
		if (strcmp(cache, "ident") == 0)
313
			return (IDENT);
314
		if (strcmp(cache, "expect") == 0)
315
			return (EXPECT);
316
	} else {
317
42
		++cptr;
318
42
		if (c == '{')
319
21
			return (TEXT);
320
21
		if (c == '%' || c == '\\')
321
21
			return (MARK);
322
		if (c == '<')
323
			return (LEFT);
324
		if (c == '>')
325
			return (RIGHT);
326
		if (c == '0')
327
			return (TOKEN);
328
		if (c == '2')
329
			return (NONASSOC);
330
	}
331
	syntax_error(lineno, line, t_cptr);
332
	/* NOTREACHED */
333
	return (0);
334
}
335
336
337
void
338
copy_ident(void)
339
{
340
	int c;
341
	FILE *f = output_file;
342
343
	c = nextc();
344
	if (c == EOF)
345
		unexpected_EOF();
346
	if (c != '"')
347
		syntax_error(lineno, line, cptr);
348
	++outline;
349
	fprintf(f, "#ident \"");
350
	for (;;) {
351
		c = (unsigned char) *++cptr;
352
		if (c == '\n') {
353
			fprintf(f, "\"\n");
354
			return;
355
		}
356
		putc(c, f);
357
		if (c == '"') {
358
			putc('\n', f);
359
			++cptr;
360
			return;
361
		}
362
	}
363
}
364
365
366
void
367
copy_text(void)
368
21
{
369
	int c;
370
	int quote;
371
21
	FILE *f = text_file;
372
21
	int need_newline = 0;
373
21
	int t_lineno = lineno;
374
21
	char *t_line = dup_line();
375
21
	char *t_cptr = t_line + (cptr - line - 2);
376
377
21
	if (*cptr == '\n') {
378
21
		get_line();
379
21
		if (line == NULL)
380
			unterminated_text(t_lineno, t_line, t_cptr);
381
	}
382
21
	if (!lflag)
383
21
		fprintf(f, line_format, lineno, input_file_name);
384
385
40569
loop:
386
40569
	c = (unsigned char) *cptr++;
387

40569
	switch (c) {
388
	case '\n':
389
1772
next_line:
390
1772
		putc('\n', f);
391
1772
		need_newline = 0;
392
1772
		get_line();
393
1772
		if (line)
394
1772
			goto loop;
395
		unterminated_text(t_lineno, t_line, t_cptr);
396
397
	case '\'':
398
	case '"': {
399
69
		int s_lineno = lineno;
400
69
		char *s_line = dup_line();
401
69
		char *s_cptr = s_line + (cptr - line - 1);
402
403
69
		quote = c;
404
69
		putc(c, f);
405
		for (;;) {
406
572
			c = (unsigned char) *cptr++;
407
572
			putc(c, f);
408
572
			if (c == quote) {
409
69
				need_newline = 1;
410
69
				free(s_line);
411
69
				goto loop;
412
			}
413
503
			if (c == '\n')
414
				unterminated_string(s_lineno, s_line, s_cptr);
415
503
			if (c == '\\') {
416
				c = (unsigned char) *cptr++;
417
				putc(c, f);
418
				if (c == '\n') {
419
					get_line();
420
					if (line == NULL)
421
						unterminated_string(s_lineno, s_line, s_cptr);
422
				}
423
			}
424
		}
425
	}
426
427
	case '/':
428
146
		putc(c, f);
429
146
		need_newline = 1;
430
146
		c = (unsigned char) *cptr;
431
146
		if (c == '/') {
432
			putc('*', f);
433
			while ((c = (unsigned char) *++cptr) != '\n') {
434
				if (c == '*' && cptr[1] == '/')
435
					fprintf(f, "* ");
436
				else
437
					putc(c, f);
438
			}
439
			fprintf(f, "*/");
440
			goto next_line;
441
		}
442
146
		if (c == '*') {
443
23
			int c_lineno = lineno;
444
23
			char *c_line = dup_line();
445
23
			char *c_cptr = c_line + (cptr - line - 1);
446
447
23
			putc('*', f);
448
23
			++cptr;
449
			for (;;) {
450
3790
				c = (unsigned char) *cptr++;
451
3790
				putc(c, f);
452

3790
				if (c == '*' && *cptr == '/') {
453
23
					putc('/', f);
454
23
					++cptr;
455
23
					free(c_line);
456
23
					goto loop;
457
				}
458
3767
				if (c == '\n') {
459
67
					get_line();
460
67
					if (line == NULL)
461
						unterminated_comment(c_lineno, c_line, c_cptr);
462
				}
463
			}
464
		}
465
123
		need_newline = 1;
466
123
		goto loop;
467
468
	case '%':
469
	case '\\':
470
41
		if (*cptr == '}') {
471
21
			if (need_newline)
472
				putc('\n', f);
473
21
			++cptr;
474
21
			free(t_line);
475
			return;
476
		}
477
		/* fall through */
478
479
	default:
480
38561
		putc(c, f);
481
38561
		need_newline = 1;
482
38561
		goto loop;
483
	}
484
}
485
486
487
void
488
copy_union(void)
489
4
{
490
	int c, quote, depth;
491
4
	int u_lineno = lineno;
492
4
	char *u_line = dup_line();
493
4
	char *u_cptr = u_line + (cptr - line - 6);
494
495
4
	if (unionized)
496
		over_unionized(cptr - 6);
497
4
	unionized = 1;
498
499
4
	if (!lflag)
500
4
		fprintf(text_file, line_format, lineno, input_file_name);
501
502
4
	fprintf(text_file, "#ifndef YYSTYPE_DEFINED\n");
503
4
	fprintf(text_file, "#define YYSTYPE_DEFINED\n");
504
4
	fprintf(text_file, "typedef union");
505
4
	if (dflag) {
506
4
		fprintf(union_file, "#ifndef YYSTYPE_DEFINED\n");
507
4
		fprintf(union_file, "#define YYSTYPE_DEFINED\n");
508
4
		fprintf(union_file, "typedef union");
509
	}
510
511
4
	depth = 0;
512
356
loop:
513
356
	c = (unsigned char) *cptr++;
514
356
	putc(c, text_file);
515
356
	if (dflag)
516
356
		putc(c, union_file);
517

356
	switch (c) {
518
	case '\n':
519
23
next_line:
520
23
		get_line();
521
23
		if (line == NULL)
522
			unterminated_union(u_lineno, u_line, u_cptr);
523
		goto loop;
524
525
	case '{':
526
4
		++depth;
527
4
		goto loop;
528
529
	case '}':
530
4
		if (--depth == 0) {
531
4
			fprintf(text_file, " YYSTYPE;\n");
532
4
			fprintf(text_file, "#endif /* YYSTYPE_DEFINED */\n");
533
4
			free(u_line);
534
			return;
535
		}
536
		goto loop;
537
538
	case '\'':
539
	case '"': {
540
		int s_lineno = lineno;
541
		char *s_line = dup_line();
542
		char *s_cptr = s_line + (cptr - line - 1);
543
544
		quote = c;
545
		for (;;) {
546
			c = (unsigned char) *cptr++;
547
			putc(c, text_file);
548
			if (dflag)
549
				putc(c, union_file);
550
			if (c == quote) {
551
				free(s_line);
552
				goto loop;
553
			}
554
			if (c == '\n')
555
				unterminated_string(s_lineno, s_line, s_cptr);
556
			if (c == '\\') {
557
				c = (unsigned char) *cptr++;
558
				putc(c, text_file);
559
				if (dflag)
560
					putc(c, union_file);
561
				if (c == '\n') {
562
					get_line();
563
					if (line == NULL)
564
						unterminated_string(s_lineno,
565
						    s_line, s_cptr);
566
				}
567
			}
568
		}
569
	}
570
571
	case '/':
572
		c = (unsigned char) *cptr;
573
		if (c == '/') {
574
			putc('*', text_file);
575
			if (dflag)
576
				putc('*', union_file);
577
			while ((c = (unsigned char) *++cptr) != '\n') {
578
				if (c == '*' && cptr[1] == '/') {
579
					fprintf(text_file, "* ");
580
					if (dflag)
581
						fprintf(union_file, "* ");
582
				} else {
583
					putc(c, text_file);
584
					if (dflag)
585
						putc(c, union_file);
586
				}
587
			}
588
			fprintf(text_file, "*/\n");
589
			if (dflag)
590
				fprintf(union_file, "*/\n");
591
			goto next_line;
592
		}
593
		if (c == '*') {
594
			int c_lineno = lineno;
595
			char *c_line = dup_line();
596
			char *c_cptr = c_line + (cptr - line - 1);
597
598
			putc('*', text_file);
599
			if (dflag)
600
				putc('*', union_file);
601
			++cptr;
602
			for (;;) {
603
				c = (unsigned char) *cptr++;
604
				putc(c, text_file);
605
				if (dflag)
606
					putc(c, union_file);
607
				if (c == '*' && *cptr == '/') {
608
					putc('/', text_file);
609
					if (dflag)
610
						putc('/', union_file);
611
					++cptr;
612
					free(c_line);
613
					goto loop;
614
				}
615
				if (c == '\n') {
616
					get_line();
617
					if (line == NULL)
618
						unterminated_comment(c_lineno,
619
						    c_line, c_cptr);
620
				}
621
			}
622
		}
623
		goto loop;
624
625
	default:
626
		goto loop;
627
	}
628
}
629
630
631
bucket *
632
get_literal(void)
633
434
{
634
	int c, quote, i, n;
635
	char *s;
636
	bucket *bp;
637
434
	int s_lineno = lineno;
638
434
	char *s_line = dup_line();
639
434
	char *s_cptr = s_line + (cptr - line);
640
641
434
	quote = (unsigned char) *cptr++;
642
434
	cinc = 0;
643
	for (;;) {
644
869
		c = (unsigned char) *cptr++;
645
869
		if (c == quote)
646
434
			break;
647
435
		if (c == '\n')
648
			unterminated_string(s_lineno, s_line, s_cptr);
649
435
		if (c == '\\') {
650
162
			char *c_cptr = cptr - 1;
651
			unsigned long ulval;
652
653
162
			c = (unsigned char) *cptr++;
654


162
			switch (c) {
655
			case '\n':
656
				get_line();
657
				if (line == NULL)
658
					unterminated_string(s_lineno, s_line,
659
					    s_cptr);
660
				continue;
661
662
			case '0':
663
			case '1':
664
			case '2':
665
			case '3':
666
			case '4':
667
			case '5':
668
			case '6':
669
			case '7':
670
				ulval = strtoul(cptr - 1, &s, 8);
671
				if (s == cptr - 1 || ulval > MAXCHAR)
672
					illegal_character(c_cptr);
673
				c = (int) ulval;
674
				cptr = s;
675
				break;
676
677
			case 'x':
678
				ulval = strtoul(cptr, &s, 16);
679
				if (s == cptr || ulval > MAXCHAR)
680
					illegal_character(c_cptr);
681
				c = (int) ulval;
682
				cptr = s;
683
				break;
684
685
			case 'a':
686
				c = 7;
687
				break;
688
			case 'b':
689
				c = '\b';
690
				break;
691
			case 'f':
692
				c = '\f';
693
				break;
694
			case 'n':
695
162
				c = '\n';
696
162
				break;
697
			case 'r':
698
				c = '\r';
699
				break;
700
			case 't':
701
				c = '\t';
702
				break;
703
			case 'v':
704
				c = '\v';
705
				break;
706
			}
707
		}
708
435
		cachec(c);
709
	}
710
434
	free(s_line);
711
712
434
	n = cinc;
713
434
	s = malloc(n);
714
434
	if (s == NULL)
715
		no_space();
716
717
434
	memcpy(s, cache, n);
718
719
434
	cinc = 0;
720
434
	if (n == 1)
721
433
		cachec('\'');
722
	else
723
1
		cachec('"');
724
725
869
	for (i = 0; i < n; ++i) {
726
435
		c = ((unsigned char *) s)[i];
727

435
		if (c == '\\' || c == cache[0]) {
728
			cachec('\\');
729
			cachec(c);
730
435
		} else if (isprint(c))
731
273
			cachec(c);
732
		else {
733
162
			cachec('\\');
734


162
			switch (c) {
735
			case 7:
736
				cachec('a');
737
				break;
738
			case '\b':
739
				cachec('b');
740
				break;
741
			case '\f':
742
				cachec('f');
743
				break;
744
			case '\n':
745
162
				cachec('n');
746
162
				break;
747
			case '\r':
748
				cachec('r');
749
				break;
750
			case '\t':
751
				cachec('t');
752
				break;
753
			case '\v':
754
				cachec('v');
755
				break;
756
			default:
757
				cachec(((c >> 6) & 7) + '0');
758
				cachec(((c >> 3) & 7) + '0');
759
				cachec((c & 7) + '0');
760
				break;
761
			}
762
		}
763
	}
764
765
434
	if (n == 1)
766
433
		cachec('\'');
767
	else
768
1
		cachec('"');
769
770
434
	cachec(NUL);
771
434
	bp = lookup(cache);
772
434
	bp->class = TERM;
773

434
	if (n == 1 && bp->value == UNDEFINED)
774
110
		bp->value = *(unsigned char *) s;
775
434
	free(s);
776
777
434
	return (bp);
778
}
779
780
781
int
782
is_reserved(char *name)
783
6202
{
784
	char *s;
785
786

6202
	if (strcmp(name, ".") == 0 ||
787
	    strcmp(name, "$accept") == 0 ||
788
	    strcmp(name, "$end") == 0)
789
		return (1);
790
791

6202
	if (name[0] == '$' && name[1] == '$' && isdigit((unsigned char) name[2])) {
792
		s = name + 3;
793
		while (isdigit((unsigned char) *s))
794
			++s;
795
		if (*s == NUL)
796
			return (1);
797
	}
798
6202
	return (0);
799
}
800
801
802
bucket *
803
get_name(void)
804
6202
{
805
	int c;
806
807
6202
	cinc = 0;
808

105482
	for (c = (unsigned char) *cptr; IS_IDENT(c); c = (unsigned char) *++cptr)
809
46539
		cachec(c);
810
6202
	cachec(NUL);
811
812
6202
	if (is_reserved(cache))
813
		used_reserved(cache);
814
815
6202
	return (lookup(cache));
816
}
817
818
819
int
820
get_number(void)
821
3254
{
822
	unsigned long ul;
823
	char *p;
824
825
3254
	ul = strtoul(cptr, &p, 10);
826
3254
	if (ul > INT_MAX)
827
		syntax_error(lineno, line, cptr);
828
3254
	cptr = p;
829
3254
	return (ul);
830
}
831
832
833
char *
834
get_tag(void)
835
200
{
836
	int c, i;
837
	char *s;
838
200
	int t_lineno = lineno;
839
200
	char *t_line = dup_line();
840
200
	char *t_cptr = t_line + (cptr - line);
841
842
200
	++cptr;
843
200
	c = nextc();
844
200
	if (c == EOF)
845
		unexpected_EOF();
846

200
	if (!isalpha(c) && c != '_' && c != '$')
847
		illegal_tag(t_lineno, t_line, t_cptr);
848
849
200
	cinc = 0;
850
	do {
851
1400
		cachec(c);
852
1400
		c = (unsigned char) *++cptr;
853

1400
	} while (IS_IDENT(c));
854
200
	cachec(NUL);
855
856
200
	c = nextc();
857
200
	if (c == EOF)
858
		unexpected_EOF();
859
200
	if (c != '>')
860
		illegal_tag(t_lineno, t_line, t_cptr);
861
200
	free(t_line);
862
200
	++cptr;
863
864
580
	for (i = 0; i < ntags; ++i) {
865
478
		if (strcmp(cache, tag_table[i]) == 0)
866
98
			return (tag_table[i]);
867
	}
868
869
102
	if (ntags >= tagmax) {
870
21
		tagmax += 16;
871
21
		tag_table = reallocarray(tag_table, tagmax, sizeof(char *));
872
21
		if (tag_table == NULL)
873
			no_space();
874
	}
875
102
	s = malloc(cinc);
876
102
	if (s == NULL)
877
		no_space();
878
102
	strlcpy(s, cache, cinc);
879
102
	tag_table[ntags] = s;
880
102
	++ntags;
881
102
	return (s);
882
}
883
884
885
void
886
declare_tokens(int assoc)
887
261
{
888
	int c;
889
	bucket *bp;
890
	int value;
891
261
	char *tag = 0;
892
893
261
	if (assoc != TOKEN)
894
4
		++prec;
895
896
261
	c = nextc();
897
261
	if (c == EOF)
898
		unexpected_EOF();
899
261
	if (c == '<') {
900
55
		tag = get_tag();
901
55
		c = nextc();
902
55
		if (c == EOF)
903
			unexpected_EOF();
904
	}
905
	for (;;) {
906

2311
		if (isalpha(c) || c == '_' || c == '.' || c == '$')
907
1024
			bp = get_name();
908
263
		else if (c == '\'' || c == '"')
909
2
			bp = get_literal();
910
		else
911
261
			return;
912
913
1026
		if (bp == goal)
914
			tokenized_start(bp->name);
915
1026
		bp->class = TERM;
916
917
1026
		if (tag) {
918

125
			if (bp->tag && tag != bp->tag)
919
				retyped_warning(bp->name);
920
125
			bp->tag = tag;
921
		}
922
1026
		if (assoc != TOKEN) {
923

5
			if (bp->prec && prec != bp->prec)
924
				reprec_warning(bp->name);
925
5
			bp->assoc = assoc;
926
5
			bp->prec = prec;
927
		}
928
1026
		c = nextc();
929
1026
		if (c == EOF)
930
			unexpected_EOF();
931
1026
		if (isdigit(c)) {
932
			value = get_number();
933
			if (bp->value != UNDEFINED && value != bp->value)
934
				revalued_warning(bp->name);
935
			bp->value = value;
936
			c = nextc();
937
			if (c == EOF)
938
				unexpected_EOF();
939
		}
940
	}
941
}
942
943
944
/*
945
 * %expect requires special handling as it really isn't part of the yacc
946
 * grammar only a flag for yacc proper.
947
 */
948
void
949
declare_expect(int assoc)
950
{
951
	int c;
952
953
	if (assoc != EXPECT)
954
		++prec;
955
956
	/*
957
         * Stay away from nextc - doesn't detect EOL and will read to EOF.
958
         */
959
	c = (unsigned char) *++cptr;
960
	if (c == EOF)
961
		unexpected_EOF();
962
963
	for (;;) {
964
		if (isdigit(c)) {
965
			SRexpect = get_number();
966
			break;
967
		}
968
		/*
969
	         * Looking for number before EOL.
970
	         * Spaces, tabs, and numbers are ok.
971
	         * Words, punc., etc. are syntax errors.
972
	         */
973
		else if (c == '\n' || isalpha(c) || !isspace(c)) {
974
			syntax_error(lineno, line, cptr);
975
		} else {
976
			c = (unsigned char) *++cptr;
977
			if (c == EOF)
978
				unexpected_EOF();
979
		}
980
	}
981
}
982
983
984
void
985
declare_types(void)
986
145
{
987
	int c;
988
	bucket *bp;
989
	char *tag;
990
991
145
	c = nextc();
992
145
	if (c == EOF)
993
		unexpected_EOF();
994
145
	if (c != '<')
995
		syntax_error(lineno, line, cptr);
996
145
	tag = get_tag();
997
998
	for (;;) {
999
416
		c = nextc();
1000

687
		if (isalpha(c) || c == '_' || c == '.' || c == '$')
1001
271
			bp = get_name();
1002
145
		else if (c == '\'' || c == '"')
1003
			bp = get_literal();
1004
		else
1005
145
			return;
1006
1007

271
		if (bp->tag && tag != bp->tag)
1008
			retyped_warning(bp->name);
1009
271
		bp->tag = tag;
1010
271
	}
1011
}
1012
1013
1014
void
1015
declare_start(void)
1016
1
{
1017
	int c;
1018
	bucket *bp;
1019
1020
1
	c = nextc();
1021
1
	if (c == EOF)
1022
		unexpected_EOF();
1023

1
	if (!isalpha(c) && c != '_' && c != '.' && c != '$')
1024
		syntax_error(lineno, line, cptr);
1025
1
	bp = get_name();
1026
1
	if (bp->class == TERM)
1027
		terminal_start(bp->name);
1028

1
	if (goal && goal != bp)
1029
		restarted_warning();
1030
1
	goal = bp;
1031
1
}
1032
1033
1034
void
1035
read_declarations(void)
1036
21
{
1037
	int c, k;
1038
1039
21
	cache_size = 256;
1040
21
	cache = malloc(cache_size);
1041
21
	if (cache == NULL)
1042
		no_space();
1043
1044
	for (;;) {
1045
453
		c = nextc();
1046
453
		if (c == EOF)
1047
			unexpected_EOF();
1048
453
		if (c != '%')
1049
			syntax_error(lineno, line, cptr);
1050


453
		switch (k = keyword()) {
1051
		case MARK:
1052
			return;
1053
1054
		case IDENT:
1055
			copy_ident();
1056
			break;
1057
1058
		case TEXT:
1059
21
			copy_text();
1060
21
			break;
1061
1062
		case UNION:
1063
4
			copy_union();
1064
4
			break;
1065
1066
		case TOKEN:
1067
		case LEFT:
1068
		case RIGHT:
1069
		case NONASSOC:
1070
261
			declare_tokens(k);
1071
261
			break;
1072
1073
		case EXPECT:
1074
			declare_expect(k);
1075
			break;
1076
1077
		case TYPE:
1078
145
			declare_types();
1079
145
			break;
1080
1081
		case START:
1082
1
			declare_start();
1083
			break;
1084
		}
1085
	}
1086
}
1087
1088
1089
void
1090
initialize_grammar(void)
1091
21
{
1092
21
	nitems = 4;
1093
21
	maxitems = 300;
1094
21
	pitem = calloc(maxitems, sizeof(bucket *));
1095
21
	if (pitem == NULL)
1096
		no_space();
1097
1098
21
	nrules = 3;
1099
21
	maxrules = 100;
1100
21
	plhs = reallocarray(NULL, maxrules, sizeof(bucket *));
1101
21
	if (plhs == NULL)
1102
		no_space();
1103
21
	plhs[0] = 0;
1104
21
	plhs[1] = 0;
1105
21
	plhs[2] = 0;
1106
21
	rprec = reallocarray(NULL, maxrules, sizeof(short));
1107
21
	if (rprec == NULL)
1108
		no_space();
1109
21
	rprec[0] = 0;
1110
21
	rprec[1] = 0;
1111
21
	rprec[2] = 0;
1112
21
	rassoc = reallocarray(NULL, maxrules, sizeof(char));
1113
21
	if (rassoc == NULL)
1114
		no_space();
1115
21
	rassoc[0] = TOKEN;
1116
21
	rassoc[1] = TOKEN;
1117
21
	rassoc[2] = TOKEN;
1118
21
}
1119
1120
1121
void
1122
expand_items(void)
1123
14
{
1124
14
	int olditems = maxitems;
1125
1126
14
	maxitems += 300;
1127
14
	pitem = reallocarray(pitem, maxitems, sizeof(bucket *));
1128
14
	if (pitem == NULL)
1129
		no_space();
1130
14
	memset(pitem + olditems, 0, (maxitems - olditems) * sizeof(bucket *));
1131
14
}
1132
1133
1134
void
1135
expand_rules(void)
1136
13
{
1137
13
	maxrules += 100;
1138
13
	plhs = reallocarray(plhs, maxrules, sizeof(bucket *));
1139
13
	if (plhs == NULL)
1140
		no_space();
1141
13
	rprec = reallocarray(rprec, maxrules, sizeof(short));
1142
13
	if (rprec == NULL)
1143
		no_space();
1144
13
	rassoc = reallocarray(rassoc, maxrules, sizeof(char));
1145
13
	if (rassoc == NULL)
1146
		no_space();
1147
13
}
1148
1149
1150
void
1151
advance_to_start(void)
1152
21
{
1153
	int c;
1154
	bucket *bp;
1155
	char *s_cptr;
1156
	int s_lineno;
1157
1158
	for (;;) {
1159
21
		c = nextc();
1160
21
		if (c != '%')
1161
21
			break;
1162
		s_cptr = cptr;
1163
		switch (keyword()) {
1164
		case MARK:
1165
			no_grammar();
1166
1167
		case TEXT:
1168
			copy_text();
1169
			break;
1170
1171
		case START:
1172
			declare_start();
1173
			break;
1174
1175
		default:
1176
			syntax_error(lineno, line, s_cptr);
1177
		}
1178
	}
1179
1180
21
	c = nextc();
1181
21
	if (!isalpha(c) && c != '_' && c != '.' && c != '_')
1182
		syntax_error(lineno, line, cptr);
1183
21
	bp = get_name();
1184
21
	if (goal == NULL) {
1185
20
		if (bp->class == TERM)
1186
			terminal_start(bp->name);
1187
20
		goal = bp;
1188
	}
1189
21
	s_lineno = lineno;
1190
21
	c = nextc();
1191
21
	if (c == EOF)
1192
		unexpected_EOF();
1193
21
	if (c != ':')
1194
		syntax_error(lineno, line, cptr);
1195
21
	start_rule(bp, s_lineno);
1196
21
	++cptr;
1197
21
}
1198
1199
1200
void
1201
start_rule(bucket * bp, int s_lineno)
1202
2187
{
1203
2187
	if (bp->class == TERM)
1204
		terminal_lhs(s_lineno);
1205
2187
	bp->class = NONTERM;
1206
2187
	if (nrules >= maxrules)
1207
13
		expand_rules();
1208
2187
	plhs[nrules] = bp;
1209
2187
	rprec[nrules] = UNDEFINED;
1210
2187
	rassoc[nrules] = TOKEN;
1211
2187
}
1212
1213
1214
void
1215
end_rule(void)
1216
2187
{
1217
	int i;
1218
1219

2187
	if (!last_was_action && plhs[nrules]->tag) {
1220
97
		for (i = nitems - 1; pitem[i]; --i)
1221
			continue;
1222

97
		if (i == maxitems - 1 || pitem[i + 1] == 0 ||
1223
		    pitem[i + 1]->tag != plhs[nrules]->tag)
1224
			default_action_warning();
1225
	}
1226
2187
	last_was_action = 0;
1227
2187
	if (nitems >= maxitems)
1228
5
		expand_items();
1229
2187
	pitem[nitems] = 0;
1230
2187
	++nitems;
1231
2187
	++nrules;
1232
2187
}
1233
1234
1235
void
1236
insert_empty_rule(void)
1237
55
{
1238
	bucket *bp, **bpp;
1239
1240
55
	assert(cache);
1241
55
	snprintf(cache, cache_size, "$$%d", ++gensym);
1242
55
	bp = make_bucket(cache);
1243
55
	last_symbol->next = bp;
1244
55
	last_symbol = bp;
1245
55
	bp->tag = plhs[nrules]->tag;
1246
55
	bp->class = NONTERM;
1247
1248
55
	if ((nitems += 2) > maxitems)
1249
		expand_items();
1250
55
	bpp = pitem + nitems - 1;
1251
55
	*bpp-- = bp;
1252
236
	while ((bpp[0] = bpp[-1]))
1253
126
		--bpp;
1254
1255
55
	if (++nrules >= maxrules)
1256
		expand_rules();
1257
55
	plhs[nrules] = plhs[nrules - 1];
1258
55
	plhs[nrules - 1] = bp;
1259
55
	rprec[nrules] = rprec[nrules - 1];
1260
55
	rprec[nrules - 1] = 0;
1261
55
	rassoc[nrules] = rassoc[nrules - 1];
1262
55
	rassoc[nrules - 1] = TOKEN;
1263
55
}
1264
1265
1266
void
1267
add_symbol(void)
1268
5316
{
1269
	int c;
1270
	bucket *bp;
1271
5316
	int s_lineno = lineno;
1272
1273
5316
	c = (unsigned char) *cptr;
1274
5316
	if (c == '\'' || c == '"')
1275
432
		bp = get_literal();
1276
	else
1277
4884
		bp = get_name();
1278
1279
5316
	c = nextc();
1280
5316
	if (c == ':') {
1281
790
		end_rule();
1282
790
		start_rule(bp, s_lineno);
1283
790
		++cptr;
1284
790
		return;
1285
	}
1286
4526
	if (last_was_action)
1287
55
		insert_empty_rule();
1288
4526
	last_was_action = 0;
1289
1290
4526
	if (++nitems > maxitems)
1291
9
		expand_items();
1292
4526
	pitem[nitems - 1] = bp;
1293
}
1294
1295
1296
void
1297
copy_action(void)
1298
1498
{
1299
	int c, i, n, depth, quote;
1300
	char *tag;
1301
1498
	FILE *f = action_file;
1302
1498
	int a_lineno = lineno;
1303
1498
	char *a_line = dup_line();
1304
1498
	char *a_cptr = a_line + (cptr - line);
1305
1306
1498
	if (last_was_action)
1307
		insert_empty_rule();
1308
1498
	last_was_action = 1;
1309
1310
1498
	fprintf(f, "case %d:\n", nrules - 2);
1311
1498
	if (!lflag)
1312
1498
		fprintf(f, line_format, lineno, input_file_name);
1313
1498
	if (*cptr == '=')
1314
		++cptr;
1315
1316
1498
	n = 0;
1317
4811
	for (i = nitems - 1; pitem[i]; --i)
1318
3313
		++n;
1319
1320
1498
	depth = 0;
1321
113029
loop:
1322
113029
	c = (unsigned char) *cptr;
1323
113029
	if (c == '$') {
1324
4190
		if (cptr[1] == '<') {
1325
			int d_lineno = lineno;
1326
			char *d_line = dup_line();
1327
			char *d_cptr = d_line + (cptr - line);
1328
1329
			++cptr;
1330
			tag = get_tag();
1331
			c = (unsigned char) *cptr;
1332
			if (c == '$') {
1333
				fprintf(f, "yyval.%s", tag);
1334
				++cptr;
1335
				free(d_line);
1336
				goto loop;
1337
			} else if (isdigit(c)) {
1338
				i = get_number();
1339
				if (i > n)
1340
					dollar_warning(d_lineno, i);
1341
				fprintf(f, "yyvsp[%d].%s", i - n, tag);
1342
				free(d_line);
1343
				goto loop;
1344
			} else if (c == '-' && isdigit((unsigned char) cptr[1])) {
1345
				++cptr;
1346
				i = -get_number() - n;
1347
				fprintf(f, "yyvsp[%d].%s", i, tag);
1348
				free(d_line);
1349
				goto loop;
1350
			} else
1351
				dollar_error(d_lineno, d_line, d_cptr);
1352
4190
		} else if (cptr[1] == '$') {
1353
936
			if (ntags) {
1354
936
				tag = plhs[nrules]->tag;
1355
936
				if (tag == NULL)
1356
					untyped_lhs();
1357
936
				fprintf(f, "yyval.%s", tag);
1358
			} else
1359
				fprintf(f, "yyval");
1360
936
			cptr += 2;
1361
936
			goto loop;
1362
3254
		} else if (isdigit((unsigned char) cptr[1])) {
1363
3254
			++cptr;
1364
3254
			i = get_number();
1365
3254
			if (ntags) {
1366
3254
				if (i <= 0 || i > n)
1367
					unknown_rhs(i);
1368
3254
				tag = pitem[nitems + i - n - 1]->tag;
1369
3254
				if (tag == NULL)
1370
					untyped_rhs(i, pitem[nitems + i - n - 1]->name);
1371
3254
				fprintf(f, "yyvsp[%d].%s", i - n, tag);
1372
			} else {
1373
				if (i > n)
1374
					dollar_warning(lineno, i);
1375
				fprintf(f, "yyvsp[%d]", i - n);
1376
			}
1377
			goto loop;
1378
		} else if (cptr[1] == '-') {
1379
			cptr += 2;
1380
			i = get_number();
1381
			if (ntags)
1382
				unknown_rhs(-i);
1383
			fprintf(f, "yyvsp[%d]", -i - n);
1384
			goto loop;
1385
		}
1386
	}
1387

108839
	if (isalpha(c) || c == '_' || c == '$') {
1388
		do {
1389
108503
			putc(c, f);
1390
108503
			c = (unsigned char) *++cptr;
1391

108503
		} while (isalnum(c) || c == '_' || c == '$');
1392
		goto loop;
1393
	}
1394
92687
	putc(c, f);
1395
92687
	++cptr;
1396

92687
	switch (c) {
1397
	case '\n':
1398
9051
next_line:
1399
9051
		get_line();
1400
9051
		if (line)
1401
9051
			goto loop;
1402
		unterminated_action(a_lineno, a_line, a_cptr);
1403
1404
	case ';':
1405
5344
		if (depth > 0)
1406
5344
			goto loop;
1407
		fprintf(f, "\nbreak;\n");
1408
		free(a_line);
1409
		return;
1410
1411
	case '{':
1412
2303
		++depth;
1413
2303
		goto loop;
1414
1415
	case '}':
1416
2303
		if (--depth > 0)
1417
805
			goto loop;
1418
1498
		fprintf(f, "\nbreak;\n");
1419
1498
		free(a_line);
1420
1498
		return;
1421
1422
	case '\'':
1423
	case '"': {
1424
1195
		int s_lineno = lineno;
1425
1195
		char *s_line = dup_line();
1426
1195
		char *s_cptr = s_line + (cptr - line - 1);
1427
1428
1195
		quote = c;
1429
		for (;;) {
1430
23825
			c = (unsigned char) *cptr++;
1431
23825
			putc(c, f);
1432
23825
			if (c == quote) {
1433
1195
				free(s_line);
1434
1195
				goto loop;
1435
			}
1436
22630
			if (c == '\n')
1437
				unterminated_string(s_lineno, s_line, s_cptr);
1438
22630
			if (c == '\\') {
1439
245
				c = (unsigned char) *cptr++;
1440
245
				putc(c, f);
1441
245
				if (c == '\n') {
1442
					get_line();
1443
					if (line == NULL)
1444
						unterminated_string(s_lineno, s_line, s_cptr);
1445
				}
1446
			}
1447
		}
1448
	}
1449
1450
	case '/':
1451
169
		c = (unsigned char) *cptr;
1452
169
		if (c == '/') {
1453
			putc('*', f);
1454
			while ((c = (unsigned char) *++cptr) != '\n') {
1455
				if (c == '*' && cptr[1] == '/')
1456
					fprintf(f, "* ");
1457
				else
1458
					putc(c, f);
1459
			}
1460
			fprintf(f, "*/\n");
1461
			goto next_line;
1462
		}
1463
169
		if (c == '*') {
1464
161
			int c_lineno = lineno;
1465
161
			char *c_line = dup_line();
1466
161
			char *c_cptr = c_line + (cptr - line - 1);
1467
1468
161
			putc('*', f);
1469
161
			++cptr;
1470
			for (;;) {
1471
3197
				c = (unsigned char) *cptr++;
1472
3197
				putc(c, f);
1473

3197
				if (c == '*' && *cptr == '/') {
1474
161
					putc('/', f);
1475
161
					++cptr;
1476
161
					free(c_line);
1477
161
					goto loop;
1478
				}
1479
3036
				if (c == '\n') {
1480
22
					get_line();
1481
22
					if (line == NULL)
1482
						unterminated_comment(c_lineno, c_line, c_cptr);
1483
				}
1484
			}
1485
		}
1486
		goto loop;
1487
1488
	default:
1489
		goto loop;
1490
	}
1491
}
1492
1493
1494
int
1495
mark_symbol(void)
1496
22
{
1497
	int c;
1498
22
	bucket *bp = NULL;
1499
1500
22
	c = (unsigned char) cptr[1];
1501
22
	if (c == '%' || c == '\\') {
1502
21
		cptr += 2;
1503
21
		return (1);
1504
	}
1505
1
	if (c == '=')
1506
		cptr += 2;
1507





3
	else if ((c == 'p' || c == 'P') &&
1508
	    ((c = cptr[2]) == 'r' || c == 'R') &&
1509
	    ((c = cptr[3]) == 'e' || c == 'E') &&
1510
	    ((c = cptr[4]) == 'c' || c == 'C') &&
1511
	    ((c = (unsigned char) cptr[5], !IS_IDENT(c))))
1512
1
		cptr += 5;
1513
	else
1514
		syntax_error(lineno, line, cptr);
1515
1516
1
	c = nextc();
1517

2
	if (isalpha(c) || c == '_' || c == '.' || c == '$')
1518
1
		bp = get_name();
1519
	else if (c == '\'' || c == '"')
1520
		bp = get_literal();
1521
	else {
1522
		syntax_error(lineno, line, cptr);
1523
		/* NOTREACHED */
1524
	}
1525
1526

1
	if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
1527
		prec_redeclared();
1528
1529
1
	rprec[nrules] = bp->prec;
1530
1
	rassoc[nrules] = bp->assoc;
1531
1
	return (0);
1532
}
1533
1534
1535
void
1536
read_grammar(void)
1537
21
{
1538
	int c;
1539
1540
21
	initialize_grammar();
1541
21
	advance_to_start();
1542
1543
	for (;;) {
1544
8212
		c = nextc();
1545
8212
		if (c == EOF)
1546
			break;
1547

13528
		if (isalpha(c) || c == '_' || c == '.' || c == '$' || c == '\'' ||
1548
		    c == '"')
1549
5316
			add_symbol();
1550
2896
		else if (c == '{' || c == '=')
1551
1498
			copy_action();
1552
1398
		else if (c == '|') {
1553
1376
			end_rule();
1554
1376
			start_rule(plhs[nrules - 1], 0);
1555
1376
			++cptr;
1556
22
		} else if (c == '%') {
1557
22
			if (mark_symbol())
1558
21
				break;
1559
		} else
1560
			syntax_error(lineno, line, cptr);
1561
	}
1562
21
	end_rule();
1563
21
}
1564
1565
1566
void
1567
free_tags(void)
1568
21
{
1569
	int i;
1570
1571
21
	if (tag_table == NULL)
1572
		return;
1573
1574
123
	for (i = 0; i < ntags; ++i) {
1575
102
		assert(tag_table[i]);
1576
102
		free(tag_table[i]);
1577
	}
1578
21
	free(tag_table);
1579
}
1580
1581
1582
void
1583
pack_names(void)
1584
21
{
1585
	bucket *bp;
1586
	char *p, *s, *t;
1587
1588
21
	name_pool_size = 13;	/* 13 == sizeof("$end") + sizeof("$accept") */
1589
2041
	for (bp = first_symbol; bp; bp = bp->next)
1590
2020
		name_pool_size += strlen(bp->name) + 1;
1591
21
	name_pool = malloc(name_pool_size);
1592
21
	if (name_pool == NULL)
1593
		no_space();
1594
1595
21
	strlcpy(name_pool, "$accept", name_pool_size);
1596
21
	strlcpy(name_pool + 8, "$end", name_pool_size - 8);
1597
21
	t = name_pool + 13;
1598
2041
	for (bp = first_symbol; bp; bp = bp->next) {
1599
2020
		p = t;
1600
2020
		s = bp->name;
1601
17958
		while ((*t++ = *s++))
1602
			continue;
1603
2020
		free(bp->name);
1604
2020
		bp->name = p;
1605
	}
1606
21
}
1607
1608
1609
void
1610
check_symbols(void)
1611
21
{
1612
	bucket *bp;
1613
1614
21
	if (goal->class == UNKNOWN)
1615
		undefined_goal(goal->name);
1616
1617
2041
	for (bp = first_symbol; bp; bp = bp->next) {
1618
2020
		if (bp->class == UNKNOWN) {
1619
			undefined_symbol_warning(bp->name);
1620
			bp->class = TERM;
1621
		}
1622
	}
1623
21
}
1624
1625
1626
void
1627
pack_symbols(void)
1628
21
{
1629
	bucket *bp;
1630
	bucket **v;
1631
	int i, j, k, n;
1632
1633
21
	nsyms = 2;
1634
21
	ntokens = 1;
1635
2041
	for (bp = first_symbol; bp; bp = bp->next) {
1636
2020
		++nsyms;
1637
2020
		if (bp->class == TERM)
1638
1154
			++ntokens;
1639
	}
1640
21
	start_symbol = ntokens;
1641
21
	nvars = nsyms - ntokens;
1642
1643
21
	symbol_name = reallocarray(NULL, nsyms, sizeof(char *));
1644
21
	if (symbol_name == NULL)
1645
		no_space();
1646
21
	symbol_value = reallocarray(NULL, nsyms, sizeof(short));
1647
21
	if (symbol_value == NULL)
1648
		no_space();
1649
21
	symbol_prec = reallocarray(NULL, nsyms, sizeof(short));
1650
21
	if (symbol_prec == NULL)
1651
		no_space();
1652
21
	symbol_assoc = malloc(nsyms);
1653
21
	if (symbol_assoc == NULL)
1654
		no_space();
1655
1656
21
	v = reallocarray(NULL, nsyms, sizeof(bucket *));
1657
21
	if (v == NULL)
1658
		no_space();
1659
1660
21
	v[0] = 0;
1661
21
	v[start_symbol] = 0;
1662
1663
21
	i = 1;
1664
21
	j = start_symbol + 1;
1665
2041
	for (bp = first_symbol; bp; bp = bp->next) {
1666
2020
		if (bp->class == TERM)
1667
1154
			v[i++] = bp;
1668
		else
1669
866
			v[j++] = bp;
1670
	}
1671

21
	assert(i == ntokens && j == nsyms);
1672
1673
1175
	for (i = 1; i < ntokens; ++i)
1674
1154
		v[i]->index = i;
1675
1676
21
	goal->index = start_symbol + 1;
1677
21
	k = start_symbol + 2;
1678
908
	while (++i < nsyms)
1679
866
		if (v[i] != goal) {
1680
845
			v[i]->index = k;
1681
845
			++k;
1682
		}
1683
21
	goal->value = 0;
1684
21
	k = 1;
1685
887
	for (i = start_symbol + 1; i < nsyms; ++i) {
1686
866
		if (v[i] != goal) {
1687
845
			v[i]->value = k;
1688
845
			++k;
1689
		}
1690
	}
1691
1692
21
	k = 0;
1693
1175
	for (i = 1; i < ntokens; ++i) {
1694
1154
		n = v[i]->value;
1695
1154
		if (n > 256) {
1696
			for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
1697
				symbol_value[j] = symbol_value[j - 1];
1698
			symbol_value[j] = n;
1699
		}
1700
	}
1701
1702
21
	if (v[1]->value == UNDEFINED)
1703
21
		v[1]->value = 256;
1704
1705
21
	j = 0;
1706
21
	n = 257;
1707
1154
	for (i = 2; i < ntokens; ++i) {
1708
1133
		if (v[i]->value == UNDEFINED) {
1709

1023
			while (j < k && n == symbol_value[j]) {
1710
				while (++j < k && n == symbol_value[j])
1711
					continue;
1712
				++n;
1713
			}
1714
1023
			v[i]->value = n;
1715
1023
			++n;
1716
		}
1717
	}
1718
1719
21
	symbol_name[0] = name_pool + 8;
1720
21
	symbol_value[0] = 0;
1721
21
	symbol_prec[0] = 0;
1722
21
	symbol_assoc[0] = TOKEN;
1723
1175
	for (i = 1; i < ntokens; ++i) {
1724
1154
		symbol_name[i] = v[i]->name;
1725
1154
		symbol_value[i] = v[i]->value;
1726
1154
		symbol_prec[i] = v[i]->prec;
1727
1154
		symbol_assoc[i] = v[i]->assoc;
1728
	}
1729
21
	symbol_name[start_symbol] = name_pool;
1730
21
	symbol_value[start_symbol] = -1;
1731
21
	symbol_prec[start_symbol] = 0;
1732
21
	symbol_assoc[start_symbol] = TOKEN;
1733
887
	for (++i; i < nsyms; ++i) {
1734
866
		k = v[i]->index;
1735
866
		symbol_name[k] = v[i]->name;
1736
866
		symbol_value[k] = v[i]->value;
1737
866
		symbol_prec[k] = v[i]->prec;
1738
866
		symbol_assoc[k] = v[i]->assoc;
1739
	}
1740
1741
21
	free(v);
1742
21
}
1743
1744
1745
void
1746
pack_grammar(void)
1747
21
{
1748
	int i, j;
1749
	int assoc, prec;
1750
1751
21
	ritem = reallocarray(NULL, nitems, sizeof(short));
1752
21
	if (ritem == NULL)
1753
		no_space();
1754
21
	rlhs = reallocarray(NULL, nrules, sizeof(short));
1755
21
	if (rlhs == NULL)
1756
		no_space();
1757
21
	rrhs = reallocarray(NULL, nrules + 1, sizeof(short));
1758
21
	if (rrhs == NULL)
1759
		no_space();
1760
21
	rprec = reallocarray(rprec, nrules, sizeof(short));
1761
21
	if (rprec == NULL)
1762
		no_space();
1763
21
	rassoc = realloc(rassoc, nrules);
1764
21
	if (rassoc == NULL)
1765
		no_space();
1766
1767
21
	ritem[0] = -1;
1768
21
	ritem[1] = goal->index;
1769
21
	ritem[2] = 0;
1770
21
	ritem[3] = -2;
1771
21
	rlhs[0] = 0;
1772
21
	rlhs[1] = 0;
1773
21
	rlhs[2] = start_symbol;
1774
21
	rrhs[0] = 0;
1775
21
	rrhs[1] = 0;
1776
21
	rrhs[2] = 1;
1777
1778
21
	j = 4;
1779
2263
	for (i = 3; i < nrules; ++i) {
1780
2242
		rlhs[i] = plhs[i]->index;
1781
2242
		rrhs[i] = j;
1782
2242
		assoc = TOKEN;
1783
2242
		prec = 0;
1784
9065
		while (pitem[j]) {
1785
4581
			ritem[j] = pitem[j]->index;
1786
4581
			if (pitem[j]->class == TERM) {
1787
2547
				prec = pitem[j]->prec;
1788
2547
				assoc = pitem[j]->assoc;
1789
			}
1790
4581
			++j;
1791
		}
1792
2242
		ritem[j] = -i;
1793
2242
		++j;
1794
2242
		if (rprec[i] == UNDEFINED) {
1795
2186
			rprec[i] = prec;
1796
2186
			rassoc[i] = assoc;
1797
		}
1798
	}
1799
21
	rrhs[i] = j;
1800
1801
21
	free(plhs);
1802
21
	free(pitem);
1803
21
}
1804
1805
1806
void
1807
print_grammar(void)
1808
21
{
1809
	int i, j, k;
1810
21
	int spacing = 0;
1811
21
	FILE *f = verbose_file;
1812
1813
21
	if (!vflag)
1814
21
		return;
1815
1816
	k = 1;
1817
	for (i = 2; i < nrules; ++i) {
1818
		if (rlhs[i] != rlhs[i - 1]) {
1819
			if (i != 2)
1820
				fprintf(f, "\n");
1821
			fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
1822
			spacing = strlen(symbol_name[rlhs[i]]) + 1;
1823
		} else {
1824
			fprintf(f, "%4d  ", i - 2);
1825
			j = spacing;
1826
			while (--j >= 0)
1827
				putc(' ', f);
1828
			putc('|', f);
1829
		}
1830
1831
		while (ritem[k] >= 0) {
1832
			fprintf(f, " %s", symbol_name[ritem[k]]);
1833
			++k;
1834
		}
1835
		++k;
1836
		putc('\n', f);
1837
	}
1838
}
1839
1840
1841
void
1842
reader(void)
1843
21
{
1844
21
	write_section(banner);
1845
21
	create_symbol_table();
1846
21
	read_declarations();
1847
21
	read_grammar();
1848
21
	free_symbol_table();
1849
21
	free_tags();
1850
21
	pack_names();
1851
21
	check_symbols();
1852
21
	pack_symbols();
1853
21
	pack_grammar();
1854
21
	free_symbols();
1855
21
	print_grammar();
1856
21
}