⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scpp.c

📁 一个去掉程序中#ifdef #if 等预处理条件为假的程序
💻 C
字号:
/* * scpp.c - main processing for the selective C preprocessor, scpp. * * Copyright (c) 1985 by * Tektronix, Incorporated Beaverton, Oregon 97077 * All rights reserved. * * Permission is hereby granted for personal, non-commercial * reproduction and use of this program, provided that this * notice and all copyright notices are included in any copy. */#define VARS# include <stdio.h># include "scpp.h"# include "y.tab.h"/* * actual[] - the array of actual parameters of the macro currently being *  interpreted. */struct anactual {	char *aa_val;	/*			 * the value of this actual (a pointer to the null-			 * terminator.  see amacro.am_val in scpp.h).			 */	char *aa_mem;	/*			 * points to the beginning of the aa_val string.			 * Used to later free the value's memory.			 */};#define ACTSIZ MAXPARMSstruct anactual actual[ACTSIZ];struct anactual *actp;	/* the next available slot in actual[] */main(argc, argv)int argc;char **argv;{	int tok;	/* current token's value	*/	char *cp;	char *ep;	char **dp;	/* where within dirlist to put the next directory */        char **ip;	/* where within ilist to put the next include file */	struct amacro *np;	char *name;	/* name of the current macro	*/	char *val;	/* value of the current macro	*/	char *defmagic = "defined";	/* name of the 'defined()' macro */	struct amacro *magmac;	/* (temp) slot for the magic macro */	/*	 * init all the global structures	 */	nxtout = &pend[0];	curfile = &filestk[-1];	nxtin = &istk[ISTKSIZ];	curif = &ifstk[-1];		nxtfile = &catlist[0];	dp = &dirlist[0];        ip = &ilist[0];	/*	 * setup the keyword symbols and the special macro, 'defined()'.	 */	ikeywords();	magmac = findmac(defmagic, defmagic + strlen(defmagic));	if (magmac->am_name) {		bomb("INTERNAL: 'defined()' macro slot in use");	}	magmac->am_name = defmagic;	magmac->am_npar = 1;	magmac->am_val = &magicval;	while (++argv, --argc > 0) {		cp = *argv;		if (*cp == '-' && *(cp + 1) != '\0') {			switch(*++cp) {			case 'C':				savcom = TRUE;				break;			case 'i':				*ip++ = cp + 1;				break;			case 'I':				*dp++ = cp + 1;				break;			case 'M':				/*				 * for each name in the list of whitespace-				 *  separated macro names,				 * Setup a slot for that macro, but leave it				 *  undefined.				 */				while (*cp) {					while (*++cp == ' ' || *cp == '\t' ||					    *cp == '\n')						;					if (*cp == '\0') {						break;					}					for (name = cp; *cp != '\0' &&					  *cp != ' ' && *cp != '\t' &&					  *cp != '\n'; ++cp)						;					np = findmac(name, cp);					if (np->am_name == (char *) 0) {					    np->am_name = savtok(name, cp);						np->am_npar = -1;					}					/* am_val is left as zero */				}				break;			case 'D':				for (name = ++cp; *cp != '\0' && *cp != '=';				  ++cp)					;				if (name == cp) {					warn("missing macro name in `%s'",					  name - 2);					break;				}				if (*cp == '\0') {					/*					 * macro name with no definition.					 * Define the name with no parameters					 *  and with a value of "1".					 */					defmac(name, cp, -1, "1");				} else {					/* macro + definition */					for (*cp++ = '\0', val = cp;					  *cp != '\0'; ++cp)						;					defmac(name, name + strlen(name),					  -1, val);				}				break;			default:				bomb("unknown switch `%c'", *cp);			}		} else {			*nxtfile++ = cp;		}	}	if (nxtfile == &catlist[0]) {		*nxtfile++ = "-";	}	*nxtfile = (char *) 0;	nxtfile = &catlist[0];	*dp++ = "/usr/include";	*dp = (char *) 0;	/*	 * prime the input stack and go,	 * interpreting preprocessor directives along the way.	 */	pushfile(*nxtfile++, PF_NOLOOK, PF_NOHIDE);	do {		tok = gintok();		if (tok == POUNDLINE) {			tok = doctrl(curtext);		}		outpend();	/* even the 0 token needs to be flushed.				 * Otherwise, incomplete comments at the end				 * of the file would be destroyed.				 */	} while (tok != 0);	writepend();		/* flush trailing output	*/	if (curif >= &ifstk[0]) {		warnf("missing endif");	}	exit(sawerror ? 1 : 0);}intgintok()	/* get a token, interpreting macro's	*/{	int tok;		/* the current token's value	*/	struct amacro *mac;	/* the current macro		*/	struct amacro *defsym;	/* the macro being checked for 'defined()' */	char *mactext;		/*				 * the start of the invocation of a macro				 * which has parameters.				 */	char *start;		/* the start of the current parameter	*/	int nest;		/*				 * current nesting level of parentheses.				 * used to avoid misinterpreting commas within				 * nested parens as parameter separators.				 */	char *defident;		/*				 * The IDENT parameter for the magic macro,				 * 'defined()' (dynamically alloc'ed).				 * If gintok() is interpreting the magic macro,				 * this variable is marked so that, during the				 * parameter parsing, the first IDENT is saved				 * here.				 */	int parmgripe;		/*				 * "an error message about parameters of				 * this macro has already been printed."				 */	int i;			/* an actual-parameter index	*/	char *cp;		/* a temp pointer		*/	/*	 * special macro values (see scpp.h: struct amacro, field am_val):	 *  noval == a null macro value;	 *  oneval == a macro value of '1';	 *  zeroval == a macro value of '0';	 */	static char nv[2] = {'\0', '\0'};	static char *noval = &nv[1];	static char ov[3] = {'\0', '1', '\0'};	static char *oneval = &ov[2];	static char zv[3] = {'\0', '0', '\0'};	static char *zeroval = &zv[2];	tok = OTHER;	while (tok != DEFMAC && (tok = gtok()) != 0) {		if (tok == QUOTE || tok == DQUOTE) {			tok = gstrtok(tok);		}		if (tok != IDENT) {			return(tok);		}		if ((mac = findmac(curtext, nxtout))->am_name == (char *) 0 ||		    mac->am_val == (char *) 0) {			/* there is no macro by this name currently defined */			return(tok);		}		/*		 * tally this interpretation		 */		++ninterp;		if (mac->am_npar < 0) {			/*			 * the macro has no formal parameters.			 * pushback the replacement text and continue.			 */			(void) dispose(curtext);			(void) pushmac(mac->am_val);			continue;		}		/* this is a macro with formals */		/*		 * save the starting-point of the macro's text.		 * Used for later disposal.  The text is not disposed		 * here in case the macro is a 'defined()' of some non--M'ed		 * macro.		 */		mactext = curtext;		/*		 * collect the comma-separated actual parameters of the macro,		 * ignoring commas within pairs of parens or within strings.		 */		parmgripe = FALSE;		actp = &actual[0];		nest = 0;		if (mac->am_val == &magicval) {			defident = &magicval;		} else {			defident = (char *) 0;		}		if ((tok = nonwhite(gtok)) != LP) {		        warnf("missing parenthesis in macro '%s'",			    mac->am_name);			parmgripe = TRUE;				/* pushback the erroneous token	*/			untok();		} else {			do {				/* collect one parameter */				start = nxtout;				while ((tok = gtok())) {					if (tok == CM && nest == 0) {						break;					} else if (tok == RP) {						if (nest > 0) {							--nest;						} else if (nest == 0) {							break;						}					} else if (tok == LP) {						++nest;					} else if (tok == QUOTE ||					  tok == DQUOTE) {						tok = gstrtok(tok);					} else if (tok == IDENT &&					  defident == &magicval) {						defident =						  savtok(curtext, nxtout);					}				}				/*				 * Warn about too many parameters, otherwise,				 * store the parameter in the format of				 * a macro value.				 */				if ((actp - &actual[0]) >= mac->am_npar) {					if (!parmgripe) {					  warnf("macro parameter mismatch");					  parmgripe = TRUE;					}				} else {					cp = savtok(start - 1, curtext);					*cp = '\0';					actp->aa_mem = cp;					while (*++cp)						;					actp->aa_val = cp;					++actp;				}			} while (tok == CM);			if (tok != RP) {				if (!parmgripe) {				  warnf("missing parenthesis in macro '%s'",					mac->am_name);				  parmgripe = TRUE;				}			}		}		/*		 * If there are too few actual parameters, fill out the		 * list with null values.		 */		while (actp - &actual[0] < mac->am_npar) {			if (!parmgripe) {				warnf("parameter mismatch");				parmgripe = TRUE;			}			actp->aa_val = noval;			actp->aa_mem = (char *) 0;			++actp;		}		/*		 * replace the macro invocation with the value of the macro,		 *  replacing formal arguments with the corresponding actual.		 */		if ((cp = mac->am_val) == &magicval) {			/*			 * This is the magic macro, "defined(x)".			 * Interpret only if the parameter is a -M'ed			 *  macro and we are currently parsing a			 *  #if expression.			 * Lookup the parameter (if any);			 * If the parameter is -M'ed, pushback a '1' or '0',			 * depending on whether the macro is defined.			 */			defsym = findmac(defident, defident + strlen(defident));			if (!defsym->am_name || !expparse) {				/*				 * Leave the invocation of defined() untouched.				 */				curtext = mactext;				tok = DEFMAC;			} else {				(void) dispose(mactext);				if (defsym->am_val) {					(void) pushmac(oneval);				} else {					(void) pushmac(zeroval);				}			}                        if (defident != &magicval)			    free(defident);		} else {			(void) dispose(mactext);			while (*(cp = pushmac(cp)) == ATTN) {				i = (int) (*--cp) - 1;				if (i < 0 || i >= mac->am_npar) {					warnf("INTERNAL: parameter number %d out of bounds", i);				} else {					(void) pushmac(actual[i].aa_val);				}			}		}		/*		 * free the actual parameters.		 */		while (--actp >= &actual[0]) {			if (actp->aa_mem) {				free(actp->aa_mem);			}		}	}	return(tok);}/* * gtok() - get a token without interpreting macros or preprocessor directives. *  This is the low-level lexical analyzer.  It exists only because Lex's *  analyzer chokes on long comments. */intgtok(){	int tok;	curtext = nxtout;	tok = xxlex();	if (tok == OPENC) {		while ((tok = xxlex()) != CLOSEC) {			if (tok == 0) {				warnf("unterminated comment");				return(0);			}		}		tok = COMMENT;	}	return(tok);}/* * gstrtok - get a string token.  Given the token which starts a string *  or character constant (I.E. QUOTE or DQUOTE), collect the string token *  as if it had been recognised by the lexical analyzer as a single token. */intgstrtok(tok)int tok;		/* token which started the quoted string	*/{	int tok2;		/* the next token's value	*/	char *qstrt;		/* start of a string in pend[]	*/	/*	 * collect the string without interpreting	 * macros.  Allow \' and \" within strings.	 * Newline or EOF terminate strings.	 * Save and restore curtext so that on returning,	 * curtext points to the beginning of the token.	 */	qstrt = curtext;	while ((tok2 = gtok()) != tok) {		if (tok2 == 0) {			/* unterminated quote	*/			curtext = qstrt;			return(0);		}		if (tok2 == NL) {			/* unterminated quote. pushback the newline	*/			untok();			break;		}		if (tok2 == BACKS) {			if (gtok() == 0) {				/* unterminated quote */				curtext = qstrt;				return(0);			}		}	}	curtext = qstrt;	return(tok == DQUOTE ? STRING : CHARS);}/* * findmac - find a macro *  given the bounds of what might be a macro name (possibly containing ATTN *   bytes), return a pointer to the symbol table slot *  corresponding to that name. */struct amacro *findmac(name, last)char *name;	/* points to the beginning of the name.			*/char *last;	/* points to the char beyond the end of the name	*/{	/*	 * hash the first 8 chars of the name (less ATTN bytes) into an index;	 * Use that index as a starting point for a linear search	 *  for either the matching slot or an empty slot.	 */	int idx;	char *cp;	char *tp;	int cnt;	struct amacro *np, *start;	for (idx = 0, cp = name, cnt = 0; cp < last && cnt < 8; ++cp) {		if (*cp == ATTN) {			++cp;		} else {			idx += (int) *cp++ & 0xff;			++cnt;		}	}	start = np = &sym[idx % SYMSIZ];	while (np->am_name) {		/*		 * compare the token at 'name' with the macro's name,		 * skipping ATTN bytes and their associated codes.		 */		for (tp = name, cp = np->am_name; tp < last; ++tp) {			if (*tp == ATTN) {				++tp;				continue;			}			if (*tp != *cp++) {				break;			}		}		if (tp == last) {			/* the names match */			break;		}		if (++np >= &sym[SYMSIZ]) {			np = &sym[0];		}		if (np == start) {			bombf("symbol table overflow");		}	}	return(np);}/* * defmac - define a macro */defmac(name, end, npar, val)char *name;		/* the start of the macro's name		*/char *end;		/* points to one char beyond the end of the name */int npar;		/* # of parameters (-1 == none)			*/char *val;		/* the beginning of the value string		*/{	char *cp;	struct amacro *np;	struct akeyword *kp;	char *malloc();	/*	 * find the slot for the macro and give it a name if this is the	 * first occurrence of this name.	 */	np = findmac(name, end);	if (!np->am_name) {		np->am_name = savtok(name, end);	} else {		/*		 * Don't allow preprocessor keywords to be defined.		 */		if ((kp = findkey(np)) != (struct akeyword *) 0) {			warnf("redeclaration of keyword \"%s\"", kp->ak_name);			return;		}		/*		 * if the macro is currently defined (I.E. has a value),		 *  reject redefinitions of magic macros.		 * compare the new and old values.		 * If the value or number of parameters differs,		 *  print a warning and destroy the old value.		 * If they are the same, do nothing (return).		 */		if (np->am_val) {			if (np->am_val == &magicval) {				warnf("cannot redefine implicit macro");				return;			}			cp = np->am_val;			while (*--cp)				;			if (np->am_npar == npar && strcmp(cp + 1, val) == 0) {				return;			}			warnf("redeclaration of \"%s\"", np->am_name);			free(cp);		}	}	/*	 * Set the new value and number of parameters.	 * Put a null introduction on the value;	 * Remember that am_val points to the *end* of the value.	 */	np->am_npar = npar;	if (!(cp = malloc((unsigned) strlen(val) + 2))) {		bombf("out of memory");	}	*cp++ = '\0';	strcpy(cp, val);	np->am_val = cp + strlen(cp);}/* * savtok - given the limits of a token string, *  copy that string (less ATTN bytes) into a dynamically allocated buffer *  then return the buffer. */char *savtok(s, e)char *s;	/* first char of token			*/char *e;	/* points beyond the last char of token	*/{	char *name;	/* the text of the token -- the value to return	*/	char *cp;	char *malloc();	if (!(name = malloc(e - s + 1))) {		bombf("out of memory");	}	for (cp = name; s < e; ++s) {		if (*s == ATTN) {			++s;		} else {			*cp++ = *s;		}	}	*cp = '\0';	return(name);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -