PageRenderTime 90ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/mrbc/mrbc.c

https://bitbucket.org/monami_ya_mrb/monami-ya.mrb
C | 337 lines | 310 code | 27 blank | 0 comment | 80 complexity | 418793f995048b57037c5e07b042fb9c MD5 | raw file
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "mruby.h"
  5. #include "mruby/compile.h"
  6. #include "mruby/dump.h"
  7. #include "mruby/proc.h"
  8. #define RITEBIN_EXT ".mrb"
  9. #define C_EXT ".c"
  10. struct mrbc_args {
  11. int argc;
  12. char **argv;
  13. int idx;
  14. const char *prog;
  15. const char *outfile;
  16. const char *initname;
  17. mrb_bool check_syntax : 1;
  18. mrb_bool verbose : 1;
  19. unsigned int flags : 4;
  20. };
  21. static void
  22. usage(const char *name)
  23. {
  24. static const char *const usage_msg[] = {
  25. "switches:",
  26. "-c check syntax only",
  27. "-o<outfile> place the output into <outfile>",
  28. "-v print version number, then turn on verbose mode",
  29. "-g produce debugging information",
  30. "-B<symbol> binary <symbol> output in C language format",
  31. "-e generate little endian iseq data",
  32. "-E generate big endian iseq data",
  33. "--verbose run at verbose mode",
  34. "--version print the version",
  35. "--copyright print the copyright",
  36. NULL
  37. };
  38. const char *const *p = usage_msg;
  39. printf("Usage: %s [switches] programfile\n", name);
  40. while (*p)
  41. printf(" %s\n", *p++);
  42. }
  43. static char *
  44. get_outfilename(mrb_state *mrb, char *infile, const char *ext)
  45. {
  46. size_t infilelen;
  47. size_t extlen;
  48. char *outfile;
  49. char *p;
  50. infilelen = strlen(infile);
  51. extlen = strlen(ext);
  52. outfile = (char*)mrb_malloc(mrb, infilelen + extlen + 1);
  53. memcpy(outfile, infile, infilelen + 1);
  54. if (*ext) {
  55. if ((p = strrchr(outfile, '.')) == NULL)
  56. p = outfile + infilelen;
  57. memcpy(p, ext, extlen + 1);
  58. }
  59. return outfile;
  60. }
  61. static int
  62. parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args)
  63. {
  64. char *outfile = NULL;
  65. static const struct mrbc_args args_zero = { 0 };
  66. int i;
  67. *args = args_zero;
  68. args->argc = argc;
  69. args->argv = argv;
  70. args->prog = argv[0];
  71. for (i=1; i<argc; i++) {
  72. if (argv[i][0] == '-') {
  73. switch ((argv[i])[1]) {
  74. case 'o':
  75. if (args->outfile) {
  76. fprintf(stderr, "%s: an output file is already specified. (%s)\n",
  77. args->prog, outfile);
  78. return -1;
  79. }
  80. if (argv[i][2] == '\0' && argv[i+1]) {
  81. i++;
  82. args->outfile = get_outfilename(mrb, argv[i], "");
  83. }
  84. else {
  85. args->outfile = get_outfilename(mrb, argv[i] + 2, "");
  86. }
  87. break;
  88. case 'B':
  89. if (argv[i][2] == '\0' && argv[i+1]) {
  90. i++;
  91. args->initname = argv[i];
  92. }
  93. else {
  94. args->initname = argv[i]+2;
  95. }
  96. if (*args->initname == '\0') {
  97. fprintf(stderr, "%s: function name is not specified.\n", args->prog);
  98. return -1;
  99. }
  100. break;
  101. case 'c':
  102. args->check_syntax = TRUE;
  103. break;
  104. case 'v':
  105. if (!args->verbose) mrb_show_version(mrb);
  106. args->verbose = TRUE;
  107. break;
  108. case 'g':
  109. args->flags |= DUMP_DEBUG_INFO;
  110. break;
  111. case 'E':
  112. args->flags = DUMP_ENDIAN_BIG | (args->flags & DUMP_DEBUG_INFO);
  113. break;
  114. case 'e':
  115. args->flags = DUMP_ENDIAN_LIL | (args->flags & DUMP_DEBUG_INFO);
  116. break;
  117. case 'h':
  118. return -1;
  119. case '-':
  120. if (argv[i][1] == '\n') {
  121. return i;
  122. }
  123. if (strcmp(argv[i] + 2, "version") == 0) {
  124. mrb_show_version(mrb);
  125. exit(EXIT_SUCCESS);
  126. }
  127. else if (strcmp(argv[i] + 2, "verbose") == 0) {
  128. args->verbose = TRUE;
  129. break;
  130. }
  131. else if (strcmp(argv[i] + 2, "copyright") == 0) {
  132. mrb_show_copyright(mrb);
  133. exit(EXIT_SUCCESS);
  134. }
  135. return -1;
  136. default:
  137. return i;
  138. }
  139. }
  140. else {
  141. break;
  142. }
  143. }
  144. if (args->verbose && args->initname && (args->flags & DUMP_ENDIAN_MASK) == 0) {
  145. fprintf(stderr, "%s: generating %s endian C file. specify -e/-E for cross compiling.\n",
  146. args->prog, bigendian_p() ? "big" : "little");
  147. }
  148. return i;
  149. }
  150. static void
  151. cleanup(mrb_state *mrb, struct mrbc_args *args)
  152. {
  153. if (args->outfile)
  154. mrb_free(mrb, (void*)args->outfile);
  155. mrb_close(mrb);
  156. }
  157. static int
  158. partial_hook(struct mrb_parser_state *p)
  159. {
  160. mrbc_context *c = p->cxt;
  161. struct mrbc_args *args = (struct mrbc_args *)c->partial_data;
  162. const char *fn;
  163. if (p->f) fclose(p->f);
  164. if (args->idx >= args->argc) {
  165. p->f = NULL;
  166. return -1;
  167. }
  168. fn = args->argv[args->idx++];
  169. p->f = fopen(fn, "r");
  170. if (p->f == NULL) {
  171. fprintf(stderr, "%s: cannot open program file. (%s)\n", args->prog, fn);
  172. return -1;
  173. }
  174. mrb_parser_set_filename(p, fn);
  175. return 0;
  176. }
  177. static mrb_value
  178. load_file(mrb_state *mrb, struct mrbc_args *args)
  179. {
  180. mrbc_context *c;
  181. mrb_value result;
  182. char *input = args->argv[args->idx];
  183. FILE *infile;
  184. mrb_bool need_close = FALSE;
  185. c = mrbc_context_new(mrb);
  186. if (args->verbose)
  187. c->dump_result = TRUE;
  188. c->no_exec = TRUE;
  189. if (input[0] == '-' && input[1] == '\0') {
  190. infile = stdin;
  191. }
  192. else {
  193. need_close = TRUE;
  194. if ((infile = fopen(input, "r")) == NULL) {
  195. fprintf(stderr, "%s: cannot open program file. (%s)\n", args->prog, input);
  196. return mrb_nil_value();
  197. }
  198. }
  199. mrbc_filename(mrb, c, input);
  200. args->idx++;
  201. if (args->idx < args->argc) {
  202. need_close = FALSE;
  203. mrbc_partial_hook(mrb, c, partial_hook, (void*)args);
  204. }
  205. result = mrb_load_file_cxt(mrb, infile, c);
  206. if (need_close) fclose(infile);
  207. mrbc_context_free(mrb, c);
  208. if (mrb_undef_p(result)) {
  209. return mrb_nil_value();
  210. }
  211. return result;
  212. }
  213. static int
  214. dump_file(mrb_state *mrb, FILE *wfp, const char *outfile, struct RProc *proc, struct mrbc_args *args)
  215. {
  216. int n = MRB_DUMP_OK;
  217. mrb_irep *irep = proc->body.irep;
  218. if (args->initname) {
  219. n = mrb_dump_irep_cfunc(mrb, irep, args->flags, wfp, args->initname);
  220. if (n == MRB_DUMP_INVALID_ARGUMENT) {
  221. fprintf(stderr, "%s: invalid C language symbol name\n", args->initname);
  222. }
  223. }
  224. else {
  225. n = mrb_dump_irep_binary(mrb, irep, args->flags, wfp);
  226. }
  227. if (n != MRB_DUMP_OK) {
  228. fprintf(stderr, "%s: error in mrb dump (%s) %d\n", args->prog, outfile, n);
  229. }
  230. return n;
  231. }
  232. int
  233. main(int argc, char **argv)
  234. {
  235. mrb_state *mrb = mrb_open();
  236. int n, result;
  237. struct mrbc_args args;
  238. FILE *wfp;
  239. mrb_value load;
  240. if (mrb == NULL) {
  241. fputs("Invalid mrb_state, exiting mrbc\n", stderr);
  242. return EXIT_FAILURE;
  243. }
  244. n = parse_args(mrb, argc, argv, &args);
  245. if (n < 0) {
  246. cleanup(mrb, &args);
  247. usage(argv[0]);
  248. return EXIT_FAILURE;
  249. }
  250. if (n == argc) {
  251. fprintf(stderr, "%s: no program file given\n", args.prog);
  252. return EXIT_FAILURE;
  253. }
  254. if (args.outfile == NULL && !args.check_syntax) {
  255. if (n + 1 == argc) {
  256. args.outfile = get_outfilename(mrb, argv[n], args.initname ? C_EXT : RITEBIN_EXT);
  257. }
  258. else {
  259. fprintf(stderr, "%s: output file should be specified to compile multiple files\n", args.prog);
  260. return EXIT_FAILURE;
  261. }
  262. }
  263. args.idx = n;
  264. load = load_file(mrb, &args);
  265. if (mrb_nil_p(load)) {
  266. cleanup(mrb, &args);
  267. return EXIT_FAILURE;
  268. }
  269. if (args.check_syntax) {
  270. printf("%s:%s:Syntax OK\n", args.prog, argv[n]);
  271. }
  272. if (args.check_syntax) {
  273. cleanup(mrb, &args);
  274. return EXIT_SUCCESS;
  275. }
  276. if (args.outfile) {
  277. if (strcmp("-", args.outfile) == 0) {
  278. wfp = stdout;
  279. }
  280. else if ((wfp = fopen(args.outfile, "wb")) == NULL) {
  281. fprintf(stderr, "%s: cannot open output file:(%s)\n", args.prog, args.outfile);
  282. return EXIT_FAILURE;
  283. }
  284. }
  285. else {
  286. fprintf(stderr, "Output file is required\n");
  287. return EXIT_FAILURE;
  288. }
  289. result = dump_file(mrb, wfp, args.outfile, mrb_proc_ptr(load), &args);
  290. fclose(wfp);
  291. cleanup(mrb, &args);
  292. if (result != MRB_DUMP_OK) {
  293. return EXIT_FAILURE;
  294. }
  295. return EXIT_SUCCESS;
  296. }
  297. void
  298. mrb_init_mrblib(mrb_state *mrb)
  299. {
  300. }
  301. #ifndef DISABLE_GEMS
  302. void
  303. mrb_init_mrbgems(mrb_state *mrb)
  304. {
  305. }
  306. void
  307. mrb_final_mrbgems(mrb_state *mrb)
  308. {
  309. }
  310. #endif