Index: uspace/app/pcc/cc/cpp/token.c
===================================================================
--- uspace/app/pcc/cc/cpp/token.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
+++ uspace/app/pcc/cc/cpp/token.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
@@ -0,0 +1,1318 @@
+/*	$Id: token.c,v 1.48.2.2 2011/03/12 17:08:26 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2004,2009 Anders Magnusson. All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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.
+ */
+
+/*
+ * Tokenizer for the C preprocessor.
+ * There are three main routines:
+ *	- fastscan() loops over the input stream searching for magic
+ *		characters that may require actions.
+ *	- sloscan() tokenize the input stream and returns tokens.
+ *		It may recurse into itself during expansion.
+ *	- yylex() returns something from the input stream that 
+ *		is suitable for yacc.
+ *
+ *	Other functions of common use:
+ *	- inpch() returns a raw character from the current input stream.
+ *	- inch() is like inpch but \\n and trigraphs are expanded.
+ *	- unch() pushes back a character to the input stream.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
+
+#include "compat.h"
+#include "cpp.h"
+#include "y.tab.h"
+
+static void cvtdig(int rad);
+static int charcon(usch *);
+static void elsestmt(void);
+static void ifdefstmt(void);
+static void ifndefstmt(void);
+static void endifstmt(void);
+static void ifstmt(void);
+static void cpperror(void);
+static void pragmastmt(void);
+static void undefstmt(void);
+static void cppwarning(void);
+static void elifstmt(void);
+static void badop(const char *);
+static int chktg(void);
+static void ppdir(void);
+void  include(void);
+void  include_next(void);
+void  define(void);
+static int inpch(void);
+
+extern int yyget_lineno (void);
+extern void yyset_lineno (int);
+
+static int inch(void);
+
+int inif;
+extern int dflag;
+
+#define	PUTCH(ch) if (!flslvl) putch(ch)
+/* protection against recursion in #include */
+#define MAX_INCLEVEL	100
+static int inclevel;
+
+/* get next character unaltered */
+#define	NXTCH() (ifiles->curptr < ifiles->maxread ? *ifiles->curptr++ : inpch())
+
+usch yytext[CPPBUF];
+
+char spechr[256] = {
+	0,	0,	0,	0,	C_SPEC,	C_SPEC,	0,	0,
+	0,	C_WSNL,	C_SPEC|C_WSNL,	0,
+	0,	C_WSNL,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+
+	C_WSNL,	C_2,	C_SPEC,	0,	0,	0,	C_2,	C_SPEC,
+	0,	0,	0,	C_2,	0,	C_2,	0,	C_SPEC|C_2,
+	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,
+	C_I,	C_I,	0,	0,	C_2,	C_2,	C_2,	C_SPEC,
+
+	0,	C_I,	C_I,	C_I,	C_I,	C_I|C_EP, C_I,	C_I,
+	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,
+	C_I|C_EP, C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,
+	C_I,	C_I,	C_I,	0,	C_I,	0,	0,	C_I,
+
+	0,	C_I,	C_I,	C_I,	C_I,	C_I|C_EP, C_I,	C_I,
+	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,
+	C_I|C_EP, C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,
+	C_I,	C_I,	C_I,	0,	C_2,	0,	0,	0,
+
+};
+
+/*
+ * No-replacement array.  If a macro is found and exists in this array
+ * then no replacement shall occur.  This is a stack.
+ */
+struct symtab *norep[RECMAX];	/* Symbol table index table */
+int norepptr = 1;			/* Top of index table */
+unsigned short bptr[RECMAX];	/* currently active noexpand macro stack */
+int bidx;			/* Top of bptr stack */
+
+static void
+unch(int c)
+{
+		
+	--ifiles->curptr;
+	if (ifiles->curptr < ifiles->bbuf)
+		error("pushback buffer full");
+	*ifiles->curptr = (usch)c;
+}
+
+static int
+eatcmnt(void)
+{
+	int ch;
+
+	if (Cflag) { PUTCH('/'); PUTCH('*'); }
+	for (;;) {
+		ch = inch();
+		if (ch == '\n') {
+			ifiles->lineno++;
+			PUTCH('\n');
+		}
+		if (ch == -1)
+			return -1;
+		if (ch == '*') {
+			ch = inch();
+			if (ch == '/') {
+				if (Cflag) {
+					PUTCH('*');
+					PUTCH('/');
+				} else
+					PUTCH(' ');
+				break;
+			}
+			unch(ch);
+			ch = '*';
+		}
+		if (Cflag) PUTCH(ch);
+	}
+	return 0;
+}
+
+/*
+ * Scan quickly the input file searching for:
+ *	- '#' directives
+ *	- keywords (if not flslvl)
+ *	- comments
+ *
+ *	Handle strings, numbers and trigraphs with care.
+ *	Only data from pp files are scanned here, never any rescans.
+ *	TODO: Only print out strings before calling other functions.
+ */
+static void
+fastscan(void)
+{
+	struct symtab *nl;
+	int ch, i, ccnt, onemore;
+	usch *cp;
+
+	goto run;
+	for (;;) {
+		ch = NXTCH();
+xloop:		if (ch == -1)
+			return;
+		if (dflag>1)
+			printf("fastscan ch %d (%c)\n", ch, ch > 31 ? ch : '@');
+		if ((spechr[ch] & C_SPEC) == 0) {
+			PUTCH(ch);
+			continue;
+		}
+		switch (ch) {
+		case EBLOCK:
+		case WARN:
+		case CONC:
+			error("bad char passed");
+			break;
+
+		case '/': /* Comments */
+			if ((ch = inch()) == '/') {
+cppcmt:				if (Cflag) { PUTCH(ch); } else { PUTCH(' '); }
+				do {
+					if (Cflag) PUTCH(ch);
+					ch = inch();
+				} while (ch != -1 && ch != '\n');
+				goto xloop;
+			} else if (ch == '*') {
+				if (eatcmnt())
+					return;
+			} else {
+				PUTCH('/');
+				goto xloop;
+			}
+			break;
+
+		case '?':  /* trigraphs */
+			if ((ch = chktg()))
+				goto xloop;
+			PUTCH('?');
+			break;
+
+		case '\\':
+			if ((ch = NXTCH()) == '\n') {
+				ifiles->lineno++;
+				continue;
+			} else {
+				PUTCH('\\');
+			}
+			goto xloop;
+
+		case '\n': /* newlines, for pp directives */
+run2:			ifiles->lineno++;
+			do {
+				PUTCH(ch);
+run:				ch = NXTCH();
+				if (ch == '/') {
+					ch = NXTCH();
+					if (ch == '/')
+						goto cppcmt;
+					if (ch == '*') {
+						if (eatcmnt())
+							return;
+						goto run;
+					} 
+					unch(ch);
+					ch = '/';
+				}
+			} while (ch == ' ' || ch == '\t');
+			if (ch == '\\') {
+				ch = NXTCH();
+				if (ch == '\n')
+					goto run2;
+				unch(ch);
+				ch = '\\';
+			}
+			if (ch == '#') {
+				ppdir();
+				continue;
+			} else if (ch == '%') {
+				ch = NXTCH();
+				if (ch == ':') {
+					ppdir();
+					continue;
+				} else {
+					unch(ch);
+					ch = '%';
+				}
+			}
+			goto xloop;
+
+		case '\"': /* strings */
+str:			PUTCH(ch);
+			while ((ch = inch()) != '\"') {
+					PUTCH(ch);
+				if (ch == '\\') {
+					ch = inch();
+					PUTCH(ch);
+				}
+				if (ch < 0)
+					return;
+			}
+			PUTCH(ch);
+			break;
+
+		case '.':  /* for pp-number */
+			PUTCH(ch);
+			ch = NXTCH();
+			if (ch < '0' || ch > '9')
+				goto xloop;
+			/* FALLTHROUGH */
+		case '0': case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+			do {
+				PUTCH(ch);
+nxt:				ch = NXTCH();
+				if (ch == '\\') {
+					ch = NXTCH();
+					if (ch == '\n') {
+						goto nxt;
+					} else {
+						unch(ch);
+						ch = '\\';
+					}
+				}
+				if (spechr[ch] & C_EP) {
+					PUTCH(ch);
+					ch = NXTCH();
+					if (ch == '-' || ch == '+')
+						continue;
+				}
+			} while ((spechr[ch] & C_ID) || (ch == '.'));
+			goto xloop;
+
+		case '\'': /* character literal */
+con:			PUTCH(ch);
+			if (tflag)
+				continue; /* character constants ignored */
+			while ((ch = NXTCH()) != '\'') {
+				PUTCH(ch);
+				if (ch == '\\') {
+					ch = NXTCH();
+					PUTCH(ch);
+				} else if (ch < 0)
+					return;
+				else if (ch == '\n')
+					goto xloop;
+			}
+			PUTCH(ch);
+			break;
+
+		case 'L':
+			ch = NXTCH();
+			if (ch == '\"') {
+				PUTCH('L');
+				goto str;
+			}
+			if (ch == '\'') {
+				PUTCH('L');
+				goto con;
+			}
+			unch(ch);
+			ch = 'L';
+			/* FALLTHROUGH */
+		default:
+			if ((spechr[ch] & C_ID) == 0)
+				error("fastscan");
+			if (flslvl) {
+				while (spechr[ch] & C_ID)
+					ch = NXTCH();
+				goto xloop;
+			}
+			onemore = i = ccnt = 0;
+			do {
+				yytext[i++] = (usch)ch;
+				ch = NXTCH();
+				if (ch == '\\') {
+					ch = NXTCH();
+					if (ch != '\n') {
+						unch('\n');
+						ch = '\\';
+					} else {
+						ifiles->lineno++;
+						ch = NXTCH();
+					}
+				}
+				if (ch < 0)
+					return;
+			} while (spechr[ch] & C_ID);
+
+			yytext[i] = 0;
+			unch(ch);
+
+			cp = stringbuf;
+			if ((nl = lookup((usch *)yytext, FIND)) && kfind(nl)) {
+				putstr(stringbuf);
+			} else
+				putstr((usch *)yytext);
+			stringbuf = cp;
+
+			break;
+		}
+	}
+}
+
+int
+sloscan()
+{
+	int ch;
+	int yyp;
+
+zagain:
+	yyp = 0;
+ 	ch = inch();
+	yytext[yyp++] = (usch)ch;
+	switch (ch) {
+	case -1:
+		return 0;
+	case '\n':
+		/* sloscan() never passes \n, that's up to fastscan() */
+		unch(ch);
+		goto yyret;
+
+	case '\r': /* Ignore CR's */
+		yyp = 0;
+		break;
+
+	case '0': case '1': case '2': case '3': case '4': case '5': 
+	case '6': case '7': case '8': case '9':
+		/* readin a "pp-number" */
+ppnum:		for (;;) {
+			ch = inch();
+			if (spechr[ch] & C_EP) {
+				yytext[yyp++] = (usch)ch;
+				ch = inch();
+				if (ch == '-' || ch == '+') {
+					yytext[yyp++] = (usch)ch;
+				} else
+					unch(ch);
+				continue;
+			}
+			if ((spechr[ch] & C_ID) || ch == '.') {
+				yytext[yyp++] = (usch)ch;
+				continue;
+			} 
+			break;
+		}
+		unch(ch);
+		yytext[yyp] = 0;
+
+		return NUMBER;
+
+	case '\'':
+chlit:		
+		for (;;) {
+			if ((ch = inch()) == '\\') {
+				yytext[yyp++] = (usch)ch;
+				yytext[yyp++] = (usch)inch();
+				continue;
+			} else if (ch == '\n') {
+				/* not a constant */
+				while (yyp > 1)
+					unch(yytext[--yyp]);
+				ch = '\'';
+				goto any;
+			} else
+				yytext[yyp++] = (usch)ch;
+			if (ch == '\'')
+				break;
+		}
+		yytext[yyp] = 0;
+
+		return (NUMBER);
+
+	case ' ':
+	case '\t':
+		while ((ch = inch()) == ' ' || ch == '\t')
+			yytext[yyp++] = (usch)ch;
+		unch(ch);
+		yytext[yyp] = 0;
+		return(WSPACE);
+
+	case '/':
+		if ((ch = inch()) == '/') {
+			do {
+				yytext[yyp++] = (usch)ch;
+				ch = inch();
+			} while (ch && ch != '\n');
+			yytext[yyp] = 0;
+			unch(ch);
+			goto zagain;
+		} else if (ch == '*') {
+			int c, wrn;
+			extern int readmac;
+
+			if (Cflag && !flslvl && readmac) {
+				unch(ch);
+				yytext[yyp] = 0;
+				return CMNT;
+			}
+
+			wrn = 0;
+		more:	while ((c = inch()) && c != '*') {
+				if (c == '\n')
+					putch(c), ifiles->lineno++;
+				else if (c == EBLOCK) {
+					(void)inch();
+					(void)inch();
+				} else if (c == 1) /* WARN */
+					wrn = 1;
+			}
+			if (c == 0)
+				return 0;
+			if ((c = inch()) && c != '/') {
+				unch(c);
+				goto more;
+			}
+			if (c == 0)
+				return 0;
+			if (!tflag && !Cflag && !flslvl)
+				unch(' ');
+			if (wrn)
+				unch(1);
+			goto zagain;
+		}
+		unch(ch);
+		ch = '/';
+		goto any;
+
+	case '.':
+		ch = inch();
+		if (isdigit(ch)) {
+			yytext[yyp++] = (usch)ch;
+			goto ppnum;
+		} else {
+			unch(ch);
+			ch = '.';
+		}
+		goto any;
+
+	case '\"':
+		if (tflag)
+			goto any;
+	strng:
+		for (;;) {
+			if ((ch = inch()) == '\\') {
+				yytext[yyp++] = (usch)ch;
+				yytext[yyp++] = (usch)inch();
+				continue;
+			} else 
+				yytext[yyp++] = (usch)ch;
+			if (ch == '\"')
+				break;
+		}
+		yytext[yyp] = 0;
+		return(STRING);
+
+	case 'L':
+		if ((ch = inch()) == '\"' && !tflag) {
+			yytext[yyp++] = (usch)ch;
+			goto strng;
+		} else if (ch == '\'' && !tflag) {
+			yytext[yyp++] = (usch)ch;
+			goto chlit;
+		}
+		unch(ch);
+		/* FALLTHROUGH */
+
+	/* Yetch, all identifiers */
+	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 
+	case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': 
+	case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': 
+	case 's': case 't': case 'u': case 'v': case 'w': case 'x': 
+	case 'y': case 'z':
+	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 
+	case 'G': case 'H': case 'I': case 'J': case 'K':
+	case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': 
+	case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': 
+	case 'Y': case 'Z':
+	case '_': /* {L}({L}|{D})* */
+
+		/* Special hacks */
+		for (;;) { /* get chars */
+			ch = inch();
+			if (isalpha(ch) || isdigit(ch) || ch == '_') {
+				yytext[yyp++] = (usch)ch;
+			} else {
+				unch(ch);
+				break;
+			}
+		}
+		yytext[yyp] = 0; /* need already string */
+		/* end special hacks */
+
+		return IDENT;
+	default:
+	any:
+		yytext[yyp] = 0;
+		return yytext[0];
+
+	} /* endcase */
+	goto zagain;
+
+yyret:
+	yytext[yyp] = 0;
+	return ch;
+}
+
+int
+yylex()
+{
+	static int ifdef, noex;
+	struct symtab *nl;
+	int ch, c2;
+
+	while ((ch = sloscan()) == WSPACE)
+		;
+	if (ch < 128 && spechr[ch] & C_2)
+		c2 = inpch();
+	else
+		c2 = 0;
+
+#define	C2(a,b,c) case a: if (c2 == b) return c; break
+	switch (ch) {
+	C2('=', '=', EQ);
+	C2('!', '=', NE);
+	C2('|', '|', OROR);
+	C2('&', '&', ANDAND);
+	case '<':
+		if (c2 == '<') return LS;
+		if (c2 == '=') return LE;
+		break;
+	case '>':
+		if (c2 == '>') return RS;
+		if (c2 == '=') return GE;
+		break;
+	case '+':
+	case '-':
+		if (ch == c2)
+			badop("");
+		break;
+
+	case '/':
+		if (Cflag == 0 || c2 != '*')
+			break;
+		/* Found comment that need to be skipped */
+		for (;;) {
+			ch = inpch();
+		c1:	if (ch != '*')
+				continue;
+			if ((ch = inpch()) == '/')
+				break;
+			goto c1;
+		}
+		return yylex();
+
+	case NUMBER:
+		if (yytext[0] == '\'') {
+			yylval.node.op = NUMBER;
+			yylval.node.nd_val = charcon((usch *)yytext);
+		} else
+			cvtdig(yytext[0] != '0' ? 10 :
+			    yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8);
+		return NUMBER;
+
+	case IDENT:
+		if (strcmp((char *)yytext, "defined") == 0) {
+			ifdef = 1;
+			return DEFINED;
+		}
+		nl = lookup((usch *)yytext, FIND);
+		if (ifdef) {
+			yylval.node.nd_val = nl != NULL;
+			ifdef = 0;
+		} else if (nl && noex == 0) {
+			usch *och = stringbuf;
+			int i;
+
+			i = kfind(nl);
+			unch(WARN);
+			if (i)
+				unpstr(stringbuf);
+			else
+				unpstr(nl->namep);
+			stringbuf = och;
+			noex = 1;
+			return yylex();
+		} else {
+			yylval.node.nd_val = 0;
+		}
+		yylval.node.op = NUMBER;
+		return NUMBER;
+	case WARN:
+		noex = 0;
+		return yylex();
+	default:
+		return ch;
+	}
+	unch(c2);
+	return ch;
+}
+
+usch *yyp, yybuf[CPPBUF];
+
+int yywrap(void);
+
+static int
+inpch(void)
+{
+	int len;
+
+	if (ifiles->curptr < ifiles->maxread)
+		return *ifiles->curptr++;
+
+	if (ifiles->infil == -1)
+		return -1;
+	if ((len = read(ifiles->infil, ifiles->buffer, CPPBUF)) < 0)
+		error("read error on file %s", ifiles->orgfn);
+	if (len == 0)
+		return -1;
+	ifiles->curptr = ifiles->buffer;
+	ifiles->maxread = ifiles->buffer + len;
+	return inpch();
+}
+
+static int
+inch(void)
+{
+	int c;
+
+again:	switch (c = inpch()) {
+	case '\\': /* continued lines */
+msdos:		if ((c = inpch()) == '\n') {
+			ifiles->lineno++;
+			goto again;
+		} else if (c == '\r')
+			goto msdos;
+		unch(c);
+		return '\\';
+	case '?': /* trigraphs */
+		if ((c = chktg())) {
+			unch(c);
+			goto again;
+		}
+		return '?';
+	default:
+		return c;
+	}
+}
+
+/*
+ * Let the command-line args be faked defines at beginning of file.
+ */
+static void
+prinit(struct initar *it, struct includ *ic)
+{
+	const char *pre, *post;
+	char *a;
+
+	if (it->next)
+		prinit(it->next, ic);
+	pre = post = NULL; /* XXX gcc */
+	switch (it->type) {
+	case 'D':
+		pre = "#define ";
+		if ((a = strchr(it->str, '=')) != NULL) {
+			*a = ' ';
+			post = "\n";
+		} else
+			post = " 1\n";
+		break;
+	case 'U':
+		pre = "#undef ";
+		post = "\n";
+		break;
+	case 'i':
+		pre = "#include \"";
+		post = "\"\n";
+		break;
+	default:
+		error("prinit");
+	}
+	strlcat((char *)ic->buffer, pre, CPPBUF+1);
+	strlcat((char *)ic->buffer, it->str, CPPBUF+1);
+	if (strlcat((char *)ic->buffer, post, CPPBUF+1) >= CPPBUF+1)
+		error("line exceeds buffer size");
+
+	ic->lineno--;
+	while (*ic->maxread)
+		ic->maxread++;
+}
+
+/*
+ * A new file included.
+ * If ifiles == NULL, this is the first file and already opened (stdin).
+ * Return 0 on success, -1 if file to be included is not found.
+ */
+int
+pushfile(const usch *file, const usch *fn, int idx, void *incs)
+{
+	extern struct initar *initar;
+	struct includ ibuf;
+	struct includ *ic;
+	int otrulvl;
+
+	ic = &ibuf;
+	ic->next = ifiles;
+
+	if (file != NULL) {
+		if ((ic->infil = open((const char *)file, O_RDONLY)) < 0)
+			return -1;
+		ic->orgfn = ic->fname = file;
+		if (++inclevel > MAX_INCLEVEL)
+			error("Limit for nested includes exceeded");
+	} else {
+		ic->infil = 0;
+		ic->orgfn = ic->fname = (const usch *)"<stdin>";
+	}
+#ifndef BUF_STACK
+	ic->bbuf = malloc(BBUFSZ);
+#endif
+	ic->buffer = ic->bbuf+NAMEMAX;
+	ic->curptr = ic->buffer;
+	ifiles = ic;
+	ic->lineno = 1;
+	ic->maxread = ic->curptr;
+	ic->idx = idx;
+	ic->incs = incs;
+	ic->fn = fn;
+	prtline();
+	if (initar) {
+		int oin = ic->infil;
+		ic->infil = -1;
+		*ic->maxread = 0;
+		prinit(initar, ic);
+		initar = NULL;
+		if (dMflag)
+			write(ofd, ic->buffer, strlen((char *)ic->buffer));
+		fastscan();
+		prtline();
+		ic->infil = oin;
+	}
+
+	otrulvl = trulvl;
+
+	fastscan();
+
+	if (otrulvl != trulvl || flslvl)
+		error("unterminated conditional");
+
+#ifndef BUF_STACK
+	free(ic->bbuf);
+#endif
+	ifiles = ic->next;
+	close(ic->infil);
+	inclevel--;
+	return 0;
+}
+
+/*
+ * Print current position to output file.
+ */
+void
+prtline()
+{
+	usch *s, *os = stringbuf;
+
+	if (Mflag) {
+		if (dMflag)
+			return; /* no output */
+		if (ifiles->lineno == 1) {
+			s = sheap("%s: %s\n", Mfile, ifiles->fname);
+			write(ofd, s, strlen((char *)s));
+		}
+	} else if (!Pflag)
+		putstr(sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname));
+	stringbuf = os;
+}
+
+void
+cunput(int c)
+{
+#ifdef CPP_DEBUG
+//	extern int dflag;
+//	if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c);
+#endif
+#if 0
+if (c == 10) {
+	printf("c == 10!!!\n");
+}
+#endif
+	unch(c);
+}
+
+int yywrap(void) { return 1; }
+
+static int
+dig2num(int c)
+{
+	if (c >= 'a')
+		c = c - 'a' + 10;
+	else if (c >= 'A')
+		c = c - 'A' + 10;
+	else
+		c = c - '0';
+	return c;
+}
+
+/*
+ * Convert string numbers to unsigned long long and check overflow.
+ */
+static void
+cvtdig(int rad)
+{
+	unsigned long long rv = 0;
+	unsigned long long rv2 = 0;
+	usch *y = yytext;
+	int c;
+
+	c = *y++;
+	if (rad == 16)
+		y++;
+	while (isxdigit(c)) {
+		rv = rv * rad + dig2num(c);
+		/* check overflow */
+		if (rv / rad < rv2)
+			error("Constant \"%s\" is out of range", yytext);
+		rv2 = rv;
+		c = *y++;
+	}
+	y--;
+	while (*y == 'l' || *y == 'L')
+		y++;
+	yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER;
+	yylval.node.nd_uval = rv;
+	if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0)
+		yylval.node.op = UNUMBER;
+	if (yylval.node.op == NUMBER && yylval.node.nd_val < 0)
+		/* too large for signed, see 6.4.4.1 */
+		error("Constant \"%s\" is out of range", yytext);
+}
+
+static int
+charcon(usch *p)
+{
+	int val, c;
+
+	p++; /* skip first ' */
+	val = 0;
+	if (*p++ == '\\') {
+		switch (*p++) {
+		case 'a': val = '\a'; break;
+		case 'b': val = '\b'; break;
+		case 'f': val = '\f'; break;
+		case 'n': val = '\n'; break;
+		case 'r': val = '\r'; break;
+		case 't': val = '\t'; break;
+		case 'v': val = '\v'; break;
+		case '\"': val = '\"'; break;
+		case '\'': val = '\''; break;
+		case '\\': val = '\\'; break;
+		case 'x':
+			while (isxdigit(c = *p)) {
+				val = val * 16 + dig2num(c);
+				p++;
+			}
+			break;
+		case '0': case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7':
+			p--;
+			while (isdigit(c = *p)) {
+				val = val * 8 + (c - '0');
+				p++;
+			}
+			break;
+		default: val = p[-1];
+		}
+
+	} else
+		val = p[-1];
+	return val;
+}
+
+static void
+chknl(int ignore)
+{
+	int t;
+
+	while ((t = sloscan()) == WSPACE)
+		;
+	if (t != '\n') {
+		if (ignore) {
+			warning("newline expected, got \"%s\"", yytext);
+			/* ignore rest of line */
+			while ((t = sloscan()) && t != '\n')
+				;
+		}
+		else
+			error("newline expected, got \"%s\"", yytext);
+	}
+}
+
+static void
+elsestmt(void)
+{
+	if (flslvl) {
+		if (elflvl > trulvl)
+			;
+		else if (--flslvl!=0) {
+			flslvl++;
+		} else {
+			trulvl++;
+			prtline();
+		}
+	} else if (trulvl) {
+		flslvl++;
+		trulvl--;
+	} else
+		error("If-less else");
+	if (elslvl==trulvl+flslvl)
+		error("Too many else");
+	elslvl=trulvl+flslvl;
+	chknl(1);
+}
+
+static void
+skpln(void)
+{
+	/* just ignore the rest of the line */
+	while (inch() != '\n')
+		;
+	unch('\n');
+	flslvl++;
+}
+
+static void
+ifdefstmt(void)		 
+{ 
+	int t;
+
+	if (flslvl) {
+		skpln();
+		return;
+	}
+	do
+		t = sloscan();
+	while (t == WSPACE);
+	if (t != IDENT)
+		error("bad ifdef");
+	if (lookup((usch *)yytext, FIND) == 0) {
+		putch('\n');
+		flslvl++;
+	} else
+		trulvl++;
+	chknl(0);
+}
+
+static void
+ifndefstmt(void)	  
+{ 
+	int t;
+
+	if (flslvl) {
+		skpln();
+		return;
+	}
+	do
+		t = sloscan();
+	while (t == WSPACE);
+	if (t != IDENT)
+		error("bad ifndef");
+	if (lookup((usch *)yytext, FIND) != 0) {
+		putch('\n');
+		flslvl++;
+	} else
+		trulvl++;
+	chknl(0);
+}
+
+static void
+endifstmt(void)		 
+{
+	if (flslvl) {
+		flslvl--;
+		if (flslvl == 0) {
+			putch('\n');
+			prtline();
+		}
+	} else if (trulvl)
+		trulvl--;
+	else
+		error("If-less endif");
+	if (flslvl == 0)
+		elflvl = 0;
+	elslvl = 0;
+	chknl(1);
+}
+
+static void
+ifstmt(void)
+{
+	if (flslvl == 0) {
+		if (yyparse() == 0) {
+			putch('\n');
+			++flslvl;
+		} else
+			++trulvl;
+	} else
+		++flslvl;
+}
+
+static void
+elifstmt(void)
+{
+	if (flslvl == 0)
+		elflvl = trulvl;
+	if (flslvl) {
+		if (elflvl > trulvl)
+			;
+		else if (--flslvl!=0)
+			++flslvl;
+		else {
+			if (yyparse()) {
+				++trulvl;
+				prtline();
+			} else {
+				putch('\n');
+				++flslvl;
+			}
+		}
+	} else if (trulvl) {
+		++flslvl;
+		--trulvl;
+	} else
+		error("If-less elif");
+}
+
+static usch *
+svinp(void)
+{
+	int c;
+	usch *cp = stringbuf;
+
+	while ((c = inch()) && c != '\n')
+		savch(c);
+	savch('\n');
+	savch(0);
+	return cp;
+}
+
+static void
+cpperror(void)
+{
+	usch *cp;
+	int c;
+
+	if (flslvl)
+		return;
+	c = sloscan();
+	if (c != WSPACE && c != '\n')
+		error("bad error");
+	cp = svinp();
+	if (flslvl)
+		stringbuf = cp;
+	else
+		error("%s", cp);
+}
+
+static void
+cppwarning(void)
+{
+	usch *cp;
+	int c;
+
+	if (flslvl)
+		return;
+	c = sloscan();
+	if (c != WSPACE && c != '\n')
+		error("bad warning");
+
+	/* svinp() add an unwanted \n */
+	cp = stringbuf;
+	while ((c = inch()) && c != '\n')
+		savch(c);
+	savch(0);
+
+	if (flslvl)
+		stringbuf = cp;
+	else
+		warning("#warning %s", cp);
+
+	unch('\n');
+}
+
+static void
+undefstmt(void)
+{
+	struct symtab *np;
+
+	if (sloscan() != WSPACE || sloscan() != IDENT)
+		error("bad undef");
+	if (flslvl == 0 && (np = lookup((usch *)yytext, FIND)))
+		np->value = 0;
+	chknl(0);
+}
+
+static void
+pragmastmt(void)
+{
+	int c;
+
+	if (sloscan() != WSPACE)
+		error("bad pragma");
+	if (!flslvl)
+		putstr((const usch *)"\n#pragma ");
+	do {
+		c = inch();
+		if (!flslvl)
+			putch(c);	/* Do arg expansion instead? */
+	} while (c && c != '\n');
+	if (c == '\n')
+		unch(c);
+	prtline();
+}
+
+static void
+badop(const char *op)
+{
+	error("invalid operator in preprocessor expression: %s", op);
+}
+
+int
+cinput()
+{
+	return inch();
+}
+
+/*
+ * Check for (and convert) trigraphs.
+ */
+int
+chktg()
+{
+	int c;
+
+	if ((c = inpch()) != '?') {
+		unch(c);
+		return 0;
+	}
+	switch (c = inpch()) {
+	case '=': c = '#'; break;
+	case '(': c = '['; break;
+	case ')': c = ']'; break;
+	case '<': c = '{'; break;
+	case '>': c = '}'; break;
+	case '/': c = '\\'; break;
+	case '\'': c = '^'; break;
+	case '!': c = '|'; break;
+	case '-': c = '~'; break;
+	default:
+		unch(c);
+		unch('?');
+		c = 0;
+	}
+	return c;
+}
+
+static struct {
+	const char *name;
+	void (*fun)(void);
+} ppd[] = {
+	{ "ifndef", ifndefstmt },
+	{ "ifdef", ifdefstmt },
+	{ "if", ifstmt },
+	{ "include", include },
+	{ "else", elsestmt },
+	{ "endif", endifstmt },
+	{ "error", cpperror },
+	{ "warning", cppwarning },
+	{ "define", define },
+	{ "undef", undefstmt },
+	{ "line", line },
+	{ "pragma", pragmastmt },
+	{ "elif", elifstmt },
+#ifdef GCC_COMPAT
+	{ "include_next", include_next },
+#endif
+};
+
+/*
+ * Handle a preprocessor directive.
+ */
+void
+ppdir(void)
+{
+	char bp[20];
+	int ch, i;
+
+	while ((ch = inch()) == ' ' || ch == '\t')
+		;
+	if (ch == '\n') { /* empty directive */
+		unch(ch);
+		return;
+	}
+	if (ch < 'a' || ch > 'z')
+		goto out; /* something else, ignore */
+	i = 0;
+	do {
+		bp[i++] = (usch)ch;
+		if (i == sizeof(bp)-1)
+			goto out; /* too long */
+		ch = inch();
+	} while ((ch >= 'a' && ch <= 'z') || (ch == '_'));
+	unch(ch);
+	bp[i++] = 0;
+
+	/* got keyword */
+#define	SZ (int)(sizeof(ppd)/sizeof(ppd[0]))
+	for (i = 0; i < SZ; i++)
+		if (bp[0] == ppd[i].name[0] && strcmp(bp, ppd[i].name) == 0)
+			break;
+	if (i == SZ)
+		goto out;
+
+	/* Found matching keyword */
+	(*ppd[i].fun)();
+	return;
+
+out:	while ((ch = inch()) != '\n' && ch != -1)
+		;
+	unch('\n');
+}
