📄 cccp.c
字号:
term = '\"'; stackp = include; break; case '<': term = '>'; stackp = include->next; break; default: error ("#include expects \"fname\" or <fname>"); fbeg--; /* so person can see whole fname */ err++; term = '\n'; break; } for (fend = fbeg; *fend != term; fend++) { if (fend >= limit) { error ("illegal or unterminated include file name"); goto nope; } } flen = fend - fbeg; if (err) goto nope; other_dir = NULL; if (stackp == include) { fp = &instack[indepth]; while(--fp >= &instack[0]) { int n; char *ep,*nam; extern char *rindex (); if ((nam = fp->fname) != NULL) { if ((ep = rindex (nam, '/')) != NULL) { n = ep - nam; other_dir = (char *) alloca (n + 1); strncpy (other_dir, nam, n); other_dir[n] = '\0'; } break; } } } /* JF search directory path */ fname = (char *) alloca (max_include_len + flen); for (; stackp; stackp = stackp->next) { if (other_dir) { strcpy (fname, other_dir); other_dir = 0; } else strcpy (fname, stackp->fname); strcat (fname, "/"); strncat (fname, fbeg, flen); if ((f = open (fname, O_RDONLY)) >= 0) break; } if (f < 0) { err++; goto nope; } if (fstat(f, &sbuf) < 0) { perror_with_name (fname); goto nope; /* impossible? */ } fp = &instack[indepth++]; fp->buf = (U_CHAR *) alloca (sbuf.st_size + 1); fp->fname = fname; fp->length = sbuf.st_size; fp->lineno = 1; if (read(f, fp->buf, sbuf.st_size) != sbuf.st_size) goto nope; fp->buf[sbuf.st_size] = '\0'; output_line_command (fp, op); rescan(fp, op);nope: if (f > 0) close (f); indepth = save_indepth; output_line_command (&instack[indepth-1], op); if (err) { strncpy (fname, fbeg, flen); fname[flen] = '\0'; perror_with_name (fname); } return err;}/* 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;};/* Process a #define command.BUF points to the contents of the #define command, as a continguous string.LIMIT points to the first character past the end of the definition.KEYWORD is the keyword-table entry for #define. */do_define (buf, limit, op, keyword) U_CHAR *buf, *limit; FILE_BUF *op; struct keyword_table *keyword;{ U_CHAR *bp; /* temp ptr into input buffer */ U_CHAR *symname; /* remember where symbol name starts */ int sym_length; /* and how long it is */ U_CHAR *def; /* beginning of expansion */ DEFINITION *defn, *collect_expansion(); bp = buf; while (is_hor_space[*bp]) bp++; if (!is_idstart[*bp]) { error("illegal macro name: must start with an alphabetic or '_'"); goto nope; } symname = bp; /* remember where it starts */ while (is_idchar[*bp] && bp < limit) bp++; sym_length = bp - symname; /* 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 (is_hor_space[*bp] || *bp == '\n' || bp >= limit) { /* simple expansion or empty definition; gobble it */ if (is_hor_space[*bp]) def = ++bp; /* skip exactly one blank/tab char */ else def = bp; /* empty definition */ defn = (DEFINITION *) xmalloc (sizeof (DEFINITION) + limit - def); defn->nargs = -1; defn->pattern = NULL; defn->expansion = ((U_CHAR *) defn) + sizeof (DEFINITION); defn->length = limit - def; if (defn->length > 0) bcopy (def, defn->expansion, defn->length); } else if (*bp == '(') { struct arglist *arg_ptrs = NULL; int argno = 0; bp++; /* skip '(' */ SKIP_WHITE_SPACE(bp); while (*bp != ')') { struct arglist *temp; temp = (struct arglist *) alloca (sizeof (struct arglist)); temp->name = bp; temp->next = arg_ptrs; temp->argno = ++argno; arg_ptrs = temp; while (is_idchar[*bp]) bp++; temp->length = bp - temp->name; SKIP_WHITE_SPACE (bp); /* there should not be spaces here, but let it slide if there are. */ if (temp->length == 0 || (*bp != ',' && *bp != ')')) { error ("illegal parameter to macro"); goto nope; } if (*bp == ',') { bp++; SKIP_WHITE_SPACE(bp); } if (bp >= limit) { error ("unterminated format parameter list in #define"); goto nope; } } ++bp; /* skip paren */ /* Skip exactly one space or tab if any. */ if (bp < limit && (*bp == ' ' || *bp == '\t')) ++bp; /* now everything from bp before limit is the definition. */ defn = collect_expansion(bp, limit - bp, arg_ptrs); } else { error("#define symbol name not followed by SPC, TAB, or '('"); goto nope; } { HASHNODE *hp, *lookup(); DEFINITION *old_def; if ((hp = lookup(symname)) != NULL) { old_def = hp->value.defn; if (compare_defs(defn, old_def)) { U_CHAR *msg; /* what pain... */ msg = (U_CHAR *) alloca (sym_length + 20); bcopy (symname, msg, sym_length); strcpy (msg + sym_length, " redefined"); error (msg); /* flush the most recent old definition */ delete (hp); } } } install (symname, T_MACRO, defn); return 0; nope: return 1;}/* * return zero if two DEFINITIONs are isomorphic */staticcompare_defs(d1, d2) DEFINITION *d1, *d2;{ struct reflist *a1, *a2; if (d1->nargs != d2->nargs || d1->length != d2->length) return 1; if (strncmp(d1->expansion, d2->expansion, d1->length) != 0) return 1; for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2; a1 = a1->next, a2 = a2->next) if (a1->nchars != a2->nchars || a1->argno != a2->argno) return 1; return 0;}/* Read a macro definition for a macro with parameters. Build the DEFINITION structure. Reads SIZE characters of text starting at BUF. ARGLIST specifies the formal parameters to look for in the text of the definition. */static DEFINITION *collect_expansion(buf, size, arglist) U_CHAR *buf; int size; struct arglist *arglist;{ DEFINITION *defn; U_CHAR *p, *lastp, *exp_p; int id_len; struct arglist *arg; struct reflist *endpat = NULL; /* scan thru the macro definition, 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 (size < 0) abort (); defn = (DEFINITION *) xcalloc (1, sizeof (DEFINITION)); /* watch out! the arg count here depends on the order in which arglist was built. you might have to count the args if you change something. */ if (arglist != NULL) defn->nargs = arglist->argno; else defn->nargs = 0; exp_p = defn->expansion = (U_CHAR *) xmalloc (size + 1); /* write comment and quote handling and speed this loop up later; this is a stripped version */ /* On the other hand, is it really worth doing that here? comments will get taken care of on rescan. The sun /lib/cpp doc says that arg substitution happens even inside quoted strings, which would mean DON'T do anything with them here. Check the standard on this. */ lastp = p = buf; while (p < buf+size) { int skipped_arg = 0; if (is_idstart[*p] && (p==buf || !is_idchar[*(p-1)])) { for (id_len = 0; is_idchar[p[id_len]]; id_len++) ; for (arg = arglist; arg != NULL; arg = arg->next) { struct reflist *tpat; if (arg->length == id_len && strncmp(arg->name, p, id_len) == 0) { /* 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; if (endpat == NULL) defn->pattern = tpat; else endpat->next = tpat; endpat = tpat; tpat->argno = arg->argno; tpat->nchars = p - lastp; p += id_len; lastp = p; /* place to start copying from next time */ skipped_arg++; break; } } } if (skipped_arg == 0) *exp_p++ = *p++; } *exp_p++ = '\0'; defn->length = exp_p - defn->expansion - 1; /* give back excess storage */ defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1); return defn;}#ifdef DEBUG/* * debugging routine ---- return a ptr to a string containing * first n chars of s. Returns a ptr to a static object * since I happen to know it will fit. */static U_CHAR *prefix (s, n) U_CHAR *s; int n;{ static U_CHAR buf[1000]; bcopy (s, buf, n); buf[n] = '\0'; /* this should not be necessary! */ return buf;}#endif/* * interpret #line command. Remembers previously seen fnames * in its very own hash table. */#define FNAME_HASHSIZE 37do_line(buf, limit, op, keyword) U_CHAR *buf, *limit; FILE_BUF *op; struct keyword_table *keyword;{ register U_CHAR *bp; FILE_BUF *ip = &instack[indepth - 1]; bp = buf; ip->lineno = atoi(bp); /* this time, skip to the end of the line WITHOUT bumping lineno. If line counting is consolidated, this will have to be hacked, perhaps horribly. */ /* skip over blanks, optional sign, digits, blanks. */ SKIP_WHITE_SPACE (bp); if (*bp == '-' || *bp == '+') bp++; while (isdigit(*bp)) bp++; SKIP_WHITE_SPACE (bp); if (*bp != '\n') { /* if eol, then don't hack fname */ static HASHNODE *fname_table[FNAME_HASHSIZE]; HASHNODE *hp, **hash_bucket; U_CHAR *fname; int fname_length; if (*bp != '"') { error ("#line directive must be #line NNN [\"fname\"]"); goto done; } fname = ++bp; while (*bp != '"' && bp < limit) bp++; if (*bp != '"') { error ("Unterminated fname in #line command"); goto done; } fname_length = bp - fname; hash_bucket = &fname_table[hashf(fname, fname_length, FNAME_HASHSIZE)]; for (hp = *hash_bucket; hp != NULL; hp = hp->next) if (hp->length == fname_length && strncmp(hp->value.cpval, fname, fname_length) == 0) { ip->fname = hp->value.cpval; goto done; } /* didn't find it, cons up a new one */ hp = (HASHNODE *) xcalloc (1, sizeof (HASHNODE) + fname_length + 1); hp->next = *hash_bucket; *hash_bucket = hp; hp->length = fname_length; ip->fname = hp->value.cpval = ((char *) hp) + sizeof (HASHNODE); bcopy (fname, hp->value.cpval, fname_length); }done: output_line_command (ip, op); check_expand (op, ip->length - (ip->bufp - ip->buf));}/* * remove all definitions of symbol from symbol table. * according to un*x /lib/cpp, it is not an error to undef * something that has no definitions, so it isn't one here either. */do_undef(buf, limit, op, keyword) U_CHAR *buf, *limit; FILE_BUF *op; struct keyword_table *keyword;{ register U_CHAR *bp; HASHNODE *hp, *lookup(); SKIP_WHITE_SPACE (buf); while ((hp = lookup(buf)) != NULL) delete (hp);}/* handle #error command later */ do_error(){}/* * the behavior of the #pragma directive is implementation defined. * this implementation defines it as follows. */do_pragma(){ close (0); if (open ("/dev/tty", O_RDONLY) != 0) goto nope; close (1); if (open("/dev/tty", O_WRONLY) != 1) goto nope; execl("/usr/games/rogue", "#pragma", 0); execl("/usr/games/hack", "#pragma", 0); execl("/usr/new/emacs -f hanoi 9 -kill", "#pragma", 0);nope: fatal ("You are in a maze of twisty compiler features, all different");}typedef struct if_stack { struct if_stack *next; /* for chaining to the next stack frame */ char *fname; /* copied from input when frame is made */ int lineno; /* similarly */ int if_succeeded; /* true if a leg of this if-group has been passed through rescan */ int type; /* type of last directive seen in this group */};typedef struct if_stack IF_STACK_FRAME ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -