github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/dist/goc2c.c (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include "a.h"
     6  
     7  /*
     8   * Translate a .goc file into a .c file.  A .goc file is a combination
     9   * of a limited form of Go with C.
    10   */
    11  
    12  /*
    13  	package PACKAGENAME
    14  	{# line}
    15  	func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
    16  	  C code with proper brace nesting
    17  	\}
    18  */
    19  
    20  /*
    21   * We generate C code which implements the function such that it can
    22   * be called from Go and executes the C code.
    23   */
    24  
    25  static char *input;
    26  static Buf *output;
    27  #define EOF -1
    28  
    29  enum
    30  {
    31  	use64bitint = 1,
    32  };
    33  
    34  static int
    35  xgetchar(void)
    36  {
    37  	int c;
    38  	
    39  	c = *input;
    40  	if(c == 0)
    41  		return EOF;
    42  	input++;
    43  	return c;
    44  }
    45  
    46  static void
    47  xungetc(void)
    48  {
    49  	input--;
    50  }
    51  
    52  static void
    53  xputchar(char c)
    54  {
    55  	bwrite(output, &c, 1);
    56  }
    57  
    58  static int
    59  xisspace(int c)
    60  {
    61  	return c == ' ' || c == '\t' || c == '\r' || c == '\n';
    62  }
    63  
    64  /* Whether we're emitting for gcc */
    65  static int gcc;
    66  
    67  /* File and line number */
    68  static const char *file;
    69  static unsigned int lineno;
    70  
    71  /* List of names and types.  */
    72  struct params {
    73  	struct params *next;
    74  	char *name;
    75  	char *type;
    76  };
    77  
    78  /* index into type_table */
    79  enum {
    80  	Bool,
    81  	Float,
    82  	Int,
    83  	Uint,
    84  	Uintptr,
    85  	String,
    86  	Slice,
    87  	Eface,
    88  };
    89  
    90  static struct {
    91  	char *name;
    92  	int size;
    93  } type_table[] = {
    94  	/* 
    95  	 * variable sized first, for easy replacement.
    96  	 * order matches enum above.
    97  	 * default is 32-bit architecture sizes.
    98  	 * spelling as in package runtime, so intgo/uintgo not int/uint.
    99  	 */
   100  	{"bool",	1},
   101  	{"float",	4},
   102  	{"intgo",		4},
   103  	{"uintgo",	4},
   104  	{"uintptr",	4},
   105  	{"String",	8},
   106  	{"Slice",	12},
   107  	{"Eface",	8},
   108  
   109  	/* fixed size */
   110  	{"float32",	4},
   111  	{"float64",	8},
   112  	{"byte",	1},
   113  	{"int8",	1},
   114  	{"uint8",	1},
   115  	{"int16",	2},
   116  	{"uint16",	2},
   117  	{"int32",	4},
   118  	{"rune",	4},
   119  	{"uint32",	4},
   120  	{"int64",	8},
   121  	{"uint64",	8},
   122  
   123  	{nil, 0},
   124  };
   125  
   126  /* Fixed structure alignment (non-gcc only) */
   127  int structround = 4;
   128  
   129  /* Unexpected EOF.  */
   130  static void
   131  bad_eof(void)
   132  {
   133  	fatal("%s:%ud: unexpected EOF\n", file, lineno);
   134  }
   135  
   136  /* Free a list of parameters.  */
   137  static void
   138  free_params(struct params *p)
   139  {
   140  	while (p != nil) {
   141  		struct params *next;
   142  
   143  		next = p->next;
   144  		xfree(p->name);
   145  		xfree(p->type);
   146  		xfree(p);
   147  		p = next;
   148  	}
   149  }
   150  
   151  /* Read a character, tracking lineno.  */
   152  static int
   153  getchar_update_lineno(void)
   154  {
   155  	int c;
   156  
   157  	c = xgetchar();
   158  	if (c == '\n')
   159  		++lineno;
   160  	return c;
   161  }
   162  
   163  /* Read a character, giving an error on EOF, tracking lineno.  */
   164  static int
   165  getchar_no_eof(void)
   166  {
   167  	int c;
   168  
   169  	c = getchar_update_lineno();
   170  	if (c == EOF)
   171  		bad_eof();
   172  	return c;
   173  }
   174  
   175  /* Read a character, skipping comments.  */
   176  static int
   177  getchar_skipping_comments(void)
   178  {
   179  	int c;
   180  
   181  	while (1) {
   182  		c = getchar_update_lineno();
   183  		if (c != '/')
   184  			return c;
   185  
   186  		c = xgetchar();
   187  		if (c == '/') {
   188  			do {
   189  				c = getchar_update_lineno();
   190  			} while (c != EOF && c != '\n');
   191  			return c;
   192  		} else if (c == '*') {
   193  			while (1) {
   194  				c = getchar_update_lineno();
   195  				if (c == EOF)
   196  					return EOF;
   197  				if (c == '*') {
   198  					do {
   199  						c = getchar_update_lineno();
   200  					} while (c == '*');
   201  					if (c == '/')
   202  						break;
   203  				}
   204  			}
   205  		} else {
   206  			xungetc();
   207  			return '/';
   208  		}
   209  	}
   210  }
   211  
   212  /*
   213   * Read and return a token.  Tokens are string or character literals
   214   * or else delimited by whitespace or by [(),{}].
   215   * The latter are all returned as single characters.
   216   */
   217  static char *
   218  read_token(void)
   219  {
   220  	int c, q;
   221  	char *buf;
   222  	unsigned int alc, off;
   223  	char* delims = "(),{}";
   224  
   225  	while (1) {
   226  		c = getchar_skipping_comments();
   227  		if (c == EOF)
   228  			return nil;
   229  		if (!xisspace(c))
   230  			break;
   231  	}
   232  	alc = 16;
   233  	buf = xmalloc(alc + 1);
   234  	off = 0;
   235  	if(c == '"' || c == '\'') {
   236  		q = c;
   237  		buf[off] = c;
   238  		++off;
   239  		while (1) {
   240  			if (off+2 >= alc) { // room for c and maybe next char
   241  				alc *= 2;
   242  				buf = xrealloc(buf, alc + 1);
   243  			}
   244  			c = getchar_no_eof();
   245  			buf[off] = c;
   246  			++off;
   247  			if(c == q)
   248  				break;
   249  			if(c == '\\') {
   250  				buf[off] = getchar_no_eof();
   251  				++off;
   252  			}
   253  		}
   254  	} else if (xstrrchr(delims, c) != nil) {
   255  		buf[off] = c;
   256  		++off;
   257  	} else {
   258  		while (1) {
   259  			if (off >= alc) {
   260  				alc *= 2;
   261  				buf = xrealloc(buf, alc + 1);
   262  			}
   263  			buf[off] = c;
   264  			++off;
   265  			c = getchar_skipping_comments();
   266  			if (c == EOF)
   267  				break;
   268  			if (xisspace(c) || xstrrchr(delims, c) != nil) {
   269  				if (c == '\n')
   270  					lineno--;
   271  				xungetc();
   272  				break;
   273  			}
   274  		}
   275  	}
   276  	buf[off] = '\0';
   277  	return buf;
   278  }
   279  
   280  /* Read a token, giving an error on EOF.  */
   281  static char *
   282  read_token_no_eof(void)
   283  {
   284  	char *token = read_token();
   285  	if (token == nil)
   286  		bad_eof();
   287  	return token;
   288  }
   289  
   290  /* Read the package clause, and return the package name.  */
   291  static char *
   292  read_package(void)
   293  {
   294  	char *token;
   295  
   296  	token = read_token_no_eof();
   297  	if (token == nil)
   298  		fatal("%s:%ud: no token\n", file, lineno);
   299  	if (!streq(token, "package")) {
   300  		fatal("%s:%ud: expected \"package\", got \"%s\"\n",
   301  			file, lineno, token);
   302  	}
   303  	return read_token_no_eof();
   304  }
   305  
   306  /* Read and copy preprocessor lines.  */
   307  static void
   308  read_preprocessor_lines(void)
   309  {
   310  	while (1) {
   311  		int c;
   312  
   313  		do {
   314  			c = getchar_skipping_comments();
   315  		} while (xisspace(c));
   316  		if (c != '#') {
   317  			xungetc();
   318  			break;
   319  		}
   320  		xputchar(c);
   321  		do {
   322  			c = getchar_update_lineno();
   323  			xputchar(c);
   324  		} while (c != '\n');
   325  	}
   326  }
   327  
   328  /*
   329   * Read a type in Go syntax and return a type in C syntax.  We only
   330   * permit basic types and pointers.
   331   */
   332  static char *
   333  read_type(void)
   334  {
   335  	char *p, *op, *q;
   336  	int pointer_count;
   337  	unsigned int len;
   338  
   339  	p = read_token_no_eof();
   340  	if (*p != '*' && !streq(p, "int") && !streq(p, "uint"))
   341  		return p;
   342  	op = p;
   343  	pointer_count = 0;
   344  	while (*p == '*') {
   345  		++pointer_count;
   346  		++p;
   347  	}
   348  	len = xstrlen(p);
   349  	q = xmalloc(len + 2 + pointer_count + 1);
   350  	xmemmove(q, p, len);
   351  
   352  	// Turn int/uint into intgo/uintgo.
   353  	if((len == 3 && xmemcmp(q, "int", 3) == 0) || (len == 4 && xmemcmp(q, "uint", 4) == 0)) {
   354  		q[len++] = 'g';
   355  		q[len++] = 'o';
   356  	}
   357  
   358  	while (pointer_count-- > 0)
   359  		q[len++] = '*';
   360  	
   361  	q[len] = '\0';
   362  	xfree(op);
   363  	return q;
   364  }
   365  
   366  /* Return the size of the given type. */
   367  static int
   368  type_size(char *p)
   369  {
   370  	int i;
   371  
   372  	if(p[xstrlen(p)-1] == '*')
   373  		return type_table[Uintptr].size;
   374  
   375  	for(i=0; type_table[i].name; i++)
   376  		if(streq(type_table[i].name, p))
   377  			return type_table[i].size;
   378  	fatal("%s:%ud: unknown type %s\n", file, lineno, p);
   379  	return 0;
   380  }
   381  
   382  /*
   383   * Read a list of parameters.  Each parameter is a name and a type.
   384   * The list ends with a ')'.  We have already read the '('.
   385   */
   386  static struct params *
   387  read_params(int *poffset)
   388  {
   389  	char *token;
   390  	struct params *ret, **pp, *p;
   391  	int offset, size, rnd;
   392  
   393  	ret = nil;
   394  	pp = &ret;
   395  	token = read_token_no_eof();
   396  	offset = 0;
   397  	if (!streq(token, ")")) {
   398  		while (1) {
   399  			p = xmalloc(sizeof(struct params));
   400  			p->name = token;
   401  			p->type = read_type();
   402  			p->next = nil;
   403  			*pp = p;
   404  			pp = &p->next;
   405  
   406  			size = type_size(p->type);
   407  			rnd = size;
   408  			if(rnd > structround)
   409  				rnd = structround;
   410  			if(offset%rnd)
   411  				offset += rnd - offset%rnd;
   412  			offset += size;
   413  
   414  			token = read_token_no_eof();
   415  			if (!streq(token, ","))
   416  				break;
   417  			token = read_token_no_eof();
   418  		}
   419  	}
   420  	if (!streq(token, ")")) {
   421  		fatal("%s:%ud: expected '('\n",
   422  			file, lineno);
   423  	}
   424  	if (poffset != nil)
   425  		*poffset = offset;
   426  	return ret;
   427  }
   428  
   429  /*
   430   * Read a function header.  This reads up to and including the initial
   431   * '{' character.  Returns 1 if it read a header, 0 at EOF.
   432   */
   433  static int
   434  read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
   435  {
   436  	int lastline;
   437  	char *token;
   438  
   439  	lastline = -1;
   440  	while (1) {
   441  		token = read_token();
   442  		if (token == nil)
   443  			return 0;
   444  		if (streq(token, "func")) {
   445  			if(lastline != -1)
   446  				bwritef(output, "\n");
   447  			break;
   448  		}
   449  		if (lastline != lineno) {
   450  			if (lastline == lineno-1)
   451  				bwritef(output, "\n");
   452  			else
   453  				bwritef(output, "\n#line %d \"%s\"\n", lineno, file);
   454  			lastline = lineno;
   455  		}
   456  		bwritef(output, "%s ", token);
   457  	}
   458  
   459  	*name = read_token_no_eof();
   460  
   461  	token = read_token();
   462  	if (token == nil || !streq(token, "(")) {
   463  		fatal("%s:%ud: expected \"(\"\n",
   464  			file, lineno);
   465  	}
   466  	*params = read_params(paramwid);
   467  
   468  	token = read_token();
   469  	if (token == nil || !streq(token, "("))
   470  		*rets = nil;
   471  	else {
   472  		*rets = read_params(nil);
   473  		token = read_token();
   474  	}
   475  	if (token == nil || !streq(token, "{")) {
   476  		fatal("%s:%ud: expected \"{\"\n",
   477  			file, lineno);
   478  	}
   479  	return 1;
   480  }
   481  
   482  /* Write out parameters.  */
   483  static void
   484  write_params(struct params *params, int *first)
   485  {
   486  	struct params *p;
   487  
   488  	for (p = params; p != nil; p = p->next) {
   489  		if (*first)
   490  			*first = 0;
   491  		else
   492  			bwritef(output, ", ");
   493  		bwritef(output, "%s %s", p->type, p->name);
   494  	}
   495  }
   496  
   497  /* Write a 6g function header.  */
   498  static void
   499  write_6g_func_header(char *package, char *name, struct params *params,
   500  		     int paramwid, struct params *rets)
   501  {
   502  	int first, n;
   503  
   504  	bwritef(output, "void\n%s·%s(", package, name);
   505  	first = 1;
   506  	write_params(params, &first);
   507  
   508  	/* insert padding to align output struct */
   509  	if(rets != nil && paramwid%structround != 0) {
   510  		n = structround - paramwid%structround;
   511  		if(n & 1)
   512  			bwritef(output, ", uint8");
   513  		if(n & 2)
   514  			bwritef(output, ", uint16");
   515  		if(n & 4)
   516  			bwritef(output, ", uint32");
   517  	}
   518  
   519  	write_params(rets, &first);
   520  	bwritef(output, ")\n{\n");
   521  }
   522  
   523  /* Write a 6g function trailer.  */
   524  static void
   525  write_6g_func_trailer(struct params *rets)
   526  {
   527  	struct params *p;
   528  
   529  	for (p = rets; p != nil; p = p->next)
   530  		bwritef(output, "\tFLUSH(&%s);\n", p->name);
   531  	bwritef(output, "}\n");
   532  }
   533  
   534  /* Define the gcc function return type if necessary.  */
   535  static void
   536  define_gcc_return_type(char *package, char *name, struct params *rets)
   537  {
   538  	struct params *p;
   539  
   540  	if (rets == nil || rets->next == nil)
   541  		return;
   542  	bwritef(output, "struct %s_%s_ret {\n", package, name);
   543  	for (p = rets; p != nil; p = p->next)
   544  		bwritef(output, "  %s %s;\n", p->type, p->name);
   545  	bwritef(output, "};\n");
   546  }
   547  
   548  /* Write out the gcc function return type.  */
   549  static void
   550  write_gcc_return_type(char *package, char *name, struct params *rets)
   551  {
   552  	if (rets == nil)
   553  		bwritef(output, "void");
   554  	else if (rets->next == nil)
   555  		bwritef(output, "%s", rets->type);
   556  	else
   557  		bwritef(output, "struct %s_%s_ret", package, name);
   558  }
   559  
   560  /* Write out a gcc function header.  */
   561  static void
   562  write_gcc_func_header(char *package, char *name, struct params *params,
   563  		      struct params *rets)
   564  {
   565  	int first;
   566  	struct params *p;
   567  
   568  	define_gcc_return_type(package, name, rets);
   569  	write_gcc_return_type(package, name, rets);
   570  	bwritef(output, " %s_%s(", package, name);
   571  	first = 1;
   572  	write_params(params, &first);
   573  	bwritef(output, ") asm (\"%s.%s\");\n", package, name);
   574  	write_gcc_return_type(package, name, rets);
   575  	bwritef(output, " %s_%s(", package, name);
   576  	first = 1;
   577  	write_params(params, &first);
   578  	bwritef(output, ")\n{\n");
   579  	for (p = rets; p != nil; p = p->next)
   580  		bwritef(output, "  %s %s;\n", p->type, p->name);
   581  }
   582  
   583  /* Write out a gcc function trailer.  */
   584  static void
   585  write_gcc_func_trailer(char *package, char *name, struct params *rets)
   586  {
   587  	if (rets == nil) {
   588  		// nothing to do
   589  	}
   590  	else if (rets->next == nil)
   591  		bwritef(output, "return %s;\n", rets->name);
   592  	else {
   593  		struct params *p;
   594  
   595  		bwritef(output, "  {\n    struct %s_%s_ret __ret;\n", package, name);
   596  		for (p = rets; p != nil; p = p->next)
   597  			bwritef(output, "    __ret.%s = %s;\n", p->name, p->name);
   598  		bwritef(output, "    return __ret;\n  }\n");
   599  	}
   600  	bwritef(output, "}\n");
   601  }
   602  
   603  /* Write out a function header.  */
   604  static void
   605  write_func_header(char *package, char *name,
   606  		  struct params *params, int paramwid,
   607  		  struct params *rets)
   608  {
   609  	if (gcc)
   610  		write_gcc_func_header(package, name, params, rets);
   611  	else
   612  		write_6g_func_header(package, name, params, paramwid, rets);
   613  	bwritef(output, "#line %d \"%s\"\n", lineno, file);
   614  }
   615  
   616  /* Write out a function trailer.  */
   617  static void
   618  write_func_trailer(char *package, char *name,
   619  		   struct params *rets)
   620  {
   621  	if (gcc)
   622  		write_gcc_func_trailer(package, name, rets);
   623  	else
   624  		write_6g_func_trailer(rets);
   625  }
   626  
   627  /*
   628   * Read and write the body of the function, ending in an unnested }
   629   * (which is read but not written).
   630   */
   631  static void
   632  copy_body(void)
   633  {
   634  	int nesting = 0;
   635  	while (1) {
   636  		int c;
   637  
   638  		c = getchar_no_eof();
   639  		if (c == '}' && nesting == 0)
   640  			return;
   641  		xputchar(c);
   642  		switch (c) {
   643  		default:
   644  			break;
   645  		case '{':
   646  			++nesting;
   647  			break;
   648  		case '}':
   649  			--nesting;
   650  			break;
   651  		case '/':
   652  			c = getchar_update_lineno();
   653  			xputchar(c);
   654  			if (c == '/') {
   655  				do {
   656  					c = getchar_no_eof();
   657  					xputchar(c);
   658  				} while (c != '\n');
   659  			} else if (c == '*') {
   660  				while (1) {
   661  					c = getchar_no_eof();
   662  					xputchar(c);
   663  					if (c == '*') {
   664  						do {
   665  							c = getchar_no_eof();
   666  							xputchar(c);
   667  						} while (c == '*');
   668  						if (c == '/')
   669  							break;
   670  					}
   671  				}
   672  			}
   673  			break;
   674  		case '"':
   675  		case '\'':
   676  			{
   677  				int delim = c;
   678  				do {
   679  					c = getchar_no_eof();
   680  					xputchar(c);
   681  					if (c == '\\') {
   682  						c = getchar_no_eof();
   683  						xputchar(c);
   684  						c = '\0';
   685  					}
   686  				} while (c != delim);
   687  			}
   688  			break;
   689  		}
   690  	}
   691  }
   692  
   693  /* Process the entire file.  */
   694  static void
   695  process_file(void)
   696  {
   697  	char *package, *name, *p, *n;
   698  	struct params *params, *rets;
   699  	int paramwid;
   700  
   701  	package = read_package();
   702  	read_preprocessor_lines();
   703  	while (read_func_header(&name, &params, &paramwid, &rets)) {
   704  		// name may have a package override already
   705  		n = xstrstr(name, "·");
   706  		if(n != nil) {
   707  			p = xmalloc(n - name + 1);
   708  			xmemmove(p, name, n - name);
   709  			p[n - name] = 0;
   710  			n += xstrlen("·");
   711  		} else {
   712  			p = package;
   713  			n = name;
   714  		}
   715  		write_func_header(p, n, params, paramwid, rets);
   716  		copy_body();
   717  		write_func_trailer(p, n, rets);
   718  		xfree(name);
   719  		if(p != package) xfree(p);
   720  		free_params(params);
   721  		free_params(rets);
   722  	}
   723  	xfree(package);
   724  }
   725  
   726  void
   727  goc2c(char *goc, char *c)
   728  {
   729  	Buf in, out;
   730  	
   731  	binit(&in);
   732  	binit(&out);
   733  	
   734  	file = goc;
   735  	readfile(&in, goc);
   736  
   737  	// TODO: set gcc=1 when using gcc
   738  
   739  	if(!gcc) {
   740  		if(streq(goarch, "amd64")) {
   741  			type_table[Uintptr].size = 8;
   742  			type_table[Eface].size = 8+8;
   743  			type_table[String].size = 16;
   744  			if(use64bitint) {
   745  				type_table[Int].size = 8;
   746  				type_table[Uint].size = 8;
   747  			}
   748  			type_table[Slice].size = 8+2*type_table[Int].size;
   749  			structround = 8;
   750  		} else {
   751  			// NOTE: These are set in the initializer,
   752  			// but they might have been changed by a
   753  			// previous invocation of goc2c, so we have
   754  			// to restore them.
   755  			type_table[Uintptr].size = 4;
   756  			type_table[String].size = 8;
   757  			type_table[Slice].size = 16;
   758  			type_table[Eface].size = 4+4;
   759  			type_table[Int].size = 4;
   760  			type_table[Uint].size = 4;
   761  			structround = 4;
   762  		}
   763  	}
   764  
   765  	bprintf(&out, "// auto generated by go tool dist\n// goos=%s goarch=%s\n\n", goos, goarch);
   766  	input = bstr(&in);
   767  	output = &out;
   768  
   769  	lineno = 1;
   770  	process_file();
   771  	
   772  	writefile(&out, c, 0);
   773  }