📄 ctrl.c
字号:
/* * ctrl - interpretation of preprocessor control lines (e.g. #define...) * for the selective C preprocessor, scpp. * * Copyright (c) 1985 by * Tektronix, Incorporated Beaverton, Oregon 97077 * All rights reserved. * * Permission is hereby granted for personal, non-commercial * reproduction and use of this program, provided that this * notice and all copyright notices are included in any copy. */# include <stdio.h># include "scpp.h"# include "y.tab.h"/* * valbuf[] the buffer in which to build the value of a macro which has * parameters. */# define VALLEN 1000 /* max # of chars in a macro value string */char valbuf[VALLEN];char *valend; /* * always points to the null-terminator * of the value while the value is being built *//* * form[] the array of formal parameters for a macro. * Each formal argument of a macro acts as a "local variable" during the * scan for the value of the macro. The form[] array contains * pointers to each argument's slot in the symbol table (used to recognize * the formal argument in the value) and the previous value of that slot * (so that the symbol table can be restored to normal after the value * of the macro has been scanned. */struct aformal { struct amacro *fm_sym; /* symbol table slot for this formal */ struct amacro fm_copy; /* copy of the old contents of that slot */};# define FORMSIZ 40 /* max number of parameters to a macro */struct aformal form[FORMSIZ];struct aformal *formtop; /* points to the next empty slot in form[] *//* * do_xxx() - functions for processing preprocessor control lines. */int do_line();int do_include();int do_define();int do_undef();int do_ifdef();int do_ifndef();int do_if();int do_elif();int do_else();int do_endif();/* * key - the array of preprocessor keywords. */struct akeyword key[] = { {"line", do_line, 0}, {"include", do_include, 0}, {"define", do_define, 0}, {"undef", do_undef, 0}, {"ifdef", do_ifdef, 0}, {"ifndef", do_ifndef, 0}, {"if", do_if, 0}, {"elif", do_elif, 0}, {"else", do_else, 0}, {"endif", do_endif, 0}, {0,0,0} /* a zero ak_name marks the end of the list */};/* * ikeywords() - initialize the preprocessor keywords. * For each keyword, set its ak_sym field and act as if it has been -M'ed. */ikeywords(){ struct akeyword *kp; for (kp = &key[0]; kp->ak_name; ++kp) { kp->ak_sym = findmac(kp->ak_name, kp->ak_name + strlen(kp->ak_name)); if (kp->ak_sym->am_name) { bomb("INTERNAL: identical keywords in key[]"); } kp->ak_sym->am_name = kp->ak_name; kp->ak_sym->am_npar = -1; /* leave am_val as 0 */ }}/* * findkey() - find the keyword corresponding to the given symbol table entry, * returning a pointer to that keyword in key[], * or zero if no match. */struct akeyword *findkey(mac)struct amacro *mac;{ struct akeyword *kp; for (kp = &key[0]; kp->ak_name && kp->ak_sym != mac; ++kp) ; if (!kp->ak_name) { return((struct akeyword *) 0); } return(kp);}/* * doctrl() - process a control line (a line beginning with '#'). */int /* returned token (NL or 0) */doctrl(f) /* process control lines */char *f; /* first char of this line (the '#' token) in pend[] */{ int tok; /* the current token */ struct amacro *cmd; /* the preprocessor command (symbol table) */ struct akeyword *kp; /* the preprocessor command (keyword table) */ /* * skip initial whitespace and comments (if any); * ignore empty command lines; * print warnings for garbled command lines; * switch on the command name. */ if ((tok = nonwhite(gintok)) == 0 || tok == NL) { return(tok); } if (tok != IDENT) { warnf("undefined control"); tok = endline(); return(tok); } cmd = findmac(curtext, nxtout); if (!cmd->am_name || !(kp = findkey(cmd))) { /* name is not a preprocessor command */ warnf("undefined control"); tok = endline(); return(tok); } /* * invoke the appropriate handler */ tok = (*kp->ak_proc)(f); return(tok);}/* * do_line - parse a #line command. * #line syntax: * #[<whitespace>]line[<whitespace>][<int>[<whitespace>]<string> * where: <int> is the new integer line number for this line, * <string> is the new double-quote enclosed filename. */intdo_line(f)char *f;{ int tok; char *name; /* the new filename */ char *src; char *dst; if ((tok = nonwhite(gintok)) == 0 || tok == NL) { return(tok); } if (tok == INT) { if (curfile >= &filestk[0]) { curfile->af_line = inttok(curtext, nxtout); } if ((tok = nonwhite(gintok)) == 0 || tok == NL) { return(tok); } } if (tok != STRING) { tok = endline(); return(tok); } name = savtok(curtext, nxtout); for (dst = name, src = name + 1; (*dst = *src) != '\0'; ++dst, ++src) ; if (--dst <= name || *dst != '"') { free(name); tok = endline(); return(tok); } *dst = '\0'; if (curfile >= &filestk[0]) { free(curfile->af_name); curfile->af_name = name; } tok = endline(); return(tok);}intdo_include(f)char *f; /* (unused because #include lines are never deleted) */{ char *ifile; /* the (dynamically alloc'ed) filename */ int looktype; /* type of directory search to perform */ int tok; /* the current token's type */ char *src, *dst; char **ip; /* * pickup the filename, scan the rest of the command line, * then include the file. */ ifile = (char *) 0; if ((tok = nonwhite(gintok)) == 0) { goto badinc; } if (tok == STRING) { /* * the filename is enclosed in double-quotes. * Set the search type to include the current file's directory; * Save the filename, then remove the string delimiters from it. */ looktype = PF_DOT; ifile = savtok(curtext, nxtout); for (dst = ifile, src = ifile + 1; (*dst = *src) != '\0'; ++dst, ++src) ; if (--dst <= ifile || *dst != '"') { goto badinc; } *dst = '\0'; } else if (tok == LT) { /* * The filename is enclosed in angle-brackets. * Set the directory search to exclude the current file's * directory; collect and save the filename. */ looktype = PF_NODOT; src = nxtout; while ((tok = gtok()) != GT && tok != NL && tok != 0) ; if (tok != GT) { goto badinc; } ifile = savtok(src, curtext); } else {badinc: bombf("bad include syntax"); if (ifile) { free(ifile); } tok = endline(); return(tok); } tok = endline(); for (ip = &ilist[0]; *ip; ip++) { if (!strcmp(ifile, *ip)) { pushfile(ifile, looktype, !PF_HIDE); dispose(f); free(ifile); return(tok); } } pushfile(ifile, looktype, PF_HIDE); free(ifile); return(tok);}intdo_define(f)char *f;{ int tok; struct amacro *mac; /* the macro being defined */ struct amacro *arg; /* * points to the slot for the current argument * from the definition of a macro with * parameters. */ struct amacro maccopy; /* * a copy of some of the info from the slot * for the macro being defined. Copying the * slot allows perverse macro definitions * such as: * # define boo(boo) boo() */ struct aformal *formp; /* a temp pointer */ int defok = TRUE; /* * 'ok to define the macro.' Used to prevent * definition of a macro with parameters if * there was a syntax error in the definition. */ /* * scan for the macro name with identifier expansion turned off. * Find the slot corresponding to the macro name. */ if ((tok = nonwhite(gtok)) == 0) { return(0); } if (tok != IDENT) { warnf("illegal macro name"); tok = endline(); return(tok); } mac = findmac(curtext, nxtout); if ((tok = gtok()) != LP) { /* * a simple macro. If it hasn't been -M'ed, ignore it. * Otherwise, save the replacement text (disposing of * any quoted newlines, comments, and appropriate * whitespace), define the macro, and dispose of this line. */ char *valstrt; /* points to the macro value within pend[] */ char *valstr; /* the dynamically alloc'ed value string */ if (!mac->am_name) { tok = endline(); return(tok); } valstrt = curtext; /* * if the delimiter is whitespace, skip the first character * of the whitespace (and any preceeding ATTN bytes). */ if (tok == WHITE) { while (valstrt < nxtout && *valstrt == ATTN) { valstrt += 2; } if (valstrt < nxtout) { valstrt++; } } while (tok != NL && tok != 0) { if (tok == QNL || (!savcom && tok == COMMENT)) { (void) dispose(curtext); } tok = gtok(); } if (tok == 0) { warnf("unterminated preprocessor command"); } else { valstr = savtok(valstrt, curtext); if (!savcom) { stripwhite(valstr); } defmac(mac->am_name, mac->am_name + strlen(mac->am_name), -1 /* npar */, valstr); free(valstr); } (void) dispose(f); return(tok); } /* a macro with parameters. Copy relevant parts of it. */ maccopy.am_name = mac->am_name; /* * Collect the comma-separated formals of the macro. * Temporarily define each formal of the macro, saving the old * contents of that formal's slot in the symbol table, * marking that symbol as -M'ed, but undefined (so that * scanning an uninterpreted macro definition works in the * following case: * scpp -MMOO * #define MOO lose * #define goo(MOO) is a MOO. * should generate * #define goo(MOO) is a MOO. * rather than * #define goo(MOO) is a lose. */ formtop = &form[0]; while (formtop < &form[FORMSIZ]) { if ((tok = nonwhite(gtok)) != IDENT) { break; } /* process the formal argument */ formtop->fm_sym = findmac(curtext, nxtout); for (formp = &form[0]; formp < formtop && formp->fm_sym != formtop->fm_sym; ++formp) ; if (formp < formtop) { warnf("duplicate formal names in macro definition"); } formtop->fm_copy.am_name = formtop->fm_sym->am_name; formtop->fm_copy.am_npar = formtop->fm_sym->am_npar; formtop->fm_copy.am_val = formtop->fm_sym->am_val; formtop->fm_sym->am_name = savtok(curtext, nxtout); formtop->fm_sym->am_npar = -1; formtop->fm_sym->am_val = (char *) 0; ++formtop; if ((tok = nonwhite(gtok)) != CM) { break; } } if (tok != RP) { if (formtop >= &form[FORMSIZ]) { warnf("too many formal arguments"); } else { warnf("syntax error in formal arguments"); } tok = endline(); defok = FALSE; goto rollback; } if (!maccopy.am_name) { /* * This macro is not -M'ed, so don't interpret this #define. * scan to the end of the line. */ tok = endline(); defok = FALSE; } else { /* * This macro is -M'ed. Record the number of parameters, * then save the value of this macro, * marking occurrences of the formal arguments. */ maccopy.am_npar = formtop - &form[0]; valend = &valbuf[0]; *valend = '\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -