Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 417 lines (339 sloc) 10.149 kb
97dc010 Mariano Guerra license to fnc files
marianoguerra authored
1 // New BSD License, part of efene, see LICENSE for details
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <getopt.h>
7 #include <string.h>
8 #include <assert.h>
188e2dd Mariano Guerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0]))...
marianoguerra authored
9 #include <libgen.h>
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
10 #include <sys/types.h>
11 #include <sys/stat.h>
12
13 #include "fnc.h"
14
1405441 Mariano Guerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
15 #define STR_BUFFER_SIZE 2048
16 #define PATHS_SIZE 512
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
17
18 // copy the path to efene from the environment variable FNPATH if available
19 // if not found return NULL
20 // you have to free the variable
21 char* get_efene_path_from_env() {
22 char *fnpath, *result;
23
24 result = NULL;
25 fnpath = getenv("FNPATH");
26
27 if (fnpath != NULL) {
188e2dd Mariano Guerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0]))...
marianoguerra authored
28 result = strdup(fnpath);
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
29 assert(result != NULL);
30 }
31
32 return result;
33 }
34
35 void show_usage() {
36 printf("usage:\n");
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
37 printf("\tfnc -s: run the interactive shell\n");
4c4e3cc Mariano Guerra some simplifications in fnc.c
marianoguerra authored
38 printf("\tfnc -h: shows this help\n");
77493d1 Mariano Guerra added the -r option to run commands (replaces fn) and -T option to debug...
marianoguerra authored
39 printf("\tfnc -r module function [argumens*]: runs function from module passing optional arguments\n");
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
40 printf("options:\n");
41 printf("\t-t: type, can be beam (the default), lex, tree, ast, mod, erl or erl2ast\n");
42 printf("\t-o: output path, the path where the compiled files will be written\n");
77493d1 Mariano Guerra added the -r option to run commands (replaces fn) and -T option to debug...
marianoguerra authored
43 printf("\t-T: test, instead of running the command print it to the screen\n");
6b5b8cb Mariano Guerra add help for -a and -p
marianoguerra authored
44 printf("\t-a: append a path to look for modules\n");
45 printf("\t-p: prepend a path to look for modules\n");
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
46 printf("examples:\n");
47 printf("\tfnc foo.ifn: compile foo.ifn, write the result in the current directory\n");
48 printf("\tfnc foo.ifn bar.fn baz.ifn: same as before but multiple files compiled\n");
49 printf("\tfnc foo.ifn -o /tmp: compile foo.ifn, write the result in /tmp\n");
50 printf("\tfnc -t beam -o /tmp foo.ifn: same as before but with the type set\n");
51 printf("\tfnc -t erl foo.ifn: translate foo.ifn to erlang\n");
77493d1 Mariano Guerra added the -r option to run commands (replaces fn) and -T option to debug...
marianoguerra authored
52 printf("\tfnc -r foo run: runs the run function in the foo module\n");
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
53 }
54
55 int is_dir(const char *path) {
56 struct stat st;
57 return (stat(path, &st) == 0 && S_ISDIR(st.st_mode));
58 }
59
77493d1 Mariano Guerra added the -r option to run commands (replaces fn) and -T option to debug...
marianoguerra authored
60 int fn_run(const char *args, char *argv0, int is_test) {
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
61 int count, status;
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
62 char *fnpath, buffer[STR_BUFFER_SIZE], *basepath;
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
63 fnpath = get_efene_path_from_env();
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
64 basepath = dirname(dirname(argv0));
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
65
66 if (fnpath == NULL) {
67 if (!is_dir("../ebin")) {
68
188e2dd Mariano Guerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0]))...
marianoguerra authored
69 count = snprintf(buffer, STR_BUFFER_SIZE, "%s/ebin", basepath);
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
70 assert(count <= STR_BUFFER_SIZE);
188e2dd Mariano Guerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0]))...
marianoguerra authored
71
72 fnpath = strdup(buffer);
73 assert(fnpath != NULL);
74
75 if (!is_dir(fnpath)) {
76 fprintf(stderr, "$FNPATH is not defined, %s and ../ebin don't exist, options:\n", fnpath);
77 fprintf(stderr, " * set $FNPATH to the path where efene is installed\n");
78 fprintf(stderr, " * run fnc -s from the bin directory\n");
79 fprintf(stderr, " * stop doing maginc tricks with your path\n");
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
80 status = EXIT_FAILURE;
188e2dd Mariano Guerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0]))...
marianoguerra authored
81 }
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
82 else {
83 count = snprintf(buffer, STR_BUFFER_SIZE,
4c4e3cc Mariano Guerra some simplifications in fnc.c
marianoguerra authored
84 "erl -run %s -run init stop -noshell -pa \"%s\"",
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
85 args, fnpath);
188e2dd Mariano Guerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0]))...
marianoguerra authored
86
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
87 assert(count <= STR_BUFFER_SIZE);
77493d1 Mariano Guerra added the -r option to run commands (replaces fn) and -T option to debug...
marianoguerra authored
88
89 if (is_test) {
90 printf("%s\n", buffer);
91 }
92 else {
93 status = system(buffer);
94 }
188e2dd Mariano Guerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0]))...
marianoguerra authored
95 }
96 }
97 else {
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
98 count = snprintf(buffer, STR_BUFFER_SIZE,
4c4e3cc Mariano Guerra some simplifications in fnc.c
marianoguerra authored
99 "erl -run %s -run init stop -noshell -pa \"../ebin\"",
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
100 args);
101
102 assert(count <= STR_BUFFER_SIZE);
77493d1 Mariano Guerra added the -r option to run commands (replaces fn) and -T option to debug...
marianoguerra authored
103
104 if (is_test) {
105 printf("%s\n", buffer);
106 }
107 else {
108 status = system(buffer);
109 }
188e2dd Mariano Guerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0]))...
marianoguerra authored
110 }
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
111 }
112 else {
188e2dd Mariano Guerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0]))...
marianoguerra authored
113 count = snprintf(buffer, STR_BUFFER_SIZE,
4c4e3cc Mariano Guerra some simplifications in fnc.c
marianoguerra authored
114 "erl -run %s -run init stop -noshell -pa \"%s/ebin\"",
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
115 args, fnpath);
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
116
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
117 assert(count <= STR_BUFFER_SIZE);
77493d1 Mariano Guerra added the -r option to run commands (replaces fn) and -T option to debug...
marianoguerra authored
118
119 if (is_test) {
120 printf("%s\n", buffer);
121 }
122 else {
123 status = system(buffer);
124 }
125
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
126 free(fnpath);
127 }
128
129 exit(status);
130 }
131
132 struct FnOptions* fn_options_new() {
133 struct FnOptions* options = (struct FnOptions*) malloc(sizeof(struct FnOptions));
134
77493d1 Mariano Guerra added the -r option to run commands (replaces fn) and -T option to debug...
marianoguerra authored
135 assert(options != NULL);
136 options->output_path = NULL;
137 options->files = NULL;
138 options->files_num = 0;
139 options->output_type = NULL;
140 options->mode = '?';
141 options->is_test = 0;
1405441 Mariano Guerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
142 options->appends = (char*) malloc(sizeof(char) * PATHS_SIZE);
143 options->prepends = (char*) malloc(sizeof(char) * PATHS_SIZE);
144 options->appends[0] = '\0';
145 options->prepends[0] = '\0';
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
146
147 return options;
148 }
149
150 void fn_options_free_files(struct FnOptions* options) {
151 int index;
152
153 if (options != NULL && options->files != NULL && options->files_num > 0) {
154 for (index = 0; index < options->files_num; index++) {
155 free(options->files[index]);
156 }
157
158 free(options->files);
159 }
160 }
161
162 void fn_options_delete(struct FnOptions* options) {
163 if (options != NULL) {
164
165 if (options->output_path != NULL) {
166 free(options->output_path);
167 }
168
169 fn_options_free_files(options);
170
171 if (options->output_type != NULL) {
172 free(options->output_type);
173 }
174
1405441 Mariano Guerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
175 free(options->appends);
176 free(options->prepends);
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
177 free(options);
178 }
179 }
180
181 void fn_options_print(struct FnOptions* options) {
182 int index;
183
184 if (options != NULL) {
185 printf("options:\n");
186
187 if (options->output_path != NULL) {
188 printf("\toutput: %s\n", options->output_path);
189 }
190
191 if (options->files != NULL && options->files_num > 0) {
192 for (index = 0; index < options->files_num; index++) {
193 printf("\tfile: %s\n", options->files[index]);
194 }
195 }
196
197 if (options->output_type != NULL) {
198 printf("\toutput type: %s\n", options->output_type);
199 }
200 }
201 else {
202 printf("options: NULL\n");
203 }
204 }
205
206 int fn_options_copy_output_type(struct FnOptions* options, const char* arg) {
207 if (arg == NULL || options == NULL) {
208 return 0;
209 }
210
211 if (options->output_type != NULL) {
212 free(options->output_type);
213 }
214
188e2dd Mariano Guerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0]))...
marianoguerra authored
215 options->output_type = strdup(optarg);
216 assert(options->output_type != NULL);
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
217
218 return 1;
219 }
220
221 int fn_options_copy_output_path(struct FnOptions* options, const char* arg) {
222 if (arg == NULL || options == NULL) {
223 return 0;
224 }
225
226 if (options->output_path != NULL) {
227 free(options->output_path);
228 }
229
188e2dd Mariano Guerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0]))...
marianoguerra authored
230 options->output_path = strdup(optarg);
231 assert(options->output_path != NULL);
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
232
233 return 1;
234 }
235
236 void fn_options_copy_extra_args(struct FnOptions* options, int optind, int argc, char **argv) {
237 int index;
238
239 if (options == NULL) {
240 return;
241 }
242
243 if (optind == argc) {
244 return;
245 }
246
247 fn_options_free_files(options);
248
249 options->files_num = argc - optind;
250 options->files = (char**) malloc(sizeof(char*) * options->files_num);
251
252 for (index = optind; index < argc; index++) {
188e2dd Mariano Guerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0]))...
marianoguerra authored
253 options->files[index - optind] = strdup(argv[index]);
254 assert(options->files[index - optind] != NULL);
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
255 }
256 }
257
1405441 Mariano Guerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
258 void set_mode(struct FnOptions *options, char new_mode) {
259 if (options->mode != '?') {
260 fprintf(stderr, "warning! overriding %c flag with %c flag\n", options->mode, new_mode);
261 }
262
263 options->mode = new_mode;
264 }
265
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
266 struct FnOptions* parse_options (int argc, char **argv) {
267 int c;
268 struct FnOptions* options = fn_options_new();
269
1405441 Mariano Guerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
270 while ((c = getopt (argc, argv, "o:ht:sTra:p:")) != -1) {
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
271 switch (c) {
1405441 Mariano Guerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
272 case 'a':
273 if (options->appends[0] == '\0') {
274 strcat(options->appends, " -pa");
275 }
276
277 strcat(options->appends, " ");
278 strncat(options->appends, optarg, PATHS_SIZE);
279 break;
280 case 'p':
281 if (options->prepends[0] == '\0') {
282 strcat(options->prepends, " -pz");
283 }
284
285 strcat(options->prepends, " ");
286 strncat(options->prepends, optarg, PATHS_SIZE);
287 break;
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
288 case 'o':
289 if (fn_options_copy_output_path(options, optarg) == 0) {
290 fprintf(stderr, "error copying output path\n");
291 }
292
293 break;
294 case 'h':
295 show_usage();
296 exit(EXIT_SUCCESS);
77493d1 Mariano Guerra added the -r option to run commands (replaces fn) and -T option to debug...
marianoguerra authored
297 case 'T':
298 options->is_test = 1;
299 break;
300 case 'r':
1405441 Mariano Guerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
301 set_mode(options, 'r');
77493d1 Mariano Guerra added the -r option to run commands (replaces fn) and -T option to debug...
marianoguerra authored
302 break;
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
303 case 't':
304 if (fn_options_copy_output_type(options, optarg) == 0) {
305 fprintf(stderr, "error copying output type\n");
306 }
307
308 break;
309 case 's':
1405441 Mariano Guerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
310 set_mode(options, 's');
311 break;
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
312 case '?':
313 if (optopt == 'o') {
314 fprintf(stderr, "output path option requires an argument\n");
315 }
316 else if (optopt == 't') {
317 fprintf(stderr, "output type option requires an argument\n");
318 }
319 else if (isprint(optopt)) {
320 fprintf(stderr, "Unknown option `-%c'.\n", optopt);
321 }
322 else {
323 fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
324 }
325
326 exit(EXIT_FAILURE);
327 }
328 }
329
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
330 if (options->output_type == NULL) {
331 options->output_type = strdup("beam");
332 }
333
334 if (options->output_path == NULL) {
335 options->output_path = strdup(".");
336 }
337
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
338 fn_options_copy_extra_args(options, optind, argc, argv);
339
340 return options;
341 }
342
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
343 char* str_join(int count, char **strs) {
344 int i, size = 0, len, offset = 0;
345 char *result;
346 assert(count > 0);
347 assert(strs != NULL);
348
349 for (i = 0; i < count; i++) {
350 // the + 1 is for the spaces in all and for \0 in the last one
351 size += strlen(strs[i]) + 1;
352 }
353
354 result = (char*) malloc(sizeof(char) * size);
355 assert(result != NULL);
356
357 for (i = 0; i < count; i++) {
358 len = strlen(strs[i]);
359 strncpy(result + offset, strs[i], len);
360 offset += len;
361 result[offset] = ' ';
362 offset++;
363 }
364
9cef3fd Mariano Guerra off by one error and access after free memory, thanks valgrind
marianoguerra authored
365 result[offset - 1] = '\0';
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
366 return result;
367 }
368
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
369 int main (int argc, char **argv) {
9cef3fd Mariano Guerra off by one error and access after free memory, thanks valgrind
marianoguerra authored
370 int count, is_test;
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
371 char buffer[STR_BUFFER_SIZE], *extra_args;
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
372 struct FnOptions* options = parse_options(argc, argv);
373
1405441 Mariano Guerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
374 if (options->mode == 's') {
375 count = snprintf(buffer, STR_BUFFER_SIZE, "fn run shell%s%s",
376 options->appends, options->prepends);
4c4e3cc Mariano Guerra some simplifications in fnc.c
marianoguerra authored
377 }
1405441 Mariano Guerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
378 else {
379 if (options->files_num == 0) {
380 fn_options_delete(options);
381 fprintf(stderr, "at least one extra argument required\n");
382 return EXIT_FAILURE;
383 }
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
384
1405441 Mariano Guerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
385 extra_args = str_join(options->files_num, options->files);
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
386
1405441 Mariano Guerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
387 if (options->mode == 'r') {
388 if (options->files_num < 2) {
389 fprintf(stderr, "at least two arguments required, got %d\n",
390 options->files_num);
391 fprintf(stderr, " -r module function [arguments*]\n");
392 fprintf(stderr, " -r module function [arguments*]\n");
393 return EXIT_FAILURE;
394 }
395
396 count = snprintf(buffer, STR_BUFFER_SIZE, "%s%s%s", extra_args,
397 options->appends, options->prepends);
398 }
399 else if (strcmp(options->output_type, "beam") == 0) {
400 count = snprintf(buffer, STR_BUFFER_SIZE, "fn run %s \"%s\" %s",
401 options->output_type, options->output_path, extra_args);
402 }
403 else {
404 count = snprintf(buffer, STR_BUFFER_SIZE, "fn run %s %s",
405 options->output_type, extra_args);
77493d1 Mariano Guerra added the -r option to run commands (replaces fn) and -T option to debug...
marianoguerra authored
406 }
407
1405441 Mariano Guerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
408 free(extra_args);
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
409 }
410
411 assert(count <= STR_BUFFER_SIZE);
9cef3fd Mariano Guerra off by one error and access after free memory, thanks valgrind
marianoguerra authored
412 is_test = options->is_test;
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
413 fn_options_delete(options);
cc5d656 Mariano Guerra first working implementation of efene compiler frontend in C
marianoguerra authored
414
9cef3fd Mariano Guerra off by one error and access after free memory, thanks valgrind
marianoguerra authored
415 return fn_run(buffer, argv[0], is_test);
2fd6e38 Mariano Guerra initial import of the new compiler frontend
marianoguerra authored
416 }
Something went wrong with that request. Please try again.