📄 cccp.c
字号:
if (dump_macros == dump_only) dump_all_macros (); else if (! inhibit_output) { write_output (); } if (print_deps) { /* Don't actually write the deps file if compilation has failed. */ if (errors == 0) { if (deps_file && ! (deps_stream = fopen (deps_file, "a"))) pfatal_with_name (deps_file); fputs (deps_buffer, deps_stream); putc ('\n', deps_stream); if (deps_file) { if (ferror (deps_stream) || fclose (deps_stream) != 0) fatal ("I/O error on output"); } } } if (ferror (stdout) || fclose (stdout) != 0) fatal ("I/O error on output"); if (errors) exit (FAILURE_EXIT_CODE); exit (SUCCESS_EXIT_CODE); perror: pfatal_with_name (in_fname); return 0;}/* Given a colon-separated list of file names PATH, add all the names to the search path for include files. */static voidpath_include (path) char *path;{ char *p; p = path; if (*p) while (1) { char *q = p; char *name; struct file_name_list *dirtmp; /* Find the end of this name. */ while (*q != 0 && *q != PATH_SEPARATOR) q++; if (p == q) { /* An empty name in the path stands for the current directory. */ name = (char *) xmalloc (2); name[0] = '.'; name[1] = 0; } else { /* Otherwise use the directory that is named. */ name = (char *) xmalloc (q - p + 1); bcopy (p, name, q - p); name[q - p] = 0; } dirtmp = (struct file_name_list *) xmalloc (sizeof (struct file_name_list)); dirtmp->next = 0; /* New one goes on the end */ dirtmp->control_macro = 0; dirtmp->fname = name; append_include_chain (dirtmp, dirtmp); /* Advance past this name. */ p = q; if (*p == 0) break; /* Skip the colon. */ p++; }}/* Pre-C-Preprocessor to translate ANSI trigraph idiocy in BUF before main CCCP processing. Name `pcp' is also in honor of the drugs the trigraph designers must have been on. Using an extra pass through the buffer takes a little extra time, but is infinitely less hairy than trying to handle trigraphs inside strings, etc. everywhere, and also makes sure that trigraphs are only translated in the top level of processing. */static voidtrigraph_pcp (buf) FILE_BUF *buf;{ register U_CHAR c, *fptr, *bptr, *sptr; int len; fptr = bptr = sptr = buf->buf; while ((sptr = (U_CHAR *) index (sptr, '?')) != NULL) { if (*++sptr != '?') continue; switch (*++sptr) { 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; case '?': sptr--; continue; default: continue; } len = sptr - fptr - 2; if (bptr != fptr && len > 0) bcopy (fptr, bptr, len); /* BSD doc says bcopy () works right for overlapping strings. In ANSI C, this will be memmove (). */ bptr += len; *bptr++ = c; fptr = ++sptr; } len = buf->length - (fptr - buf->buf); if (bptr != fptr && len > 0) bcopy (fptr, bptr, len); buf->length -= fptr - bptr; buf->buf[buf->length] = '\0'; if (warn_trigraphs && fptr != bptr) warning ("%d trigraph(s) encountered", (fptr - bptr) / 2);}/* Move all backslash-newline pairs out of embarrassing places. Exchange all such pairs following BP with any potentially-embarrassing characters that follow them. Potentially-embarrassing characters are / and * (because a backslash-newline inside a comment delimiter would cause it not to be recognized). */static voidnewline_fix (bp) U_CHAR *bp;{ register U_CHAR *p = bp; register int count = 0; /* First count the backslash-newline pairs here. */ while (1) { if (p[0] == '\\') { if (p[1] == '\n') p += 2, count++; else if (p[1] == '\r' && p[2] == '\n') p += 3, count++; else break; } else break; } /* What follows the backslash-newlines is not embarrassing. */ if (count == 0 || (*p != '/' && *p != '*')) return; /* Copy all potentially embarrassing characters that follow the backslash-newline pairs down to where the pairs originally started. */ while (*p == '*' || *p == '/') *bp++ = *p++; /* Now write the same number of pairs after the embarrassing chars. */ while (count-- > 0) { *bp++ = '\\'; *bp++ = '\n'; }}/* Like newline_fix but for use within a directive-name. Move any backslash-newlines up past any following symbol constituents. */static voidname_newline_fix (bp) U_CHAR *bp;{ register U_CHAR *p = bp; register int count = 0; /* First count the backslash-newline pairs here. */ while (1) { if (p[0] == '\\') { if (p[1] == '\n') p += 2, count++; else if (p[1] == '\r' && p[2] == '\n') p += 3, count++; else break; } else break; } /* What follows the backslash-newlines is not embarrassing. */ if (count == 0 || !is_idchar[*p]) return; /* Copy all potentially embarrassing characters that follow the backslash-newline pairs down to where the pairs originally started. */ while (is_idchar[*p]) *bp++ = *p++; /* Now write the same number of pairs after the embarrassing chars. */ while (count-- > 0) { *bp++ = '\\'; *bp++ = '\n'; }}/* Look for lint commands in comments. When we come in here, ibp points into a comment. Limit is as one expects. scan within the comment -- it should start, after lwsp, with a lint command. If so that command is returned as a (constant) string. Upon return, any arg will be pointed to with argstart and will be arglen long. Note that we don't parse that arg since it will just be printed out again.*/static char *get_lintcmd (ibp, limit, argstart, arglen, cmdlen) register U_CHAR *ibp; register U_CHAR *limit; U_CHAR **argstart; /* point to command arg */ int *arglen, *cmdlen; /* how long they are */{ long linsize; register U_CHAR *numptr; /* temp for arg parsing */ *arglen = 0; SKIP_WHITE_SPACE (ibp); if (ibp >= limit) return NULL; linsize = limit - ibp; /* Oh, I wish C had lexical functions... hell, I'll just open-code the set */ if ((linsize >= 10) && !strncmp (ibp, "NOTREACHED", 10)) { *cmdlen = 10; return "NOTREACHED"; } if ((linsize >= 8) && !strncmp (ibp, "ARGSUSED", 8)) { *cmdlen = 8; return "ARGSUSED"; } if ((linsize >= 11) && !strncmp (ibp, "LINTLIBRARY", 11)) { *cmdlen = 11; return "LINTLIBRARY"; } if ((linsize >= 7) && !strncmp (ibp, "VARARGS", 7)) { *cmdlen = 7; ibp += 7; linsize -= 7; if ((linsize == 0) || ! isdigit (*ibp)) return "VARARGS"; /* OK, read a number */ for (numptr = *argstart = ibp; (numptr < limit) && isdigit (*numptr); numptr++); *arglen = numptr - *argstart; return "VARARGS"; } return NULL;}/* * The main loop of the program. * * Read characters from the input stack, transferring them to the * output buffer OP. * * Macros are expanded and push levels on the input stack. * At the end of such a level it is popped off and we keep reading. * At the end of any other kind of level, we return. * #-directives are handled, except within macros. * * If OUTPUT_MARKS is nonzero, keep Newline markers found in the input * and insert them when appropriate. This is set while scanning macro * arguments before substitution. It is zero when scanning for final output. * There are three types of Newline markers: * * Newline - follows a macro name that was not expanded * because it appeared inside an expansion of the same macro. * This marker prevents future expansion of that identifier. * When the input is rescanned into the final output, these are deleted. * These are also deleted by ## concatenation. * * Newline Space (or Newline and any other whitespace character) * stands for a place that tokens must be separated or whitespace * is otherwise desirable, but where the ANSI standard specifies there * is no whitespace. This marker turns into a Space (or whichever other * whitespace char appears in the marker) in the final output, * but it turns into nothing in an argument that is stringified with #. * Such stringified arguments are the only place where the ANSI standard * specifies with precision that whitespace may not appear. * * During this function, IP->bufp is kept cached in IBP for speed of access. * Likewise, OP->bufp is kept in OBP. Before calling a subroutine * IBP, IP and OBP must be copied back to memory. IP and IBP are * copied back with the RECACHE macro. OBP must be copied back from OP->bufp * explicitly, and before RECACHE, since RECACHE uses OBP. */static voidrescan (op, output_marks) FILE_BUF *op; int output_marks;{ /* Character being scanned in main loop. */ register U_CHAR c; /* Length of pending accumulated identifier. */ register int ident_length = 0; /* Hash code of pending accumulated identifier. */ register int hash = 0; /* Current input level (&instack[indepth]). */ FILE_BUF *ip; /* Pointer for scanning input. */ register U_CHAR *ibp; /* Pointer to end of input. End of scan is controlled by LIMIT. */ register U_CHAR *limit; /* Pointer for storing output. */ register U_CHAR *obp; /* REDO_CHAR is nonzero if we are processing an identifier after backing up over the terminating character. Sometimes we process an identifier without backing up over the terminating character, if the terminating character is not special. Backing up is done so that the terminating character will be dispatched on again once the identifier is dealt with. */ int redo_char = 0; /* 1 if within an identifier inside of which a concatenation marker (Newline -) has been seen. */ int concatenated = 0; /* While scanning a comment or a string constant, this records the line it started on, for error messages. */ int start_line; /* Line where a newline was first seen in a string constant. */ int multiline_string_line = 0; /* Record position of last `real' newline. */ U_CHAR *beg_of_line;/* Pop the innermost input stack level, assuming it is a macro expansion. */#define POPMACRO \do { ip->macro->type = T_MACRO; \ if (ip->free_ptr) free (ip->free_ptr); \ --indepth; } while (0)/* Reload `rescan's local variables that describe the current level of the input stack. */#define RECACHE \do { ip = &instack[indepth]; \ ibp = ip->bufp; \ limit = ip->buf + ip->length; \ op->bufp = obp; \ check_expand (op, limit - ibp); \ beg_of_line = 0; \ obp = op->bufp; } while (0) if (no_output && instack[indepth].fname != 0) skip_if_group (&instack[indepth], 1); obp = op->bufp; RECACHE; beg_of_line = ibp; /* Our caller must always put a null after the end of the input at each input stack level. */ if (*limit != 0) abort (); while (1) { c = *ibp++; *obp++ = c; switch (c) { case '\\': if (ibp >= limit) break; if (*ibp == '\n') { /* Always merge lines ending with backslash-newline, even in middle of identifier. */ ++ibp; ++ip->lineno; --obp; /* remove backslash from obuf */ break; } /* Otherwise, backslash suppresses specialness of following char, so copy it here to prevent the switch from seeing it. But first get any pending identifier processed. */ if (ident_length > 0) goto specialchar; *obp++ = *ibp++; break; case '#': if (assertions_flag) { /* Copy #foo (bar lose) without macro expansion. */ SKIP_WHITE_SPACE (ibp); while (is_idchar[*ibp]) *obp++ = *ibp++; SKIP_WHITE_SPACE (ibp); if (*ibp == '(') { ip->bufp = ibp; skip_paren_group (ip); bcopy (ibp, obp, ip->bufp - ibp); obp += ip
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -