main.c revision 100014
11590Srgrimes/*	$OpenBSD: main.c,v 1.53 2002/04/26 16:15:16 espie Exp $	*/
21590Srgrimes/*	$NetBSD: main.c,v 1.12 1997/02/08 23:54:49 cgd Exp $	*/
31590Srgrimes
41590Srgrimes/*-
51590Srgrimes * Copyright (c) 1989, 1993
61590Srgrimes *	The Regents of the University of California.  All rights reserved.
71590Srgrimes *
81590Srgrimes * This code is derived from software contributed to Berkeley by
91590Srgrimes * Ozan Yigit at York University.
101590Srgrimes *
111590Srgrimes * Redistribution and use in source and binary forms, with or without
121590Srgrimes * modification, are permitted provided that the following conditions
131590Srgrimes * are met:
141590Srgrimes * 1. Redistributions of source code must retain the above copyright
151590Srgrimes *    notice, this list of conditions and the following disclaimer.
161590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171590Srgrimes *    notice, this list of conditions and the following disclaimer in the
181590Srgrimes *    documentation and/or other materials provided with the distribution.
191590Srgrimes * 3. All advertising materials mentioning features or use of this software
201590Srgrimes *    must display the following acknowledgement:
211590Srgrimes *	This product includes software developed by the University of
221590Srgrimes *	California, Berkeley and its contributors.
231590Srgrimes * 4. Neither the name of the University nor the names of its contributors
241590Srgrimes *    may be used to endorse or promote products derived from this software
251590Srgrimes *    without specific prior written permission.
261590Srgrimes *
271590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
281590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
291590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
301590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
311590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
321590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
331590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3428503Scharnier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
351590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
361590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
371590Srgrimes * SUCH DAMAGE.
381590Srgrimes */
391590Srgrimes
4028503Scharnier#ifndef lint
4123690Speterstatic char copyright[] =
4228503Scharnier"@(#) Copyright (c) 1989, 1993\n\
4328503Scharnier	The Regents of the University of California.  All rights reserved.\n";
4450477Speter#endif /* not lint */
451590Srgrimes
461590Srgrimes#ifndef lint
47280250Srwatson#if 0
48253457Spjdstatic char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/6/93";
4928503Scharnier#else
5028503Scharnier#if 0
51253457Spjdstatic char rcsid[] = "$OpenBSD: main.c,v 1.53 2002/04/26 16:15:16 espie Exp $";
5252455Sache#endif
5334323Sache#endif
54253457Spjd#endif /* not lint */
55200633Sjh
56204876Sache#include <sys/cdefs.h>
571590Srgrimes__FBSDID("$FreeBSD: head/usr.bin/m4/main.c 100014 2002-07-15 02:15:12Z jmallett $");
581590Srgrimes
591590Srgrimes/*
60253457Spjd * main.c
6123690Speter * Facility: m4 macro processor
62131502Stjr * by: oz
63131502Stjr */
641590Srgrimes
65227193Sed#include <sys/types.h>
66227193Sed#include <assert.h>
671590Srgrimes#include <signal.h>
68227193Sed#include <errno.h>
69227193Sed#include <unistd.h>
70227193Sed#include <stdio.h>
71227193Sed#include <ctype.h>
72227193Sed#include <string.h>
73227193Sed#include <stddef.h>
7492922Simp#include <stdlib.h>
751590Srgrimes#include <err.h>
76253457Spjd#include "mdef.h"
77253457Spjd#include "stdd.h"
78253457Spjd#include "extern.h"
79253457Spjd#include "pathnames.h"
80253457Spjd
81253457Spjdndptr hashtab[HASHSIZE];	/* hash table for macros etc.  */
82253457Spjdstae *mstack;		 	/* stack of m4 machine         */
83253457Spjdchar *sstack;		 	/* shadow stack, for string space extension */
84253457Spjdstatic size_t STACKMAX;		/* current maximum size of stack */
85253457Spjdint sp; 			/* current m4  stack pointer   */
86253457Spjdint fp; 			/* m4 call frame pointer       */
871590Srgrimesstruct input_file infile[MAXINP];/* input file stack (0=stdin)  */
88102944Sdwmalonechar *inname[MAXINP];		/* names of these input files */
891590Srgrimesint inlineno[MAXINP];		/* current number in each input file */
90204876SacheFILE **outfile;			/* diversion array(0=bitbucket)*/
911590Srgrimesint maxout;
92204803SacheFILE *active;			/* active output file pointer  */
93204876Sacheint ilevel = 0; 		/* input file stack pointer    */
94204803Sacheint oindex = 0; 		/* diversion index..	       */
95131502Stjrconst char *null = "";          /* as it says.. just a null..  */
96253457Spjdconst char *m4wraps = "";       /* m4wrap string default..     */
971590Srgrimeschar lquote[MAXCCHARS+1] = {LQUOTE};	/* left quote character  (`)   */
9895030Sachechar rquote[MAXCCHARS+1] = {RQUOTE};	/* right quote character (')   */
9934323Sachechar scommt[MAXCCHARS+1] = {SCOMMT};	/* start character for comment */
1001590Srgrimeschar ecommt[MAXCCHARS+1] = {ECOMMT};	/* end character for comment   */
10197527Stjrint synccpp;			/* Line synchronisation for C preprocessor */
1021590Srgrimes
1031590Srgrimesstruct keyblk keywrds[] = {	/* m4 keywords to be installed */
1041590Srgrimes	{ "include",      INCLTYPE },
1051590Srgrimes	{ "sinclude",     SINCTYPE },
1061590Srgrimes	{ "define",       DEFITYPE },
1071590Srgrimes	{ "defn",         DEFNTYPE },
1081590Srgrimes	{ "divert",       DIVRTYPE | NOARGS },
10929207Sjoerg	{ "expr",         EXPRTYPE },
11029207Sjoerg	{ "eval",         EXPRTYPE },
11129207Sjoerg	{ "substr",       SUBSTYPE },
1121590Srgrimes	{ "ifelse",       IFELTYPE },
1131590Srgrimes	{ "ifdef",        IFDFTYPE },
1141590Srgrimes	{ "len",          LENGTYPE },
11528503Scharnier	{ "incr",         INCRTYPE },
1161590Srgrimes	{ "decr",         DECRTYPE },
1171590Srgrimes	{ "dnl",          DNLNTYPE | NOARGS },
1181590Srgrimes	{ "changequote",  CHNQTYPE | NOARGS },
1191590Srgrimes	{ "changecom",    CHNCTYPE | NOARGS },
12028503Scharnier	{ "index",        INDXTYPE },
1211590Srgrimes#ifdef EXTENDED
1221590Srgrimes	{ "paste",        PASTTYPE },
1231590Srgrimes	{ "spaste",       SPASTYPE },
1241590Srgrimes    	/* Newer extensions, needed to handle gnu-m4 scripts */
1251590Srgrimes	{ "indir",        INDIRTYPE},
1261590Srgrimes	{ "builtin",      BUILTINTYPE},
1271590Srgrimes	{ "patsubst",	  PATSTYPE},
128169636Sjmallett	{ "regexp",	  REGEXPTYPE},
1291590Srgrimes	{ "esyscmd",	  ESYSCMDTYPE},
13097527Stjr	{ "__file__",	  FILENAMETYPE | NOARGS},
131169638Sjmallett	{ "__line__",	  LINETYPE | NOARGS},
1321590Srgrimes#endif
1331590Srgrimes	{ "popdef",       POPDTYPE },
1341590Srgrimes	{ "pushdef",      PUSDTYPE },
1351590Srgrimes	{ "dumpdef",      DUMPTYPE | NOARGS },
1361590Srgrimes	{ "shift",        SHIFTYPE | NOARGS },
1371590Srgrimes	{ "translit",     TRNLTYPE },
1381590Srgrimes	{ "undefine",     UNDFTYPE },
1391590Srgrimes	{ "undivert",     UNDVTYPE | NOARGS },
14097529Stjr	{ "divnum",       DIVNTYPE | NOARGS },
14197529Stjr	{ "maketemp",     MKTMTYPE },
14297529Stjr	{ "errprint",     ERRPTYPE | NOARGS },
14397529Stjr	{ "m4wrap",       M4WRTYPE | NOARGS },
144131502Stjr	{ "m4exit",       EXITTYPE | NOARGS },
14597529Stjr	{ "syscmd",       SYSCTYPE },
14697529Stjr	{ "sysval",       SYSVTYPE | NOARGS },
147131502Stjr	{ "traceon",	  TRACEONTYPE | NOARGS },
148255219Spjd	{ "traceoff",	  TRACEOFFTYPE | NOARGS },
149255219Spjd
150253457Spjd#if defined(unix) || defined(__unix__)
151255219Spjd	{ "unix",         SELFTYPE | NOARGS },
15297529Stjr#else
1531590Srgrimes#ifdef vms
154253457Spjd	{ "vms",          SELFTYPE | NOARGS },
155255219Spjd#endif
156255219Spjd#endif
157253457Spjd};
158253457Spjd
159253457Spjd#define MAXKEYS	(sizeof(keywrds)/sizeof(struct keyblk))
160255219Spjd
161253457Spjd#define MAXRECORD 50
1621590Srgrimesstatic struct position {
163253457Spjd	char *name;
164253457Spjd	unsigned long line;
165253457Spjd} quotes[MAXRECORD], paren[MAXRECORD];
166253457Spjd
167253457Spjdstatic void record(struct position *, int);
168253457Spjdstatic void dump_stack(struct position *, int);
169253457Spjd
170253457Spjdstatic void macro(void);
171253457Spjdstatic void initkwds(void);
172253457Spjdstatic ndptr inspect(int, char *);
173253457Spjdstatic int do_look_ahead(int, const char *);
174253457Spjd
175253457Spjdstatic void enlarge_stack(void);
176204876Sache
177204876Sacheint
1781590Srgrimesmain(int argc, char *argv[])
179204876Sache{
180169639Sjmallett	int c;
181169638Sjmallett	int n;
1821590Srgrimes	int rval;
183131502Stjr	char *p;
184204876Sache
185204803Sache	traceout = stderr;
18699433Stjr
18799433Stjr	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1881590Srgrimes		signal(SIGINT, onintr);
189204876Sache
190204876Sache	initkwds();
191204876Sache	initspaces();
192204876Sache	STACKMAX = INITSTACKMAX;
193204876Sache
1941590Srgrimes	mstack = (stae *)xalloc(sizeof(stae) * STACKMAX);
195204803Sache	sstack = (char *)xalloc(STACKMAX);
196204876Sache
197204803Sache	maxout = 0;
198204803Sache	outfile = NULL;
19929207Sjoerg	resizedivs(MAXOUT);
200204803Sache
20129207Sjoerg	while ((c = getopt(argc, argv, "gst:d:D:U:o:I:")) != -1)
20229207Sjoerg		switch(c) {
203204803Sache		case 'D':               /* define something..*/
20499433Stjr			for (p = optarg; *p; p++)
20599433Stjr				if (*p == '=')
206204803Sache					break;
207204876Sache			if (*p)
2081590Srgrimes				*p++ = EOS;
209204876Sache			dodefine(optarg, p);
210204876Sache			break;
211204876Sache		case 'I':
212204803Sache			addtoincludepath(optarg);
21399433Stjr			break;
21499433Stjr		case 'U':               /* undefine...       */
215204803Sache			remhash(optarg, TOP);
216204876Sache			break;
217204876Sache		case 'g':
2181590Srgrimes			mimic_gnu = 1;
2191590Srgrimes			break;
2201590Srgrimes		case 'd':
2211590Srgrimes			set_trace_flags(optarg);
222131502Stjr			break;
223169638Sjmallett		case 's':
22499433Stjr			synccpp = 1;
22599433Stjr			break;
2261590Srgrimes		case 't':
2271590Srgrimes			mark_traced(optarg, 1);
2281590Srgrimes			break;
229227193Sed		case 'o':
230204876Sache			trace_file(optarg);
23198545Stjr                        break;
232204876Sache		case '?':
233204876Sache		default:
23498545Stjr			usage();
235204876Sache		}
236204876Sache
237204927Sache        argc -= optind;
238204927Sache        argv += optind;
239204876Sache
240204876Sache	rval = 0;
241204876Sache	active = stdout;		/* default active output     */
242204876Sache	bbase[0] = bufbase;
243204876Sache        if (!argc) {
244204876Sache 		sp = -1;		/* stack pointer initialized */
245204876Sache		fp = 0; 		/* frame pointer initialized */
246204876Sache		set_input(infile+0, stdin, "stdin");
247204876Sache					/* default input (naturally) */
248204876Sache		if ((inname[0] = strdup("-")) == NULL)
249204876Sache			err(1, NULL);
250204876Sache		inlineno[0] = 1;
251204876Sache		emitline();
252204876Sache		macro();
253204876Sache	} else
254204876Sache		for (; argc--; ++argv) {
255204876Sache			p = *argv;
256204876Sache			if (p[0] == '-' && p[1] == EOS)
257204876Sache				set_input(infile, stdin, "stdin");
258176119Sghelmer			else if (fopen_trypath(infile, p) == NULL) {
25998545Stjr				warn("%s", p);
260204876Sache				rval = 1;
26198545Stjr				continue;
26298545Stjr			}
263227193Sed			sp = -1;
264204876Sache			fp = 0;
265204803Sache			if ((inname[0] = strdup(p)) == NULL)
266204876Sache				err(1, NULL);
267204803Sache			inlineno[0] = 1;
268204876Sache			emitline();
269204876Sache			macro();
270204876Sache		    	release_input(infile);
271204876Sache		}
272204876Sache
273204876Sache	if (*m4wraps) { 		/* anything for rundown ??   */
274204876Sache		ilevel = 0;		/* in case m4wrap includes.. */
275204876Sache		bufbase = bp = buf;	/* use the entire buffer   */
276204876Sache		pbstr(m4wraps); 	/* user-defined wrapup act   */
277204876Sache		macro();		/* last will and testament   */
278204876Sache	}
279204803Sache
280204803Sache	if (active != stdout)
2811590Srgrimes		active = stdout;	/* reset output just in case */
2821590Srgrimes	for (n = 1; n < maxout; n++)	/* default wrap-up: undivert */
2831590Srgrimes		if (outfile[n] != NULL)
2841590Srgrimes			getdiv(n);
2851590Srgrimes					/* remove bitbucket if used  */
286227193Sed	if (outfile[0] != NULL) {
287204803Sache		(void) fclose(outfile[0]);
2881590Srgrimes	}
28923690Speter
290135214Stjr	exit(rval);
291204876Sache}
29228503Scharnier
293204876Sache/*
2941590Srgrimes * Look ahead for `token'.
2951590Srgrimes * (on input `t == token[0]')
296227193Sed * Used for comment and quoting delimiters.
297131502Stjr * Returns 1 if `token' present; copied to output.
2981590Srgrimes *         0 if `token' not found; all characters pushed back
299102944Sdwmalone */
3001590Srgrimesstatic int
301204803Sachedo_look_ahead(int t, const char *token)
302131502Stjr{
30398547Stjr	int i;
304204803Sache
30598547Stjr	assert((unsigned char)t == (unsigned char)token[0]);
30698547Stjr
307204803Sache	for (i = 1; *++token; i++) {
308204803Sache		t = gpbc();
3091590Srgrimes		if (t == EOF || (unsigned char)t != (unsigned char)*token) {
3101590Srgrimes			putback(t);
3111590Srgrimes			while (--i)
312227193Sed				putback(*--token);
313102944Sdwmalone			return 0;
3141590Srgrimes		}
3151590Srgrimes	}
3161590Srgrimes	return 1;
3171590Srgrimes}
31828503Scharnier
3191590Srgrimes#define LOOK_AHEAD(t, token) (t != EOF && 		\
3201590Srgrimes    (unsigned char)(t)==(unsigned char)(token)[0] && 	\
3211590Srgrimes    do_look_ahead(t,token))
322227193Sed
323102944Sdwmalone/*
3241590Srgrimes * macro - the work horse..
3251590Srgrimes */
3261590Srgrimesstatic void
3271590Srgrimesmacro(void)
32828503Scharnier{
3291590Srgrimes	char token[MAXTOK+1];
3301590Srgrimes	int t, l;
3311590Srgrimes	ndptr p;
3321590Srgrimes	int  nlpar;
3331590Srgrimes
3341590Srgrimes	cycle {
33534323Sache		t = gpbc();
3361590Srgrimes		if (t == '_' || isalpha(t)) {
3371590Srgrimes			p = inspect(t, token);
3381590Srgrimes			if (p != nil)
3391590Srgrimes				putback(l = gpbc());
3401590Srgrimes			if (p == nil || (l != LPAREN &&
3411590Srgrimes			    (p->type & NEEDARGS) != 0))
3421590Srgrimes				outputstr(token);
34399433Stjr			else {
3441590Srgrimes		/*
3451590Srgrimes		 * real thing.. First build a call frame:
3461590Srgrimes		 */
3471590Srgrimes				pushf(fp);	/* previous call frm */
3481590Srgrimes				pushf(p->type); /* type of the call  */
3491590Srgrimes				pushf(0);	/* parenthesis level */
3501590Srgrimes				fp = sp;	/* new frame pointer */
35128503Scharnier		/*
352102944Sdwmalone		 * now push the string arguments:
3531590Srgrimes		 */
3541590Srgrimes				pushs1(p->defn);	/* defn string */
35597905Stjr				pushs1(p->name);	/* macro name  */
3561590Srgrimes				pushs(ep);	      	/* start next..*/
3571590Srgrimes
358				if (l != LPAREN && PARLEV == 0)  {
359				    /* no bracks  */
360					chrsave(EOS);
361
362					if ((uintptr_t)sp == STACKMAX)
363						errx(1, "internal stack overflow");
364					eval((const char **) mstack+fp+1, 2,
365					    CALTYP);
366
367					ep = PREVEP;	/* flush strspace */
368					sp = PREVSP;	/* previous sp..  */
369					fp = PREVFP;	/* rewind stack...*/
370				}
371			}
372		} else if (t == EOF) {
373			if (sp > -1) {
374				warnx( "unexpected end of input, unclosed parenthesis:");
375				dump_stack(paren, PARLEV);
376				exit(1);
377			}
378			if (ilevel <= 0)
379				break;			/* all done thanks.. */
380			release_input(infile+ilevel--);
381			free(inname[ilevel+1]);
382			bufbase = bbase[ilevel];
383			emitline();
384			continue;
385		}
386	/*
387	 * non-alpha token possibly seen..
388	 * [the order of else if .. stmts is important.]
389	 */
390		else if (LOOK_AHEAD(t,lquote)) {	/* strip quotes */
391			nlpar = 0;
392			record(quotes, nlpar++);
393			/*
394			 * Opening quote: scan forward until matching
395			 * closing quote has been found.
396			 */
397			do {
398
399				l = gpbc();
400				if (LOOK_AHEAD(l,rquote)) {
401					if (--nlpar > 0)
402						outputstr(rquote);
403				} else if (LOOK_AHEAD(l,lquote)) {
404					record(quotes, nlpar++);
405					outputstr(lquote);
406				} else if (l == EOF) {
407					if (nlpar == 1)
408						warnx("unclosed quote:");
409					else
410						warnx("%d unclosed quotes:", nlpar);
411					dump_stack(quotes, nlpar);
412					exit(1);
413				} else {
414					if (nlpar > 0) {
415						if (sp < 0)
416							putc(l, active);
417						else
418							CHRSAVE(l);
419					}
420				}
421			}
422			while (nlpar != 0);
423		}
424
425		else if (sp < 0 && LOOK_AHEAD(t, scommt)) {
426			fputs(scommt, active);
427
428			for(;;) {
429				t = gpbc();
430				if (LOOK_AHEAD(t, ecommt)) {
431					fputs(ecommt, active);
432					break;
433				}
434				if (t == EOF)
435					break;
436				putc(t, active);
437			}
438		}
439
440		else if (sp < 0) {		/* not in a macro at all */
441			putc(t, active);	/* output directly..	 */
442		}
443
444		else switch(t) {
445
446		case LPAREN:
447			if (PARLEV > 0)
448				chrsave(t);
449			while (isspace(l = gpbc()))
450				;		/* skip blank, tab, nl.. */
451			putback(l);
452			record(paren, PARLEV++);
453			break;
454
455		case RPAREN:
456			if (--PARLEV > 0)
457				chrsave(t);
458			else {			/* end of argument list */
459				chrsave(EOS);
460
461				if ((uintptr_t)sp == STACKMAX)
462					errx(1, "internal stack overflow");
463
464				eval((const char **) mstack+fp+1, sp-fp,
465				    CALTYP);
466
467				ep = PREVEP;	/* flush strspace */
468				sp = PREVSP;	/* previous sp..  */
469				fp = PREVFP;	/* rewind stack...*/
470			}
471			break;
472
473		case COMMA:
474			if (PARLEV == 1) {
475				chrsave(EOS);		/* new argument   */
476				while (isspace(l = gpbc()))
477					;
478				putback(l);
479				pushs(ep);
480			} else
481				chrsave(t);
482			break;
483
484		default:
485			if (LOOK_AHEAD(t, scommt)) {
486				char *pc;
487				for (pc = scommt; *pc; pc++)
488					chrsave(*pc);
489				for(;;) {
490					t = gpbc();
491					if (LOOK_AHEAD(t, ecommt)) {
492						for (pc = ecommt; *pc; pc++)
493							chrsave(*pc);
494						break;
495					}
496					if (t == EOF)
497					    break;
498					CHRSAVE(t);
499				}
500			} else
501				CHRSAVE(t);		/* stack the char */
502			break;
503		}
504	}
505}
506
507/*
508 * output string directly, without pushing it for reparses.
509 */
510void
511outputstr(const char *s)
512{
513	if (sp < 0)
514		while (*s)
515			putc(*s++, active);
516	else
517		while (*s)
518			CHRSAVE(*s++);
519}
520
521/*
522 * build an input token..
523 * consider only those starting with _ or A-Za-z. This is a
524 * combo with lookup to speed things up.
525 */
526static ndptr
527inspect(int c, char *tp)
528{
529	char *name = tp;
530	char *etp = tp+MAXTOK;
531	ndptr p;
532	unsigned int h;
533
534	h = *tp++ = c;
535
536	while ((isalnum(c = gpbc()) || c == '_') && tp < etp)
537		h = (h << 5) + h + (*tp++ = c);
538	if (c != EOF)
539		PUTBACK(c);
540	*tp = EOS;
541	/* token is too long, it won't match anything, but it can still
542	 * be output. */
543	if (tp == ep) {
544		outputstr(name);
545		while (isalnum(c = gpbc()) || c == '_') {
546			if (sp < 0)
547				putc(c, active);
548			else
549				CHRSAVE(c);
550		}
551		*name = EOS;
552		return nil;
553	}
554
555	for (p = hashtab[h % HASHSIZE]; p != nil; p = p->nxtptr)
556		if (h == p->hv && STREQ(name, p->name))
557			break;
558	return p;
559}
560
561/*
562 * initkwds - initialise m4 keywords as fast as possible.
563 * This very similar to install, but without certain overheads,
564 * such as calling lookup. Malloc is not used for storing the
565 * keyword strings, since we simply use the static pointers
566 * within keywrds block.
567 */
568static void
569initkwds(void)
570{
571	size_t i;
572	unsigned int h;
573	ndptr p;
574
575	for (i = 0; i < MAXKEYS; i++) {
576		h = hash(keywrds[i].knam);
577		p = (ndptr) xalloc(sizeof(struct ndblock));
578		p->nxtptr = hashtab[h % HASHSIZE];
579		hashtab[h % HASHSIZE] = p;
580		p->name = xstrdup(keywrds[i].knam);
581		p->defn = xstrdup(null);
582		p->hv = h;
583		p->type = keywrds[i].ktyp & TYPEMASK;
584		if ((keywrds[i].ktyp & NOARGS) == 0)
585			p->type |= NEEDARGS;
586	}
587}
588
589/* Look up a builtin type, even if overridden by the user */
590int
591builtin_type(const char *key)
592{
593	int i;
594
595	for (i = 0; i != MAXKEYS; i++)
596		if (STREQ(keywrds[i].knam, key))
597			return keywrds[i].ktyp;
598	return -1;
599}
600
601const char *
602builtin_realname(int n)
603{
604	int i;
605
606	for (i = 0; i != MAXKEYS; i++)
607		if (((keywrds[i].ktyp ^ n) & TYPEMASK) == 0)
608			return keywrds[i].knam;
609	return NULL;
610}
611
612static void
613record(struct position *t, int lev)
614{
615	if (lev < MAXRECORD) {
616		t[lev].name = CURRENT_NAME;
617		t[lev].line = CURRENT_LINE;
618	}
619}
620
621static void
622dump_stack(struct position *t, int lev)
623{
624	int i;
625
626	for (i = 0; i < lev; i++) {
627		if (i == MAXRECORD) {
628			fprintf(stderr, "   ...\n");
629			break;
630		}
631		fprintf(stderr, "   %s at line %lu\n",
632			t[i].name, t[i].line);
633	}
634}
635
636
637static void
638enlarge_stack(void)
639{
640	STACKMAX *= 2;
641	mstack = realloc(mstack, sizeof(stae) * STACKMAX);
642	sstack = realloc(sstack, STACKMAX);
643	if (mstack == NULL || sstack == NULL)
644		errx(1, "Evaluation stack overflow (%lu)",
645		    (unsigned long)STACKMAX);
646}
647
648/* Emit preprocessor #line directive if -s option used. */
649void
650emitline(void)
651{
652
653	if (synccpp)
654		fprintf(active, "#line %d \"%s\"\n", inlineno[ilevel],
655			inname[ilevel]);
656}
657