1870 lines · 45.5 KB · C
RawDownload
/* * (c) Thomas Pornin 1999, 2000 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 4. The name of the authors may not be used to endorse or promote *    products derived from this software without specific prior written *    permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /*vb*/#ifdef HAVE_MISRAvoid misra(int,...);void misra_neu(int, int, int, int, ...);int misra_is_reserved(const char*);#endif #include <stdio.h>#include <string.h>#include <stddef.h>#include <limits.h>#include <ctype.h>#include "ucppi.h"#include "mem.h"#include "hash.h"#include "tune.h" /*vb*/extern int nesting;#ifdef HAVE_MISRAextern int misracheck;#endif /* * we store macros in a hash table, and retrieve them using their name * as identifier. */static struct HT *macros = 0; static void del_macro(void *m){	struct macro *n = m;	int i; 	if (n->name) freemem(n->name);	for (i = 0; i < n->narg; i ++) freemem(n->arg[i]);	if (n->narg > 0) freemem(n->arg);#ifdef LOW_MEM	if (n->cval.length) freemem(n->cval.t);#else	if (n->val.nt) {		for (i = 0; i < n->val.nt; i ++)			if (S_TOKEN(n->val.t[i].type))				freemem(n->val.t[i].name);		freemem(n->val.t);	}#endif	freemem(n);} static inline struct macro *new_macro(void){	struct macro *m = getmem(sizeof(struct macro)); 	m->name = 0;	m->narg = -1;	m->nest = 0;#ifdef LOW_MEM	m->cval.length = 0;#else	m->val.nt = m->val.art = 0;#endif	m->vaarg = 0;	return m;} /* * for special macros, and the "defined" operator */enum {	MAC_NONE, MAC_DEFINED,	MAC_LINE, MAC_FILE, MAC_DATE, MAC_ADATE, MAC_TIME, MAC_STDC, MAC_PRAGMA};#define MAC_SPECIAL	MAC_LINE /* * returns 1 for "defined" * returns x > 1 for a special macro such as __FILE__ * returns 0 otherwise */static inline int check_special_macro(char *name){	if (!strcmp(name, "defined")) return MAC_DEFINED;	if (*name != '_') return MAC_NONE;	if (*(name + 1) == 'P') {		if (!strcmp(name, "_Pragma")) return MAC_PRAGMA;		return MAC_NONE;	} else if (*(name + 1) != '_') return MAC_NONE;	if (no_special_macros) return MAC_NONE;	if (!strcmp(name, "__LINE__")) return MAC_LINE;	else if (!strcmp(name, "__FILE__")) return MAC_FILE;	else if (!strcmp(name, "__DATE__")) return MAC_DATE;	else if (!strcmp(name, "__AMIGADATE__")) return MAC_ADATE;	else if (!strcmp(name, "__TIME__")) return MAC_TIME;	else if (!strcmp(name, "__STDC__")) return MAC_STDC;	return MAC_NONE;} int c99_compliant = 1;int c99_hosted = 1; /* * add the special macros to the macro table */static void add_special_macros(void){	struct macro *m; 	m = new_macro(); m->name = sdup("__LINE__"); putHT(macros, m);	m = new_macro(); m->name = sdup("__FILE__"); putHT(macros, m);	m = new_macro(); m->name = sdup("__DATE__"); putHT(macros, m);	m = new_macro(); m->name = sdup("__AMIGADATE__"); putHT(macros, m);	m = new_macro(); m->name = sdup("__TIME__"); putHT(macros, m);	m = new_macro(); m->name = sdup("__STDC__"); putHT(macros, m);	m = new_macro(); m->name = sdup("_Pragma"); m->narg = 1;	m->arg = getmem(sizeof(char *)); m->arg[0] = sdup("foo");	putHT(macros, m);	if (c99_compliant) {#ifndef LOW_MEM		struct token t;#endif 		m = new_macro();		m->name = sdup("__STDC_VERSION__");#ifdef LOW_MEM		m->cval.t = getmem(9);		m->cval.t[0] = NUMBER;		mmv(m->cval.t + 1, "199901L", 8);		m->cval.length = 9;#else		t.type = NUMBER;		t.line = 0;		t.name = sdup("199901L");		aol(m->val.t, m->val.nt, t, TOKEN_LIST_MEMG);#endif		putHT(macros, m);	}	if (c99_hosted) {#ifndef LOW_MEM		struct token t;#endif 		m = new_macro();		m->name = sdup("__STDC_HOSTED__");#ifdef LOW_MEM		m->cval.t = getmem(3);		m->cval.t[0] = NUMBER;		mmv(m->cval.t + 1, "1", 2);		m->cval.length = 3;#else		t.type = NUMBER;		t.line = 0;		t.name = sdup("1");		aol(m->val.t, m->val.nt, t, TOKEN_LIST_MEMG);#endif		putHT(macros, m);	}} /* * print the content of a macro, in #define form */static void print_macro(void *vm){	struct macro *m = vm;	int x = check_special_macro(m->name);	int i; 	if (x != MAC_NONE) {		fprintf(emit_output, "/* #define %s */ /* special */\n",			m->name);		return;	}	fprintf(emit_output, "#define %s", m->name);	if (m->narg >= 0) {		fprintf(emit_output, "(");		for (i = 0; i < m->narg; i ++) {			fprintf(emit_output, i ? ", %s" : "%s", m->arg[i]);		}		if (m->vaarg) {			fputs(m->narg ? ", ..." : "...", emit_output);		}		fprintf(emit_output, ")");	}#ifdef LOW_MEM	if (m->cval.length == 0) {		fputc('\n', emit_output);		return;	}	fputc(' ', emit_output);	for (i = 0; i < m->cval.length;) {		int tt = m->cval.t[i ++]; 		if (tt == MACROARG) {			if (m->cval.t[i] == m->narg)				fputs("__VA_ARGS__", emit_output);			else				fputs(m->arg[(size_t)(m->cval.t[i])],					emit_output);			i ++;		}		else if (S_TOKEN(tt)) {			fputs((char *)(m->cval.t + i), emit_output);			i += 1 + strlen((char *)(m->cval.t + i));		} else fputs(operators_name[tt], emit_output);	}#else	if (m->val.nt == 0) {		fputc('\n', emit_output);		return;	}	fputc(' ', emit_output);	for (i = 0; i < m->val.nt; i ++) {		if (m->val.t[i].type == MACROARG) {			if (m->val.t[i].line == m->narg)				fputs("__VA_ARGS__", emit_output);			else				fputs(m->arg[(size_t)(m->val.t[i].line)],					emit_output);		} else fputs(token_name(m->val.t + i), emit_output);	}#endif	fputc('\n', emit_output);} /* * Send a token to the output (a token_fifo in lexer mode, the output * buffer in stand alone mode). */void print_token(struct lexer_state *ls, struct token *t, long uz_line){	char *x = t->name; 	if (uz_line && t->line < 0) t->line = uz_line;	if (ls->flags & LEXER) {		struct token at; 		at = *t;		if (S_TOKEN(t->type)) {			at.name = sdup(at.name);			throw_away(ls->gf, at.name);		}		aol(ls->output_fifo->t, ls->output_fifo->nt, at,			TOKEN_LIST_MEMG);		return;	}	if (ls->flags & KEEP_OUTPUT) {		for (; ls->oline < ls->line;) put_char(ls, '\n');	}	if (!S_TOKEN(t->type)) x = operators_name[t->type];	for (; *x; x ++) put_char(ls, *x);} /* * send a reduced whitespace token to the output */#define print_space(ls)	do { \		struct token lt; \		lt.type = OPT_NONE; \		lt.line = (ls)->line; \		print_token((ls), &lt, 0); \	} while (0) /* * We found a #define directive; parse the end of the line, perform * sanity checks, store the new macro into the "macros" hash table. * * In case of a redefinition of a macro: we enforce the rule that a * macro should be redefined identically, including the spelling of * parameters. We emit an error on offending code; dura lex, sed lex. * After all, it is easy to avoid such problems, with a #undef directive. */int handle_define(struct lexer_state *ls){	struct macro *m, *n;#ifdef LOW_MEM	struct token_fifo mv;#endif	int ltwws = 1, redef = 0;	char *mname = 0;	int narg;	size_t nt;	long l = ls->line;		/*vb*/#ifdef HAVE_MISRA	if(nesting!=0) misra_neu(91,19,5,0);#endif 	/* find the next non-white token on the line, this should be	   the macro name */	while (!next_token(ls) && ls->ctok->type != NEWLINE) {		if (ttMWS(ls->ctok->type)) continue;		if (ls->ctok->type == NAME) mname = sdup(ls->ctok->name);		break;	}	if (mname == 0) {		error(l, "missing macro name");		return 1;	}	if (check_special_macro(mname)) {		error(l, "trying to redefine the special macro %s", mname);		goto warp_error;	}	/*	 * If a macro with this name was already defined: the K&R	 * states that the new macro should be identical to the old one	 * (with some arcane rule of equivalence of whitespace); otherwise,	 * redefining the macro is an error. Most preprocessors would	 * only emit a warning (or nothing at all) on an unidentical	 * redefinition.	 *	 * Since it is easy to avoid this error (with a #undef directive),	 * we choose to enforce the rule and emit an error.	 */ #ifdef HAVE_MISRA		if (misra_is_reserved(mname)) misra_neu(114,20,1,-1);#endif 	if ((n = getHT(macros, &mname)) != 0) {		/* redefinition of a macro: we must check that we define		   it identical */		redef = 1;#ifdef LOW_MEM		n->cval.rp = 0;#endif		freemem(mname);	}	if (!redef) {		m = new_macro();		m->name = mname;		m->narg = -1;#ifdef LOW_MEM		mv.art = mv.nt = 0;#define mval	mv#else#define mval	(m->val)#endif	}	if (next_token(ls)) goto define_end;	/*	 * Check if the token immediately following the macro name is	 * a left parenthesis; if so, then this is a macro with arguments.	 * Collect their names and try to match the next parenthesis.	 */	if (ls->ctok->type == LPAR) {		int i, j;		int need_comma = 0, saw_mdots = 0; 		narg = 0;		while (!next_token(ls)) {			if (ls->ctok->type == NEWLINE) {				error(l, "truncated macro definition");				return 1;			}			if (ls->ctok->type == COMMA) {				if (saw_mdots) {					error(l, "'...' must end the macro "						"argument list");					goto warp_error;				}				if (!need_comma) {					error(l, "void macro argument");					goto warp_error;				}				need_comma = 0;				continue;			} else if (ls->ctok->type == NAME) {				if (saw_mdots) {					error(l, "'...' must end the macro "						"argument list");					goto warp_error;				}				if (need_comma) {					error(l, "missing comma in "						"macro argument list");					goto warp_error;				}				if (!redef) {					aol(m->arg, narg,						sdup(ls->ctok->name), 8);					if (narg == 128						&& (ls->flags & WARN_STANDARD))						warning(l, "more arguments to "							"macro than the ISO "							"limit (127)");#ifdef LOW_MEM					if (narg == 254) {						error(l, "too many arguments "							"in macro definition "							"(max 253)");						goto warp_error;					}#endif				} else {					/* this is a redefinition of the					   macro; check equality between					   old and new definitions */					if (narg >= n->narg) goto redef_error;					if (strcmp(ls->ctok->name,						n->arg[narg ++]))						goto redef_error;				}				need_comma = 1;				continue;			} else if ((ls->flags & MACRO_VAARG)				&& ls->ctok->type == MDOTS) {				if (need_comma) {					error(l, "missing comma before '...'");					goto warp_error;				}				if (redef && !n->vaarg) goto redef_error;				if (!redef) m->vaarg = 1;				saw_mdots = 1;				need_comma = 1;				continue;			} else if (ls->ctok->type == RPAR) {				if (narg > 0 && !need_comma) {					error(l, "void macro argument");					goto warp_error;				}				if (redef && n->vaarg && !saw_mdots)					goto redef_error;				break;			} else if (ttMWS(ls->ctok->type)) {				continue;			}			error(l, "invalid macro argument");			goto warp_error;		}		if (!redef) {			for (i = 1; i < narg; i ++) for (j = 0; j < i; j ++)				if (!strcmp(m->arg[i], m->arg[j])) {					error(l, "duplicate macro "						"argument");					goto warp_error;				}		}		if (!redef) m->narg = narg;	} else {		if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD))			warning(ls->line, "identifier not followed by "				"whitespace in #define");		ls->flags |= READ_AGAIN;		narg = 0;	}	if (redef) nt = 0; 	/* now, we have the arguments. Let's get the macro contents. */	while (!next_token(ls) && ls->ctok->type != NEWLINE) {		struct token t; 		t.type = ls->ctok->type;		if (ltwws && ttMWS(t.type)) continue;		t.line = 0;		if (t.type == NAME) {			int i; 			if ((ls->flags & MACRO_VAARG)				&& !strcmp(ls->ctok->name, "__VA_ARGS__")) {				if (redef) {					if (!n->vaarg) goto redef_error;				} else if (!m->vaarg) {					error(l, "'__VA_ARGS__' is forbidden "						"in macros with a fixed "						"number of arguments");					goto warp_error;				}				t.type = MACROARG;				t.line = redef ? n->narg : m->narg;

Lines 1–500 of 1870.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t