scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

cpp.c (14562B)


      1 static char sccsid[] = "@(#) ./cc1/cpp.c";
      2 #include <ctype.h>
      3 #include <limits.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 #include <time.h>
      8 
      9 #include <cstd.h>
     10 #include "../inc/scc.h"
     11 #include "cc1.h"
     12 
     13 static char *argp, *macroname;
     14 static unsigned arglen;
     15 static unsigned ncmdlines;
     16 static Symbol *symline, *symfile;
     17 static unsigned char ifstatus[NR_COND];
     18 static int cppoff;
     19 static struct items dirinclude;
     20 
     21 unsigned cppctx;
     22 int disexpand;
     23 
     24 void
     25 defdefine(char *macro, char *val, char *source)
     26 {
     27 	char *def, *fmt = "#define %s %s\n";
     28 	Symbol dummy = {.flags = SDECLARED};
     29 
     30 	if (!val)
     31 		val = "";
     32 	def = xmalloc(strlen(fmt) + strlen(macro) + strlen(val));
     33 
     34 	sprintf(def, fmt, macro, val);
     35 	lineno = ++ncmdlines;
     36 	addinput(source, &dummy, def);
     37 	cpp();
     38 	delinput();
     39 }
     40 
     41 void
     42 undefmacro(char *s)
     43 {
     44 	killsym(lookup(NS_CPP, s, NOALLOC));
     45 }
     46 
     47 void
     48 icpp(void)
     49 {
     50 	static char sdate[14], stime[11];
     51 	struct tm *tm;
     52 	time_t t;
     53 	static char **bp, *list[] = {
     54 		"__STDC__",
     55 		"__STDC_HOSTED__",
     56 		"__SCC__",
     57 		NULL
     58 	};
     59 	static struct keyword keys[] = {
     60 		{"define", DEFINE, DEFINE},
     61 		{"include", INCLUDE, INCLUDE},
     62 		{"line", LINE, LINE},
     63 		{"ifdef", IFDEF, IFDEF},
     64 		{"if", IF, IF},
     65 		{"elif", ELIF, ELIF},
     66 		{"else", ELSE, ELSE},
     67 		{"ifndef", IFNDEF, IFNDEF},
     68 		{"endif", ENDIF, ENDIF},
     69 		{"undef", UNDEF, UNDEF},
     70 		{"pragma", PRAGMA, PRAGMA},
     71 		{"error", ERROR, ERROR},
     72 		{NULL, 0, 0}
     73 	};
     74 
     75 	keywords(keys, NS_CPPCLAUSES);
     76 
     77 	t = time(NULL);
     78 	tm = localtime(&t);
     79 	strftime(sdate, sizeof(sdate), "\"%b %d %Y\"", tm);
     80 	strftime(stime, sizeof(stime), "\"%H:%M:%S\"", tm);
     81 	defdefine("__DATE__", sdate, "built-in");
     82 	defdefine("__TIME__", stime, "built-in");
     83 	defdefine("__STDC_VERSION__", STDC_VERSION, "built-in");
     84 	defdefine("__LINE__", NULL, "built-in");
     85 	defdefine("__FILE__", NULL, "built-in");
     86 
     87 	symline = lookup(NS_CPP, "__LINE__", ALLOC);
     88 	symfile = lookup(NS_CPP, "__FILE__", ALLOC);
     89 
     90 	for (bp = list; *bp; ++bp)
     91 		defdefine(*bp, "1", "built-in");
     92 
     93 	ncmdlines = 0;
     94 }
     95 
     96 static void
     97 nextcpp(void)
     98 {
     99 	next();
    100 	if (yytoken == EOFTOK)
    101 		error("unterminated argument list invoking macro \"%s\"",
    102 		      macroname);
    103 	if (yylen + 1 > arglen)
    104 		error("argument overflow invoking macro \"%s\"",
    105 		      macroname);
    106 	if (yytoken == IDEN)
    107 		yylval.sym->flags |= SUSED;
    108 	memcpy(argp, yytext, yylen);
    109 	argp += yylen;
    110 	*argp++ = ' ';
    111 	arglen -= yylen + 1;
    112 }
    113 
    114 static void
    115 paren(void)
    116 {
    117 	for (;;) {
    118 		nextcpp();
    119 		switch (yytoken) {
    120 		case ')':
    121 			return;
    122 		case '(':
    123 			paren();
    124 			break;
    125 		}
    126 	}
    127 }
    128 
    129 static void
    130 parameter(void)
    131 {
    132 	for (;;) {
    133 		nextcpp();
    134 		switch (yytoken) {
    135 		case ')':
    136 		case ',':
    137 			argp -= 3;  /* remove " , "  or " ) "*/
    138 			*argp++ = '\0';
    139 			return;
    140 		case '(':
    141 			paren();
    142 			break;
    143 		}
    144 	}
    145 }
    146 
    147 static int
    148 parsepars(char *buffer, char **listp, int nargs)
    149 {
    150 	int n;
    151 
    152 	if (nargs == -1)
    153 		return -1;
    154 	if (ahead() != '(' && nargs > 0)
    155 		return 0;
    156 
    157 	disexpand = 1;
    158 	next();
    159 	n = 0;
    160 	argp = buffer;
    161 	arglen = INPUTSIZ;
    162 	if (ahead() == ')') {
    163 		next();
    164 	} else {
    165 		do {
    166 			*listp++ = argp;
    167 			parameter();
    168 		} while (++n < NR_MACROARG && yytoken == ',');
    169 	}
    170 	if (yytoken != ')')
    171 		error("incorrect macro function-alike invocation");
    172 	disexpand = 0;
    173 
    174 	if (n == NR_MACROARG)
    175 		error("too many parameters in macro \"%s\"", macroname);
    176 	if (n != nargs) {
    177 		error("macro \"%s\" received %d arguments, but it takes %d",
    178 		      macroname, n, nargs);
    179 	}
    180 
    181 	return 1;
    182 }
    183 
    184 static size_t
    185 copymacro(char *buffer, char *s, size_t bufsiz, char *arglist[])
    186 {
    187 	int delim, prevc, c;
    188 	char *p, *arg, *bp = buffer;
    189 	size_t size;
    190 
    191 	for (prevc = '\0'; c = *s; prevc = c, ++s) {
    192 		switch (c) {
    193 		case '$':
    194 			while (bp[-1] == ' ')
    195 				--bp, ++bufsiz;
    196 			while (s[1] == ' ')
    197 				++s;
    198 		case '#':
    199 			break;
    200 		case '\'':
    201 			delim = '\'';
    202 			goto search_delim;
    203 		case '\"':
    204 			delim = '"';
    205 		search_delim:
    206 			for (p = s; *++s != delim; )
    207 				/* nothing */;
    208 			size = s - p + 1;
    209 			if (size > bufsiz)
    210 				goto expansion_too_long;
    211 			memcpy(bp, p, size);
    212 			bufsiz -= size;
    213 			bp += size;
    214 			break;
    215 		case '@':
    216 			if (prevc == '#')
    217 				bufsiz -= 2;
    218 			arg = arglist[atoi(++s)];
    219 			size = strlen(arg);
    220 			if (size > bufsiz)
    221 				goto expansion_too_long;
    222 			if (prevc == '#')
    223 				*bp++ = '"';
    224 			memcpy(bp, arg, size);
    225 			bp += size;
    226 			if (prevc == '#')
    227 				*bp++ = '"';
    228 			bufsiz -= size;
    229 			s += 2;
    230 			break;
    231 		default:
    232 			if (bufsiz-- == 0)
    233 				goto expansion_too_long;
    234 			*bp++ = c;
    235 			break;
    236 		}
    237 	}
    238 	*bp = '\0';
    239 
    240 	return bp - buffer;
    241 
    242 expansion_too_long:
    243 	error("macro expansion of \"%s\" too long", macroname);
    244 }
    245 
    246 int
    247 expand(char *begin, Symbol *sym)
    248 {
    249 	size_t elen;
    250 	int n, i;
    251 	char *s = sym->u.s;
    252 	char *arglist[NR_MACROARG], arguments[INPUTSIZ], buffer[INPUTSIZ];
    253 
    254 	macroname = sym->name;
    255 	if (sym == symfile) {
    256 		elen = sprintf(buffer, "\"%s\" ", filenam);
    257 		goto substitute;
    258 	}
    259 	if (sym == symline) {
    260 		elen = sprintf(buffer, "%d ", lineno);
    261 		goto substitute;
    262 	}
    263 	if (!s)
    264 		return 1;
    265 
    266 	n = atoi(s);
    267 	if (!parsepars(arguments, arglist, atoi(s)))
    268 		return 0;
    269 	for (i = 0; i < n; ++i)
    270 		DBG("MACRO par%d:%s", i, arglist[i]);
    271 
    272 	elen = copymacro(buffer, s+3, INPUTSIZ-1, arglist);
    273 
    274 substitute:
    275 	DBG("MACRO '%s' expanded to :'%s'", macroname, buffer);
    276 	buffer[elen] = '\0';
    277 	addinput(filenam, sym, xstrdup(buffer));
    278 
    279 	return 1;
    280 }
    281 
    282 static int
    283 getpars(Symbol *args[NR_MACROARG])
    284 {
    285 	int n, c;
    286 	Symbol *sym;
    287 
    288 	c = *input->p;
    289 	next();
    290 	if (c != '(')
    291 		return -1;
    292 	next(); /* skip the '(' */
    293 	if (accept(')'))
    294 		return 0;
    295 
    296 	n = 0;
    297 	do {
    298 		if (n == NR_MACROARG) {
    299 			cpperror("too many parameters in macro");
    300 			return NR_MACROARG;
    301 		}
    302 		if (accept(ELLIPSIS)) {
    303 			args[n++] = NULL;
    304 			break;
    305 		}
    306 		if (yytoken != IDEN) {
    307 			cpperror("macro arguments must be identifiers");
    308 			return NR_MACROARG;
    309 		}
    310 		sym = install(NS_IDEN, yylval.sym);
    311 		sym->flags |= SUSED;
    312 		args[n++] = sym;
    313 		next();
    314 	} while (accept(','));
    315 	expect(')');
    316 
    317 	return n;
    318 }
    319 
    320 static int
    321 getdefs(Symbol *args[NR_MACROARG], int nargs, char *bp, size_t bufsiz)
    322 {
    323 	Symbol **argp;
    324 	size_t len;
    325 	int prevc = 0, ispar;
    326 
    327 	if (yytoken == '$') {
    328 		cpperror("'##' cannot appear at either ends of a macro expansion");
    329 		return 0;
    330 	}
    331 
    332 	for (;;) {
    333 		ispar = 0;
    334 		if (yytoken == IDEN && nargs >= 0) {
    335 			for (argp = args; argp < &args[nargs]; ++argp) {
    336 				if (*argp == yylval.sym)
    337 					break;
    338 			}
    339 			if (argp != &args[nargs]) {
    340 				sprintf(yytext, "@%02d@", (int) (argp - args));
    341 				ispar = 1;
    342 			}
    343 		}
    344 		if (prevc == '#' && !ispar) {
    345 			cpperror("'#' is not followed by a macro parameter");
    346 			return 0;
    347 		}
    348 		if (yytoken == '\n')
    349 			break;
    350 
    351 		if ((len = strlen(yytext)) >= bufsiz) {
    352 			cpperror("macro too long");
    353 			return 0;
    354 		}
    355 		if (yytoken == '$') {
    356 			*bp++ = '$';
    357 			 --bufsiz;
    358 		} else {
    359 			memcpy(bp, yytext, len);
    360 			bp += len;
    361 			bufsiz -= len;
    362 		}
    363 		if ((prevc = yytoken) != '#') {
    364 			*bp++ = ' ';
    365 			--bufsiz;
    366 		}
    367 		next();
    368 	}
    369 	*bp = '\0';
    370 	return 1;
    371 }
    372 
    373 static void
    374 define(void)
    375 {
    376 	Symbol *sym,*args[NR_MACROARG];
    377 	char buff[LINESIZ+1];
    378 	int n;
    379 
    380 	if (cppoff)
    381 		return;
    382 
    383 	namespace = NS_CPP;
    384 	next();
    385 
    386 	if (yytoken != IDEN) {
    387 		cpperror("macro names must be identifiers");
    388 		return;
    389 	}
    390 	sym = yylval.sym;
    391 	if (sym->flags & SDECLARED) {
    392 		warn("'%s' redefined", yytext);
    393 		free(sym->u.s);
    394 	} else {
    395 		sym = install(NS_CPP, sym);
    396 		sym->flags |= SDECLARED|SSTRING;
    397 	}
    398 
    399 	namespace = NS_IDEN;       /* Avoid polution in NS_CPP */
    400 	if ((n = getpars(args)) == NR_MACROARG)
    401 		goto delete;
    402 	if (n > 0 && !args[n-1])  /* it is a variadic function */
    403 		--n;
    404 	sprintf(buff, "%02d#", n);
    405 	if (!getdefs(args, n, buff+3, LINESIZ-3))
    406 		goto delete;
    407 	sym->u.s = xstrdup(buff);
    408 	DBG("MACRO '%s' defined as '%s'", sym->name, buff);
    409 	return;
    410 
    411 delete:
    412 	killsym(sym);
    413 }
    414 
    415 void
    416 incdir(char *dir)
    417 {
    418 	if (!dir || *dir == '\0')
    419 		die("incorrect -I flag");
    420 	newitem(&dirinclude, dir);
    421 }
    422 
    423 static int
    424 includefile(char *dir, char *file, size_t filelen)
    425 {
    426 	size_t dirlen;
    427 	char path[FILENAME_MAX];
    428 
    429 	if (!dir) {
    430 		dirlen = 0;
    431 		if (filelen > FILENAME_MAX-1)
    432 			return 0;
    433 	} else {
    434 		dirlen = strlen(dir);
    435 		if (dirlen + filelen > FILENAME_MAX-2)
    436 			return 0;
    437 		memcpy(path, dir, dirlen);
    438 		if (dir[dirlen-1] != '/')
    439 			path[dirlen++] = '/';
    440 	}
    441 	memcpy(path+dirlen, file, filelen);
    442 	path[dirlen + filelen] = '\0';
    443 
    444 	return addinput(path, NULL, NULL);
    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("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 		/* nothing */;
    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 		/* nothing */;
    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