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

Last change on this file since 279 was 279, checked in by coas-nagasima, 7 years ago

ファイルを追加、更新。

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