cpp6.c

来自「类PASCAL语言的编译器,LINUX环境的,我没试过是否正确.」· C语言 代码 · 共 1,221 行 · 第 1/3 页

C
1,221
字号
    if (file->fp == NULL) {             /* NULL if macro        */      popped++;      global->recursion -= file->unrecur;      if (global->recursion < 0)	global->recursion = 0;      global->infile = file->parent;		/* Unwind file chain	*/    } else {				/* Else get from a file */      /*       * If a input routine has been specified in the initial taglist,       * we should get the next line from that function IF we're reading       * from that certain file!       */      if(global->input && global->first_file && !strcmp(global->first_file, file->filename))	file->bptr = global->input(file->buffer, NBUFF, global->userdata);      else 	file->bptr = fgets(file->buffer, NBUFF, file->fp);      if(file->bptr != NULL) {	goto newline;		/* process the line	*/      } else {	if(!(global->input && global->first_file && !strcmp(global->first_file, file->filename)))	  /* If the input function isn't user supplied, close the file! */	  fclose(file->fp);           /* Close finished file  */	if ((global->infile = file->parent) != NULL) {	  /*	   * There is an "ungotten" newline in the current	   * infile buffer (set there by doinclude() in	   * cpp1.c).  Thus, we know that the mainline code	   * is skipping over blank lines and will do a	   * #line at its convenience.	   */	  global->wrongline = TRUE;	/* Need a #line now	*/	}      }    }    /*     * Free up space used by the (finished) file or macro and     * restart input from the parent file/macro, if any.     */    Freemem(file->filename);            /* Free name and        */    if (file->progname != NULL)         /* if a #line was seen, */      Freemem(file->progname);          /* free it, too.        */    Freemem(file);                      /* Free file space      */    if (global->infile == NULL)         /* If at end of file    */      return (EOF_CHAR);                /* Return end of file   */    global->line = global->infile->line; /* Reset line number	*/    goto get_from_file; 		/* Get from the top.	*/  }  /*   * Common processing for the new character.   */  if (c == DEF_MAGIC && file->fp != NULL) /* Don't allow delete   */    goto newline;			/* from a file		*/  if (file->parent != NULL) {           /* Macro or #include    */    if (popped != 0)      file->parent->unrecur += popped;    else {      global->recursion -= file->parent->unrecur;      if (global->recursion < 0)	global->recursion = 0;      file->parent->unrecur = 0;    }  }  if (c == '\n')                        /* Maintain current     */    ++global->line;			/* line counter 	*/  if (global->instring)                 /* Strings just return  */    return (c);                         /* the character.       */  else if (c == '/') {                  /* Comment?             */    global->instring = TRUE;		/* So get() won't loop  */    /* Check next byte for '*' and if(cplusplus) also '/' */    if ( (c = get(global)) != '*' )      if(!global->cplusplus || (global->cplusplus && c!='/')) {	global->instring = FALSE;	/* Nope, no comment	*/	unget(global);                  /* Push the char. back  */	return ('/');                   /* Return the slash     */      }        comments = 1;    if (global->keepcomments) {         /* If writing comments   */      global->comment = TRUE; /* information that a comment has been output */      if(global->showspace) {        /* Show all whitespaces! */        global->spacebuf[global->chpos] = '\0';        Putstring(global, global->spacebuf);      }      if(c=='*') {	Putchar(global, '/');           /* Write out the         */	Putchar(global, '*');           /*   initializer         */      } else {	/* C++ style comment */	Putchar(global, '/');           /* Write out the         */	Putchar(global, '/');           /*   initializer         */      }    }    if(global->cplusplus && c=='/') {   /* Eat C++ comment!      */      do {	c=get(global);	if(global->keepcomments)	  Putchar(global, c);      } while(c!='\n' && c!=EOF_CHAR);  /* eat all to EOL or EOF */      global->instring = FALSE;	        /* End of comment        */      return(c);		        /* Return the end char   */    }    for (;;) {                          /* Eat a comment         */      c = get(global);    test:      if (global->keepcomments && c != EOF_CHAR)	Putchar(global, c);      switch (c) {      case EOF_CHAR:	cerror(global, ERROR_EOF_IN_COMMENT);	return (EOF_CHAR);      case '/':	if(global->nestcomments || global->warnnestcomments) {	  if((c = get(global)) != '*')	    goto test;	  if(global->warnnestcomments) {	    cwarn(global, WARN_NESTED_COMMENT);	  }	  if(global->nestcomments)	    comments++;	}	break;	      case '*':	if ((c = get(global)) != '/')     	/* If comment doesn't   */	  goto test;			/* end, look at next	*/	if (global->keepcomments) {    	/* Put out the comment  */	  Putchar(global, c);         	/* terminator, too      */	}	if(--comments)	  /* nested comment, continue! */	  break;	global->instring = FALSE;	/* End of comment,	*/	/*	 * A comment is syntactically "whitespace" --	 * however, there are certain strange sequences	 * such as	 *		#define foo(x)  (something)	 *			foo|* comment *|(123)	 *	     these are '/' ^           ^	 * where just returning space (or COM_SEP) will cause	 * problems.  This can be "fixed" by overwriting the	 * '/' in the input line buffer with ' ' (or COM_SEP)	 * but that may mess up an error message.	 * So, we peek ahead -- if the next character is	 * "whitespace" we just get another character, if not,	 * we modify the buffer.  All in the name of purity.	 */	if (*file->bptr == '\n'	    || type[*file->bptr & 0xFF] == SPA)	  goto newline;#if COMMENT_INVISIBLE	/*	 * Return magic (old-fashioned) syntactic space.	 */	return ((file->bptr[-1] = COM_SEP));#else	return ((file->bptr[-1] = ' '));#endif	      case '\n':                	/* we'll need a #line   */	if (!global->keepcomments)	  global->wrongline = TRUE;	/* later...		*/      default:				/* Anything else is	*/	break;				/* Just a character	*/      }					/* End switch		*/    }					/* End comment loop	*/  }					/* End if in comment	*/  else if (!global->inmacro && c == '\\') { /* If backslash, peek   */    if ((c = get(global)) == '\n') {    /* for a <nl>.  If so,  */      global->wrongline = TRUE;      goto newline;    } else {				/* Backslash anything	*/      unget(global);                  	/* Get it later         */      return ('\\');             	/* Return the backslash */    }  } else if (c == '\f' || c == VT)      /* Form Feed, Vertical  */    c = ' ';                            /* Tab are whitespace   */  return (c);                           /* Just return the char */}void unget(struct Global *global){  /*   * Backup the pointer to reread the last character.  Fatal error   * (code bug) if we backup too far.  unget() may be called,   * without problems, at end of file.  Only one character may   * be ungotten.  If you need to unget more, call ungetstring().   */   FILEINFO *file;  if ((file = global->infile) == NULL)    return;			/* Unget after EOF	      */  if (--file->bptr < file->buffer) {    cfatal(global, FATAL_TOO_MUCH_PUSHBACK);    /* This happens only if used the wrong way! */    return;  }  if (*file->bptr == '\n')        	/* Ungetting a newline?       */    --global->line;			/* Unget the line number, too */}ReturnCode ungetstring(struct Global *global, char *text){  /*   * Push a string back on the input stream.  This is done by treating   * the text as if it were a macro.   */  FILEINFO *file;  ReturnCode ret;    ret = getfile(global, strlen(text) + 1, "", &file);  if(!ret)    strcpy(file->buffer, text);  return(ret);}int cget(struct Global *global){  /*   * Get one character, absorb "funny space" after comments or   * token concatenation   */  int c;    do {    c = get(global);#if COMMENT_INVISIBLE  } while (c == TOK_SEP || c == COM_SEP);#else  } while (c == TOK_SEP);#endif  return (c);}/* * Error messages and other hacks. */INLINE FILE_LOCALvoid domsg(struct Global *global,  ErrorCode error,  /* error message number */  va_list arg)      /* Something for the message    */{  /*   * Print filenames, macro names, and line numbers for error messages.   */    static char *ErrorMessage[]={    /*     * ERRORS:     */    "#%s must be in an #if",    "#%s may not follow #else",    "#error directive encountered",    "Preprocessor assertion failure",    "#if, #ifdef, or #ifndef without an argument",    "#include syntax error",    "#define syntax error",    "Redefining defined variable \"%s\"",    "Illegal #undef argument",    "Recursive macro definition of \"%s\"(Defined by \"%s\")",    "end of file within macro argument",    "misplaced constant in #if",    "#if value stack overflow",    "Illegal #if line",    "Operator %s in incorrect context",    "expression stack overflow at op \"%s\"",    "unbalanced paren's, op is \"%s\"",    "Misplaced '?' or ':', previous operator is %s",    "Can't use a string in an #if",    "Bad #if ... defined() syntax",    "= not allowed in #if",    "Unexpected \\ in #if",    "#if ... sizeof() syntax error",    "#if sizeof, unknown type \"%s\"",    "#if ... sizeof: illegal type combination",    "#if sizeof() error, no type specified",    "Unterminated string",    "EOF in comment",    "Inside #ifdef block at end of input, depth = %d",    "illegal character '%c' in #if",    "illegal character (%d decimal) in #if",    "#if ... sizeof: bug, unknown type code 0x%x",    "#if bug, operand = %d.",    "Strange character '%c' after ##",    "Strange character (%d.) after ##",    "", /* Dummy, to visualize the border between errors and warnings */    /*     * WARNINGS:     */    "Control line \"%s\" within macro expansion",    "Illegal # command \"%s\"",    "Unexpected text in #control line ignored",    "too few values specified to sizeof",    "too many values specified to sizeof! Not used.",    "\"%s\" wasn't defined",    "Internal error!",    "Macro \"%s\" needs arguments",    "Wrong number of macro arguments for \"%s\"",    "%s by zero in #if, zero result assumed",    "Illegal digit in octal number",    "multi-byte constant '%c' isn't portable",    "Cannot open include file \"%s\"",    "Illegal bracket '[]' balance, depth = %d",    "Illegal parentheses '()' balance, depth = %d",    "Illegal brace '{}' balance, depth = %d",    "Nested comment",    "", /* Dummy, to visualize the border between warnings and fatals */    /*     * FATALS:     */    "Too many nested #%s statements",    "Filename work buffer overflow",    "Too many include directories",    "Too many include files",    "Too many arguments for macro",    "Macro work area overflow",    "Bug: Illegal __ macro \"%s\"",    "Too many arguments in macro expansion",    "Out of space in macro \"%s\" arg expansion",    "work buffer overflow doing %s ##",    "Work buffer overflow",    "Out of memory",    "Too much pushback", /* internal */    };    char *tp;  FILEINFO *file;  char *severity=error<BORDER_ERROR_WARN?"Error":    error<BORDER_WARN_FATAL?"Warning":      "Fatal";    for (file = global->infile; file && !file->fp; file = file->parent)    ;  tp = file ? file->filename : 0;  Error(global, "%s\"%s\", line %d: %s: ",	MSG_PREFIX, tp, global->infile->fp?global->line:file->line, severity);  if(global->error)    global->error(global->userdata, ErrorMessage[error], arg);#if defined(UNIX)  else    vfprintf(stderr, ErrorMessage[error], arg);#elif defined(AMIGA)  else    return;#endif  Error(global, "\n");    if (file)   /*OIS*0.92*/    while ((file = file->parent) != NULL) { /* Print #includes, too */      tp = file->parent ? "," : ".";      if (file->fp == NULL)	Error(global, " from macro %s%s\n", file->filename, tp);      else	Error(global, " from file %s, line %d%s\n",	      (file->progname != NULL) ? file->progname : file->filename,	      file->line, tp);    }    if(error<BORDER_ERROR_WARN)    /* Error! Increase error counter! */    global->errors++;}void cerror(struct Global *global,	    ErrorCode message,	    ...)	/* arguments	*/{  /*   * Print a normal error message, string argument.   */  va_list arg;  va_start(arg, message);  domsg(global, message, arg);}void Error(struct Global *global, char *format, ...){  /*   * Just get the arguments and send a decent string to the user error   * string handler or to stderr.   */  va_list arg;  va_start(arg, format);  if(global->error)    global->error(global->userdata, format, arg);#if defined(UNIX)  else    vfprintf(stderr, format, arg);#endif}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?