github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/cmd/cc/macbody (about)

     1  // Inferno utils/cc/macbody
     2  // http://code.google.com/p/inferno-os/source/browse/utils/cc/macbody
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  #define VARMAC 0x80
    32  
    33  int32
    34  getnsn(void)
    35  {
    36  	int32 n;
    37  	int c;
    38  
    39  	c = getnsc();
    40  	if(c < '0' || c > '9')
    41  		return -1;
    42  	n = 0;
    43  	while(c >= '0' && c <= '9') {
    44  		n = n*10 + c-'0';
    45  		c = getc();
    46  	}
    47  	unget(c);
    48  	return n;
    49  }
    50  
    51  Sym*
    52  getsym(void)
    53  {
    54  	int c;
    55  	char *cp;
    56  
    57  	c = getnsc();
    58  	if(!isalpha(c) && c != '_' && c < 0x80) {
    59  		unget(c);
    60  		return S;
    61  	}
    62  	for(cp = symb;;) {
    63  		if(cp <= symb+NSYMB-4)
    64  			*cp++ = c;
    65  		c = getc();
    66  		if(isalnum(c) || c == '_' || c >= 0x80)
    67  			continue;
    68  		unget(c);
    69  		break;
    70  	}
    71  	*cp = 0;
    72  	if(cp > symb+NSYMB-4)
    73  		yyerror("symbol too large: %s", symb);
    74  	return lookup();
    75  }
    76  
    77  Sym*
    78  getsymdots(int *dots)
    79  {
    80  	int c;
    81  	Sym *s;
    82  
    83  	s = getsym();
    84  	if(s != S)
    85  		return s;
    86  
    87  	c = getnsc();
    88  	if(c != '.'){
    89  		unget(c);
    90  		return S;
    91  	}
    92  	if(getc() != '.' || getc() != '.')
    93  		yyerror("bad dots in macro");
    94  	*dots = 1;
    95  	return slookup("__VA_ARGS__");
    96  }
    97  
    98  int
    99  getcom(void)
   100  {
   101  	int c;
   102  
   103  	for(;;) {
   104  		c = getnsc();
   105  		if(c != '/')
   106  			break;
   107  		c = getc();
   108  		if(c == '/') {
   109  			while(c != '\n')
   110  				c = getc();
   111  			break;
   112  		}
   113  		if(c != '*')
   114  			break;
   115  		c = getc();
   116  		for(;;) {
   117  			if(c == '*') {
   118  				c = getc();
   119  				if(c != '/')
   120  					continue;
   121  				c = getc();
   122  				break;
   123  			}
   124  			if(c == '\n') {
   125  				yyerror("comment across newline");
   126  				break;
   127  			}
   128  			c = getc();
   129  		}
   130  		if(c == '\n')
   131  			break;
   132  	}
   133  	return c;
   134  }
   135  
   136  void
   137  dodefine(char *cp)
   138  {
   139  	Sym *s;
   140  	char *p;
   141  	int32 l;
   142  
   143  	ensuresymb(strlen(cp));
   144  	strcpy(symb, cp);
   145  	p = strchr(symb, '=');
   146  	if(p) {
   147  		*p++ = 0;
   148  		s = lookup();
   149  		l = strlen(p) + 2;	/* +1 null, +1 nargs */
   150  		s->macro = alloc(l);
   151  		strcpy(s->macro+1, p);
   152  	} else {
   153  		s = lookup();
   154  		s->macro = "\0001";	/* \000 is nargs */
   155  	}
   156  	if(debug['m'])
   157  		print("#define (-D) %s %s\n", s->name, s->macro+1);
   158  }
   159  
   160  struct
   161  {
   162  	char	*macname;
   163  	void	(*macf)(void);
   164  } mactab[] =
   165  {
   166  	"ifdef",	0,	/* macif(0) */
   167  	"ifndef",	0,	/* macif(1) */
   168  	"else",		0,	/* macif(2) */
   169  
   170  	"line",		maclin,
   171  	"define",	macdef,
   172  	"include",	macinc,
   173  	"undef",	macund,
   174  
   175  	"pragma",	macprag,
   176  	"endif",	macend,
   177  	0
   178  };
   179  
   180  void
   181  domacro(void)
   182  {
   183  	int i;
   184  	Sym *s;
   185  
   186  	s = getsym();
   187  	if(s == S)
   188  		s = slookup("endif");
   189  	for(i=0; mactab[i].macname; i++)
   190  		if(strcmp(s->name, mactab[i].macname) == 0) {
   191  			if(mactab[i].macf)
   192  				(*mactab[i].macf)();
   193  			else
   194  				macif(i);
   195  			return;
   196  		}
   197  	yyerror("unknown #: %s", s->name);
   198  	macend();
   199  }
   200  
   201  void
   202  macund(void)
   203  {
   204  	Sym *s;
   205  
   206  	s = getsym();
   207  	macend();
   208  	if(s == S) {
   209  		yyerror("syntax in #undef");
   210  		return;
   211  	}
   212  	s->macro = 0;
   213  }
   214  
   215  #define	NARG	25
   216  void
   217  macdef(void)
   218  {
   219  	Sym *s, *a;
   220  	char *args[NARG], *np, *base;
   221  	int n, i, c, len, dots;
   222  	int ischr;
   223  
   224  	s = getsym();
   225  	if(s == S)
   226  		goto bad;
   227  	if(s->macro)
   228  		yyerror("macro redefined: %s", s->name);
   229  	c = getc();
   230  	n = -1;
   231  	dots = 0;
   232  	if(c == '(') {
   233  		n++;
   234  		c = getnsc();
   235  		if(c != ')') {
   236  			unget(c);
   237  			for(;;) {
   238  				a = getsymdots(&dots);
   239  				if(a == S)
   240  					goto bad;
   241  				if(n >= NARG) {
   242  					yyerror("too many arguments in #define: %s", s->name);
   243  					goto bad;
   244  				}
   245  				args[n++] = a->name;
   246  				c = getnsc();
   247  				if(c == ')')
   248  					break;
   249  				if(c != ',' || dots)
   250  					goto bad;
   251  			}
   252  		}
   253  		c = getc();
   254  	}
   255  	if(isspace(c))
   256  		if(c != '\n')
   257  			c = getnsc();
   258  	base = hunk;
   259  	len = 1;
   260  	ischr = 0;
   261  	for(;;) {
   262  		if(isalpha(c) || c == '_') {
   263  			np = symb;
   264  			*np++ = c;
   265  			c = getc();
   266  			while(isalnum(c) || c == '_') {
   267  				*np++ = c;
   268  				c = getc();
   269  			}
   270  			*np = 0;
   271  			for(i=0; i<n; i++)
   272  				if(strcmp(symb, args[i]) == 0)
   273  					break;
   274  			if(i >= n) {
   275  				i = strlen(symb);
   276  				base = allocn(base, len, i);
   277  				memcpy(base+len, symb, i);
   278  				len += i;
   279  				continue;
   280  			}
   281  			base = allocn(base, len, 2);
   282  			base[len++] = '#';
   283  			base[len++] = 'a' + i;
   284  			continue;
   285  		}
   286  		if(ischr){
   287  			if(c == '\\'){
   288  				base = allocn(base, len, 1);
   289  				base[len++] = c;
   290  				c = getc();
   291  			}else if(c == ischr)
   292  				ischr = 0;
   293  		}else{
   294  			if(c == '"' || c == '\''){
   295  				base = allocn(base, len, 1);
   296  				base[len++] = c;
   297  				ischr = c;
   298  				c = getc();
   299  				continue;
   300  			}
   301  			if(c == '/') {
   302  				c = getc();
   303  				if(c == '/'){
   304  					c = getc();
   305  					for(;;) {
   306  						if(c == '\n')
   307  							break;
   308  						c = getc();
   309  					}
   310  					continue;
   311  				}
   312  				if(c == '*'){
   313  					c = getc();
   314  					for(;;) {
   315  						if(c == '*') {
   316  							c = getc();
   317  							if(c != '/')
   318  								continue;
   319  							c = getc();
   320  							break;
   321  						}
   322  						if(c == '\n') {
   323  							yyerror("comment and newline in define: %s", s->name);
   324  							break;
   325  						}
   326  						c = getc();
   327  					}
   328  					continue;
   329  				}
   330  				base = allocn(base, len, 1);
   331  				base[len++] = '/';
   332  				continue;
   333  			}
   334  		}
   335  		if(c == '\\') {
   336  			c = getc();
   337  			if(c == '\n') {
   338  				c = getc();
   339  				continue;
   340  			}
   341  			else if(c == '\r') {
   342  				c = getc();
   343  				if(c == '\n') {
   344  					c = getc();
   345  					continue;
   346  				}
   347  			}
   348  			base = allocn(base, len, 1);
   349  			base[len++] = '\\';
   350  			continue;
   351  		}
   352  		if(c == '\n')
   353  			break;
   354  		if(c == '#')
   355  		if(n > 0) {
   356  			base = allocn(base, len, 1);
   357  			base[len++] = c;
   358  		}
   359  		base = allocn(base, len, 1);
   360  		base[len++] = c;
   361  		c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff));
   362  		if(c == '\n')
   363  			lineno++;
   364  		if(c == -1) {
   365  			yyerror("eof in a macro: %s", s->name);
   366  			break;
   367  		}
   368  	}
   369  	do {
   370  		base = allocn(base, len, 1);
   371  		base[len++] = 0;
   372  	} while(len & 3);
   373  
   374  	*base = n+1;
   375  	if(dots)
   376  		*base |= VARMAC;
   377  	s->macro = base;
   378  	if(debug['m'])
   379  		print("#define %s %s\n", s->name, s->macro+1);
   380  	return;
   381  
   382  bad:
   383  	if(s == S)
   384  		yyerror("syntax in #define");
   385  	else
   386  		yyerror("syntax in #define: %s", s->name);
   387  	macend();
   388  }
   389  
   390  void
   391  macexpand(Sym *s, char *b)
   392  {
   393  	char buf[2000];
   394  	int n, l, c, nargs;
   395  	char *arg[NARG], *cp, *ob, *ecp, dots;
   396  
   397  	ob = b;
   398  	if(*s->macro == 0) {
   399  		strcpy(b, s->macro+1);
   400  		if(debug['m'])
   401  			print("#expand %s %s\n", s->name, ob);
   402  		return;
   403  	}
   404  
   405  	nargs = (char)(*s->macro & ~VARMAC) - 1;
   406  	dots = *s->macro & VARMAC;
   407  
   408  	c = getnsc();
   409  	if(c != '(')
   410  		goto bad;
   411  	n = 0;
   412  	c = getc();
   413  	if(c != ')') {
   414  		unget(c);
   415  		l = 0;
   416  		cp = buf;
   417  		ecp = cp + sizeof(buf)-4;
   418  		arg[n++] = cp;
   419  		for(;;) {
   420  			if(cp >= ecp)
   421  				goto toobig;
   422  			c = getc();
   423  			if(c == '"')
   424  				for(;;) {
   425  					if(cp >= ecp)
   426  						goto toobig;
   427  					*cp++ = c;
   428  					c = getc();
   429  					if(c == '\\') {
   430  						*cp++ = c;
   431  						c = getc();
   432  						continue;
   433  					}
   434  					if(c == '\n')
   435  						goto bad;
   436  					if(c == '"')
   437  						break;
   438  				}
   439  			if(c == '\'')
   440  				for(;;) {
   441  					if(cp >= ecp)
   442  						goto toobig;
   443  					*cp++ = c;
   444  					c = getc();
   445  					if(c == '\\') {
   446  						*cp++ = c;
   447  						c = getc();
   448  						continue;
   449  					}
   450  					if(c == '\n')
   451  						goto bad;
   452  					if(c == '\'')
   453  						break;
   454  				}
   455  			if(c == '/') {
   456  				c = getc();
   457  				switch(c) {
   458  				case '*':
   459  					for(;;) {
   460  						c = getc();
   461  						if(c == '*') {
   462  							c = getc();
   463  							if(c == '/')
   464  								break;
   465  						}
   466  					}
   467  					*cp++ = ' ';
   468  					continue;
   469  				case '/':
   470  					while((c = getc()) != '\n')
   471  						;
   472  					break;
   473  				default:
   474  					unget(c);
   475  					c = '/';
   476  				}
   477  			}
   478  			if(l == 0) {
   479  				if(c == ',') {
   480  					if(n == nargs && dots) {
   481  						*cp++ = ',';
   482  						continue;
   483  					}
   484  					*cp++ = 0;
   485  					arg[n++] = cp;
   486  					if(n > nargs)
   487  						break;
   488  					continue;
   489  				}
   490  				if(c == ')')
   491  					break;
   492  			}
   493  			if(c == '\n')
   494  				c = ' ';
   495  			*cp++ = c;
   496  			if(c == '(')
   497  				l++;
   498  			if(c == ')')
   499  				l--;
   500  		}
   501  		*cp = 0;
   502  	}
   503  	if(n != nargs) {
   504  		yyerror("argument mismatch expanding: %s", s->name);
   505  		*b = 0;
   506  		return;
   507  	}
   508  	cp = s->macro+1;
   509  	for(;;) {
   510  		c = *cp++;
   511  		if(c == '\n')
   512  			c = ' ';
   513  		if(c != '#') {
   514  			*b++ = c;
   515  			if(c == 0)
   516  				break;
   517  			continue;
   518  		}
   519  		c = *cp++;
   520  		if(c == 0)
   521  			goto bad;
   522  		if(c == '#') {
   523  			*b++ = c;
   524  			continue;
   525  		}
   526  		c -= 'a';
   527  		if(c < 0 || c >= n)
   528  			continue;
   529  		strcpy(b, arg[c]);
   530  		b += strlen(arg[c]);
   531  	}
   532  	*b = 0;
   533  	if(debug['m'])
   534  		print("#expand %s %s\n", s->name, ob);
   535  	return;
   536  
   537  bad:
   538  	yyerror("syntax in macro expansion: %s", s->name);
   539  	*b = 0;
   540  	return;
   541  
   542  toobig:
   543  	yyerror("too much text in macro expansion: %s", s->name);
   544  	*b = 0;
   545  }
   546  
   547  void
   548  macinc(void)
   549  {
   550  	int c0, c, i, f;
   551  	char str[STRINGSZ], *hp;
   552  
   553  	c0 = getnsc();
   554  	if(c0 != '"') {
   555  		c = c0;
   556  		if(c0 != '<')
   557  			goto bad;
   558  		c0 = '>';
   559  	}
   560  	for(hp = str;;) {
   561  		c = getc();
   562  		if(c == c0)
   563  			break;
   564  		if(c == '\n')
   565  			goto bad;
   566  		*hp++ = c;
   567  	}
   568  	*hp = 0;
   569  
   570  	c = getcom();
   571  	if(c != '\n')
   572  		goto bad;
   573  
   574  	f = -1;
   575  	for(i=0; i<ninclude; i++) {
   576  		if(i == 0 && c0 == '>')
   577  			continue;
   578  		ensuresymb(strlen(include[i])+strlen(str)+2);
   579  		strcpy(symb, include[i]);
   580  		strcat(symb, "/");
   581  		if(strcmp(symb, "./") == 0)
   582  			symb[0] = 0;
   583  		strcat(symb, str);
   584  		f = open(symb, OREAD);
   585  		if(f >= 0)
   586  			break;
   587  	}
   588  	if(f < 0)
   589  		strcpy(symb, str);
   590  	c = strlen(symb) + 1;
   591  	hp = alloc(c);
   592  	memcpy(hp, symb, c);
   593  	newio();
   594  	pushio();
   595  	newfile(hp, f);
   596  	return;
   597  
   598  bad:
   599  	unget(c);
   600  	yyerror("syntax in #include");
   601  	macend();
   602  }
   603  
   604  void
   605  maclin(void)
   606  {
   607  	char *cp;
   608  	int c;
   609  	int32 n;
   610  
   611  	n = getnsn();
   612  	c = getc();
   613  	if(n < 0)
   614  		goto bad;
   615  
   616  	for(;;) {
   617  		if(c == ' ' || c == '\t') {
   618  			c = getc();
   619  			continue;
   620  		}
   621  		if(c == '"')
   622  			break;
   623  		if(c == '\n') {
   624  			strcpy(symb, "<noname>");
   625  			goto nn;
   626  		}
   627  		goto bad;
   628  	}
   629  	cp = symb;
   630  	for(;;) {
   631  		c = getc();
   632  		if(c == '"')
   633  			break;
   634  		*cp++ = c;
   635  	}
   636  	*cp = 0;
   637  	c = getcom();
   638  	if(c != '\n')
   639  		goto bad;
   640  
   641  nn:
   642  	c = strlen(symb) + 1;
   643  	cp = alloc(c);
   644  	memcpy(cp, symb, c);
   645  	linklinehist(ctxt, lineno, cp, n);
   646  	return;
   647  
   648  bad:
   649  	unget(c);
   650  	yyerror("syntax in #line");
   651  	macend();
   652  }
   653  
   654  void
   655  macif(int f)
   656  {
   657  	int c, l, bol;
   658  	Sym *s;
   659  
   660  	if(f == 2)
   661  		goto skip;
   662  	s = getsym();
   663  	if(s == S)
   664  		goto bad;
   665  	if(getcom() != '\n')
   666  		goto bad;
   667  	if((s->macro != 0) ^ f)
   668  		return;
   669  
   670  skip:
   671  	bol = 1;
   672  	l = 0;
   673  	for(;;) {
   674  		c = getc();
   675  		if(c != '#') {
   676  			if(!isspace(c))
   677  				bol = 0;
   678  			if(c == '\n')
   679  				bol = 1;
   680  			continue;
   681  		}
   682  		if(!bol)
   683  			continue;
   684  		s = getsym();
   685  		if(s == S)
   686  			continue;
   687  		if(strcmp(s->name, "endif") == 0) {
   688  			if(l) {
   689  				l--;
   690  				continue;
   691  			}
   692  			macend();
   693  			return;
   694  		}
   695  		if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
   696  			l++;
   697  			continue;
   698  		}
   699  		if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
   700  			macend();
   701  			return;
   702  		}
   703  	}
   704  
   705  bad:
   706  	yyerror("syntax in #if(n)def");
   707  	macend();
   708  }
   709  
   710  void
   711  macprag(void)
   712  {
   713  	Sym *s;
   714  	int c0, c;
   715  	char *hp;
   716  
   717  	s = getsym();
   718  
   719  	if(s && strcmp(s->name, "lib") == 0)
   720  		goto praglib;
   721  	if(s && strcmp(s->name, "pack") == 0) {
   722  		pragpack();
   723  		return;
   724  	}
   725  	if(s && strcmp(s->name, "fpround") == 0) {
   726  		pragfpround();
   727  		return;
   728  	}
   729  	if(s && strcmp(s->name, "textflag") == 0) {
   730  		pragtextflag();
   731  		return;
   732  	}
   733  	if(s && strcmp(s->name, "dataflag") == 0) {
   734  		pragdataflag();
   735  		return;
   736  	}
   737  	if(s && strcmp(s->name, "varargck") == 0) {
   738  		pragvararg();
   739  		return;
   740  	}
   741  	if(s && strcmp(s->name, "incomplete") == 0) {
   742  		pragincomplete();
   743  		return;
   744  	}
   745  	if(s && (strncmp(s->name, "cgo_", 4) == 0 || strncmp(s->name, "dyn", 3) == 0)) {
   746  		pragcgo(s->name);
   747  		return;
   748  	}
   749  	while(getnsc() != '\n')
   750  		;
   751  	return;
   752  
   753  praglib:
   754  	c0 = getnsc();
   755  	if(c0 != '"') {
   756  		c = c0;
   757  		if(c0 != '<')
   758  			goto bad;
   759  		c0 = '>';
   760  	}
   761  	for(hp = symb;;) {
   762  		c = getc();
   763  		if(c == c0)
   764  			break;
   765  		if(c == '\n')
   766  			goto bad;
   767  		*hp++ = c;
   768  	}
   769  	*hp = 0;
   770  	c = getcom();
   771  	if(c != '\n')
   772  		goto bad;
   773  
   774  	/*
   775  	 * put pragma-line in as a funny history
   776  	 */
   777  	c = strlen(symb) + 1;
   778  	hp = alloc(c);
   779  	memcpy(hp, symb, c);
   780  
   781  	linklinehist(ctxt, lineno, hp, -1);
   782  	return;
   783  
   784  bad:
   785  	unget(c);
   786  	yyerror("syntax in #pragma lib");
   787  	macend();
   788  }
   789  
   790  void
   791  macend(void)
   792  {
   793  	int c;
   794  
   795  	for(;;) {
   796  		c = getnsc();
   797  		if(c < 0 || c == '\n')
   798  			return;
   799  	}
   800  }