m4.c

来自「unix v7是最后一个广泛发布的研究型UNIX版本」· C语言 代码 · 共 900 行

C
900
字号
#include <stdio.h>#include <signal.h>#define ERROR NULL#define	READ	"r"#define	WRITE	"w"#define	EOS	0int	lpar	= '(';#define	LPAR	lpar#define	RPAR	')'#define	COMMA	','#define	GRAVE	'`'#define	ACUTE	'\''#define LBRAK	'['#define RBRAK	']'#ifdef  M4char	lquote	LBRAK;char	rquote	RBRAK;#endif#ifndef M4char	lquote	= GRAVE;char	rquote	= ACUTE;#endif#define	COMMENT	'#'#define	ALPH	1#define	DIG	2#define	HSHSIZ	199	/* prime */#define	STACKS	50#define	SAVS	4096#define	TOKS	128#define	putbak(c)	*ip++ = c;#define	getchr()	(ip>cur_ip?*--ip: getc(infile[infptr]))#define	putchr(c)	if (cp==NULL) {if (curfile)putc(c,curfile);} else *op++ = cchar	type[] = {	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	DIG,	DIG,	DIG,	DIG,	DIG,	DIG,	DIG,	DIG,	DIG,	DIG,	0,	0,	0,	0,	0,	0,	0,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	0,	0,	0,	0,	ALPH,	0,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	0,	0,	0,	0,	0,};char	token[TOKS];char	eoa[]	= "\0";struct	nlist {	char	*name;	char	*def;	struct	nlist *next;};struct	nlist	*hshtab[HSHSIZ];char	ibuf[SAVS+TOKS];char	obuf[SAVS+TOKS];char	*op	= obuf;char	*ip	= ibuf;char *ip_stk[10] = {ibuf};char *cur_ip = ibuf;struct call {	char	**argp;	int	plev;};struct	call	*cp = NULL;char	*makeloc;char	*ifdefloc;char	*lenloc;char	*undefloc;char	*shiftloc;char	*cqloc;char	*defloc;char	*evaloc;char	*incrloc;char	*substrloc;char	*indexloc;char	*transloc;char	*ifloc;char	*divloc;char	*divnumloc;char	*undivloc;char	*dnlloc;char	*inclloc;char	*sinclloc;char	*syscmdloc;char	*dumploc;char	*errploc;char	*tempname;struct nlist	*lookup();char	*install();char	*malloc();char	*mktemp();char	*copy();long	ctol();int	hshval;FILE	*olist[11] = { stdout };int	okret;int	curout	= 0;FILE	*curfile = { stdout };FILE	*infile[10] = { stdin };int	infptr	= 0;main(argc, argv)char **argv;{	char *argstk[STACKS+10];	struct call callst[STACKS];	register char *tp, **ap;	int delexit(), catchsig();	register t;	int i;#ifdef gcos#ifdef M4	install("GCOS", eoa);#endif#ifndef M4	install("gcos", eoa);#endif#endif#ifdef unix#ifdef M4	install("UNIX", eoa);#endif#ifndef M4	install("unix", eoa);#endif#endif#ifdef M4	makeloc = install("MAKETEMP", eoa);	ifdefloc = install("IFDEF", eoa);	lenloc = install("LEN", eoa);	undefloc = install("UNDEFINE", eoa);	shiftloc = install("SHIFT", eoa);	cqloc = install("CHANGEQUOTE", eoa);	defloc = install("DEFINE", eoa);	evaloc = install("EVAL", eoa);	inclloc = install("INCLUDE", eoa);	sinclloc = install("SINCLUDE", eoa);	syscmdloc = install("SYSCMD", eoa);	dumploc = install("DUMPDEF", eoa);	errploc = install("ERRPRINT", eoa);	incrloc = install("INCR", eoa);	substrloc = install("SUBSTR", eoa);	indexloc = install("INDEX", eoa);	transloc = install("TRANSLIT", eoa);	ifloc = install("IFELSE", eoa);	divloc = install("DIVERT", eoa);	divnumloc = install("DIVNUM", eoa);	undivloc = install("UNDIVERT", eoa);	dnlloc = install("DNL", eoa);#endif#ifndef M4	makeloc = install("maketemp", eoa);	ifdefloc = install("ifdef", eoa);	lenloc = install("len", eoa);	undefloc = install("undefine", eoa);	shiftloc = install("shift", eoa);	cqloc = install("changequote", eoa);	defloc = install("define", eoa);	evaloc = install("eval", eoa);	inclloc = install("include", eoa);	sinclloc = install("sinclude", eoa);	syscmdloc = install("syscmd", eoa);	dumploc = install("dumpdef", eoa);	errploc = install("errprint", eoa);	incrloc = install("incr", eoa);	substrloc = install("substr", eoa);	indexloc = install("index", eoa);	transloc = install("translit", eoa);	ifloc = install("ifelse", eoa);	divloc = install("divert", eoa);	divnumloc = install("divnum", eoa);	undivloc = install("undivert", eoa);	dnlloc = install("dnl", eoa);#endif	ap = argstk;#ifndef gcos	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)		signal(SIGHUP, catchsig);	if (signal(SIGINT, SIG_IGN) != SIG_IGN)		signal(SIGINT, catchsig);	tempname = mktemp("/tmp/m4aXXXXX");	close(creat(tempname, 0));#endif#ifdef gcos	tempname = "m4.tempa";#endif	if (argc>1)		putbak(0);	for (;;) {		tp = token;		*tp++ = t = getchr();		*tp = EOS;		if (t<=0) {			if (infptr > 0) {				fclose(infile[infptr]);				infptr--;				cur_ip = ip_stk[infptr];				continue;			}			if (argc<=1)				break;			argc--;			argv++;			if (infile[infptr]!=stdin)				fclose(infile[infptr]);			if (**argv=='-')				infile[infptr] = stdin;			else if ((infile[infptr]=fopen(argv[0], READ))==ERROR) {				fprintf(stderr, "m4: file not found: %s\n", argv[0]);				delexit();			}			continue;		}		if (type[t]==ALPH) {			while ((t=type[*tp++=getchr()])==ALPH||t==DIG);			putbak(*--tp);			*tp = EOS;			if (*ap = lookup(token)->def) {				if (++ap >= &argstk[STACKS]) {					fprintf(stderr, "m4: arg stack overflow\n");					delexit();				}				if (cp==NULL)					cp = callst;				else if (++cp > &callst[STACKS]) {					fprintf(stderr, "m4: call stack overflow\n");					delexit();				}				cp->argp = ap;				*ap++ = op;				puttok();				*op++ = '\0';				t = getchr();				putbak(t);				if (t!=LPAR) {					/* if (t!=' ' && t!='\t') */						putbak(')');					putbak('(');				}				else	/* try to fix arg count */					*ap++ = op;				cp->plev = 0;			} else				puttok();		} else if (t==lquote) {			i = 1;			for (;;) {				t = getchr();				if (t==rquote) {					i--;					if (i==0)						break;				} else if (t==lquote)					i++;				else if (t<0) {					fprintf(stderr, "m4: EOF in string\n");					delexit();				}				putchr(t);			}		} else if (t==COMMENT) {			putbak(t);			while ((t = getchr())!='\n'&& t>=0)				if (cp==NULL)					putchr(t);			putbak(t);		} else if (cp==NULL) {			puttok();		} else if (t==LPAR) {			if (cp->plev)				*op++ = t;			cp->plev++;			while ( (t=getchr())==' ' || t=='\t' || t=='\n')				;	/* skip leading white space during arg collection */			putbak(t);/*		} else if (t==' ' || t=='\t' || t=='\n') {			continue;*/		} else if (t==RPAR) {			cp->plev--;			if (cp->plev==0) {				*op++ = '\0';				expand(cp->argp, ap-cp->argp-1);				op = *cp->argp;				ap = cp->argp-1;				cp--;				if (cp < callst)					cp = NULL;			} else				*op++ = t;		} else if (t==COMMA && cp->plev<=1) {			*op++ = '\0';			*ap++ = op;			while ((t=getchr())==' ' || t=='\t' || t=='\n')				;	/* skip leading white space during arg collection */			putbak(t);		} else			*op++ = t;	}	if (cp!=NULL) {		fprintf(stderr, "m4: unexpected EOF\n");		delexit();	}	okret = 1;	delexit();}catchsig(){	okret = 0;	delexit();}delexit(){	register FILE *fp;	register i, c;	if (!okret) {		signal(SIGHUP, SIG_IGN);		signal(SIGINT, SIG_IGN);	}	for (i=1; i<10; i++) {		if (olist[i]==NULL)			continue;		fclose(olist[i]);		tempname[7] = 'a'+i;		if (okret) {			fp = fopen(tempname, READ);			while ((c = getc(fp)) > 0)				putchar(c);			fclose(fp);		}		unlink(tempname);	}	tempname[7] = 'a';	unlink(tempname);	exit(1-okret);}puttok(){	register char *tp;	tp = token;	if (cp) {		if (op >= &obuf[SAVS]) {			fprintf(stderr, "m4: argument overflow\n");			delexit();		}		while (*tp)			*op++ = *tp++;	} else if (curfile)		while (*tp)			putc(*tp++, curfile);}pbstr(str)register char *str;{	register char *p;	p = str;	while (*p++);	--p;	if (ip >= &ibuf[SAVS]) {		fprintf(stderr, "m4: pushback overflow\n");		delexit();	}	while (p > str)		putbak(*--p);}expand(a1, c)register char **a1;{	register char *dp;	register n;	dp = a1[-1];	if (dp==defloc)		dodef(a1, c);	else if (dp==evaloc)		doeval(a1, c);	else if (dp==inclloc)		doincl(a1, c, 1);	else if (dp==sinclloc)		doincl(a1, c, 0);	else if (dp==makeloc)		domake(a1, c);	else if (dp==syscmdloc)		dosyscmd(a1, c);	else if (dp==incrloc)		doincr(a1, c);	else if (dp==substrloc)		dosubstr(a1, c);	else if (dp==indexloc)		doindex(a1, c);	else if (dp==transloc)		dotransl(a1, c);	else if (dp==ifloc)		doif(a1, c);	else if (dp==divloc)		dodiv(a1, c);	else if (dp==divnumloc)		dodivnum(a1, c);	else if (dp==undivloc)		doundiv(a1, c);	else if (dp==dnlloc)		dodnl(a1, c);	else if (dp==dumploc)		dodump(a1, c);	else if (dp==errploc)		doerrp(a1, c);	else if (dp==lenloc)		dolen(a1, c);	else if (dp==ifdefloc)		doifdef(a1, c);	else if (dp==undefloc)		doundef(a1, c);	else if (dp==shiftloc)		doshift(a1, c);	else if (dp==cqloc)		docq(a1, c);	else {		while (*dp++);		for (dp--; dp>a1[-1]; ) {			if (--dp>a1[-1] && dp[-1]=='$') {				n = *dp-'0';				if (n>=0 && n<=9) {					if (n <= c)						pbstr(a1[n]);					dp--;				} else					putbak(*dp);			} else				putbak(*dp);		}	}}struct nlist *lookup(str)char *str;{	register char *s1, *s2;	register struct nlist *np;	static struct nlist nodef;	s1 = str;	for (hshval = 0; *s1; )		hshval += *s1++;	hshval %= HSHSIZ;	for (np = hshtab[hshval]; np!=NULL; np = np->next) {		s1 = str;		s2 = np->name;		while (*s1++ == *s2)			if (*s2++ == EOS)				return(np);	}	return(&nodef);}char *install(nam, val)char *nam, *val;{	register struct nlist *np;	if ((np = lookup(nam))->name == NULL) {		np = (struct nlist *)malloc(sizeof(*np));		if (np == NULL) {			fprintf(stderr, "m4: no space for alloc\n");			exit(1);		}		np->name = copy(nam);		np->def = copy(val);		np->next = hshtab[hshval];		hshtab[hshval] = np;		return(np->def);	}	free(np->def);	np->def = copy(val);	return(np->def);}doundef(ap, c)char **ap;{	register struct nlist *np, *tnp;	if (c < 1 || (np = lookup(ap[1]))->name == NULL)		return;	tnp = hshtab[hshval];	/* lookup sets hshval */	if (tnp == np)	/* it's in first place */		hshtab[hshval] = np->next;	else {		for ( ; tnp->next != np; tnp = tnp->next)			;		tnp->next = np->next;	}	free(np->name);	free(np->def);	free((char *)np);}char *copy(s)register char *s;{	register char *p, *s1;	p = s1 = malloc((unsigned)strlen(s)+1);	if (p == NULL) {		fprintf(stderr, "m4: no space for alloc\n");		exit(1);	}	while (*s1++ = *s++);	return(p);}dodef(ap, c)char **ap;{	if (c >= 2) {		if (strcmp(ap[1], ap[2]) == 0) {			fprintf(stderr, "m4: %s defined as itself\n", ap[1]);			delexit();		}		install(ap[1], ap[2]);	}	else if (c == 1)		install(ap[1], "");}doifdef(ap, c)char **ap;{	register struct nlist *np;	if (c < 2)		return;	if (lookup(ap[1])->name != NULL)		pbstr(ap[2]);	else if (c >= 3)		pbstr(ap[3]);}dolen(ap, c)char **ap;{	putnum((long) strlen(ap[1]));}docq(ap, c)char **ap;{	if (c > 1) {		lquote = *ap[1];		rquote = *ap[2];	} else if (c == 1) {		lquote = rquote = *ap[1];	} else {#ifndef M4		lquote = GRAVE;		rquote = ACUTE;#endif#ifdef M4		lquote = LBRAK;		rquote = RBRAK;#endif	}}doshift(ap, c)char **ap;{	fprintf(stderr, "m4: shift not yet implemented\n");}dodump(ap, c)char **ap;{	int i;	register struct nlist *np;	if (c > 0)		while (c--) {			if ((np = lookup(*++ap))->name != NULL)				fprintf(stderr, "`%s'	`%s'\n", np->name, np->def);		}	else		for (i=0; i<HSHSIZ; i++)			for (np=hshtab[i]; np!=NULL; np=np->next)				fprintf(stderr, "`%s'	`%s'\n", np->name, np->def);}doerrp(ap, c)char **ap;{	if (c > 0) {		fprintf(stderr, ap[1], ap[2], ap[3], ap[4], ap[5], ap[6]);		fprintf(stderr, "\n");	}}long	evalval;	/* return value from yacc stuff */char	*pe;	/* used by grammar */doeval(ap, c)char **ap;{	if (c > 0) {		pe = ap[1];		if (yyparse() == 0)			putnum(evalval);		else			fprintf(stderr, "m4: invalid expression in eval: %s\n", ap[1]);	}}doincl(ap, c, noisy)char **ap;{	if (c > 0 && strlen(ap[1]) > 0) {		infptr++;		ip_stk[infptr] = cur_ip = ip;		if ((infile[infptr] = fopen(ap[1], READ))==ERROR) {			if (noisy) {				fprintf(stderr, "m4: file not found: %s\n", ap[1]);				delexit();			}			else				infptr--;		}	}}dosyscmd(ap, c)char **ap;{	if (c > 0)		system(ap[1]);}domake(ap, c)char **ap;{	if (c > 0)		pbstr(mktemp(ap[1]));}doincr(ap, c)char **ap;{	if (c >= 1)		putnum(ctol(ap[1])+1);}putnum(num)long num;{	register sign;	sign = (num < 0) ? '-' : '\0';	if (num < 0)		num = -num;	do {		putbak(num%10+'0');		num = num/10;	} while (num!=0);	if (sign == '-')		putbak('-');}dosubstr(ap, c)char **ap;{	int nc;	register char *sp, *fc;	if (c<2)		return;	if (c<3)		nc = TOKS;	else		nc = ctoi(ap[3]);	fc = ap[1] + max(0, min(ctoi(ap[2]), strlen(ap[1])));	sp = fc + min(nc, strlen(fc));	while (sp > fc)		putbak(*--sp);}doindex(ap, c)char **ap;{	if (c >= 2)		putnum((long) strindex(ap[1], ap[2]));}strindex(p1, p2)char *p1, *p2;{	register m;	register char *s, *t, *p;	for (p=p1; *p; p++) {		s = p;		m = 1;		for (t=p2; *t; )			if (*t++ != *s++)				m = 0;		if (m == 1)			return(p-p1);	}	return(-1);}dotransl(ap, c)char **ap;{	register char *s, *fr, *to;	if (c <= 1) return;	if (c == 2) {		register int i;		to = ap[1];		for (s = ap[1]; *s; s++) {			i = 0;			for (fr = ap[2]; *fr; fr++)				if (*s == *fr) {					i++;					break;				}			if (i == 0)				*to++ = *s;		}		*to = '\0';	}	if (c >= 3) {		for (s = ap[1]; *s; s++)			for (fr = ap[2], to = ap[3]; *fr && *to; fr++, to++)				if (*s == *fr)					*s = *to;	}	pbstr(ap[1]);}doif(ap, c)register char **ap;{	if (c < 3)		return;	while (c >= 3) {		if (strcmp(ap[1], ap[2]) == 0) {			pbstr(ap[3]);			return;		}		c -= 3;		ap += 3;	}	if (c > 0)		pbstr(ap[1]);}dodiv(ap, c)register char **ap;{	register int f;	if (c<1)		f = 0;	else		f = ctoi(ap[1]);	if (f>=10 || f<0) {		curfile = NULL;		return;	}	tempname[7] = 'a' + f;	if (olist[f] || (olist[f]=fopen(tempname, WRITE))) {		curout = f;		curfile = olist[f];	}}doundiv(ap, c)char **ap;{	register FILE *fp;	register int i, ch;	int j;	if (c == 0) {		for (i=1; i<10; i++) {			if (i==curout || olist[i]==NULL)				continue;			fclose(olist[i]);			tempname[7] = 'a'+i;			fp = fopen(tempname, READ);			if (curfile != NULL)				while ((ch = getc(fp)) > 0)					putc(ch, curfile);			fclose(fp);			unlink(tempname);			olist[i] = NULL;		}	}	else {		for (j = 1; j <= c; j++) {			i = ctoi(*++ap);			if (i<1 || i>9 || i==curout || olist[i]==NULL)				continue;			fclose(olist[i]);			tempname[7] = 'a'+i;			fp = fopen(tempname, READ);			if (curfile != NULL)				while ((ch = getc(fp)) > 0)					putc(ch, curfile);			fclose(fp);			unlink(tempname);			olist[i] = NULL;		}	}}dodivnum(ap, c)char **ap;{	putnum((long) curout);}dodnl(ap, c)char **ap;{	register t;	while ((t=getchr())!='\n' && t>=0)		;}long ctol(str)register char *str;{	register sign;	long num;	while (*str==' ' || *str=='\t' || *str=='\n')		str++;	num = 0;	if (*str == '-') {		sign = -1;		str++;	}	else		sign = 1;	while (*str>='0' && *str<='9')		num = num*10 + *str++ - '0';	return(sign * num);}ctoi(s)char *s;{	return(ctol(s));}min(a, b){	if (a>b)		return(b);	return(a);}max(a, b){	if (a>b)		return(a);	return(b);}

⌨️ 快捷键说明

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