goc2c.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  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. // +build ignore
  5. /*
  6. * Translate a .goc file into a .c file. A .goc file is a combination
  7. * of a limited form of Go with C.
  8. */
  9. /*
  10. package PACKAGENAME
  11. {# line}
  12. func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
  13. C code with proper brace nesting
  14. \}
  15. */
  16. /*
  17. * We generate C code which implements the function such that it can
  18. * be called from Go and executes the C code.
  19. */
  20. #include <assert.h>
  21. #include <ctype.h>
  22. #include <stdarg.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <errno.h>
  27. /* Package path to use. */
  28. static const char *pkgpath;
  29. /* Package prefix to use. */
  30. static const char *prefix;
  31. /* File and line number */
  32. static const char *file;
  33. static unsigned int lineno = 1;
  34. /* List of names and types. */
  35. struct params {
  36. struct params *next;
  37. char *name;
  38. char *type;
  39. };
  40. char *argv0;
  41. static void
  42. sysfatal(char *fmt, ...)
  43. {
  44. char buf[256];
  45. va_list arg;
  46. va_start(arg, fmt);
  47. vsnprintf(buf, sizeof buf, fmt, arg);
  48. va_end(arg);
  49. fprintf(stderr, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
  50. exit(1);
  51. }
  52. /* Unexpected EOF. */
  53. static void
  54. bad_eof(void)
  55. {
  56. sysfatal("%s:%ud: unexpected EOF\n", file, lineno);
  57. }
  58. /* Out of memory. */
  59. static void
  60. bad_mem(void)
  61. {
  62. sysfatal("%s:%ud: out of memory\n", file, lineno);
  63. }
  64. /* Allocate memory without fail. */
  65. static void *
  66. xmalloc(unsigned int size)
  67. {
  68. void *ret = malloc(size);
  69. if (ret == NULL)
  70. bad_mem();
  71. return ret;
  72. }
  73. /* Reallocate memory without fail. */
  74. static void*
  75. xrealloc(void *buf, unsigned int size)
  76. {
  77. void *ret = realloc(buf, size);
  78. if (ret == NULL)
  79. bad_mem();
  80. return ret;
  81. }
  82. /* Copy a string into memory without fail. */
  83. static char *
  84. xstrdup(const char *p)
  85. {
  86. char *ret = xmalloc(strlen(p) + 1);
  87. strcpy(ret, p);
  88. return ret;
  89. }
  90. /* Free a list of parameters. */
  91. static void
  92. free_params(struct params *p)
  93. {
  94. while (p != NULL) {
  95. struct params *next;
  96. next = p->next;
  97. free(p->name);
  98. free(p->type);
  99. free(p);
  100. p = next;
  101. }
  102. }
  103. /* Read a character, tracking lineno. */
  104. static int
  105. getchar_update_lineno(void)
  106. {
  107. int c;
  108. c = getchar();
  109. if (c == '\n')
  110. ++lineno;
  111. return c;
  112. }
  113. /* Read a character, giving an error on EOF, tracking lineno. */
  114. static int
  115. getchar_no_eof(void)
  116. {
  117. int c;
  118. c = getchar_update_lineno();
  119. if (c == EOF)
  120. bad_eof();
  121. return c;
  122. }
  123. /* Read a character, skipping comments. */
  124. static int
  125. getchar_skipping_comments(void)
  126. {
  127. int c;
  128. while (1) {
  129. c = getchar_update_lineno();
  130. if (c != '/')
  131. return c;
  132. c = getchar();
  133. if (c == '/') {
  134. do {
  135. c = getchar_update_lineno();
  136. } while (c != EOF && c != '\n');
  137. return c;
  138. } else if (c == '*') {
  139. while (1) {
  140. c = getchar_update_lineno();
  141. if (c == EOF)
  142. return EOF;
  143. if (c == '*') {
  144. do {
  145. c = getchar_update_lineno();
  146. } while (c == '*');
  147. if (c == '/')
  148. break;
  149. }
  150. }
  151. } else {
  152. ungetc(c, stdin);
  153. return '/';
  154. }
  155. }
  156. }
  157. /*
  158. * Read and return a token. Tokens are string or character literals
  159. * or else delimited by whitespace or by [(),{}].
  160. * The latter are all returned as single characters.
  161. */
  162. static char *
  163. read_token(void)
  164. {
  165. int c, q;
  166. char *buf;
  167. unsigned int alc, off;
  168. const char* delims = "(),{}";
  169. while (1) {
  170. c = getchar_skipping_comments();
  171. if (c == EOF)
  172. return NULL;
  173. if (!isspace(c))
  174. break;
  175. }
  176. alc = 16;
  177. buf = xmalloc(alc + 1);
  178. off = 0;
  179. if(c == '"' || c == '\'') {
  180. q = c;
  181. buf[off] = c;
  182. ++off;
  183. while (1) {
  184. if (off+2 >= alc) { // room for c and maybe next char
  185. alc *= 2;
  186. buf = xrealloc(buf, alc + 1);
  187. }
  188. c = getchar_no_eof();
  189. buf[off] = c;
  190. ++off;
  191. if(c == q)
  192. break;
  193. if(c == '\\') {
  194. buf[off] = getchar_no_eof();
  195. ++off;
  196. }
  197. }
  198. } else if (strchr(delims, c) != NULL) {
  199. buf[off] = c;
  200. ++off;
  201. } else {
  202. while (1) {
  203. if (off >= alc) {
  204. alc *= 2;
  205. buf = xrealloc(buf, alc + 1);
  206. }
  207. buf[off] = c;
  208. ++off;
  209. c = getchar_skipping_comments();
  210. if (c == EOF)
  211. break;
  212. if (isspace(c) || strchr(delims, c) != NULL) {
  213. if (c == '\n')
  214. lineno--;
  215. ungetc(c, stdin);
  216. break;
  217. }
  218. }
  219. }
  220. buf[off] = '\0';
  221. return buf;
  222. }
  223. /* Read a token, giving an error on EOF. */
  224. static char *
  225. read_token_no_eof(void)
  226. {
  227. char *token = read_token();
  228. if (token == NULL)
  229. bad_eof();
  230. return token;
  231. }
  232. /* Read the package clause, and return the package name. */
  233. static char *
  234. read_package(void)
  235. {
  236. char *token;
  237. token = read_token_no_eof();
  238. if (token == NULL)
  239. sysfatal("%s:%ud: no token\n", file, lineno);
  240. if (strcmp(token, "package") != 0) {
  241. sysfatal("%s:%ud: expected \"package\", got \"%s\"\n",
  242. file, lineno, token);
  243. }
  244. return read_token_no_eof();
  245. }
  246. /* Read and copy preprocessor lines. */
  247. static void
  248. read_preprocessor_lines(void)
  249. {
  250. while (1) {
  251. int c;
  252. do {
  253. c = getchar_skipping_comments();
  254. } while (isspace(c));
  255. if (c != '#') {
  256. ungetc(c, stdin);
  257. break;
  258. }
  259. putchar(c);
  260. do {
  261. c = getchar_update_lineno();
  262. putchar(c);
  263. } while (c != '\n');
  264. }
  265. }
  266. /*
  267. * Read a type in Go syntax and return a type in C syntax. We only
  268. * permit basic types and pointers.
  269. */
  270. static char *
  271. read_type(void)
  272. {
  273. char *p, *op, *q;
  274. int pointer_count;
  275. unsigned int len;
  276. p = read_token_no_eof();
  277. if (*p != '*') {
  278. /* Convert the Go type "int" to the C type "intgo",
  279. and similarly for "uint". */
  280. if (strcmp(p, "int") == 0)
  281. return xstrdup("intgo");
  282. else if (strcmp(p, "uint") == 0)
  283. return xstrdup("uintgo");
  284. return p;
  285. }
  286. op = p;
  287. pointer_count = 0;
  288. while (*p == '*') {
  289. ++pointer_count;
  290. ++p;
  291. }
  292. /* Convert the Go type "int" to the C type "intgo", and
  293. similarly for "uint". */
  294. if (strcmp(p, "int") == 0)
  295. p = (char *) "intgo";
  296. else if (strcmp(p, "uint") == 0)
  297. p = (char *) "uintgo";
  298. len = strlen(p);
  299. q = xmalloc(len + pointer_count + 1);
  300. memcpy(q, p, len);
  301. while (pointer_count > 0) {
  302. q[len] = '*';
  303. ++len;
  304. --pointer_count;
  305. }
  306. q[len] = '\0';
  307. free(op);
  308. return q;
  309. }
  310. /*
  311. * Read a list of parameters. Each parameter is a name and a type.
  312. * The list ends with a ')'. We have already read the '('.
  313. */
  314. static struct params *
  315. read_params()
  316. {
  317. char *token;
  318. struct params *ret, **pp, *p;
  319. ret = NULL;
  320. pp = &ret;
  321. token = read_token_no_eof();
  322. if (strcmp(token, ")") != 0) {
  323. while (1) {
  324. p = xmalloc(sizeof(struct params));
  325. p->name = token;
  326. p->type = read_type();
  327. p->next = NULL;
  328. *pp = p;
  329. pp = &p->next;
  330. token = read_token_no_eof();
  331. if (strcmp(token, ",") != 0)
  332. break;
  333. token = read_token_no_eof();
  334. }
  335. }
  336. if (strcmp(token, ")") != 0) {
  337. sysfatal("%s:%ud: expected '('\n",
  338. file, lineno);
  339. }
  340. return ret;
  341. }
  342. /*
  343. * Read a function header. This reads up to and including the initial
  344. * '{' character. Returns 1 if it read a header, 0 at EOF.
  345. */
  346. static int
  347. read_func_header(char **name, struct params **params, struct params **rets)
  348. {
  349. int lastline;
  350. char *token;
  351. lastline = -1;
  352. while (1) {
  353. token = read_token();
  354. if (token == NULL)
  355. return 0;
  356. if (strcmp(token, "func") == 0) {
  357. if(lastline != -1)
  358. printf("\n");
  359. break;
  360. }
  361. if (lastline != lineno) {
  362. if (lastline == lineno-1)
  363. printf("\n");
  364. else
  365. printf("\n#line %d \"%s\"\n", lineno, file);
  366. lastline = lineno;
  367. }
  368. printf("%s ", token);
  369. }
  370. *name = read_token_no_eof();
  371. token = read_token();
  372. if (token == NULL || strcmp(token, "(") != 0) {
  373. sysfatal("%s:%ud: expected \"(\"\n",
  374. file, lineno);
  375. }
  376. *params = read_params();
  377. token = read_token();
  378. if (token == NULL || strcmp(token, "(") != 0)
  379. *rets = NULL;
  380. else {
  381. *rets = read_params();
  382. token = read_token();
  383. }
  384. if (token == NULL || strcmp(token, "{") != 0) {
  385. sysfatal("%s:%ud: expected \"{\"\n",
  386. file, lineno);
  387. }
  388. return 1;
  389. }
  390. /* Write out parameters. */
  391. static void
  392. write_params(struct params *params, int *first)
  393. {
  394. struct params *p;
  395. for (p = params; p != NULL; p = p->next) {
  396. if (*first)
  397. *first = 0;
  398. else
  399. printf(", ");
  400. printf("%s %s", p->type, p->name);
  401. }
  402. }
  403. /* Define the gcc function return type if necessary. */
  404. static void
  405. define_gcc_return_type(char *package, char *name, struct params *rets)
  406. {
  407. struct params *p;
  408. if (rets == NULL || rets->next == NULL)
  409. return;
  410. printf("struct %s_%s_ret {\n", package, name);
  411. for (p = rets; p != NULL; p = p->next)
  412. printf(" %s %s;\n", p->type, p->name);
  413. printf("};\n");
  414. }
  415. /* Write out the gcc function return type. */
  416. static void
  417. write_gcc_return_type(char *package, char *name, struct params *rets)
  418. {
  419. if (rets == NULL)
  420. printf("void");
  421. else if (rets->next == NULL)
  422. printf("%s", rets->type);
  423. else
  424. printf("struct %s_%s_ret", package, name);
  425. }
  426. /* Write out a gcc function header. */
  427. static void
  428. write_gcc_func_header(char *package, char *name, struct params *params,
  429. struct params *rets)
  430. {
  431. int first;
  432. struct params *p;
  433. define_gcc_return_type(package, name, rets);
  434. write_gcc_return_type(package, name, rets);
  435. printf(" %s_%s(", package, name);
  436. first = 1;
  437. write_params(params, &first);
  438. printf(") __asm__ (GOSYM_PREFIX \"");
  439. if (pkgpath != NULL)
  440. printf("%s", pkgpath);
  441. else if (prefix != NULL)
  442. printf("%s.%s", prefix, package);
  443. else
  444. printf("%s", package);
  445. printf(".%s\");\n", name);
  446. write_gcc_return_type(package, name, rets);
  447. printf(" %s_%s(", package, name);
  448. first = 1;
  449. write_params(params, &first);
  450. printf(")\n{\n");
  451. for (p = rets; p != NULL; p = p->next)
  452. printf(" %s %s;\n", p->type, p->name);
  453. }
  454. /* Write out a gcc function trailer. */
  455. static void
  456. write_gcc_func_trailer(char *package, char *name, struct params *rets)
  457. {
  458. if (rets == NULL)
  459. ;
  460. else if (rets->next == NULL)
  461. printf("return %s;\n", rets->name);
  462. else {
  463. struct params *p;
  464. printf(" {\n struct %s_%s_ret __ret;\n", package, name);
  465. for (p = rets; p != NULL; p = p->next)
  466. printf(" __ret.%s = %s;\n", p->name, p->name);
  467. printf(" return __ret;\n }\n");
  468. }
  469. printf("}\n");
  470. }
  471. /* Write out a function header. */
  472. static void
  473. write_func_header(char *package, char *name, struct params *params,
  474. struct params *rets)
  475. {
  476. write_gcc_func_header(package, name, params, rets);
  477. printf("#line %d \"%s\"\n", lineno, file);
  478. }
  479. /* Write out a function trailer. */
  480. static void
  481. write_func_trailer(char *package, char *name,
  482. struct params *rets)
  483. {
  484. write_gcc_func_trailer(package, name, rets);
  485. }
  486. /*
  487. * Read and write the body of the function, ending in an unnested }
  488. * (which is read but not written).
  489. */
  490. static void
  491. copy_body(void)
  492. {
  493. int nesting = 0;
  494. while (1) {
  495. int c;
  496. c = getchar_no_eof();
  497. if (c == '}' && nesting == 0)
  498. return;
  499. putchar(c);
  500. switch (c) {
  501. default:
  502. break;
  503. case '{':
  504. ++nesting;
  505. break;
  506. case '}':
  507. --nesting;
  508. break;
  509. case '/':
  510. c = getchar_update_lineno();
  511. putchar(c);
  512. if (c == '/') {
  513. do {
  514. c = getchar_no_eof();
  515. putchar(c);
  516. } while (c != '\n');
  517. } else if (c == '*') {
  518. while (1) {
  519. c = getchar_no_eof();
  520. putchar(c);
  521. if (c == '*') {
  522. do {
  523. c = getchar_no_eof();
  524. putchar(c);
  525. } while (c == '*');
  526. if (c == '/')
  527. break;
  528. }
  529. }
  530. }
  531. break;
  532. case '"':
  533. case '\'':
  534. {
  535. int delim = c;
  536. do {
  537. c = getchar_no_eof();
  538. putchar(c);
  539. if (c == '\\') {
  540. c = getchar_no_eof();
  541. putchar(c);
  542. c = '\0';
  543. }
  544. } while (c != delim);
  545. }
  546. break;
  547. }
  548. }
  549. }
  550. /* Process the entire file. */
  551. static void
  552. process_file(void)
  553. {
  554. char *package, *name;
  555. struct params *params, *rets;
  556. package = read_package();
  557. read_preprocessor_lines();
  558. while (read_func_header(&name, &params, &rets)) {
  559. char *p;
  560. char *pkg;
  561. char *nm;
  562. p = strchr(name, '.');
  563. if (p == NULL) {
  564. pkg = package;
  565. nm = name;
  566. } else {
  567. pkg = name;
  568. nm = p + 1;
  569. *p = '\0';
  570. }
  571. write_func_header(pkg, nm, params, rets);
  572. copy_body();
  573. write_func_trailer(pkg, nm, rets);
  574. free(name);
  575. free_params(params);
  576. free_params(rets);
  577. }
  578. free(package);
  579. }
  580. static void
  581. usage(void)
  582. {
  583. sysfatal("Usage: goc2c [--go-pkgpath PKGPATH] [--go-prefix PREFIX] [file]\n");
  584. }
  585. int
  586. main(int argc, char **argv)
  587. {
  588. char *goarch;
  589. argv0 = argv[0];
  590. while(argc > 1 && argv[1][0] == '-') {
  591. if(strcmp(argv[1], "-") == 0)
  592. break;
  593. if (strcmp(argv[1], "--go-pkgpath") == 0 && argc > 2) {
  594. pkgpath = argv[2];
  595. argc--;
  596. argv++;
  597. } else if (strcmp(argv[1], "--go-prefix") == 0 && argc > 2) {
  598. prefix = argv[2];
  599. argc--;
  600. argv++;
  601. } else
  602. usage();
  603. argc--;
  604. argv++;
  605. }
  606. if(argc <= 1 || strcmp(argv[1], "-") == 0) {
  607. file = "<stdin>";
  608. process_file();
  609. exit(0);
  610. }
  611. if(argc > 2)
  612. usage();
  613. file = argv[1];
  614. if(freopen(file, "r", stdin) == 0) {
  615. sysfatal("open %s: %r\n", file);
  616. }
  617. printf("// AUTO-GENERATED by autogen.sh; DO NOT EDIT\n\n");
  618. process_file();
  619. exit(0);
  620. }