source: EcnlProtoTool/trunk/prototool/src/mrbc.c

Last change on this file was 439, checked in by coas-nagasima, 4 years ago

mrubyを2.1.1に更新

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