📄 cpp4.c
字号:
#ifdef RCSstatic char rcsid[]="$Id: cpp4.c,v 1.3 1994/06/02 08:50:52 start Exp $";#endif/****************************************************************************** * FREXXWARE * ---------------------------------------------------------------------------- * * Project: Frexx C Preprocessor * $Source: /home/user/start/cpp/RCS/cpp4.c,v $ * $Revision: 1.3 $ * $Date: 1994/06/02 08:50:52 $ * $Author: start $ * $State: Exp $ * $Locker: $ * * ---------------------------------------------------------------------------- * $Log: cpp4.c,v $ * Revision 1.3 1994/06/02 08:50:52 start * Changed a few things to make the initial function routine to run * * Revision 1.2 1994/01/24 09:34:03 start * Made a bunch of functions FILE_LOCAL and INLINE. * * Revision 1.1 1993/11/03 09:13:08 start * Initial revision * * *****************************************************************************//* * C P P 4 . C * M a c r o D e f i n i t i o n s * * Edit History * 31-Aug-84 MM USENET net.sources release * 04-Oct-84 MM __LINE__ and __FILE__ must call ungetstring() * so they work correctly with token concatenation. * Added string formal recognition. * 25-Oct-84 MM "Short-circuit" evaluate #if's so that we * don't print unnecessary error messages for * #if !defined(FOO) && FOO != 0 && 10 / FOO ... * 31-Oct-84 ado/MM Added token concatenation * 6-Nov-84 MM Split off eval stuff * 21-Oct-85 RMS Rename `token' to `tokenbuf'. * In doundef, don't complain if arg already not defined. * 14-Mar-86 FNF Incorporate macro based C debugging package. * Port to Commodore AMIGA. * 21-Aug-88 Ois Changed concatenation operator to ##. Changed hand- * ling of tokens following ##. Added new meaning of #. */#include <stdio.h>#include <ctype.h>#include "cppdef.h"#include "cpp.h"INLINE FILE_LOCAL ReturnCode checkparm(struct Global *, int, DEFBUF *, int);INLINE FILE_LOCAL ReturnCode stparmscan(struct Global *, int);INLINE FILE_LOCAL ReturnCode textput(struct Global *, char *);FILE_LOCAL ReturnCode charput(struct Global *, int);INLINE FILE_LOCAL ReturnCode expcollect(struct Global *);INLINE FILE_LOCAL char *doquoting(char *, char *);ReturnCode dodefine(struct Global *global){ /* * Called from control when a #define is scanned. This module * parses formal parameters and the replacement string. When * the formal parameter name is encountered in the replacement * string, it is replaced by a character in the range 128 to * 128+NPARAM (this allows up to 32 parameters within the * Dec Multinational range). If cpp is ported to an EBCDIC * machine, you will have to make other arrangements. * * There is some special case code to distinguish * #define foo bar * from #define foo() bar * * Also, we make sure that * #define foo foo * expands to "foo" but doesn't put cpp into an infinite loop. * * A warning message is printed if you redefine a symbol to a * different text. I.e, * #define foo 123 * #define foo 123 * is ok, but * #define foo 123 * #define foo +123 * is not. * * The following subroutines are called from define(): * checkparm called when a token is scanned. It checks through the * array of formal parameters. If a match is found, the * token is replaced by a control byte which will be used * to locate the parameter when the macro is expanded. * textput puts a string in the macro work area (parm[]), updating * parmp to point to the first free byte in parm[]. * textput() tests for work buffer overflow. * charput puts a single character in the macro work area (parm[]) * in a manner analogous to textput(). */ int c; DEFBUF *dp; /* -> new definition */ int isredefine; /* TRUE if redefined */ char *old; /* Remember redefined */ ReturnCode ret;#if OK_CONCAT int quoting; /* Remember we saw a # */#endif if (type[(c = skipws(global))] != LET) { cerror(global, ERROR_DEFINE_SYNTAX); global->inmacro = FALSE; /* Stop <newline> hack */ return(FPP_OK); } isredefine = FALSE; /* Set if redefining */ if ((dp = lookid(global, c)) == NULL) { /* If not known now */ dp = defendel(global, global->tokenbuf, FALSE); /* Save the name */ if(!dp) return(FPP_OUT_OF_MEMORY); } else { /* It's known: */ isredefine = TRUE; /* Remember this fact */ old = dp->repl; /* Remember replacement */ dp->repl = NULL; /* No replacement now */ } global->parlist[0] = global->parmp = global->parm; /* Setup parm buffer */ if ((c = get(global)) == '(') { /* With arguments? */ global->nargs = 0; /* Init formals counter */ do { /* Collect formal parms */ if (global->nargs >= LASTPARM) { cfatal(global, FATAL_TOO_MANY_ARGUMENTS_MACRO); return(FPP_TOO_MANY_ARGUMENTS); } else if ((c = skipws(global)) == ')') break; /* Got them all */ else if (type[c] != LET) { /* Bad formal syntax */ cerror(global, ERROR_DEFINE_SYNTAX); global->inmacro = FALSE; /* Stop <newline> hack */ return(FPP_OK); } scanid(global, c); /* Get the formal param */ global->parlist[global->nargs++] = global->parmp; /* Save its start */ ret=textput(global, global->tokenbuf); /* Save text in parm[] */ if(ret) return(ret); } while ((c = skipws(global)) == ','); /* Get another argument */ if (c != ')') { /* Must end at ) */ cerror(global, ERROR_DEFINE_SYNTAX); global->inmacro = FALSE; /* Stop <newline> hack */ return(FPP_OK); } c = ' '; /* Will skip to body */ } else { /* * DEF_NOARGS is needed to distinguish between * "#define foo" and "#define foo()". */ global->nargs = DEF_NOARGS; /* No () parameters */ } if (type[c] == SPA) /* At whitespace? */ c = skipws(global); /* Not any more. */ global->workp = global->work; /* Replacement put here */ global->inmacro = TRUE; /* Keep \<newline> now */ quoting = 0; /* No # seen yet. */ while (c != EOF_CHAR && c != '\n') { /* Compile macro body */#if OK_CONCAT if (c == '#') { /* Token concatenation? */ if ((c = get(global)) != '#') { /* No, not really */ quoting = 1; /* Maybe quoting op. */ continue; } while (global->workp > global->work && type[global->workp[-1]] == SPA) --global->workp; /* Erase leading spaces */ if(ret=save(global, TOK_SEP)) /* Stuff a delimiter */ return(ret); c = skipws(global); /* Eat whitespace */ continue; }#endif switch (type[c]) { case LET:#if OK_CONCAT ret=checkparm(global, c, dp, quoting); /* Might be a formal */#else ret=checkparm(c, dp); /* Might be a formal */#endif if(ret) return(ret); break; case DIG: /* Number in mac. body */ case DOT: /* Maybe a float number */ ret=scannumber(global, c, save); /* Scan it off */ if(ret) return(ret); break; case QUO: /* String in mac. body */ ret=stparmscan(global, c); if(ret) return(ret); break; case BSH: /* Backslash */ ret=save(global, '\\'); if(ret) return(ret); if ((c = get(global)) == '\n') global->wrongline = TRUE; ret=save(global, c); if(ret) return(ret); break; case SPA: /* Absorb whitespace */ /* * Note: the "end of comment" marker is passed on * to allow comments to separate tokens. */ if (global->workp[-1] == ' ') /* Absorb multiple */ break; /* spaces */ else if (c == '\t') c = ' '; /* Normalize tabs */ /* Fall through to store character */ default: /* Other character */ ret=save(global, c); if(ret) return(ret); break; } c = get(global); quoting = 0; /* Only when immediately*/ /* preceding a formal */ } global->inmacro = FALSE; /* Stop newline hack */ unget(global); /* For control check */ if (global->workp > global->work && global->workp[-1] == ' ') /* Drop trailing blank */ global->workp--; *global->workp = EOS; /* Terminate work */ dp->repl = savestring(global, global->work); /* Save the string */ dp->nargs = global->nargs; /* Save arg count */ if (isredefine) { /* Error if redefined */ if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl)) || (old == NULL && dp->repl != NULL) || (old != NULL && dp->repl == NULL)) { cerror(global, ERROR_REDEFINE, dp->name); } if (old != NULL) /* We don't need the */ Freemem(old); /* old definition now. */ } return(FPP_OK);}INLINE FILE_LOCALReturnCode checkparm(struct Global *global, int c, DEFBUF *dp, int quoting) /* Preceded by a # ? */{ /* * Replace this param if it's defined. Note that the macro name is a * possible replacement token. We stuff DEF_MAGIC in front of the token * which is treated as a LETTER by the token scanner and eaten by * the output routine. This prevents the macro expander from * looping if someone writes "#define foo foo". */ int i; char *cp; ReturnCode ret=FPP_OK; scanid(global, c); /* Get parm to tokenbuf */ for (i = 0; i < global->nargs; i++) { /* For each argument */ if (streq(global->parlist[i], global->tokenbuf)) { /* If it's known */#if OK_CONCAT if (quoting) { /* Special handling of */ ret=save(global, QUOTE_PARM); /* #formal inside defn */ if(ret) return(ret); }#endif ret=save(global, i + MAC_PARM); /* Save a magic cookie */ return(ret); /* And exit the search */ } } if (streq(dp->name, global->tokenbuf)) /* Macro name in body? */ ret=save(global, DEF_MAGIC); /* Save magic marker */ for (cp = global->tokenbuf; *cp != EOS;) /* And save */ ret=save(global, *cp++); /* The token itself */ return(ret);}INLINE FILE_LOCALReturnCode stparmscan(struct Global *global, int delim){ /* * Normal string parameter scan. */ unsigned char *wp; int i; ReturnCode ret; wp = (unsigned char *)global->workp; /* Here's where it starts */ ret=scanstring(global, delim, save); if(ret) return(ret); /* Exit on scanstring error */ global->workp[-1] = EOS; /* Erase trailing quote */ wp++; /* -> first string content byte */ for (i = 0; i < global->nargs; i++) { if (streq(global->parlist[i], (char *)wp)) { *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */ *wp++ = (i + MAC_PARM); /* Make a formal marker */ *wp = wp[-3]; /* Add on closing quote */ global->workp = (char *)wp + 1; /* Reset string end */ return(FPP_OK); } } global->workp[-1] = wp[-1]; /* Nope, reset end quote. */ return(FPP_OK);} void doundef(struct Global *global) /* * Remove the symbol from the defined list. * Called from the #control processor. */{ int c; if (type[(c = skipws(global))] != LET) cerror(global, ERROR_ILLEGAL_UNDEF);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -