scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | LICENSE

cpp.c (14489B)


      1 #include <ctype.h>
      2 #include <limits.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include <time.h>
      7 
      8 #include <scc/cstd.h>
      9 #include <scc/scc.h>
     10 #include "cc1.h"
     11 
     12 static char *argp, *macroname;
     13 static unsigned arglen;
     14 static unsigned ncmdlines;
     15 static Symbol *symline, *symfile;
     16 static unsigned char ifstatus[NR_COND];
     17 static int cppoff;
     18 static struct items dirinclude;
     19 
     20 unsigned cppctx;
     21 int disexpand;
     22 
     23 void
     24 defdefine(char *macro, char *val, char *source)
     25 {
     26 	char *def, *fmt = "#define %s %s\n";
     27 	Symbol dummy = {.flags = SDECLARED};
     28 
     29 	if (!val)
     30 		val = "";
     31 	def = xmalloc(strlen(fmt) + strlen(macro) + strlen(val));
     32 
     33 	sprintf(def, fmt, macro, val);
     34 	lineno = ++ncmdlines;
     35 	addinput(source, &dummy, def);
     36 	cpp();
     37 	delinput();
     38 }
     39 
     40 void
     41 undefmacro(char *s)
     42 {
     43 	killsym(lookup(NS_CPP, s, NOALLOC));
     44 }
     45 
     46 void
     47 icpp(void)
     48 {
     49 	static char sdate[14], stime[11];
     50 	struct tm *tm;
     51 	time_t t;
     52 	static char **bp, *list[] = {
     53 		"__STDC__",
     54 		"__STDC_HOSTED__",
     55 		"__SCC__",
     56 		NULL
     57 	};
     58 	static struct keyword keys[] = {
     59 		{"define", DEFINE, DEFINE},
     60 		{"include", INCLUDE, INCLUDE},
     61 		{"line", LINE, LINE},
     62 		{"ifdef", IFDEF, IFDEF},
     63 		{"if", IF, IF},
     64 		{"elif", ELIF, ELIF},
     65 		{"else", ELSE, ELSE},
     66 		{"ifndef", IFNDEF, IFNDEF},
     67 		{"endif", ENDIF, ENDIF},
     68 		{"undef", UNDEF, UNDEF},
     69 		{"pragma", PRAGMA, PRAGMA},
     70 		{"error", ERROR, ERROR},
     71 		{NULL, 0, 0}
     72 	};
     73 
     74 	keywords(keys, NS_CPPCLAUSES);
     75 
     76 	t = time(NULL);
     77 	tm = localtime(&t);
     78 	strftime(sdate, sizeof(sdate), "\"%b %d %Y\"", tm);
     79 	strftime(stime, sizeof(stime), "\"%H:%M:%S\"", tm);
     80 	defdefine("__DATE__", sdate, "built-in");
     81 	defdefine("__TIME__", stime, "built-in");
     82 	defdefine("__STDC_VERSION__", STDC_VERSION, "built-in");
     83 	defdefine("__LINE__", NULL, "built-in");
     84 	defdefine("__FILE__", NULL, "built-in");
     85 
     86 	symline = lookup(NS_CPP, "__LINE__", ALLOC);
     87 	symfile = lookup(NS_CPP, "__FILE__", ALLOC);
     88 
     89 	for (bp = list; *bp; ++bp)
     90 		defdefine(*bp, "1", "built-in");
     91 
     92 	ncmdlines = 0;
     93 }
     94 
     95 static void
     96 nextcpp(void)
     97 {
     98 	next();
     99 	if (yytoken == EOFTOK)
    100 		error("unterminated argument list invoking macro \"%s\"",
    101 		      macroname);
    102 	if (yylen + 1 > arglen)
    103 		error("argument overflow invoking macro \"%s\"",
    104 		      macroname);
    105 	if (yytoken == IDEN)
    106 		yylval.sym->flags |= SUSED;
    107 	memcpy(argp, yytext, yylen);
    108 	argp += yylen;
    109 	*argp++ = ' ';
    110 	arglen -= yylen + 1;
    111 }
    112 
    113 static void
    114 paren(void)
    115 {
    116 	for (;;) {
    117 		nextcpp();
    118 		switch (yytoken) {
    119 		case ')':
    120 			return;
    121 		case '(':
    122 			paren();
    123 			break;
    124 		}
    125 	}
    126 }
    127 
    128 static void
    129 parameter(void)
    130 {
    131 	for (;;) {
    132 		nextcpp();
    133 		switch (yytoken) {
    134 		case ')':
    135 		case ',':
    136 			argp -= 3;  /* remove " , "  or " ) "*/
    137 			*argp++ = '\0';
    138 			return;
    139 		case '(':
    140 			paren();
    141 			break;
    142 		}
    143 	}
    144 }
    145 
    146 static int
    147 parsepars(char *buffer, char **listp, int nargs)
    148 {
    149 	int n;
    150 
    151 	if (nargs == -1)
    152 		return -1;
    153 	if (ahead() != '(' && nargs > 0)
    154 		return 0;
    155 
    156 	disexpand = 1;
    157 	next();
    158 	n = 0;
    159 	argp = buffer;
    160 	arglen = INPUTSIZ;
    161 	if (ahead() == ')') {
    162 		next();
    163 	} else {
    164 		do {
    165 			*listp++ = argp;
    166 			parameter();
    167 		} while (++n < NR_MACROARG && yytoken == ',');
    168 	}
    169 	if (yytoken != ')')
    170 		error("incorrect macro function-alike invocation");
    171 	disexpand = 0;
    172 
    173 	if (n == NR_MACROARG)
    174 		error("too many parameters in macro \"%s\"", macroname);
    175 	if (n != nargs) {
    176 		error("macro \"%s\" received %d arguments, but it takes %d",
    177 		      macroname, n, nargs);
    178 	}
    179 
    180 	return 1;
    181 }
    182 
    183 static size_t
    184 copymacro(char *buffer, char *s, size_t bufsiz, char *arglist[])
    185 {
    186 	int delim, prevc, c;
    187 	char *p, *arg, *bp = buffer;
    188 	size_t size;
    189 
    190 	for (prevc = '\0'; c = *s; prevc = c, ++s) {
    191 		switch (c) {
    192 		case '$':
    193 			while (bp[-1] == ' ')
    194 				--bp, ++bufsiz;
    195 			while (s[1] == ' ')
    196 				++s;
    197 		case '#':
    198 			break;
    199 		case '\'':
    200 			delim = '\'';
    201 			goto search_delim;
    202 		case '\"':
    203 			delim = '"';
    204 		search_delim:
    205 			for (p = s; *++s != delim; )
    206 				;
    207 			size = s - p + 1;
    208 			if (size > bufsiz)
    209 				goto expansion_too_long;
    210 			memcpy(bp, p, size);
    211 			bufsiz -= size;
    212 			bp += size;
    213 			break;
    214 		case '@':
    215 			if (prevc == '#')
    216 				bufsiz -= 2;
    217 			arg = arglist[atoi(++s)];
    218 			size = strlen(arg);
    219 			if (size > bufsiz)
    220 				goto expansion_too_long;
    221 			if (prevc == '#')
    222 				*bp++ = '"';
    223 			memcpy(bp, arg, size);
    224 			bp += size;
    225 			if (prevc == '#')
    226 				*bp++ = '"';
    227 			bufsiz -= size;
    228 			s += 2;
    229 			break;
    230 		default:
    231 			if (bufsiz-- == 0)
    232 				goto expansion_too_long;
    233 			*bp++ = c;
    234 			break;
    235 		}
    236 	}
    237 	*bp = '\0';
    238 
    239 	return bp - buffer;
    240 
    241 expansion_too_long:
    242 	error("macro expansion of \"%s\" too long", macroname);
    243 }
    244 
    245 int
    246 expand(char *begin, Symbol *sym)
    247 {
    248 	size_t elen;
    249 	int n, i;
    250 	char *s = sym->u.s;
    251 	char *arglist[NR_MACROARG], arguments[INPUTSIZ], buffer[INPUTSIZ];
    252 
    253 	macroname = sym->name;
    254 	if (sym == symfile) {
    255 		elen = sprintf(buffer, "\"%s\" ", filenam);
    256 		goto substitute;
    257 	}
    258 	if (sym == symline) {
    259 		elen = sprintf(buffer, "%d ", lineno);
    260 		goto substitute;
    261 	}
    262 	if (!s)
    263 		return 1;
    264 
    265 	n = atoi(s);
    266 	if (!parsepars(arguments, arglist, n))
    267 		return 0;
    268 	for (i = 0; i < n; ++i)
    269 		DBG("MACRO par%d:%s", i, arglist[i]);
    270 
    271 	elen = copymacro(buffer, s+3, INPUTSIZ-1, arglist);
    272 
    273 substitute:
    274 	DBG("MACRO '%s' expanded to :'%s'", macroname, buffer);
    275 	buffer[elen] = '\0';
    276 	addinput(filenam, sym, xstrdup(buffer));
    277 
    278 	return 1;
    279 }
    280 
    281 static int
    282 getpars(Symbol *args[NR_MACROARG])
    283 {
    284 	int n, c;
    285 	Symbol *sym;
    286 
    287 	c = *input->p;
    288 	next();
    289 	if (c != '(')
    290 		return -1;
    291 	next(); /* skip the '(' */
    292 	if (accept(')'))
    293 		return 0;
    294 
    295 	n = 0;
    296 	do {
    297 		if (n == NR_MACROARG) {
    298 			cpperror("too many parameters in macro");
    299 			return NR_MACROARG;
    300 		}
    301 		if (accept(ELLIPSIS)) {
    302 			args[n++] = NULL;
    303 			break;
    304 		}
    305 		if (yytoken != IDEN) {
    306 			cpperror("macro arguments must be identifiers");
    307 			return NR_MACROARG;
    308 		}
    309 		sym = install(NS_IDEN, yylval.sym);
    310 		sym->flags |= SUSED;
    311 		args[n++] = sym;
    312 		next();
    313 	} while (accept(','));
    314 	expect(')');
    315 
    316 	return n;
    317 }
    318 
    319 static int
    320 getdefs(Symbol *args[NR_MACROARG], int nargs, char *bp, size_t bufsiz)
    321 {
    322 	Symbol **argp;
    323 	size_t len;
    324 	int prevc = 0, ispar;
    325 
    326 	if (yytoken == '$') {
    327 		cpperror("'##' cannot appear at either ends of a macro expansion");
    328 		return 0;
    329 	}
    330 
    331 	for (;;) {
    332 		ispar = 0;
    333 		if (yytoken == IDEN && nargs >= 0) {
    334 			for (argp = args; argp < &args[nargs]; ++argp) {
    335 				if (*argp == yylval.sym)
    336 					break;
    337 			}
    338 			if (argp != &args[nargs]) {
    339 				sprintf(yytext, "@%02d@", (int) (argp - args));
    340 				ispar = 1;
    341 			}
    342 		}
    343 		if (prevc == '#' && !ispar) {
    344 			cpperror("'#' is not followed by a macro parameter");
    345 			return 0;
    346 		}
    347 		if (yytoken == '\n')
    348 			break;
    349 
    350 		if ((len = strlen(yytext)) >= bufsiz) {
    351 			cpperror("macro too long");
    352 			return 0;
    353 		}
    354 		if (yytoken == '$') {
    355 			*bp++ = '$';
    356 			 --bufsiz;
    357 		} else {
    358 			memcpy(bp, yytext, len);
    359 			bp += len;
    360 			bufsiz -= len;
    361 		}
    362 		if ((prevc = yytoken) != '#') {
    363 			*bp++ = ' ';
    364 			--bufsiz;
    365 		}
    366 		next();
    367 	}
    368 	*bp = '\0';
    369 	return 1;
    370 }
    371 
    372 static void
    373 define(void)
    374 {
    375 	Symbol *sym,*args[NR_MACROARG];
    376 	char buff[LINESIZ+1];
    377 	int n;
    378 
    379 	if (cppoff)
    380 		return;
    381 
    382 	namespace = NS_CPP;
    383 	next();
    384 
    385 	if (yytoken != IDEN) {
    386 		cpperror("macro names must be identifiers");
    387 		return;
    388 	}
    389 	sym = yylval.sym;
    390 	if (sym->flags & SDECLARED) {
    391 		warn("'%s' redefined", yytext);
    392 		free(sym->u.s);
    393 	} else {
    394 		sym = install(NS_CPP, sym);
    395 		sym->flags |= SDECLARED|SSTRING;
    396 	}
    397 
    398 	namespace = NS_IDEN;       /* Avoid polution in NS_CPP */
    399 	if ((n = getpars(args)) == NR_MACROARG)
    400 		goto delete;
    401 	if (n > 0 && !args[n-1])  /* it is a variadic function */
    402 		--n;
    403 	sprintf(buff, "%02d#", n);
    404 	if (!getdefs(args, n, buff+3, LINESIZ-3))
    405 		goto delete;
    406 	sym->u.s = xstrdup(buff);
    407 	DBG("MACRO '%s' defined as '%s'", sym->name, buff);
    408 	return;
    409 
    410 delete:
    411 	killsym(sym);
    412 }
    413 
    414 void
    415 incdir(char *dir)
    416 {
    417 	if (!dir || *dir == '\0')
    418 		die("cc1: incorrect -I flag");
    419 	newitem(&dirinclude, dir);
    420 }
    421 
    422 static int
    423 includefile(char *dir, char *file, size_t filelen)
    424 {
    425 	size_t dirlen;
    426 	char path[FILENAME_MAX];
    427 
    428 	if (!dir) {
    429 		dirlen = 0;
    430 		if (filelen > FILENAME_MAX-1)
    431 			return 0;
    432 	} else {
    433 		dirlen = strlen(dir);
    434 		if (dirlen + filelen > FILENAME_MAX-2)
    435 			return 0;
    436 		memcpy(path, dir, dirlen);
    437 		if (dir[dirlen-1] != '/')
    438 			path[dirlen++] = '/';
    439 	}
    440 	memcpy(path+dirlen, file, filelen);
    441 	path[dirlen + filelen] = '\0';
    442 
    443 	addinput(path, NULL, NULL);
    444 	return 1;
    445 }
    446 
    447 static char *
    448 cwd(char *buf)
    449 {
    450 	char *p, *s = filenam;
    451 	size_t len;
    452 
    453 	if ((p = strrchr(s, '/')) == NULL)
    454 		return NULL;
    455 	if ((len = p - s) >= FILENAME_MAX)
    456 		die("cc1: current work directory too long");
    457 	memcpy(buf, s, len);
    458 	buf[len] = '\0';
    459 	return buf;
    460 }
    461 
    462 static void
    463 include(void)
    464 {
    465 	char dir[FILENAME_MAX], file[FILENAME_MAX], *p, **bp;
    466 	size_t filelen;
    467 	int n;
    468 
    469 	if (cppoff)
    470 		return;
    471 
    472 	namespace = NS_IDEN;
    473 	next();
    474 
    475 	switch (*yytext) {
    476 	case '<':
    477 		if ((p = strchr(input->begin, '>')) == NULL || p[-1] == '<')
    478 			goto bad_include;
    479 		filelen = p - input->begin;
    480 		if (filelen >= FILENAME_MAX)
    481 			goto too_long;
    482 		memcpy(file, input->begin, filelen);
    483 		file[filelen] = '\0';
    484 
    485 		input->begin = input->p = p+1;
    486 		if (next() != '\n')
    487 			goto trailing_characters;
    488 
    489 		break;
    490 	case '"':
    491 		if (yylen < 3)
    492 			goto bad_include;
    493 		filelen = yylen-2;
    494 		if (filelen >= FILENAME_MAX)
    495 			goto too_long;
    496 		memcpy(file, yytext+1, filelen);
    497 		file[filelen] = '\0';
    498 
    499 		if (next() != '\n')
    500 			goto trailing_characters;
    501 
    502 		if (includefile(cwd(dir), file, filelen))
    503 			goto its_done;
    504 		break;
    505 	default:
    506 		goto bad_include;
    507 	}
    508 
    509 	n = dirinclude.n;
    510 	for (bp = dirinclude.s; n--; ++bp) {
    511 		if (includefile(*bp, file, filelen))
    512 			goto its_done;
    513 	}
    514 	cpperror("included file '%s' not found", file);
    515 
    516 its_done:
    517 	return;
    518 
    519 trailing_characters:
    520 	cpperror("trailing characters after preprocessor directive");
    521 	return;
    522 
    523 too_long:
    524 	cpperror("too long file name in #include");
    525 	return;
    526 
    527 bad_include:
    528 	cpperror("#include expects \"FILENAME\" or <FILENAME>");
    529 	return;
    530 }
    531 
    532 static void
    533 line(void)
    534 {
    535 	long n;
    536 	char *endp, *fname;
    537 
    538 	if (cppoff)
    539 		return;
    540 
    541 	disexpand = 0;
    542 	next();
    543 	n = strtol(yytext, &endp, 10);
    544 	if (n <= 0 || n > USHRT_MAX || *endp != '\0') {
    545 		cpperror("first parameter of #line is not a positive integer");
    546 		return;
    547 	}
    548 
    549 	next();
    550 	if (yytoken == '\n') {
    551 		fname = NULL;
    552 	} else {
    553 		if (*yytext != '\"' || yylen == 1) {
    554 			cpperror("second parameter of #line is not a valid filename");
    555 			return;
    556 		}
    557 		fname = yylval.sym->u.s;
    558 	}
    559 	setloc(fname, n - 1);
    560 	if (yytoken != '\n')
    561 		next();
    562 }
    563 
    564 static void
    565 pragma(void)
    566 {
    567 	if (cppoff)
    568 		return;
    569 	next();
    570 	warn("ignoring pragma '%s'", yytext);
    571 	*input->p = '\0';
    572 	next();
    573 }
    574 
    575 static void
    576 usererr(void)
    577 {
    578 	if (cppoff)
    579 		return;
    580 	cpperror("#error %s", input->p);
    581 	*input->p = '\0';
    582 	next();
    583 }
    584 
    585 static void
    586 ifclause(int negate, int isifdef)
    587 {
    588 	Symbol *sym;
    589 	unsigned n;
    590 	int status;
    591 	Node *expr;
    592 
    593 	if (cppctx == NR_COND-1)
    594 		error("too many nesting levels of conditional inclusion");
    595 
    596 	n = cppctx++;
    597 	namespace = NS_CPP;
    598 	next();
    599 
    600 	if (isifdef) {
    601 		if (yytoken != IDEN) {
    602 			cpperror("no macro name given in #%s directive",
    603 			         (negate) ? "ifndef" : "ifdef");
    604 			return;
    605 		}
    606 		sym = yylval.sym;
    607 		next();
    608 		status = (sym->flags & SDECLARED) != 0;
    609 		if (!status)
    610 			killsym(sym);
    611 	} else {
    612 		/* TODO: catch recovery here */
    613 		if ((expr = constexpr()) == NULL) {
    614 			cpperror("parameter of #if is not an integer constant expression");
    615 			return;
    616 		}
    617 		status = expr->sym->u.i != 0;
    618 		freetree(expr);
    619 	}
    620 
    621 	if (negate)
    622 		status = !status;
    623 	if ((ifstatus[n] = status) == 0)
    624 		++cppoff;
    625 }
    626 
    627 static void
    628 cppif(void)
    629 {
    630 	disexpand = 0;
    631 	ifclause(0, 0);
    632 }
    633 
    634 static void
    635 ifdef(void)
    636 {
    637 	ifclause(0, 1);
    638 }
    639 
    640 static void
    641 ifndef(void)
    642 {
    643 	ifclause(1, 1);
    644 }
    645 
    646 static void
    647 elseclause(void)
    648 {
    649 	int status;
    650 
    651 	if (cppctx == 0) {
    652 		cpperror("#else without #ifdef/ifndef");
    653 		return;
    654 	}
    655 
    656 	status = ifstatus[cppctx-1];
    657 	ifstatus[cppctx-1] = !status;
    658 	cppoff += (status) ? 1 : -1;
    659 }
    660 
    661 static void
    662 cppelse(void)
    663 {
    664 	elseclause();
    665 	next();
    666 }
    667 
    668 static void
    669 elif(void)
    670 {
    671 	elseclause();
    672 	if (ifstatus[cppctx-1]) {
    673 		--cppctx;
    674 		cppif();
    675 	}
    676 }
    677 
    678 static void
    679 endif(void)
    680 {
    681 	if (cppctx == 0)
    682 		error("#endif without #if");
    683 	if (!ifstatus[--cppctx])
    684 		--cppoff;
    685 	next();
    686 }
    687 
    688 static void
    689 undef(void)
    690 {
    691 	if (cppoff)
    692 		return;
    693 
    694 	namespace = NS_CPP;
    695 	next();
    696 	if (yytoken != IDEN) {
    697 		error("no macro name given in #undef directive");
    698 		return;
    699 	}
    700 	killsym(yylval.sym);
    701 	next();
    702 }
    703 
    704 int
    705 cpp(void)
    706 {
    707 	static struct {
    708 		unsigned char token;
    709 		void (*fun)(void);
    710 	} *bp, clauses [] = {
    711 		{DEFINE, define},
    712 		{INCLUDE, include},
    713 		{LINE, line},
    714 		{IFDEF, ifdef},
    715 		{IF, cppif},
    716 		{ELIF, elif},
    717 		{IFNDEF, ifndef},
    718 		{ELSE, cppelse},
    719 		{ENDIF, endif},
    720 		{UNDEF, undef},
    721 		{PRAGMA, pragma},
    722 		{ERROR, usererr},
    723 		{0, NULL}
    724 	};
    725 	int ns;
    726 	char *p;
    727 
    728 	for (p = input->p; isspace(*p); ++p)
    729 		;
    730 
    731 	if (*p != '#')
    732 		return cppoff;
    733 	input->p = p+1;
    734 
    735 	disexpand = 1;
    736 	lexmode = CPPMODE;
    737 	ns = namespace;
    738 	namespace = NS_CPPCLAUSES;
    739 	next();
    740 	namespace = NS_IDEN;
    741 
    742 	for (bp = clauses; bp->token && bp->token != yytoken; ++bp)
    743 		;
    744 	if (!bp->token) {
    745 		errorp("incorrect preprocessor directive '%s'", yytext);
    746 		goto error;
    747 	}
    748 
    749 	DBG("CPP %s", yytext);
    750 
    751 	pushctx();              /* create a new context to avoid polish */
    752 	(*bp->fun)();           /* the current context, and to get all  */
    753 	popctx();               /* the symbols freed at the  end        */
    754 
    755 	/*
    756 	 * #include changes the content of input->line, so the correctness
    757 	 * of the line must be checked in the own include(), and we have
    758 	 * to skip this tests. For the same reason include() is the only
    759 	 * function which does not prepare the next token
    760 	 */
    761 	if (yytoken != '\n' && !cppoff && bp->token != INCLUDE)
    762 		errorp("trailing characters after preprocessor directive");
    763 
    764 error:
    765 	disexpand = 0;
    766 	lexmode = CCMODE;
    767 	namespace = ns;
    768 
    769 	return 1;
    770 }
    771 
    772 void
    773 ppragmaln(void)
    774 {
    775 	static char file[FILENAME_MAX];
    776 	static unsigned nline;
    777 	char *s;
    778 
    779 	putchar('\n');
    780 	if (strcmp(file, filenam)) {
    781 		strcpy(file, filenam);
    782 		s = "#line %u \"%s\"\n";
    783 	} else if (nline+1 != lineno) {
    784 		s = "#line %u\n";
    785 	} else {
    786 		s = "";
    787 	}
    788 	nline = lineno;
    789 	printf(s, nline, file);
    790 }
    791 
    792 void
    793 outcpp(void)
    794 {
    795 	int c;
    796 	char *s, *t;
    797 
    798 	for (next(); yytoken != EOFTOK; next()) {
    799 		if (onlyheader)
    800 			continue;
    801 		if (yytoken != STRING) {
    802 			printf("%s ", yytext);
    803 			continue;
    804 		}
    805 		for (s = yytext; c = *s; ++s) {
    806 			switch (c) {
    807 			case '\n':
    808 				t = "\\n";
    809 				goto print_str;
    810 			case '\v':
    811 				t = "\\v";
    812 				goto print_str;
    813 			case '\b':
    814 				t = "\\b";
    815 				goto print_str;
    816 			case '\t':
    817 				t = "\\t";
    818 				goto print_str;
    819 			case '\a':
    820 				t = "\\a";
    821 			print_str:
    822 				fputs(t, stdout);
    823 				break;
    824 			case '\\':
    825 				putchar('\\');
    826 			default:
    827 				if (!isprint(c))
    828 					printf("\\x%x", c);
    829 				else
    830 					putchar(c);
    831 				break;
    832 			}
    833 		}
    834 		putchar(' ');
    835 	}
    836 	putchar('\n');
    837 }
    838