1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1986-2009 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                                                                      *
19***********************************************************************/
20#pragma prototyped
21/*
22 * Glenn Fowler
23 * AT&T Research
24 *
25 * preprocessor library private definitions
26 */
27
28#ifndef _PPLIB_H
29#define _PPLIB_H
30
31/*
32 * the first definitions control optional code -- 0 disables
33 */
34
35#ifndef ARCHIVE
36#define ARCHIVE		1	/* -I can specify header archives	*/
37#endif
38#ifndef CATSTRINGS
39#define CATSTRINGS	1	/* concatenate adjacent strings		*/
40#endif
41#ifndef CHECKPOINT
42#define CHECKPOINT	1	/* checkpoint preprocessed files	*/
43#endif
44#ifndef COMPATIBLE
45#define COMPATIBLE	1	/* enable COMPATIBILITY related code	*/
46#endif
47#ifndef MACKEYARGS
48#define MACKEYARGS 	_BLD_DEBUG /* name=value macro formals and actuals */
49#endif
50#ifndef POOL
51#define POOL		1	/* enable loop on input,output,error	*/
52#endif
53#ifndef PROTOTYPE
54#define PROTOTYPE	1	/* enable ppproto code			*/
55#endif
56
57#define TRUNCLENGTH	8	/* default TRUNCATE length		*/
58
59#if _BLD_DEBUG
60#undef	DEBUG
61#define DEBUG		(TRACE_message|TRACE_count|TRACE_debug)
62#else
63#ifndef DEBUG
64#define DEBUG		(TRACE_message)
65#endif
66#endif
67
68/*
69 * the lower tests are transient
70 */
71
72#define TEST_count		(1L<<24)
73#define TEST_hashcount		(1L<<25)
74#define TEST_hashdump		(1L<<26)
75#define TEST_hit		(1L<<27)
76#define TEST_noinit		(1L<<28)
77#define TEST_nonoise		(1L<<29)
78#define TEST_noproto		(1L<<30)
79
80#define TEST_INVERT		(1L<<31)
81
82#define PROTO_CLASSIC		(1<<0)	/* classic to prototyped	*/
83#define PROTO_DISABLE		(1<<1)	/* disable conversion		*/
84#define PROTO_EXTERNALIZE	(1<<2)	/* static fun() => extern fun()	*/
85#define PROTO_FORCE		(1<<3)	/* force even if no magic	*/
86#define PROTO_HEADER		(1<<4)	/* header defines too		*/
87#define PROTO_INCLUDE		(1<<5)	/* <prototyped.h> instead	*/
88#define PROTO_INITIALIZED	(1<<6)	/* internal initialization	*/
89#define PROTO_LINESYNC		(1<<7)	/* force standalone line syncs	*/
90#define PROTO_NOPRAGMA		(1<<8)	/* delete pragma prototyped	*/
91#define PROTO_PASS		(1<<9)	/* pass blocks if no magic	*/
92#define PROTO_PLUSPLUS		(1<<10)	/* extern () -> extern (...)	*/
93#define PROTO_RETAIN		(1<<11)	/* defines retained after close	*/
94#define PROTO_TEST		(1<<12)	/* enable test code		*/
95
96#define PROTO_USER		(1<<13)	/* first user flag		*/
97
98#define SEARCH_EXISTS		0	/* ppsearch for existence	*/
99#define SEARCH_HOSTED		(1<<0)	/* search hosted dirs only	*/
100#define SEARCH_IGNORE		(1<<1)	/* ignore if not found		*/
101#define SEARCH_INCLUDE		(1<<2)	/* ppsearch for include		*/
102#define SEARCH_VENDOR		(1<<3)	/* search vendor dirs only	*/
103#define SEARCH_USER		(1<<4)	/* first user flag		*/
104
105#define STYLE_gnu		(1<<0)	/* gnu style args		*/
106
107#define IN_c			(1<<0)	/* C language file		*/
108#define IN_defguard		(1<<1)	/* did multiple include check	*/
109#define IN_disable		(1<<2)	/* saved state&DISABLE		*/
110#define IN_endguard		(1<<3)	/* did multiple include check	*/
111#define IN_eof			(1<<4)	/* reached EOF			*/
112#define IN_expand		(1<<5)	/* ppexpand buffer		*/
113#define IN_flush		(1<<6)	/* flush stdout on file_refill()*/
114#define IN_hosted		(1<<7)	/* saved mode&HOSTED		*/
115#define IN_ignoreline		(1<<8)	/* ignore #line until file	*/
116#define IN_newline		(1<<9)	/* newline at end of last fill	*/
117#define IN_noguard		(1<<10)	/* no multiple include guard	*/
118#define IN_prototype		(1<<11)	/* ppproto() input		*/
119#define IN_regular		(1<<12)	/* regular input file		*/
120#define IN_static		(1<<13)	/* static buffer - don't free	*/
121#define IN_sync			(1<<14)	/* line sync required on pop	*/
122#define IN_tokens		(1L<<15)/* non-space tokens encountered	*/
123
124#define OPT_GLOBAL		(1<<0)	/* pp: pass optional		*/
125#define OPT_PASS		(1<<1)	/* pass on			*/
126
127struct ppsymbol;
128struct ppindex;
129
130typedef char*	(*PPBUILTIN)(char*, const char*, const char*);
131typedef void	(*PPCOMMENT)(const char*, const char*, const char*, int);
132typedef void	(*PPINCREF)(const char*, const char*, int, int);
133typedef void	(*PPLINESYNC)(int, const char*);
134typedef void	(*PPMACREF)(struct ppsymbol*, const char*, int, int, unsigned long);
135typedef int	(*PPOPTARG)(int, int, const char*);
136typedef void	(*PPPRAGMA)(const char*, const char*, const char*, const char*, int);
137
138struct ppinstk				/* input stream stack frame	*/
139{
140	char*		nextchr;	/* next input char (first elt)	*/
141	struct ppinstk*	next;		/* next frame (for allocation)	*/
142	struct ppinstk*	prev;		/* previous frame		*/
143	long*		control;	/* control block level		*/
144	char*		buffer;		/* buffer base pointer		*/
145	char*		file;		/* saved file name		*/
146	char*		prefix;		/* directory prefix		*/
147	struct ppsymbol* symbol;	/* macro info			*/
148#if CHECKPOINT
149	struct ppindex*	index;		/* checkpoint include index	*/
150	int		buflen;		/* buffer count			*/
151#endif
152	int		line;		/* saved line number		*/
153	int		vendor;		/* saved pp.vendor		*/
154	short		fd;		/* file descriptor		*/
155	short		hide;		/* hide index (from pp.hide)	*/
156	short		flags;		/* IN_[a-z]* flags		*/
157	char		type;		/* input type			*/
158};
159
160#if MACKEYARGS
161struct ppkeyarg				/* pp macro keyword arg info	*/
162{
163	char*		name;		/* keyword arg name		*/
164	char*		value;		/* keyword arg value		*/
165};
166#endif
167
168struct pplist				/* string list			*/
169{
170	char*		value;		/* string value			*/
171	struct pplist*	next;		/* next in list			*/
172};
173
174struct oplist				/* queue op until PP_INIT	*/
175{
176	int		op;		/* PP_* op			*/
177	char*		value;		/* op value			*/
178	struct oplist*	next;		/* next op			*/
179};
180
181struct pphide				/* hidden symbol info		*/
182{
183	struct ppmacro*	macro;		/* saved macro info		*/
184	unsigned long	flags;		/* saved symbol flags if macro	*/
185	int		level;		/* nesting level		*/
186};
187
188struct ppmacstk				/* macro invocation stack frame	*/
189{
190	struct ppmacstk* next;		/* next frame (for allocation)	*/
191	struct ppmacstk* prev;		/* previous frame		*/
192	int		line;		/* line number of first arg	*/
193	char*		arg[1];		/* arg text pointers		*/
194};
195
196struct ppmember				/* archive member pun on ppfile	*/
197{
198	struct ppdirs*	archive;	/* archive holding file		*/
199	unsigned long	offset;		/* data offset			*/
200	unsigned long	size;		/* data size			*/
201};
202
203struct counter				/* monitoring counters		*/
204{
205	int		candidate;	/* macro candidates		*/
206	int		function;	/* function macros		*/
207	int		macro;		/* macro hits			*/
208	int		pplex;		/* pplex() calls		*/
209	int		push;		/* input stream pushes		*/
210	int		terminal;	/* terminal states		*/
211	int		token;		/* emitted tokens		*/
212};
213
214struct pptuple				/* tuple macro			*/
215{
216	struct pptuple*	nomatch;	/* nomatch tuple		*/
217	struct pptuple*	match;		/* match tuple			*/
218	char		token[1];	/* matching token		*/
219};
220
221struct ppfileid				/* physical file id		*/
222{
223	unsigned long	st_dev;		/* dev				*/
224	unsigned long	st_ino;		/* ino				*/
225};
226
227struct pathid				/* physical file name and id	*/
228{
229	char*		path;		/* file path			*/
230	struct ppfileid	id;		/* file id			*/
231};
232
233#define SAMEID(a,b)	((a)->st_ino==(unsigned long)(b)->st_ino&&(a)->st_dev==(unsigned long)(b)->st_dev)
234#define SAVEID(a,b)	((a)->st_ino=(unsigned long)(b)->st_ino,(a)->st_dev=(unsigned long)(b)->st_dev)
235
236#define _PP_CONTEXT_PRIVATE_		/* ppglobals private context	*/ \
237	struct ppcontext* context;	/* current context		*/ \
238	long		state;		/* pp state flags		*/ \
239	long		mode;		/* uncoupled pp state flags	*/ \
240	long		option;		/* option flags			*/ \
241	long		test;		/* implementation tests		*/ \
242	struct								   \
243	{								   \
244	Sfio_t*		sp;		/* FILEDEPS output stream	*/ \
245	long		flags;		/* PP_FILEDEPS flags		*/ \
246	}		filedeps;	/* FILEDEPS info		*/ \
247	struct ppdirs*	firstdir;	/* first include dir		*/ \
248	struct ppdirs*	lastdir;	/* last include dir		*/ \
249	int		hide;		/* current include hide index	*/ \
250	int		column;		/* FILEDEPS column		*/ \
251	int		pending;	/* ppline() pending output	*/ \
252	char*		firstfile;	/* ppline() first file		*/ \
253	char*		lastfile;	/* ppline() most recent file	*/ \
254	char*		ignore;		/* include ignore list file	*/ \
255	char*		probe;		/* ppdefault probe key		*/ \
256	Hash_table_t*	filtab;		/* file name hash table		*/ \
257	Hash_table_t*	prdtab;		/* predicate hash table		*/ \
258	char*		date;		/* start date string		*/ \
259	char*		time;		/* start time string		*/ \
260	char*		maps;		/* directive maps		*/ \
261	long		ro_state;	/* readonly state		*/ \
262	long		ro_mode;	/* readonly mode		*/ \
263	long		ro_option;	/* readonly option		*/ \
264	struct pathid	cdir;		/* arg C dir			*/ \
265	struct pathid	hostdir;	/* arg host dir			*/ \
266	char*		ppdefault;	/* arg default info file	*/ \
267	struct ppindex*	firstindex;	/* first include index entry	*/ \
268	struct ppindex*	lastindex;	/* last include index entry	*/ \
269	struct oplist*	firstop;	/* first arg op			*/ \
270	struct oplist*	lastop;		/* last arg op			*/ \
271	struct oplist*	firsttx;	/* first text file		*/ \
272	struct oplist*	lasttx;		/* last text file		*/ \
273	unsigned char	arg_file;	/* arg file index		*/ \
274	unsigned char	arg_mode;	/* arg mode			*/ \
275	unsigned char	arg_style;	/* arg style			*/ \
276	unsigned char	c;		/* arg C state			*/ \
277	unsigned char	hosted;		/* arg hosted state		*/ \
278	unsigned char	ignoresrc;	/* arg ignore source state	*/ \
279	unsigned char	initialized;	/* arg initialized state	*/ \
280	unsigned char	standalone;	/* arg standalone state		*/ \
281	unsigned char	spare_1;	/* padding spare		*/
282
283#define _PP_GLOBALS_PRIVATE_		/* ppglobals private additions	*/ \
284	char*		checkpoint;	/* checkpoint version		*/ \
285	int		constack;	/* pp.control size		*/ \
286	struct ppinstk*	in;		/* input stream stack pointer	*/ \
287	char*		addp;	    	/* addbuf pointer		*/ \
288	char*		args;		/* predicate args		*/ \
289	char*		addbuf;		/* ADD buffer			*/ \
290	char*		catbuf;		/* catenation buffer		*/ \
291	char*		hdrbuf;		/* HEADEREXPAND buffer		*/ \
292	char*		hidebuf;	/* pp:hide buffer		*/ \
293	char*		path;		/* full path of last #include	*/ \
294	char*		tmpbuf;		/* very temporary buffer	*/ \
295	char*		valbuf;		/* builtin macro value buffer	*/ \
296	char*		optflags;	/* OPT_* flags indexed by X_*	*/ \
297	int		lastout;	/* last output char		*/ \
298		/* the rest are implicitly initialized */ \
299	char*		include;	/* saved path of last #include	*/ \
300	char*		prefix;		/* current directory prefix	*/ \
301	struct ppmember* member;	/* include archive member data	*/ \
302	int		hidden;		/* hidden newline count		*/ \
303	int		hiding;		/* number of symbols in hiding	*/ \
304	int		level;		/* pplex() recursion level	*/ \
305	struct								   \
306	{								   \
307	int		input;		/* pool input			*/ \
308	int		output;		/* pool output			*/ \
309	}		pool;		/* loop on input,output,error	*/ \
310	struct								   \
311	{								   \
312	long		ro_state;	/* original pp.ro_state		*/ \
313	long		ro_mode;	/* original pp.ro_mode		*/ \
314	long		ro_option;	/* original pp.ro_option	*/ \
315	int		on;		/* PP_RESET enabled		*/ \
316	Hash_table_t*	symtab;		/* original pp.symtab scope	*/ \
317	}		reset;		/* PP_RESET state		*/ \
318	int		truncate;	/* identifier truncation length	*/ \
319	struct ppmacstk* macp;		/* top of macro actual stack	*/ \
320	char*		maxmac;		/* maximum size of macro stack	*/ \
321	char*		mactop;		/* top of current macro frame	*/ \
322	char*		toknxt;		/* '\0' of pp.token		*/ \
323	long*		control;	/* control block flags pointer	*/ \
324	long*		maxcon;		/* max control block frame	*/ \
325	struct oplist*	chop;		/* include prefix chop list	*/ \
326	struct ppfile*	insert;		/* inserted line sync file	*/ \
327	struct ppfile*	original;	/* original include name	*/ \
328	struct ppdirs*	found;		/* last successful ppsearch dir	*/ \
329	int		vendor;		/* vendor includes only		*/ \
330	Hash_table_t*	dirtab;		/* directive hash table		*/ \
331	Hash_table_t*	strtab;		/* string hash table		*/ \
332	PPBUILTIN	builtin;	/* builtin macro handler	*/ \
333	PPCOMMENT	comment;	/* pass along comments		*/ \
334	PPINCREF	incref;		/* include file push/return	*/ \
335	PPLINESYNC	linesync;	/* pass along line sync info	*/ \
336	PPLINESYNC	olinesync;	/* original linesync value	*/ \
337	PPMACREF	macref;		/* called on macro def/ref	*/ \
338	PPOPTARG	optarg;		/* unknown option arg handler	*/ \
339	PPPRAGMA	pragma;		/* pass along unknown pragmas	*/ \
340	struct counter	counter;	/* monitoring counters		*/ \
341	char		funbuf[256];	/* last __FUNCTION__		*/
342
343#define _PP_SYMBOL_PRIVATE_		/* ppsymbol private additions	*/ \
344	struct pphide*	hidden;		/* hidden symbol info		*/
345
346#if MACKEYARGS
347#define _PP_MACRO_PRIVATE_		/* ppmacro private additions	*/ \
348	struct pptuple*	tuple;		/* tuple macro			*/ \
349	union								   \
350	{								   \
351	char*		formal;		/* normal formals list		*/ \
352	struct ppkeyarg* key;		/* keyword formals table	*/ \
353	}		args;		/* macro args info		*/ \
354	int		size;		/* body size			*/
355#define formals		args.formal	/* formal argument list		*/
356#define formkeys	args.key	/* formal keyword argument list	*/
357#else
358#define _PP_MACRO_PRIVATE_		/* ppmacro private additions	*/ \
359	struct pptuple*	tuple;		/* tuple macro			*/ \
360	char*		formals;	/* formal argument list		*/ \
361	int		size;		/* body size			*/
362#endif
363
364#define _PP_DIRS_PRIVATE_		/* ppdirs private additions	*/ \
365	unsigned char	c;		/* files here are C language	*/ \
366	unsigned char	index;		/* prefix,local,standard index	*/ \
367	unsigned char	type;		/* dir type			*/ \
368	union								   \
369	{								   \
370	char*		buffer;		/* TYPE_BUFFER buffer		*/ \
371	Sfio_t*		sp;		/* archive stream		*/ \
372	struct ppdirs*	subdir;		/* subdir list			*/ \
373	}		info;		/* type info			*/ \
374	struct ppfileid	id;		/* directory id			*/ \
375
376#if !PROTOMAIN
377#include <ast.h>
378#include <error.h>
379#endif
380
381#undef	newof
382#define newof(p,t,n,x)	((p)?(t*)realloc((char*)(p),sizeof(t)*(n)+(x)):(t*)calloc(1,sizeof(t)*(n)+(x)))
383
384#include "pp.h"
385#include "ppdef.h"
386#include "ppkey.h"
387
388#undef	setstate			/* random clash!		*/
389
390/*
391 * DEBUG is encoded with the following bits
392 */
393
394#define TRACE_message		01
395#define TRACE_count		02
396#define TRACE_debug		04
397
398#if DEBUG && !lint
399#define	PANIC		(ERROR_PANIC|ERROR_SOURCE|ERROR_SYSTEM),__FILE__,__LINE__
400#else
401#define	PANIC		ERROR_PANIC
402#endif
403
404#if DEBUG & TRACE_count
405#define count(x)	pp.counter.x++
406#else
407#define count(x)
408#endif
409
410#if DEBUG & TRACE_message
411#define message(x)	do { if (tracing) error x; } while (0)
412#else
413#define message(x)
414#endif
415
416#if DEBUG & TRACE_debug
417#define debug(x)	do { if (tracing) error x; } while (0)
418#else
419#define debug(x)
420#endif
421
422/*
423 * note that MEMCPY advances the associated pointers
424 */
425
426#define MEMCPY(to,fr,n) \
427	do switch(n) \
428	{ default : memcpy(to,fr,n); to += n; fr += n; break; \
429	  case  7 : *to++ = *fr++; \
430	  case  6 : *to++ = *fr++; \
431	  case  5 : *to++ = *fr++; \
432	  case  4 : *to++ = *fr++; \
433	  case  3 : *to++ = *fr++; \
434	  case  2 : *to++ = *fr++; \
435	  case  1 : *to++ = *fr++; \
436	  case  0 : break; \
437	} while (0)
438
439#define NEWDIRECTIVE	(-1)
440
441#undef	dirname
442#undef	error
443
444#define dirname(x)	ppkeyname(x,1)
445#define error		pperror
446#define keyname(x)	ppkeyname(x,0)
447#define nextframe(m,p)	(m->next=m+(p-(char*)m+sizeof(struct ppmacstk)-1)/sizeof(struct ppmacstk)+1)
448#define popframe(m)	(m=m->prev)
449#define pptokchr(c)	pptokstr(NiL,(c))
450#define pushcontrol()	do { if (pp.control++ >= pp.maxcon) ppnest(); } while (0)
451#define pushframe(m)	(m->next->prev=m,m=m->next)
452#define setmode(m,v)	((v)?(pp.mode|=(m)):(pp.mode&=~(m)))
453#define setoption(m,v)	((v)?(pp.option|=(m)):(pp.option&=~(m)))
454#define setstate(s,v)	((v)?(pp.state|=(s)):(pp.state&=~(s)))
455#define tracing		(error_info.trace<0)
456
457#define ppgetfile(x)	((struct ppfile*)hashlook(pp.filtab,x,HASH_LOOKUP,NiL))
458#define ppsetfile(x)	((struct ppfile*)hashlook(pp.filtab,x,HASH_CREATE|HASH_SIZE(sizeof(struct ppfile)),NiL))
459
460#define ppkeyget(t,n)	(struct ppsymkey*)hashlook(t,n,HASH_LOOKUP,NiL)
461#define ppkeyref(t,n)	(struct ppsymkey*)hashlook(t,n,HASH_LOOKUP|HASH_INTERNAL,NiL)
462#define ppkeyset(t,n)	(struct ppsymkey*)hashlook(t,n,HASH_CREATE|HASH_SIZE(sizeof(struct ppsymkey)),NiL)
463
464#define MARK		'@'		/* internal mark		*/
465#define ARGOFFSET	'1'		/* macro arg mark offset	*/
466
467#define STRAPP(p,v,r)	do{r=(v);while((*p++)=(*r++));}while(0)
468#define STRCOPY(p,v,r)	do{r=(v);while((*p++)=(*r++));p--;}while(0)
469#define STRCOPY2(p,r)	do{while((*p++)=(*r++));p--;}while(0)
470
471#define SETFILE(p,v)	(p+=sfsprintf(p,16,"%c%c%lx%c",MARK,'F',(long)v,MARK))
472#define SETLINE(p,v)	(p+=sfsprintf(p,16,"%c%c%lx%c",MARK,'L',(long)v,MARK))
473
474#define peekchr()	(*pp.in->nextchr)
475#define ungetchr(c)	(*--pp.in->nextchr=(c))
476
477#define MAXID		255		/* maximum identifier size	*/
478#define MAXTOKEN	PPTOKSIZ	/* maximum token size		*/
479#define MAXFORMALS	64		/* maximum number macro formals	*/
480#define MAXHIDDEN	8		/* ppline if hidden>=MAXHIDDEN	*/
481#define DEFMACSTACK	(MAXFORMALS*32*32)/* default macstack size	*/
482
483#define FSM_COMPATIBILITY	1	/* compatibility mode		*/
484#define FSM_IDADD	2		/* add to identifer set		*/
485#define FSM_IDDEL	3		/* delete from identifer set	*/
486#define FSM_INIT	4		/* initilize			*/
487#define FSM_MACRO	5		/* add new macro		*/
488#define FSM_OPSPACE	6		/* handle <binop><space>=	*/
489#define FSM_PLUSPLUS	7		/* C++ lexical analysis		*/
490#define FSM_QUOTADD	8		/* add to quote set		*/
491#define FSM_QUOTDEL	9		/* delete from quote set	*/
492
493#define IN_TOP		01		/* top level -- directives ok	*/
494
495#define IN_BUFFER	(2|IN_TOP)	/* buffer of lines		*/
496#define IN_COPY		2		/* macro arg (copied)		*/
497#define IN_EXPAND	4		/* macro arg (expanded)		*/
498#define IN_FILE		(4|IN_TOP)	/* file				*/
499#define IN_INIT		(6|IN_TOP)	/* initialization IN_BUFFER	*/
500#define IN_MACRO	8		/* macro text			*/
501#define IN_MULTILINE	(8|IN_TOP)	/* multi-line macro text	*/
502#define IN_QUOTE	10		/* "..." macro arg (copied)	*/
503#define IN_RESCAN	(10|IN_TOP)	/* directive rescan buffer	*/
504#define IN_SQUOTE	12		/* '...' macro arg (copied)	*/
505#define IN_STRING	14		/* string			*/
506
507#define INC_CLEAR	((struct ppsymbol*)0)
508#define INC_IGNORE	((struct ppsymbol*)pp.addbuf)
509#define INC_TEST	((struct ppsymbol*)pp.catbuf)
510
511#define INC_BOUND(n)	(1<<(n))
512#define INC_MEMBER(n)	(1<<((n)+INC_MAX))
513#define INC_PREFIX	0
514#define INC_LOCAL	1
515#define INC_STANDARD	2
516#define INC_VENDOR	3
517#define INC_MAX		4
518#define INC_SELF	(1<<(2*INC_MAX+0))
519#define INC_EXISTS	(1<<(2*INC_MAX+1))
520#define INC_LISTED	(1<<(2*INC_MAX+2))
521#define INC_MAPALL	(1<<(2*INC_MAX+3))
522#define INC_MAPHOSTED	(1<<(2*INC_MAX+4))
523#define INC_MAPNOHOSTED	(1<<(2*INC_MAX+5))
524#define INC_MAPNOLOCAL	(1<<(2*INC_MAX+6))
525#define INC_HOSTED	(1<<(2*INC_MAX+7))
526
527#define TYPE_ARCHIVE	(1<<0)
528#define TYPE_BUFFER	(1<<1)
529#define TYPE_CHECKPOINT	(1<<2)
530#define TYPE_DIRECTORY	(1<<3)
531#define TYPE_HOSTED	(1<<4)
532#define TYPE_INCLUDE	(1<<5)
533#define TYPE_VENDOR	(1<<6)
534
535#define TOK_BUILTIN	(1<<0)		/* last token was #(		*/
536#define TOK_FORMAL	(1<<1)		/* last token was arg formal id	*/
537#define TOK_ID		(1<<2)		/* last token was identifier	*/
538#define TOK_TOKCAT	(1<<3)		/* last token was ##		*/
539
540#define HADELSE		(1<<0)		/* already had else part	*/
541#define KEPT		(1<<1)		/* already kept part of block	*/
542#define SKIP		(1<<2)		/* skip this block		*/
543#define BLOCKBITS	3		/* block flag bits		*/
544
545#define SETIFBLOCK(p)	(*(p)=(*((p)-1)&SKIP)|((long)error_info.line<<BLOCKBITS))
546#define GETIFLINE(p)	((*(p)>>BLOCKBITS)&((1L<<(sizeof(long)*CHAR_BIT-BLOCKBITS))-1))
547
548#define PUSH(t,p)		\
549	do \
550	{ \
551		count(push); \
552		if (!pp.in->next) \
553		{ \
554			pp.in->next = newof(0, struct ppinstk, 1, 0); \
555			pp.in->next->prev = pp.in; \
556		} \
557		p = pp.in = pp.in->next; \
558		p->type = t; \
559		p->flags = 0; \
560	} while (0)
561
562#define PUSH_BUFFER(f,p,n)		\
563	pppush(IN_BUFFER,f,p,n)
564
565#define PUSH_COPY(p,n)		\
566	do \
567	{ \
568		register struct ppinstk*	cur; \
569		PUSH(IN_COPY, cur); \
570		cur->line = error_info.line; \
571		error_info.line = n; \
572		cur->nextchr = p; \
573		cur->prev->symbol->flags &= ~SYM_DISABLED; \
574		debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \
575	} while (0)
576
577#define PUSH_EXPAND(p,n)	\
578	do \
579	{ \
580		register struct ppinstk*	cur; \
581		PUSH(IN_EXPAND, cur); \
582		cur->line = error_info.line; \
583		error_info.line = n; \
584		cur->prev->symbol->flags &= ~SYM_DISABLED; \
585		cur->buffer = cur->nextchr = ppexpand(p); \
586		if (!(cur->prev->symbol->flags & SYM_MULTILINE)) \
587			cur->prev->symbol->flags |= SYM_DISABLED; \
588		debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \
589	} while (0)
590
591#define PUSH_FILE(f,d)	\
592	pppush(IN_FILE,f,NiL,d)
593
594#define PUSH_INIT(f,p)	\
595	pppush(IN_INIT,f,p,1)
596
597#define PUSH_MACRO(p)		\
598	do \
599	{ \
600		register struct ppinstk*	cur; \
601		PUSH(IN_MACRO, cur); \
602		cur->symbol = p; \
603		cur->nextchr = p->macro->value; \
604		p->flags |= SYM_DISABLED; \
605		if (p->flags & SYM_FUNCTION) pushframe(pp.macp); \
606		pp.state &= ~NEWLINE; \
607		debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \
608	} while (0)
609
610#define PUSH_TUPLE(p,v)		\
611	do \
612	{ \
613		register struct ppinstk*	cur; \
614		PUSH(IN_MACRO, cur); \
615		cur->symbol = p; \
616		cur->nextchr = v; \
617		p->flags |= SYM_DISABLED; \
618		pp.state &= ~NEWLINE; \
619		debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \
620	} while (0)
621
622#define PUSH_MULTILINE(p)		\
623	do \
624	{ \
625		register struct ppinstk*	cur; \
626		register int			n; \
627		PUSH(IN_MULTILINE, cur); \
628		cur->symbol = p; \
629		cur->flags |= IN_defguard|IN_endguard|IN_noguard; \
630		pushcontrol(); \
631		cur->control = pp.control; \
632		*pp.control = 0; \
633		cur->file = error_info.file; \
634		n = strlen(error_info.file) + strlen(((struct ppsymbol*)p)->name) + 24; \
635		error_info.file = cur->buffer = newof(0, char, n, 0); \
636		sfsprintf(error_info.file, n, "%s:%s,%d", cur->file, p->name, error_info.line); \
637		cur->line = error_info.line; \
638		error_info.line = 1; \
639		cur->nextchr = p->macro->value; \
640		if (p->flags & SYM_FUNCTION) pushframe(pp.macp); \
641		pp.state &= ~NEWLINE; \
642		debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \
643	} while (0)
644
645#define PUSH_QUOTE(p,n)		\
646	do \
647	{ \
648		register struct ppinstk*	cur; \
649		PUSH(IN_QUOTE, cur); \
650		cur->nextchr = p; \
651		pp.state |= QUOTE; \
652		cur->line = error_info.line; \
653		error_info.line = n; \
654		debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \
655	} while (0)
656
657#define PUSH_RESCAN(p)	\
658	pppush(IN_RESCAN,NiL,p,0)
659
660#define PUSH_SQUOTE(p,n)	\
661	do \
662	{ \
663		register struct ppinstk*	cur; \
664		PUSH(IN_SQUOTE, cur); \
665		cur->nextchr = p; \
666		pp.state |= SQUOTE; \
667		cur->line = error_info.line; \
668		error_info.line = n; \
669		debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \
670	} while (0)
671
672#define PUSH_STRING(p)		\
673	do \
674	{ \
675		register struct ppinstk*	cur; \
676		PUSH(IN_STRING, cur); \
677		cur->nextchr = p; \
678		if (pp.state & DISABLE) cur->flags |= IN_disable; \
679		debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \
680	} while (0)
681
682#define PUSH_LINE(p)		\
683	do \
684	{ \
685		register struct ppinstk*	cur; \
686		PUSH(IN_STRING, cur); \
687		cur->nextchr = p; \
688		pp.state |= DISABLE|NOSPACE|PASSEOF|STRIP; \
689		debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \
690	} while (0)
691
692#define POP_LINE()		\
693	do \
694	{ \
695		debug((-7, "POP  in=%s", ppinstr(pp.in))); \
696		pp.in = pp.in->prev; \
697		pp.state &= ~(DISABLE|NOSPACE|PASSEOF|STRIP); \
698	} while (0)
699
700struct ppcontext			/* pp context			*/
701{
702	_PP_CONTEXT_PUBLIC_
703	_PP_CONTEXT_PRIVATE_
704};
705
706struct ppfile				/* include file info		*/
707{
708	HASH_HEADER;			/* this is a hash bucket too	*/
709	struct ppsymbol* guard;		/* guard symbol			*/
710	struct ppfile*	bound[INC_MAX];	/* include bindings		*/
711	int		flags;		/* INC_* flags			*/
712};
713
714#if CHECKPOINT
715
716struct ppindex				/* checkpoint include index	*/
717{
718	struct ppindex*	next;		/* next in list			*/
719	struct ppfile*	file;		/* include file			*/
720	unsigned long	begin;		/* beginning output offset	*/
721	unsigned long	end;		/* ending output offset		*/
722};
723
724#endif
725
726struct ppsymkey				/* pun for SYM_KEYWORD lex val	*/
727{
728	struct ppsymbol	sym;		/* symbol as usual		*/
729	int		lex;		/* lex value for SYM_KEYWORD	*/
730};
731
732#if PROTOMAIN && PROTO_STANDALONE
733
734#if defined(__STDC__) || defined(__cplusplus) || defined(c_plusplus)
735#define NiL		0
736#define NoP(x)		(&x,1)
737#else
738#define NiL		((char*)0)
739#define NoP(x)
740#endif
741
742#define newof(p,t,n,x)	((p)?(t*)realloc((char*)(p),sizeof(t)*(n)+(x)):(t*)calloc(1,sizeof(t)*(n)+(x)))
743
744#define _PP_DELAY_	#
745
746_PP_DELAY_ ifdef __STDC__
747
748_PP_DELAY_ include <stdlib.h>
749_PP_DELAY_ include <unistd.h>
750_PP_DELAY_ include <time.h>
751_PP_DELAY_ include <string.h>
752
753_PP_DELAY_ else
754
755_PP_DELAY_ define size_t		int
756
757extern void*		realloc(void*, size_t);
758extern void*		calloc(size_t, size_t);
759extern char*		ctime(time_t*);
760extern void		free(void*);
761
762_PP_DELAY_ ifndef O_RDONLY
763
764extern int		access(const char*, int);
765extern int		close(int);
766extern int		creat(const char*, int);
767extern void		exit(int);
768extern int		link(const char*, const char*);
769extern int		open(const char*, int, ...);
770extern int		read(int, void*, int);
771extern time_t		time(time_t*);
772extern int		unlink(const char*);
773extern int		write(int, const void*, int);
774
775_PP_DELAY_ endif
776
777_PP_DELAY_ endif
778
779#else
780
781/*
782 * library implementation globals
783 */
784
785#define ppassert	_pp_assert
786#define ppbuiltin	_pp_builtin
787#define ppcall		_pp_call
788#define ppcontrol	_pp_control
789#define ppdump		_pp_dump
790#define ppexpand	_pp_expand
791#define ppexpr		_pp_expr
792#define ppfsm		_pp_fsm
793#define ppinmap		_pp_inmap
794#define ppinstr		_pp_instr
795#define ppkeyname	_pp_keyname
796#define pplexmap	_pp_lexmap
797#define pplexstr	_pp_lexstr
798#define ppload		_pp_load
799#define ppmodestr	_pp_modestr
800#define ppmultiple	_pp_multiple
801#define ppnest		_pp_nest
802#define ppoption	_pp_option
803#define ppoptionstr	_pp_optionstr
804#define pppclose	_pp_pclose
805#define pppdrop		_pp_pdrop
806#define pppopen		_pp_popen
807#define pppread		_pp_pread
808#define pppredargs	_pp_predargs
809#define pppush		_pp_push
810#define pprefmac	_pp_refmac
811#define ppsearch	_pp_search
812#define ppstatestr	_pp_statestr
813#define pptokstr	_pp_tokstr
814#define pptrace		_pp_trace
815
816#endif
817
818extern void		ppassert(int, char*, char*);
819extern void		ppbuiltin(void);
820extern int		ppcall(struct ppsymbol*, int);
821extern int		ppcontrol(void);
822extern void		ppdump(void);
823extern char*		ppexpand(char*);
824extern long		ppexpr(int*);
825extern void		ppfsm(int, char*);
826extern char*		ppinstr(struct ppinstk*);
827extern char*		ppkeyname(int, int);
828extern char*		pplexstr(int);
829extern void		ppload(char*);
830extern void		ppmapinclude(char*, char*);
831extern char*		ppmodestr(long);
832extern int		ppmultiple(struct ppfile*, struct ppsymbol*);
833extern void		ppnest(void);
834extern int		ppoption(char*);
835extern char*		ppoptionstr(long);
836extern void		pppclose(char*);
837extern int		pppdrop(char*);
838extern char*		pppopen(char*, int, char*, char*, char*, char*, int);
839extern int		pppread(char*);
840extern int		pppredargs(void);
841extern void		pppush(int, char*, char*, int);
842extern struct ppsymbol*	pprefmac(char*, int);
843extern int		ppsearch(char*, int, int);
844extern char*		ppstatestr(long);
845extern char*		pptokstr(char*, int);
846extern void		pptrace(int);
847
848#if _std_malloc
849
850#include <vmalloc.h>
851
852#undef	free
853#define free(p)	 	vmfree(Vmregion,(void*)p)
854#undef	newof
855#define newof(p,t,n,x)	vmnewof(Vmregion,p,t,n,x)
856#undef	oldof
857#define oldof(p,t,n,x)	vmoldof(Vmregion,p,t,n,x)
858#undef	strdup
859#define strdup(s)	vmstrdup(Vmregion,s)
860
861#endif
862
863#endif
864