📄 cpplib.c
字号:
U_CHAR *buf, *limit; cpp_reader *pfile; int predefinition;{ U_CHAR *bp; /* temp ptr into input buffer */ U_CHAR *symname; /* remember where symbol name starts */ int sym_length; /* and how long it is */ int rest_args = 0; long line, col; char *file = CPP_BUFFER (pfile) ? CPP_BUFFER (pfile)->nominal_fname : ""; DEFINITION *defn; int arglengths = 0; /* Accumulate lengths of arg names plus number of args. */ MACRODEF mdef; cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col); bp = buf; while (is_hor_space[*bp]) bp++; symname = bp; /* remember where it starts */ sym_length = check_macro_name (pfile, bp, "macro"); bp += sym_length; /* Lossage will occur if identifiers or control keywords are broken across lines using backslash. This is not the right place to take care of that. */ if (*bp == '(') { struct arglist *arg_ptrs = NULL; int argno = 0; bp++; /* skip '(' */ SKIP_WHITE_SPACE (bp); /* Loop over macro argument names. */ while (*bp != ')') { struct arglist *temp; temp = (struct arglist *) alloca (sizeof (struct arglist)); temp->name = bp; temp->next = arg_ptrs; temp->argno = argno++; temp->rest_args = 0; arg_ptrs = temp; if (rest_args) cpp_pedwarn (pfile, "another parameter follows `%s'", rest_extension); if (!is_idstart[*bp]) cpp_pedwarn (pfile, "invalid character in macro parameter name"); /* Find the end of the arg name. */ while (is_idchar[*bp]) { bp++; /* do we have a "special" rest-args extension here? */ if (limit - bp > REST_EXTENSION_LENGTH && strncmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0) { rest_args = 1; temp->rest_args = 1; break; } } temp->length = bp - temp->name; if (rest_args == 1) bp += REST_EXTENSION_LENGTH; arglengths += temp->length + 2; SKIP_WHITE_SPACE (bp); if (temp->length == 0 || (*bp != ',' && *bp != ')')) { cpp_error (pfile, "badly punctuated parameter list in `#define'"); goto nope; } if (*bp == ',') { bp++; SKIP_WHITE_SPACE (bp); } if (bp >= limit) { cpp_error (pfile, "unterminated parameter list in `#define'"); goto nope; } { struct arglist *otemp; for (otemp = temp->next; otemp != NULL; otemp = otemp->next) if (temp->length == otemp->length && strncmp (temp->name, otemp->name, temp->length) == 0) { U_CHAR *name; name = (U_CHAR *) alloca (temp->length + 1); (void) strncpy (name, temp->name, temp->length); name[temp->length] = '\0'; cpp_error (pfile, "duplicate argument name `%s' in `#define'", name); goto nope; } } } ++bp; /* skip paren */ SKIP_WHITE_SPACE (bp); /* now everything from bp before limit is the definition. */ defn = collect_expansion (pfile, bp, limit, argno, arg_ptrs); defn->rest_args = rest_args; /* Now set defn->args.argnames to the result of concatenating the argument names in reverse order with comma-space between them. */ defn->args.argnames = (U_CHAR *) xmalloc (arglengths + 1); { struct arglist *temp; int i = 0; for (temp = arg_ptrs; temp; temp = temp->next) { bcopy (temp->name, &defn->args.argnames[i], temp->length); i += temp->length; if (temp->next != 0) { defn->args.argnames[i++] = ','; defn->args.argnames[i++] = ' '; } } defn->args.argnames[i] = 0; } } else { /* Simple expansion or empty definition. */ if (bp < limit) { if (is_hor_space[*bp]) { bp++; SKIP_WHITE_SPACE (bp); } else { switch (*bp) { case '!': case '"': case '#': case '%': case '&': case '\'': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case ':': case ';': case '<': case '=': case '>': case '?': case '[': case '\\': case ']': case '^': case '{': case '|': case '}': case '~': cpp_warning (pfile, "missing white space after `#define %.*s'", sym_length, symname); break; default: cpp_pedwarn (pfile, "missing white space after `#define %.*s'", sym_length, symname); break; } } } /* now everything from bp before limit is the definition. */ defn = collect_expansion (pfile, bp, limit, -1, NULL_PTR); defn->args.argnames = (U_CHAR *) ""; } defn->line = line; defn->file = file; /* OP is null if this is a predefinition */ defn->predefined = predefinition; mdef.defn = defn; mdef.symnam = symname; mdef.symlen = sym_length; return mdef; nope: mdef.defn = 0; return mdef;}/* Check a purported macro name SYMNAME, and yield its length. USAGE is the kind of name this is intended for. */static intcheck_macro_name (pfile, symname, usage) cpp_reader *pfile; U_CHAR *symname; char *usage;{ U_CHAR *p; int sym_length; for (p = symname; is_idchar[*p]; p++) ; sym_length = p - symname; if (sym_length == 0) cpp_error (pfile, "invalid %s name", usage); else if (!is_idstart[*symname]) { U_CHAR *msg; /* what pain... */ msg = (U_CHAR *) alloca (sym_length + 1); bcopy (symname, msg, sym_length); msg[sym_length] = 0; cpp_error (pfile, "invalid %s name `%s'", usage, msg); } else { if (! strncmp (symname, "defined", 7) && sym_length == 7) cpp_error (pfile, "invalid %s name `defined'", usage); } return sym_length;}/* * return zero if two DEFINITIONs are isomorphic */static intcompare_defs (d1, d2) DEFINITION *d1, *d2;{ register struct reflist *a1, *a2; register U_CHAR *p1 = d1->expansion; register U_CHAR *p2 = d2->expansion; int first = 1; if (d1->nargs != d2->nargs) return 1; if (strcmp ((char *)d1->args.argnames, (char *)d2->args.argnames)) return 1; for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2; a1 = a1->next, a2 = a2->next) { if (!((a1->nchars == a2->nchars && ! strncmp (p1, p2, a1->nchars)) || ! comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0)) || a1->argno != a2->argno || a1->stringify != a2->stringify || a1->raw_before != a2->raw_before || a1->raw_after != a2->raw_after) return 1; first = 0; p1 += a1->nchars; p2 += a2->nchars; } if (a1 != a2) return 1; if (comp_def_part (first, p1, d1->length - (p1 - d1->expansion), p2, d2->length - (p2 - d2->expansion), 1)) return 1; return 0;}/* Return 1 if two parts of two macro definitions are effectively different. One of the parts starts at BEG1 and has LEN1 chars; the other has LEN2 chars at BEG2. Any sequence of whitespace matches any other sequence of whitespace. FIRST means these parts are the first of a macro definition; so ignore leading whitespace entirely. LAST means these parts are the last of a macro definition; so ignore trailing whitespace entirely. */static intcomp_def_part (first, beg1, len1, beg2, len2, last) int first; U_CHAR *beg1, *beg2; int len1, len2; int last;{ register U_CHAR *end1 = beg1 + len1; register U_CHAR *end2 = beg2 + len2; if (first) { while (beg1 != end1 && is_space[*beg1]) beg1++; while (beg2 != end2 && is_space[*beg2]) beg2++; } if (last) { while (beg1 != end1 && is_space[end1[-1]]) end1--; while (beg2 != end2 && is_space[end2[-1]]) end2--; } while (beg1 != end1 && beg2 != end2) { if (is_space[*beg1] && is_space[*beg2]) { while (beg1 != end1 && is_space[*beg1]) beg1++; while (beg2 != end2 && is_space[*beg2]) beg2++; } else if (*beg1 == *beg2) { beg1++; beg2++; } else break; } return (beg1 != end1) || (beg2 != end2);}/* Process a #define command.BUF points to the contents of the #define command, as a contiguous string.LIMIT points to the first character past the end of the definition.KEYWORD is the keyword-table entry for #define,or NULL for a "predefined" macro. */static intdo_define (pfile, keyword, buf, limit) cpp_reader *pfile; struct directive *keyword; U_CHAR *buf, *limit;{ int hashcode; MACRODEF mdef; HASHNODE *hp;#if 0 /* If this is a precompiler run (with -pcp) pass thru #define commands. */ if (pcp_outfile && keyword) pass_thru_directive (buf, limit, pfile, keyword);#endif mdef = create_definition (buf, limit, pfile, keyword == NULL); if (mdef.defn == 0) goto nope; hashcode = hashf (mdef.symnam, mdef.symlen, HASHSIZE); if ((hp = cpp_lookup (pfile, mdef.symnam, mdef.symlen, hashcode)) != NULL) { int ok = 0; /* Redefining a precompiled key is ok. */ if (hp->type == T_PCSTRING) ok = 1; /* Redefining a macro is ok if the definitions are the same. */ else if (hp->type == T_MACRO) ok = ! compare_defs (mdef.defn, hp->value.defn); /* Redefining a constant is ok with -D. */ else if (hp->type == T_CONST) ok = ! CPP_OPTIONS (pfile)->done_initializing; /* Print the warning if it's not ok. */ if (!ok) { U_CHAR *msg; /* what pain... */ /* If we are passing through #define and #undef directives, do that for this re-definition now. */ if (CPP_OPTIONS (pfile)->debug_output && keyword) pass_thru_directive (buf, limit, pfile, keyword); msg = (U_CHAR *) alloca (mdef.symlen + 22); *msg = '`'; bcopy (mdef.symnam, msg + 1, mdef.symlen); strcpy ((char *) (msg + mdef.symlen + 1), "' redefined"); cpp_pedwarn (pfile, msg); if (hp->type == T_MACRO) cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file, hp->value.defn->line, "this is the location of the previous definition"); } /* Replace the old definition. */ hp->type = T_MACRO; hp->value.defn = mdef.defn; } else { /* If we are passing through #define and #undef directives, do that for this new definition now. */ if (CPP_OPTIONS (pfile)->debug_output && keyword) pass_thru_directive (buf, limit, pfile, keyword); install (mdef.symnam, mdef.symlen, T_MACRO, 0, (char *) mdef.defn, hashcode); } return 0;nope: return 1;}/* This structure represents one parsed argument in a macro call. `raw' points to the argument text as written (`raw_length' is its length). `expanded' points to the argument's macro-expansion (its length is `expand_length'). `stringified_length' is the length the argument would have if stringified. `use_count' is the number of times this macro arg is substituted into the macro. If the actual use count exceeds 10, the value stored is 10. *//* raw and expanded are relative to ARG_BASE */#define ARG_BASE ((pfile)->token_buffer)struct argdata { /* Strings relative to pfile->token_buffer */ long raw, expanded, stringified; int raw_length, expand_length; int stringified_length; char newlines; char use_count;};cpp_buffer*cpp_push_buffer (pfile, buffer, length) cpp_reader *pfile; U_CHAR *buffer; long length;{#ifdef STATIC_BUFFERS register cpp_buffer *buf = CPP_BUFFER (pfile); if (buf == pfile->buffer_stack) fatal ("%s: macro or `#include' recursion too deep", buf->fname); buf--; bzero ((char *) buf, sizeof (cpp_buffer)); CPP_BUFFER (pfile) = buf;#else register cpp_buffer *buf = (cpp_buffer*) xmalloc (sizeof(cpp_buffer)); bzero ((char *) buf, sizeof (cpp_buffer)); CPP_PREV_BUFFER (buf) = CPP_BUFFER (pfile); CPP_BUFFER (pfile) = buf;#endif buf->if_stack = pfile->if_stack; buf->cleanup = null_cleanup; buf->underflow = null_underflow; buf->buf = buf->cur = buffer; buf->alimit = buf->rlimit = buffer + length; return buf;}cpp_buffer*cpp_pop_buffer (pfile) cpp_reader *pfile;{ cpp_buffer *buf = CPP_BUFFER (pfile);#ifdef STATIC_BUFFERS (*buf->cleanup) (buf, pfile); return ++CPP_BUFFER (pfile);#else cpp_buffer *next_buf = CPP_PREV_BUFFER (buf); (*buf->cleanup) (buf, pfile); CPP_BUFFER (pfile) = next_buf; free (buf); return next_buf;#endif}/* Scan until CPP_BUFFER (PFILE) is exhausted into PFILE->token_buffer. Pop the buffer when done. */voidcpp_scan_buffer (pfile) cpp_reader *pfile;{ cpp_buffer *buffer = CPP_BUFFER (pfile); for (;;) { enum cpp_token token = cpp_get_token (pfile); if (token == CPP_EOF) /* Should not happen ... */ break; if (token == CPP_POP && CPP_BUFFER (pfile) == buffer) { cpp_pop_buffer (pfile); break; } }}/* * Rescan a string (which may have escape marks) into pfile's buffer. * Place the result in pfile->token_buffer. * * The input is copied before it is scanned, so it is safe to pass * it something from the token_buffer that will get overwritten * (because it follows CPP_WRITTEN). This is used by do_include. */static voidcpp_expand_to_buffer (pfile, buf, length) cpp_reader *pfile; U_CHAR *buf; int length;{ register cpp_buffer *ip; cpp_buffer obuf; U_CHAR *limit = buf + length; U_CHAR *buf1;#if 0 int odepth = indepth;#endif if (length < 0) abort (); /* Set up the input on the input stack. */ buf1 = (U_CHAR *) alloca (length + 1); { register U_CHAR *p1 = buf; register U_CHAR *p2 = buf1; while (p1 != limit) *p2++ = *p1++; } buf1[length] = 0; ip = cpp_push_buffer (pfile, buf1, length); ip->has_escapes = 1;#if 0 ip->lineno = obuf.lineno = 1;#endif /* Scan the input, create the output. */ cpp_scan_buffer (pfile);#if 0 if (indepth != odepth) abort ();#endif CPP_NUL_TERMINATE (pfile);}static voidadjust_position (buf, limit, linep, colp) U_CHAR *buf; U_CHAR *limit;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -