📄 cpplib.c
字号:
case '\"': goto scan_directive_token; break; case '/': nextc = PEEKC(); if (nextc == '*' || (opts->cplusplus_comments && nextc == '*')) goto scan_directive_token; break; case '\f': case '\v': if (CPP_PEDANTIC (pfile)) cpp_pedwarn (pfile, "%s in preprocessing directive", c == '\f' ? "formfeed" : "vertical tab"); break; case '\n': FORWARD(-1); goto end_directive; scan_directive_token: FORWARD(-1); cpp_get_token (pfile); continue; } CPP_PUTC (pfile, c); } end_directive: ; CPP_NUL_TERMINATE (pfile);}voidskip_rest_of_line (pfile) cpp_reader *pfile;{ long old = CPP_WRITTEN (pfile); copy_rest_of_line (pfile); CPP_SET_WRITTEN (pfile, old);}/* Handle a possible # directive. '#' has already been read. */inthandle_directive (pfile) cpp_reader *pfile;{ int c; register struct directive *kt; int ident_length; long after_ident; U_CHAR *ident, *line_end; long old_written = CPP_WRITTEN (pfile); cpp_skip_hspace (pfile); c = PEEKC (); if (c >= '0' && c <= '9') { /* Handle # followed by a line number. */ if (CPP_PEDANTIC (pfile)) cpp_pedwarn (pfile, "`#' followed by integer"); do_line (pfile, NULL); goto done_a_directive; } /* Now find the directive name. */ CPP_PUTC (pfile, '#'); parse_name (pfile, GETC()); ident = pfile->token_buffer + old_written + 1; ident_length = CPP_PWRITTEN (pfile) - ident; if (ident_length == 0 && PEEKC() == '\n') { /* A line of just `#' becomes blank. */ goto done_a_directive; }#if 0 if (ident_length == 0 || !is_idstart[*ident]) { U_CHAR *p = ident; while (is_idchar[*p]) { if (*p < '0' || *p > '9') break; p++; } /* Avoid error for `###' and similar cases unless -pedantic. */ if (p == ident) { while (*p == '#' || is_hor_space[*p]) p++; if (*p == '\n') { if (pedantic && !lang_asm) cpp_warning (pfile, "invalid preprocessor directive"); return 0; } } if (!lang_asm) cpp_error (pfile, "invalid preprocessor directive name"); return 0; }#endif /* * Decode the keyword and call the appropriate expansion * routine, after moving the input pointer up to the next line. */ for (kt = directive_table; ; kt++) { if (kt->length <= 0) goto not_a_directive; if (kt->length == ident_length && !strncmp (kt->name, ident, ident_length)) break; } if (! kt->command_reads_line) { /* Nonzero means do not delete comments within the directive. #define needs this when -traditional. */ int comments = CPP_TRADITIONAL (pfile) && kt->traditional_comments; int save_put_out_comments = CPP_OPTIONS (pfile)->put_out_comments; CPP_OPTIONS (pfile)->put_out_comments = comments; after_ident = CPP_WRITTEN (pfile); copy_rest_of_line (pfile); CPP_OPTIONS (pfile)->put_out_comments = save_put_out_comments; } /* For #pragma and #define, we may want to pass through the directive. Other directives may create output, but we don't want the directive itself out, so we pop it now. For example #include may write a #line command (see comment in do_include), and conditionals may emit #failed ... #endfailed stuff. But note that popping the buffer means the parameters to kt->func may point after pfile->limit so these parameters are invalid as soon as something gets appended to the token_buffer. */ line_end = CPP_PWRITTEN (pfile); if (!kt->pass_thru && kt->type != T_DEFINE) CPP_SET_WRITTEN (pfile, old_written); (*kt->func) (pfile, kt, pfile->token_buffer + after_ident, line_end); if (kt->pass_thru || (kt->type == T_DEFINE && CPP_OPTIONS (pfile)->dump_macros == dump_definitions)) { /* Just leave the entire #define in the output stack. */ } else if (kt->type == T_DEFINE && CPP_OPTIONS (pfile)->dump_macros == dump_names) { U_CHAR *p = pfile->token_buffer + old_written + 7; /* Skip "#define". */ SKIP_WHITE_SPACE (p); while (is_idchar[*p]) p++; pfile->limit = p; CPP_PUTC (pfile, '\n'); } else if (kt->type == T_DEFINE) CPP_SET_WRITTEN (pfile, old_written); done_a_directive: return 1; not_a_directive: return 0;}/* Pass a directive through to the output file. BUF points to the contents of the directive, as a contiguous string. LIMIT points to the first character past the end of the directive. KEYWORD is the keyword-table entry for the directive. */static voidpass_thru_directive (buf, limit, pfile, keyword) U_CHAR *buf, *limit; cpp_reader *pfile; struct directive *keyword;{ register unsigned keyword_length = keyword->length; CPP_RESERVE (pfile, 1 + keyword_length + (limit - buf)); CPP_PUTC_Q (pfile, '#'); CPP_PUTS_Q (pfile, keyword->name, keyword_length); if (limit != buf && buf[0] != ' ') CPP_PUTC_Q (pfile, ' '); CPP_PUTS_Q (pfile, buf, limit - buf);#if 0 CPP_PUTS_Q (pfile, '\n'); /* Count the line we have just made in the output, to get in sync properly. */ pfile->lineno++;#endif}/* The arglist structure is built by do_define to tell collect_definition where the argument names begin. That is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist would contain pointers to the strings x, y, and z. Collect_definition would then build a DEFINITION node, with reflist nodes pointing to the places x, y, and z had appeared. So the arglist is just convenience data passed between these two routines. It is not kept around after the current #define has been processed and entered into the hash table. */struct arglist { struct arglist *next; U_CHAR *name; int length; int argno; char rest_args;};/* Read a replacement list for a macro with parameters. Build the DEFINITION structure. Reads characters of text starting at BUF until END. ARGLIST specifies the formal parameters to look for in the text of the definition; NARGS is the number of args in that list, or -1 for a macro name that wants no argument list. MACRONAME is the macro name itself (so we can avoid recursive expansion) and NAMELEN is its length in characters. Note that comments, backslash-newlines, and leading white space have already been deleted from the argument. */static DEFINITION *collect_expansion (pfile, buf, limit, nargs, arglist) cpp_reader *pfile; U_CHAR *buf, *limit; int nargs; struct arglist *arglist;{ DEFINITION *defn; register U_CHAR *p, *lastp, *exp_p; struct reflist *endpat = NULL; /* Pointer to first nonspace after last ## seen. */ U_CHAR *concat = 0; /* Pointer to first nonspace after last single-# seen. */ U_CHAR *stringify = 0; int maxsize; int expected_delimiter = '\0'; /* Scan thru the replacement list, ignoring comments and quoted strings, picking up on the macro calls. It does a linear search thru the arg list on every potential symbol. Profiling might say that something smarter should happen. */ if (limit < buf) abort (); /* Find the beginning of the trailing whitespace. */ p = buf; while (p < limit && is_space[limit[-1]]) limit--; /* Allocate space for the text in the macro definition. Leading and trailing whitespace chars need 2 bytes each. Each other input char may or may not need 1 byte, so this is an upper bound. The extra 5 are for invented leading and trailing newline-marker and final null. */ maxsize = (sizeof (DEFINITION) + (limit - p) + 5); /* Occurrences of '@' get doubled, so allocate extra space for them. */ while (p < limit) if (*p++ == '@') maxsize++; defn = (DEFINITION *) xcalloc (1, maxsize); defn->nargs = nargs; exp_p = defn->expansion = (U_CHAR *) defn + sizeof (DEFINITION); lastp = exp_p; p = buf; /* Add one initial space escape-marker to prevent accidental token-pasting (often removed by macroexpand). */ *exp_p++ = '@'; *exp_p++ = ' '; if (limit - p >= 2 && p[0] == '#' && p[1] == '#') { cpp_error (pfile, "`##' at start of macro definition"); p += 2; } /* Process the main body of the definition. */ while (p < limit) { int skipped_arg = 0; register U_CHAR c = *p++; *exp_p++ = c; if (!CPP_TRADITIONAL (pfile)) { switch (c) { case '\'': case '\"': if (expected_delimiter != '\0') { if (c == expected_delimiter) expected_delimiter = '\0'; } else expected_delimiter = c; break; case '\\': if (p < limit && expected_delimiter) { /* In a string, backslash goes through and makes next char ordinary. */ *exp_p++ = *p++; } break; case '@': /* An '@' in a string or character constant stands for itself, and does not need to be escaped. */ if (!expected_delimiter) *exp_p++ = c; break; case '#': /* # is ordinary inside a string. */ if (expected_delimiter) break; if (p < limit && *p == '#') { /* ##: concatenate preceding and following tokens. */ /* Take out the first #, discard preceding whitespace. */ exp_p--; while (exp_p > lastp && is_hor_space[exp_p[-1]]) --exp_p; /* Skip the second #. */ p++; /* Discard following whitespace. */ SKIP_WHITE_SPACE (p); concat = p; if (p == limit) cpp_error (pfile, "`##' at end of macro definition"); } else if (nargs >= 0) { /* Single #: stringify following argument ref. Don't leave the # in the expansion. */ exp_p--; SKIP_WHITE_SPACE (p); if (p == limit || ! is_idstart[*p]) cpp_error (pfile, "`#' operator is not followed by a macro argument name"); else stringify = p; } break; } } else { /* In -traditional mode, recognize arguments inside strings and and character constants, and ignore special properties of #. Arguments inside strings are considered "stringified", but no extra quote marks are supplied. */ switch (c) { case '\'': case '\"': if (expected_delimiter != '\0') { if (c == expected_delimiter) expected_delimiter = '\0'; } else expected_delimiter = c; break; case '\\': /* Backslash quotes delimiters and itself, but not macro args. */ if (expected_delimiter != 0 && p < limit && (*p == expected_delimiter || *p == '\\')) { *exp_p++ = *p++; continue; } break; case '/': if (expected_delimiter != '\0') /* No comments inside strings. */ break; if (*p == '*') { /* If we find a comment that wasn't removed by handle_directive, this must be -traditional. So replace the comment with nothing at all. */ exp_p--; p += 1; while (p < limit && !(p[-2] == '*' && p[-1] == '/')) p++;#if 0 /* Mark this as a concatenation-point, as if it had been ##. */ concat = p;#endif } break; } } /* Handle the start of a symbol. */ if (is_idchar[c] && nargs > 0) { U_CHAR *id_beg = p - 1; int id_len; --exp_p; while (p != limit && is_idchar[*p]) p++; id_len = p - id_beg; if (is_idstart[c]) { register struct arglist *arg; for (arg = arglist; arg != NULL; arg = arg->next) { struct reflist *tpat; if (arg->name[0] == c && arg->length == id_len && strncmp (arg->name, id_beg, id_len) == 0) { if (expected_delimiter && CPP_OPTIONS (pfile)->warn_stringify) { if (CPP_TRADITIONAL (pfile)) { cpp_warning (pfile, "macro argument `%.*s' is stringified.", id_len, arg->name); } else { cpp_warning (pfile, "macro arg `%.*s' would be stringified with -traditional.", id_len, arg->name); } } /* If ANSI, don't actually substitute inside a string. */ if (!CPP_TRADITIONAL (pfile) && expected_delimiter) break; /* make a pat node for this arg and append it to the end of the pat list */ tpat = (struct reflist *) xmalloc (sizeof (struct reflist)); tpat->next = NULL; tpat->raw_before = concat == id_beg; tpat->raw_after = 0; tpat->rest_args = arg->rest_args; tpat->stringify = (CPP_TRADITIONAL (pfile) ? expected_delimiter != '\0' : stringify == id_beg); if (endpat == NULL) defn->pattern = tpat; else endpat->next = tpat; endpat = tpat; tpat->argno = arg->argno; tpat->nchars = exp_p - lastp; { register U_CHAR *p1 = p; SKIP_WHITE_SPACE (p1); if (p1 + 2 <= limit && p1[0] == '#' && p1[1] == '#') tpat->raw_after = 1; } lastp = exp_p; /* place to start copying from next time */ skipped_arg = 1; break; } } } /* If this was not a macro arg, copy it into the expansion. */ if (! skipped_arg) { register U_CHAR *lim1 = p; p = id_beg; while (p != lim1) *exp_p++ = *p++; if (stringify == id_beg) cpp_error (pfile, "`#' operator should be followed by a macro argument name"); } } } if (!CPP_TRADITIONAL (pfile) && expected_delimiter == 0) { /* If ANSI, put in a "@ " marker to prevent token pasting. But not if "inside a string" (which in ANSI mode happens only for -D option). */ *exp_p++ = '@'; *exp_p++ = ' '; } *exp_p = '\0'; defn->length = exp_p - defn->expansion; /* Crash now if we overrun the allocated size. */ if (defn->length + 1 > maxsize) abort ();#if 0/* This isn't worth the time it takes. */ /* give back excess storage */ defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1);#endif return defn;}/* * special extension string that can be added to the last macro argument to * allow it to absorb the "rest" of the arguments when expanded. Ex: * #define wow(a, b...) process (b, a, b) * { wow (1, 2, 3); } -> { process (2, 3, 1, 2, 3); } * { wow (one, two); } -> { process (two, one, two); } * if this "rest_arg" is used with the concat token '##' and if it is not * supplied then the token attached to with ## will not be outputted. Ex: * #define wow (a, b...) process (b ## , a, ## b) * { wow (1, 2); } -> { process (2, 1, 2); } * { wow (one); } -> { process (one); { */static char rest_extension[] = "...";#define REST_EXTENSION_LENGTH (sizeof (rest_extension) - 1)/* Create a DEFINITION node from a #define directive. Arguments are as for do_define. */static MACRODEFcreate_definition (buf, limit, pfile, predefinition)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -