xref: /freebsd/sys/dev/aic7xxx/aicasm/aicasm.c (revision b601c69bdbe8755d26570261d7fd4c02ee4eff74)
1 /*
2  * Aic7xxx SCSI host adapter firmware asssembler
3  *
4  * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions, and the following disclaimer,
12  *    without modification, immediately at the beginning of the file.
13  * 2. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * Alternatively, this software may be distributed under the terms of the
17  * GNU Public License ("GPL").
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33 #include <sys/types.h>
34 #include <sys/mman.h>
35 
36 #include <ctype.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sysexits.h>
41 #include <unistd.h>
42 
43 #include "aicasm.h"
44 #include "aicasm_symbol.h"
45 #include "aicasm_insformat.h"
46 
47 typedef struct patch {
48 	STAILQ_ENTRY(patch) links;
49 	int		patch_func;
50 	u_int		begin;
51 	u_int		skip_instr;
52 	u_int		skip_patch;
53 } patch_t;
54 
55 STAILQ_HEAD(patch_list, patch) patches;
56 
57 static void usage(void);
58 static void back_patch(void);
59 static void output_code(void);
60 static void output_listing(char *ifilename);
61 static void dump_scope(scope_t *scope);
62 static void emit_patch(scope_t *scope, int patch);
63 static int check_patch(patch_t **start_patch, int start_instr,
64 		       int *skip_addr, int *func_vals);
65 
66 struct path_list search_path;
67 int includes_search_curdir;
68 char *appname;
69 FILE *ofile;
70 char *ofilename;
71 char *regfilename;
72 FILE *regfile;
73 char *listfilename;
74 FILE *listfile;
75 
76 static STAILQ_HEAD(,instruction) seq_program;
77 struct scope_list scope_stack;
78 symlist_t patch_functions;
79 
80 #if DEBUG
81 extern int yy_flex_debug;
82 extern int yydebug;
83 #endif
84 extern FILE *yyin;
85 extern int yyparse __P((void));
86 
87 int
88 main(argc, argv)
89 	int argc;
90 	char *argv[];
91 {
92 	extern char *optarg;
93 	extern int optind;
94 	int  ch;
95 	int  retval;
96 	char *inputfilename;
97 	scope_t *sentinal;
98 
99 	STAILQ_INIT(&patches);
100 	SLIST_INIT(&search_path);
101 	STAILQ_INIT(&seq_program);
102 	SLIST_INIT(&scope_stack);
103 
104 	/* Set Sentinal scope node */
105 	sentinal = scope_alloc();
106 	sentinal->type = SCOPE_ROOT;
107 
108 	includes_search_curdir = 1;
109 	appname = *argv;
110 	regfile = NULL;
111 	listfile = NULL;
112 #if DEBUG
113 	yy_flex_debug = 0;
114 	yydebug = 0;
115 #endif
116 	while ((ch = getopt(argc, argv, "d:l:n:o:r:I:O:")) != -1) {
117 		switch(ch) {
118 		case 'd':
119 #if DEBUG
120 			if (strcmp(optarg, "s") == 0) {
121 				yy_flex_debug = 1;
122 			} else if (strcmp(optarg, "p") == 0) {
123 				yydebug = 1;
124 			} else {
125 				fprintf(stderr, "%s: -d Requires either an "
126 					"'s' or 'p' argument\n", appname);
127 				usage();
128 			}
129 #else
130 			stop("-d: Assembler not built with debugging "
131 			     "information", EX_SOFTWARE);
132 #endif
133 			break;
134 		case 'l':
135 			/* Create a program listing */
136 			if ((listfile = fopen(optarg, "w")) == NULL) {
137 				perror(optarg);
138 				stop(NULL, EX_CANTCREAT);
139 			}
140 			listfilename = optarg;
141 			break;
142 		case 'n':
143 			/* Don't complain about the -nostdinc directrive */
144 			if (strcmp(optarg, "ostdinc")) {
145 				fprintf(stderr, "%s: Unknown option -%c%s\n",
146 					appname, ch, optarg);
147 				usage();
148 				/* NOTREACHED */
149 			}
150 			break;
151 		case 'o':
152 			if ((ofile = fopen(optarg, "w")) == NULL) {
153 				perror(optarg);
154 				stop(NULL, EX_CANTCREAT);
155 			}
156 			ofilename = optarg;
157 			break;
158 		case 'r':
159 			if ((regfile = fopen(optarg, "w")) == NULL) {
160 				perror(optarg);
161 				stop(NULL, EX_CANTCREAT);
162 			}
163 			regfilename = optarg;
164 			break;
165 		case 'I':
166 		{
167 			path_entry_t include_dir;
168 
169 			if (strcmp(optarg, "-") == 0) {
170 				if (includes_search_curdir == 0) {
171 					fprintf(stderr, "%s: Warning - '-I-' "
172 							"specified multiple "
173 							"times\n", appname);
174 				}
175 				includes_search_curdir = 0;
176 				for (include_dir = search_path.slh_first;
177 				     include_dir != NULL;
178 				     include_dir = include_dir->links.sle_next)
179 					/*
180 					 * All entries before a '-I-' only
181 					 * apply to includes specified with
182 					 * quotes instead of "<>".
183 					 */
184 					include_dir->quoted_includes_only = 1;
185 			} else {
186 				include_dir =
187 				    (path_entry_t)malloc(sizeof(*include_dir));
188 				if (include_dir == NULL) {
189 					perror(optarg);
190 					stop(NULL, EX_OSERR);
191 				}
192 				include_dir->directory = strdup(optarg);
193 				if (include_dir->directory == NULL) {
194 					perror(optarg);
195 					stop(NULL, EX_OSERR);
196 				}
197 				include_dir->quoted_includes_only = 0;
198 				SLIST_INSERT_HEAD(&search_path, include_dir,
199 						  links);
200 			}
201 			break;
202 		}
203 		case '?':
204 		default:
205 			usage();
206 			/* NOTREACHED */
207 		}
208 	}
209 	argc -= optind;
210 	argv += optind;
211 
212 	if (argc != 1) {
213 		fprintf(stderr, "%s: No input file specifiled\n", appname);
214 		usage();
215 		/* NOTREACHED */
216 	}
217 
218 	symtable_open();
219 	inputfilename = *argv;
220 	include_file(*argv, SOURCE_FILE);
221 	retval = yyparse();
222 	if (retval == 0) {
223 		if (SLIST_FIRST(&scope_stack) == NULL
224 		 || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) {
225 			stop("Unterminated conditional expression",
226 			     EX_DATAERR);
227 			/* NOTREACHED */
228 		}
229 
230 		/* Process outmost scope */
231 		process_scope(SLIST_FIRST(&scope_stack));
232 		/*
233 		 * Decend the tree of scopes and insert/emit
234 		 * patches as appropriate.  We perform a depth first
235 		 * tranversal, recursively handling each scope.
236 		 */
237 		/* start at the root scope */
238 		dump_scope(SLIST_FIRST(&scope_stack));
239 
240 		/* Patch up forward jump addresses */
241 		back_patch();
242 
243 		if (ofile != NULL)
244 			output_code();
245 		if (regfile != NULL) {
246 			symtable_dump(regfile);
247 		}
248 		if (listfile != NULL)
249 			output_listing(inputfilename);
250 	}
251 
252 	stop(NULL, 0);
253 	/* NOTREACHED */
254 	return (0);
255 }
256 
257 static void
258 usage()
259 {
260 
261 	(void)fprintf(stderr,
262 "usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file]
263 			[-r register_output_file] [-l program_list_file]
264 			input_file\n",
265 			appname);
266 	exit(EX_USAGE);
267 }
268 
269 static void
270 back_patch()
271 {
272 	struct instruction *cur_instr;
273 
274 	for(cur_instr = seq_program.stqh_first;
275 	    cur_instr != NULL;
276 	    cur_instr = cur_instr->links.stqe_next) {
277 		if (cur_instr->patch_label != NULL) {
278 			struct ins_format3 *f3_instr;
279 			u_int address;
280 
281 			if (cur_instr->patch_label->type != LABEL) {
282 				char buf[255];
283 
284 				snprintf(buf, sizeof(buf),
285 					 "Undefined label %s",
286 					 cur_instr->patch_label->name);
287 				stop(buf, EX_DATAERR);
288 				/* NOTREACHED */
289 			}
290 			f3_instr = &cur_instr->format.format3;
291 			address = f3_instr->address;
292 			address += cur_instr->patch_label->info.linfo->address;
293 			f3_instr->address = address;
294 		}
295 	}
296 }
297 
298 static void
299 output_code()
300 {
301 	struct instruction *cur_instr;
302 	patch_t *cur_patch;
303 	symbol_node_t *cur_node;
304 	int instrcount;
305 
306 	instrcount = 0;
307 	fprintf(ofile,
308 "/*
309   * DO NOT EDIT - This file is automatically generated.
310   */\n");
311 
312 	fprintf(ofile, "static uint8_t seqprog[] = {\n");
313 	for(cur_instr = seq_program.stqh_first;
314 	    cur_instr != NULL;
315 	    cur_instr = cur_instr->links.stqe_next) {
316 
317 		fprintf(ofile, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
318 #if BYTE_ORDER == LITTLE_ENDIAN
319 			cur_instr->format.bytes[0],
320 			cur_instr->format.bytes[1],
321 			cur_instr->format.bytes[2],
322 			cur_instr->format.bytes[3]);
323 #else
324 			cur_instr->format.bytes[3],
325 			cur_instr->format.bytes[2],
326 			cur_instr->format.bytes[1],
327 			cur_instr->format.bytes[0]);
328 #endif
329 		instrcount++;
330 	}
331 	fprintf(ofile, "};\n\n");
332 
333 	/*
334 	 *  Output patch information.  Patch functions first.
335 	 */
336 	for(cur_node = SLIST_FIRST(&patch_functions);
337 	    cur_node != NULL;
338 	    cur_node = SLIST_NEXT(cur_node,links)) {
339 		fprintf(ofile,
340 "static int ahc_patch%d_func(struct ahc_softc *ahc);
341 
342 static int
343 ahc_patch%d_func(struct ahc_softc *ahc)
344 {
345 	return (%s);
346 }\n\n",
347 			cur_node->symbol->info.condinfo->func_num,
348 			cur_node->symbol->info.condinfo->func_num,
349 			cur_node->symbol->name);
350 	}
351 
352 	fprintf(ofile,
353 "typedef int patch_func_t __P((struct ahc_softc *));
354 struct patch {
355 	patch_func_t	*patch_func;
356 	uint32_t	begin	   :10,
357 			skip_instr :10,
358 			skip_patch :12;
359 } patches[] = {\n");
360 
361 	for(cur_patch = STAILQ_FIRST(&patches);
362 	    cur_patch != NULL;
363 	    cur_patch = STAILQ_NEXT(cur_patch,links)) {
364 		fprintf(ofile, "\t{ ahc_patch%d_func, %d, %d, %d },\n",
365 			cur_patch->patch_func, cur_patch->begin,
366 			cur_patch->skip_instr, cur_patch->skip_patch);
367 	}
368 
369 	fprintf(ofile, "\n};\n");
370 
371 	fprintf(stderr, "%s: %d instructions used\n", appname, instrcount);
372 }
373 
374 static void
375 dump_scope(scope_t *scope)
376 {
377 	scope_t *cur_scope;
378 
379 	/*
380 	 * Emit the first patch for this scope
381 	 */
382 	emit_patch(scope, 0);
383 
384 	/*
385 	 * Dump each scope within this one.
386 	 */
387 	cur_scope = TAILQ_FIRST(&scope->inner_scope);
388 
389 	while (cur_scope != NULL) {
390 
391 		dump_scope(cur_scope);
392 
393 		cur_scope = TAILQ_NEXT(cur_scope, scope_links);
394 	}
395 
396 	/*
397 	 * Emit the second, closing, patch for this scope
398 	 */
399 	emit_patch(scope, 1);
400 }
401 
402 void
403 emit_patch(scope_t *scope, int patch)
404 {
405 	patch_info_t *pinfo;
406 	patch_t *new_patch;
407 
408 	pinfo = &scope->patches[patch];
409 
410 	if (pinfo->skip_instr == 0)
411 		/* No-Op patch */
412 		return;
413 
414 	new_patch = (patch_t *)malloc(sizeof(*new_patch));
415 
416 	if (new_patch == NULL)
417 		stop("Could not malloc patch structure", EX_OSERR);
418 
419 	memset(new_patch, 0, sizeof(*new_patch));
420 
421 	if (patch == 0) {
422 		new_patch->patch_func = scope->func_num;
423 		new_patch->begin = scope->begin_addr;
424 	} else {
425 		new_patch->patch_func = 0;
426 		new_patch->begin = scope->end_addr;
427 	}
428 	new_patch->skip_instr = pinfo->skip_instr;
429 	new_patch->skip_patch = pinfo->skip_patch;
430 	STAILQ_INSERT_TAIL(&patches, new_patch, links);
431 }
432 
433 void
434 output_listing(char *ifilename)
435 {
436 	char buf[1024];
437 	FILE *ifile;
438 	struct instruction *cur_instr;
439 	patch_t *cur_patch;
440 	symbol_node_t *cur_func;
441 	int *func_values;
442 	int instrcount;
443 	int instrptr;
444 	int line;
445 	int func_count;
446 	int skip_addr;
447 
448 	instrcount = 0;
449 	instrptr = 0;
450 	line = 1;
451 	skip_addr = 0;
452 	if ((ifile = fopen(ifilename, "r")) == NULL) {
453 		perror(ifilename);
454 		stop(NULL, EX_DATAERR);
455 	}
456 
457 	/*
458 	 * Determine which options to apply to this listing.
459 	 */
460 	for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions);
461 	    cur_func != NULL;
462 	    cur_func = SLIST_NEXT(cur_func, links))
463 		func_count++;
464 
465 	if (func_count != 0) {
466 		func_values = (int *)malloc(func_count * sizeof(int));
467 
468 		if (func_values == NULL)
469 			stop("Could not malloc", EX_OSERR);
470 
471 		func_values[0] = 0; /* FALSE func */
472 		func_count--;
473 
474 		/*
475 		 * Ask the user to fill in the return values for
476 		 * the rest of the functions.
477 		 */
478 
479 
480 		for (cur_func = SLIST_FIRST(&patch_functions);
481 		     cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL;
482 		     cur_func = SLIST_NEXT(cur_func, links), func_count--) {
483 			int input;
484 
485 			fprintf(stdout, "\n(%s)\n", cur_func->symbol->name);
486 			fprintf(stdout,
487 				"Enter the return value for "
488 				"this expression[T/F]:");
489 
490 			while (1) {
491 
492 				input = getchar();
493 				input = toupper(input);
494 
495 				if (input == 'T') {
496 					func_values[func_count] = 1;
497 					break;
498 				} else if (input == 'F') {
499 					func_values[func_count] = 0;
500 					break;
501 				}
502 			}
503 			if (isatty(fileno(stdin)) == 0)
504 				putchar(input);
505 		}
506 		fprintf(stdout, "\nThanks!\n");
507 	}
508 
509 	/* Now output the listing */
510 	cur_patch = STAILQ_FIRST(&patches);
511 	for(cur_instr = STAILQ_FIRST(&seq_program);
512 	    cur_instr != NULL;
513 	    cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) {
514 
515 		if (check_patch(&cur_patch, instrcount,
516 				&skip_addr, func_values) == 0) {
517 			/* Don't count this instruction as it is in a patch
518 			 * that was removed.
519 			 */
520                         continue;
521 		}
522 
523 		while (line < cur_instr->srcline) {
524 			fgets(buf, sizeof(buf), ifile);
525 				fprintf(listfile, "\t\t%s", buf);
526 				line++;
527 		}
528 		fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr,
529 #if BYTE_ORDER == LITTLE_ENDIAN
530 			cur_instr->format.bytes[0],
531 			cur_instr->format.bytes[1],
532 			cur_instr->format.bytes[2],
533 			cur_instr->format.bytes[3]);
534 #else
535 			cur_instr->format.bytes[3],
536 			cur_instr->format.bytes[2],
537 			cur_instr->format.bytes[1],
538 			cur_instr->format.bytes[0]);
539 #endif
540 		fgets(buf, sizeof(buf), ifile);
541 		fprintf(listfile, "\t%s", buf);
542 		line++;
543 		instrptr++;
544 	}
545 	/* Dump the remainder of the file */
546 	while(fgets(buf, sizeof(buf), ifile) != NULL)
547 		fprintf(listfile, "\t\t%s", buf);
548 
549 	fclose(ifile);
550 }
551 
552 static int
553 check_patch(patch_t **start_patch, int start_instr,
554 	    int *skip_addr, int *func_vals)
555 {
556 	patch_t *cur_patch;
557 
558 	cur_patch = *start_patch;
559 
560 	while (cur_patch != NULL && start_instr == cur_patch->begin) {
561 		if (func_vals[cur_patch->patch_func] == 0) {
562 			int skip;
563 
564 			/* Start rejecting code */
565 			*skip_addr = start_instr + cur_patch->skip_instr;
566 			for (skip = cur_patch->skip_patch;
567 			     skip > 0 && cur_patch != NULL;
568 			     skip--)
569 				cur_patch = STAILQ_NEXT(cur_patch, links);
570 		} else {
571 			/* Accepted this patch.  Advance to the next
572 			 * one and wait for our intruction pointer to
573 			 * hit this point.
574 			 */
575 			cur_patch = STAILQ_NEXT(cur_patch, links);
576 		}
577 	}
578 
579 	*start_patch = cur_patch;
580 	if (start_instr < *skip_addr)
581 		/* Still skipping */
582 		return (0);
583 
584 	return (1);
585 }
586 
587 /*
588  * Print out error information if appropriate, and clean up before
589  * terminating the program.
590  */
591 void
592 stop(string, err_code)
593 	const char *string;
594 	int  err_code;
595 {
596 	if (string != NULL) {
597 		fprintf(stderr, "%s: ", appname);
598 		if (yyfilename != NULL) {
599 			fprintf(stderr, "Stopped at file %s, line %d - ",
600 				yyfilename, yylineno);
601 		}
602 		fprintf(stderr, "%s\n", string);
603 	}
604 
605 	if (ofile != NULL) {
606 		fclose(ofile);
607 		if (err_code != 0) {
608 			fprintf(stderr, "%s: Removing %s due to error\n",
609 				appname, ofilename);
610 			unlink(ofilename);
611 		}
612 	}
613 
614 	if (regfile != NULL) {
615 		fclose(regfile);
616 		if (err_code != 0) {
617 			fprintf(stderr, "%s: Removing %s due to error\n",
618 				appname, regfilename);
619 			unlink(regfilename);
620 		}
621 	}
622 
623 	if (listfile != NULL) {
624 		fclose(listfile);
625 		if (err_code != 0) {
626 			fprintf(stderr, "%s: Removing %s due to error\n",
627 				appname, listfilename);
628 			unlink(listfilename);
629 		}
630 	}
631 
632 	symlist_free(&patch_functions);
633 	symtable_close();
634 
635 	exit(err_code);
636 }
637 
638 struct instruction *
639 seq_alloc()
640 {
641 	struct instruction *new_instr;
642 
643 	new_instr = (struct instruction *)malloc(sizeof(struct instruction));
644 	if (new_instr == NULL)
645 		stop("Unable to malloc instruction object", EX_SOFTWARE);
646 	memset(new_instr, 0, sizeof(*new_instr));
647 	STAILQ_INSERT_TAIL(&seq_program, new_instr, links);
648 	new_instr->srcline = yylineno;
649 	return new_instr;
650 }
651 
652 scope_t *
653 scope_alloc()
654 {
655 	scope_t *new_scope;
656 
657 	new_scope = (scope_t *)malloc(sizeof(scope_t));
658 	if (new_scope == NULL)
659 		stop("Unable to malloc scope object", EX_SOFTWARE);
660 	memset(new_scope, 0, sizeof(*new_scope));
661 	TAILQ_INIT(&new_scope->inner_scope);
662 
663 	if (SLIST_FIRST(&scope_stack) != NULL) {
664 		TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope,
665 				  new_scope, scope_links);
666 	}
667 	/* This patch is now the current scope */
668 	SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links);
669 	return new_scope;
670 }
671 
672 void
673 process_scope(scope_t *scope)
674 {
675 	/*
676 	 * We are "leaving" this scope.  We should now have
677 	 * enough information to process the lists of scopes
678 	 * we encapsulate.
679 	 */
680 	scope_t *cur_scope;
681 	u_int skip_patch_count;
682 	u_int skip_instr_count;
683 
684 	cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq);
685 	skip_patch_count = 0;
686 	skip_instr_count = 0;
687 	while (cur_scope != NULL) {
688 		u_int patch0_patch_skip;
689 
690 		patch0_patch_skip = 0;
691 		switch (cur_scope->type) {
692 		case SCOPE_IF:
693 		case SCOPE_ELSE_IF:
694 			if (skip_instr_count != 0) {
695 				/* Create a tail patch */
696 				patch0_patch_skip++;
697 				cur_scope->patches[1].skip_patch =
698 				    skip_patch_count + 1;
699 				cur_scope->patches[1].skip_instr =
700 				    skip_instr_count;
701 			}
702 
703 			/* Count Head patch */
704 			patch0_patch_skip++;
705 
706 			/* Count any patches contained in our inner scope */
707 			patch0_patch_skip += cur_scope->inner_scope_patches;
708 
709 			cur_scope->patches[0].skip_patch = patch0_patch_skip;
710 			cur_scope->patches[0].skip_instr =
711 			    cur_scope->end_addr - cur_scope->begin_addr;
712 
713 			skip_instr_count += cur_scope->patches[0].skip_instr;
714 
715 			skip_patch_count += patch0_patch_skip;
716 			if (cur_scope->type == SCOPE_IF) {
717 				scope->inner_scope_patches += skip_patch_count;
718 				skip_patch_count = 0;
719 			        skip_instr_count = 0;
720 			}
721 			break;
722 		case SCOPE_ELSE:
723 			/* Count any patches contained in our innter scope */
724 			skip_patch_count += cur_scope->inner_scope_patches;
725 
726 			skip_instr_count += cur_scope->end_addr
727 					  - cur_scope->begin_addr;
728 			break;
729 		case SCOPE_ROOT:
730 			stop("Unexpected scope type encountered", EX_SOFTWARE);
731 			/* NOTREACHED */
732 		}
733 
734 		cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links);
735 	}
736 }
737