⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cccp.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
/* C Compatible Compiler Preprocessor (CCCP)Copyright (C) 1986, Free Software Foundation, Inc.                    Written by Paul Rubin, June 1986		       NO WARRANTY  BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELYNO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPTWHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY ANDFITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITYAND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVEDEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR ORCORRECTION. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTYWHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BELIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OROTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THEUSE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA ORDATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES ORA FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THISPROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCHDAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.		GENERAL PUBLIC LICENSE TO COPY  1. You may copy and distribute verbatim copies of this source fileas you receive it, in any medium, provided that you conspicuouslyand appropriately publish on each copy a valid copyright notice"Copyright (C) 1986 Free Software Foundation"; and includefollowing the copyright notice a verbatim copy of the above disclaimerof warranty and of this License.  2. You may modify your copy or copies of this source file orany portion of it, and copy and distribute such modifications underthe terms of Paragraph 1 above, provided that you also do the following:    a) cause the modified files to carry prominent notices stating    that you changed the files and the date of any change; and    b) cause the whole of any work that you distribute or publish,    that in whole or in part contains or is a derivative of this    program or any part thereof, to be licensed at no charge to all    third parties on terms identical to those contained in this    License Agreement (except that you may choose to grant more extensive    warranty protection to some or all third parties, at your option).    c) You may charge a distribution fee for the physical act of    transferring a copy, and you may at your option offer warranty    protection in exchange for a fee.Mere aggregation of another unrelated program with this program (or itsderivative) on a volume of a storage or distribution medium does not bringthe other program under the scope of these terms.  3. You may copy and distribute this program (or a portion or derivativeof it, under Paragraph 2) in object code or executable form under the termsof Paragraphs 1 and 2 above provided that you also do one of the following:    a) accompany it with the complete corresponding machine-readable    source code, which must be distributed under the terms of    Paragraphs 1 and 2 above; or,    b) accompany it with a written offer, valid for at least three    years, to give any third party free (except for a nominal    shipping charge) a complete machine-readable copy of the    corresponding source code, to be distributed under the terms of    Paragraphs 1 and 2 above; or,    c) accompany it with the information you received as to where the    corresponding source code may be obtained.  (This alternative is    allowed only for noncommercial distribution and only if you    received the program in object code or executable form alone.)For an executable file, complete source code means all the source code forall modules it contains; but, as a special exception, it need not includesource code for modules which are standard libraries that accompany theoperating system on which the executable file runs.  4. You may not copy, sublicense, distribute or transfer this programexcept as expressly provided under this License Agreement.  Any attemptotherwise to copy, sublicense, distribute or transfer this program is void andyour rights to use the program under this License agreement shall beautomatically terminated.  However, parties who have received computersoftware programs from you with this License Agreement will not havetheir licenses terminated so long as such parties remain in full compliance. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them.   Help stamp out software-hoarding!  */typedef unsigned char U_CHAR;#ifdef EMACS#define NO_SHORTNAMES#include "../src/config.h"#ifdef static#undef static#endif#ifdef open#undef open#undef close#undef read#undef write#endif /* open */#endif /* EMACS */#include <sys/types.h>#include <sys/stat.h>#include <sys/file.h>#include <ctype.h>#include <stdio.h>#ifndef USG#include <sys/time.h>		/* for __DATE__ and __TIME__ */#else#define index strchr#define rindex strrchr#include <time.h>#include <fcntl.h>#endif /* USG */void bcopy (), bzero ();int bcmp ();char *xmalloc (), *xrealloc (), *xcalloc ();void fatal (), pfatal_with_name (), perror_with_name ();char *progname;#define FATAL_EXIT_CODE 33	/* gnu cc command understands this */struct directory_stack  {    struct directory_stack *next;    char *fname;  };/* #include "file" starts with the first entry in the stack *//* #include <file> starts with the second. *//* -I directories are added after the first */struct directory_stack default_includes[2] =  {    { &default_includes[1], "." },    { 0, "/usr/include" }  };struct directory_stack *include = &default_includes[0];int max_include_len = 14;	/* strlen (default_include) + 2							(for / and null) */char STDIN_FILE[] = "";		/* Empty, like real cpp */int put_out_comments = 0;	/* JF non-zero means leave comments in the				   output file.  Used by lint *//* table to tell if char can be part of a C identifier. */U_CHAR is_idchar[256];/* table to tell if char can be first char of a c identifier. */U_CHAR is_idstart[256];/* table to tell if c is horizontal space.  isspace() thinks that   newline is space; this is not a good idea for this program. */U_CHAR is_hor_space[256];/* I/O buffer structure.  Ought to be used for the output file too.   These are also used when there is no file present, for example,   when rescanning a definition.  Then, the fname field is null. */#define INPUT_STACK_MAX 100struct file_buf {  struct infile *next;	/* for making stacks of file ptrs */  char *fname;  int lineno;  int length;  U_CHAR *buf;  U_CHAR *bufp;} instack[INPUT_STACK_MAX];int indepth = 0;typedef struct file_buf FILE_BUF;/* The output buffer.  Its LENGTH field is the amount of room allocated   for the buffer, not the number of chars actually present.  To get   that, subtract outbuf.buf from outbuf.bufp. */#define OUTBUF_SIZE 10	/* initial size of output buffer */FILE_BUF outbuf;/* Structure allocated for every #define.  For a simple replacement   such as   	#define foo bar ,   nargs = -1, the `pattern' list is null, and the expansion is just   the replacement text.  Nargs = 0 means a real macro with no args,   e.g.,       #define getchar() getc(stdin) .   When there are args, the expansion is the replacement text with the   args squashed out, and the reflist is a list describing how to   build the output from the input: e.g., "3 chars, then the 1st arg,   then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg".   The chars here come from the expansion.  Thus, for any definition   d , strlen(d->expansion) should equal the sum of all the   d->pattern->nchars.  Note that the list can be arbitrarily long---   its length depends on the number of times the arguements appear in   the replacement text, not how many args there are.  Example:   #define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and   pattern list     { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL }   where (x, y) means (nchars, argno). */typedef struct definition DEFINITION;struct definition {  int nargs;  int length;			/* length of expansion string */  U_CHAR *expansion;  struct reflist {    struct reflist *next;    int nchars;    int argno;  } *pattern;};/* different kinds of things that can appear in the value field   of a hash node.  Actually, this may be useless now. */union hashval {  int ival;  char *cpval;  DEFINITION *defn;};/* The structure of a node in the hash table.  The hash table   has entries for all tokens defined by #define commands (type T_MACRO),   plus some special tokens like __LINE__ (these each have their own   type, and the appropriate code is run when that type of node is seen.   It does not contain control words like "#define", which are recognized   by a separate piece of code. */typedef struct hashnode HASHNODE;struct hashnode {  HASHNODE *next;		/* double links for easy deletion */  HASHNODE *prev;  HASHNODE **bucket_hdr;	/* also, a back pointer to this node's hash				   chain is kept, in case the node is the head				   of the chain and gets deleted. */  int type;			/* type of special token */  int length;			/* length of token, for quick comparison */  U_CHAR *name;			/* the actual name */  union hashval value;		/* pointer to expansion, or whatever */};HASHNODE *install();/* different flavors of hash nodes --- also used in keyword table */#define T_DEFINE	1	/* the "#define" keyword */#define T_INCLUDE	2	/* the "#include" keyword */#define T_IFDEF		3	/* the "#ifdef" keyword */#define T_IF		4	/* the "#if" keyword */#define T_EXPAND	5	/* argument to be expanded (now unused) */#define T_MACRO		6	/* macro defined by "#define" */#define T_ELSE		7	/* "#else" */#define T_PRAGMA	8	/* "#pragma" */#define T_ELIF		9	/* "#else" */#define T_UNDEF		10	/* "#undef" */#define T_LINE		11	/* "#line" */#define T_ERROR		12	/* "#error" */#define T_IFNDEF	13	/* "#ifndef"; forgot this earlier */#define T_ENDIF		14	/* "#endif" */#define T_SPECLINE	15	/* special symbol "__LINE__" */#define T_DATE		16	/* "__DATE__" */#define T_FILE		17	/* "__FILE__" */#define T_TIME		18	/* "__TIME__" */#define T_SPEC_DEFINED	19	/* special macro for use in #if statements *//* some more different types will be needed --- no longer bloody likely */int do_define(), do_line(), do_include(), do_undef(), do_error(),  do_pragma(), do_if(), do_xifdef(), do_else(),  do_elif(), do_endif();/* table of control words, along with code to execute when the keyword   is seen.  For now, it is searched linearly, so put the most frequently   found keywords at the beginning of the list. */struct keyword_table {  int length;  int (*func)();  char *name;  int type;} keyword_table[] = {  {  6, do_define, "define", T_DEFINE},  {  4, do_line, "line", T_LINE},  {  7, do_include, "include", T_INCLUDE},  {  5, do_undef, "undef", T_UNDEF},  {  5, do_error, "error", T_ERROR},  {  2, do_if, "if", T_IF},  {  5, do_xifdef, "ifdef", T_IFDEF},  {  6, do_xifdef, "ifndef", T_IFNDEF},  {  4, do_else, "else", T_ELSE},  {  4, do_elif, "elif", T_ELIF},  {  5, do_endif, "endif", T_ENDIF},  {  6, do_pragma, "pragma", T_PRAGMA},  {  -1, 0, "", -1},};/* Some definitions for the hash table.  The hash function MUST be   computed as shown in hashf() below.  That is because the rescan   loop computes the hash value `on the fly' for most tokens,   in order to avoid the overhead of a lot of procedure calls to   the hashf() function.  Hashf() only exists for the sake of   politeness, for use when speed isn't so important. */#define HASHSIZE 1009HASHNODE *hashtab[HASHSIZE];#define HASHSTEP(old, c) ((old << 1) + c)#define MAKE_POS(v) (v & ~0x80000000) /* make number positive */#define SKIP_WHITE_SPACE(p) { while (is_hor_space[*p]) p++; }main (argc, argv)     int argc;     char **argv;{  struct stat sbuf;  char *in_fname, *out_fname;  int out_fd = 1;	/* default to stdout */  int f, i;  FILE_BUF *fp;  progname = argv[0];  in_fname = NULL;  out_fname = NULL;  initialize_random_junk ();  fp = &instack[indepth++];/*  if (argc < 2)		JF no args means work as filter    return FATAL_EXIT_CODE; */  for (i = 1; i < argc; i++) {    if (argv[i][0] != '-') {      if (out_fname != NULL)	fatal ("Usage: %s [switches] input output\n", argv[0]);      else if (in_fname != NULL) {	out_fname = argv[i];	if ((out_fd = creat (out_fname, 0666)) < 0)	  pfatal_with_name (out_fname);      } else	in_fname = argv[i];    } else {      switch (argv[i][1]) {	U_CHAR *p;	struct directory_stack *dirtmp;      case 'D':	if ((p = (U_CHAR *) index(argv[i]+2, '=')) != NULL)	  *p = ' ';	make_definition (argv[i] + 2);	break;      case 'U':		/* JF #undef something */	make_undef(argv[i] + 2);	break;      case 'C':		/* JF do later -C means leave comments alone! */	put_out_comments++;	break;      case 'E':			/* -E comes from cc -E; ignore it.  */	break;      case 'M':			/* Makefile dependencies or something like				   that.  Not implimented yet */	break;      case 'I':			/* JF handle directory path right */        dirtmp = (struct directory_stack *)			xmalloc (sizeof (struct directory_stack));	dirtmp->next = include->next;	include->next = dirtmp;	dirtmp->fname = argv[i]+2;	include = dirtmp;	if (strlen (argv[i]) > max_include_len)	  max_include_len = strlen (argv[i]);	break;      case '\0': /* JF handle '-' as file name meaning stdin or stdout */	if (in_fname == NULL) {	  in_fname = STDIN_FILE;	  break;	} else if (out_fname == NULL) {	  out_fname = "stdout";	  break;	}	/* else fall through into error */      default:	fatal ("Illegal option %s\n", argv[i]);      }    }  }  /* JF check for stdin */  if (in_fname == STDIN_FILE || in_fname == NULL)    f = 0;  else if ((f = open (in_fname, O_RDONLY)) < 0)    goto perror;  fstat (f, &sbuf);  fp->fname = in_fname;  fp->lineno = 1;  /* JF all this is mine about reading pipes and ttys */  if ((sbuf.st_mode & S_IFMT) != S_IFREG) {    int size;    int bsize;    int cnt;    U_CHAR *bufp;    bsize = 2000;    size = 0;    fp->buf = (U_CHAR *) xmalloc (bsize + 1);    bufp = fp->buf;    for (;;) {      cnt = read (f, bufp, bsize - size);      if (cnt < 0) goto perror;	/* error! */      if (cnt == 0) break;	/* End of file */      size += cnt;      bufp += cnt;      if (bsize-size == 0) {	/* Buffer is full! */        bsize *= 2;        fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 1);	bufp = fp->buf + size;	/* May have moved */      }    }    fp->buf[size] = '\0';    fp->length = size;  } else {    fp->length = sbuf.st_size;    fp->buf = (U_CHAR *) alloca (sbuf.st_size + 1);    if (read (f, fp->buf, sbuf.st_size) != sbuf.st_size)      goto perror;    fp->buf[sbuf.st_size] = '\0';  }  /* initialize output buffer */  outbuf.buf = (U_CHAR *) xmalloc (OUTBUF_SIZE);  outbuf.bufp = outbuf.buf;  outbuf.length = OUTBUF_SIZE;  output_line_command (fp, &outbuf);  rescan (fp, &outbuf);  /* do something different than this later */  fflush (stdout);  write (out_fd, outbuf.buf, outbuf.bufp - outbuf.buf);  exit (0); perror:  pfatal_with_name (argv[1]);}/* * The main loop of the program.  Try to examine and move past most * ordinary input chars as fast as possible.  Call appropriate routines * when something special (such as a macro expansion) has to happen.IP is the source of input to scan.OP is the place to put input. */rescan (ip, op)     FILE_BUF *ip, *op;{  register int c;  register int ident_length = 0, hash = 0;  register U_CHAR *limit;  U_CHAR *check_expand ();  struct keyword_table *handle_directive ();  int excess_newlines = 0;  int escaped = 0;    U_CHAR *bp;    check_expand(op, ip->length);    ip->bufp = ip->buf;  limit = ip->buf + ip->length;  while (1) {    if (ip->bufp < limit) {      c = *ip->bufp++;      *op->bufp++ = c;    } else {      c = -1;    }    --escaped;    /* Now ESCAPED is 0 if and only if this character is escaped.  */

⌨️ 快捷键说明

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