1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB and Kjell Winblad 2019. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 /*
22  * Author: Kjell Winblad
23  */
24 
25 
26 #include "ycf_utils.h"
27 #include "ycf_yield_fun.h"
28 #include "ycf_node.h"
29 #include "lib/simple_c_gc/simple_c_gc.h"
30 
31 #include <stdlib.h>
32 #include <stdio.h>
33 
34 
file_to_str(const char * filename)35 char* file_to_str(const char* filename) {
36   char * buffer;
37   long length;
38   FILE * f = fopen (filename, "rb");
39 
40   if (f) {
41     fseek (f, 0, SEEK_END);
42     length = ftell (f);
43     fseek (f, 0, SEEK_SET);
44     buffer = ycf_malloc (length+1);
45     size_t nr_of_read_bytes =
46       fread (buffer, 1, length, f);
47     if (nr_of_read_bytes != length) {
48       printf("error: while reading file %s\n", filename);
49       exit (1);
50     }
51     fclose (f);
52     buffer[length] = 0;
53   } else {
54     printf("error: could not open file %s\n", filename);
55     exit(1);
56   }
57 
58   return buffer;
59 }
60 
str_to_file(const char * filepath,const char * data)61 void str_to_file(const char *filepath, const char *data)
62 {
63     FILE *fp = fopen(filepath, "w");
64     if (fp != NULL)
65     {
66         fputs(data, fp);
67         fclose(fp);
68     }
69 }
70 
parse_and_repeat_src_from_ast(const char * file_name)71 void parse_and_repeat_src_from_ast(const char* file_name){
72   char* content = file_to_str(file_name);
73   ycf_node* tree = ycf_node_from_string(content);
74     ycf_node_print(tree, NULL);
75 }
76 
parse_and_print_symbols(const char * file_name)77 void parse_and_print_symbols(const char* file_name){
78   char* content = file_to_str(file_name);
79     ycf_symbol_list_print(content);
80 }
81 
parse_and_print_ast(const char * file_name)82 void parse_and_print_ast(const char* file_name){
83   char* content = file_to_str(file_name);
84   ycf_node* tree = ycf_node_from_string(content);
85   print_abstract_syntax_tree(tree);
86 }
87 
print_help_text_and_exit(char * program_name,int error_code)88 void print_help_text_and_exit(char* program_name, int error_code) {
89   printf("Usage: %s [-h]\n"
90          "       %s [-use_gc [-print_gc_info]]\n"
91          "                              [-log_max_mem_usage log_file]\n"
92          "                              [(( -f | -frec | -fnoauto | -fextenal) function_name)...\n"
93          "                               [-output_file_name output_file]\n"
94          "                               [-header_file_name header_file]\n"
95          "                               [-debug]\n"
96          "                               [-only_yielding_funs]\n"
97          "                               [-static_aux_funs]\n"
98          "                               input_c_file]]\n"
99          "\n"
100          "Please see the README.md file for more details.\n",
101          program_name,
102          program_name);
103   exit(0);
104 }
105 
ycf_main(int argc,char * argv[])106 int ycf_main( int argc, char* argv[] )
107 {
108   int i = 1;
109   for(i = 1; i < argc; i++ ){
110     bool repeat = ycf_string_is_equal("-repeat", argv[i]);
111     bool print_symbols = ycf_string_is_equal("-print_symbols", argv[i]);
112     bool print_ast = ycf_string_is_equal("-print_ast", argv[i]);;
113     bool yield = ycf_string_is_equal("-yield", argv[i]);
114     if(repeat || print_symbols || print_ast || yield){
115       i++;
116       if(i >= argc){
117         printf("ERROR: Expected at least one more argument\n\n");
118         print_help_text_and_exit(argv[0], 1);
119       }
120     }
121     if (print_ast) {
122       parse_and_print_ast(argv[i]);
123     } else if (repeat) {
124       parse_and_repeat_src_from_ast(argv[i]);
125     } else if (print_symbols) {
126       parse_and_print_symbols(argv[i]);
127     } else /* Default is yield */ {
128       ycf_string_item_list funs_to_yield = ycf_string_item_list_empty();
129       ycf_string_item_list funs_to_yield_no_auto = ycf_string_item_list_empty();
130       ycf_string_item_list funs_to_yield_frec = ycf_string_item_list_empty();
131       ycf_string_item_list funs_to_yield_external = ycf_string_item_list_empty();
132       ycf_string_item_list all_yield_funs = ycf_string_item_list_empty();
133       char* header_file_name = NULL;
134       char* output_file_name = NULL;
135       bool debug = false;
136       bool only_yielding_funs = false;
137       bool static_aux_funs = false;
138       while(i < argc && (ycf_string_is_equal(argv[i], "-f") ||
139                          ycf_string_is_equal(argv[i], "-frec") ||
140                          ycf_string_is_equal(argv[i], "-fnoauto") ||
141                          ycf_string_is_equal(argv[i], "-fexternal") ||
142                          ycf_string_is_equal(argv[i], "-header_file_name") ||
143                          ycf_string_is_equal(argv[i], "-output_file_name") ||
144                          ycf_string_is_equal(argv[i], "-debug") ||
145                          ycf_string_is_equal(argv[i], "-only_yielding_funs") ||
146                          ycf_string_is_equal(argv[i], "-static_aux_funs"))){
147         bool frec = ycf_string_is_equal(argv[i], "-frec");
148         bool noauto = ycf_string_is_equal(argv[i], "-fnoauto");
149         bool external = ycf_string_is_equal(argv[i], "-fexternal");
150         bool header = ycf_string_is_equal(argv[i], "-header_file_name");
151         bool output = ycf_string_is_equal(argv[i], "-output_file_name");
152         i++;
153         if(ycf_string_is_equal(argv[i-1], "-debug")){
154           debug = true;
155           continue;
156         }
157         if(ycf_string_is_equal(argv[i-1], "-only_yielding_funs")){
158           only_yielding_funs = true;
159           continue;
160         }
161         if(ycf_string_is_equal(argv[i-1], "-static_aux_funs")){
162           static_aux_funs = true;
163           continue;
164         }
165         if(i >= argc){
166           fprintf(stderr, "ERROR: Expected a name after %s\n\n", argv[i-1]);
167           print_help_text_and_exit(argv[0], 1);
168         }
169         if(header){
170           if(header_file_name != NULL){
171             fprintf(stderr, "ERROR: Can only print a single header file\n\n");
172             print_help_text_and_exit(argv[0], 1);
173           }
174           header_file_name = (char*)argv[i];
175         } else if(output){
176           if(output_file_name != NULL){
177             fprintf(stderr, "ERROR: Can only  print a single output file\n\n");
178             print_help_text_and_exit(argv[0], 1);
179           }
180           output_file_name = (char*)argv[i];
181         } else if(external){
182           ycf_string_item_list_append(&funs_to_yield_external, ycf_string_item_new((char *) argv[i]));
183         } else if(frec){
184             ycf_string_item_list_append(&funs_to_yield_frec, ycf_string_item_new((char *) argv[i]));
185         } else if(noauto){
186             ycf_string_item_list_append(&funs_to_yield_no_auto, ycf_string_item_new((char *) argv[i]));
187         } else{
188             ycf_string_item_list_append(&funs_to_yield, ycf_string_item_new((char *) argv[i]));
189         }
190         i++;
191       }
192       ycf_string_item_list funs_to_yield_copy = ycf_string_item_list_shallow_copy(funs_to_yield);
193       ycf_string_item_list funs_to_yield_no_auto_copy = ycf_string_item_list_shallow_copy(funs_to_yield_no_auto);
194       ycf_string_item_list funs_to_yield_frec_copy = ycf_string_item_list_shallow_copy(funs_to_yield_frec);
195       ycf_string_item_list funs_to_yield_external_copy = ycf_string_item_list_shallow_copy(funs_to_yield_external);
196       ycf_string_item_list_concat(&all_yield_funs, &funs_to_yield_copy);
197       ycf_string_item_list_concat(&all_yield_funs, &funs_to_yield_no_auto_copy);
198       ycf_string_item_list_concat(&all_yield_funs, &funs_to_yield_frec_copy);
199       ycf_string_item_list_concat(&all_yield_funs, &funs_to_yield_external_copy);
200       if(funs_to_yield.head == NULL && funs_to_yield_no_auto.head == NULL && funs_to_yield_frec.head == NULL){
201         fprintf(stderr, "ERROR: Expected at least one \"(-f|-frec|-fnoauto) function_name\" argument\n\n");
202         print_help_text_and_exit(argv[0], 1);
203       }
204       if(i >= argc){
205         fprintf(stderr, "ERROR: Expected an input file name as the last parameter\n\n");
206         print_help_text_and_exit(argv[0], 1);
207       }
208       {
209         char* file_name = (char*)argv[i];
210         char* src = file_to_str(file_name);
211         ycf_string_item* current_fun = funs_to_yield.head;
212         ycf_node* header_file = ycf_node_from_string("");
213         ycf_node* tree = ycf_node_from_string(src);
214         ycf_node* only_yielding_funs_tree = NULL;
215         while(current_fun != NULL){
216           tree = ast_get_ast_with_yieldified_function(tree,
217                                                       header_file,
218                                                       current_fun->str,
219                                                       &all_yield_funs,
220                                                       true,
221                                                       false,
222                                                       debug,
223                                                       only_yielding_funs,
224                                                       &only_yielding_funs_tree,
225                                                       static_aux_funs);
226           current_fun = current_fun->next;
227         }
228         current_fun = funs_to_yield_no_auto.head;
229         while(current_fun != NULL){
230           tree = ast_get_ast_with_yieldified_function(tree,
231                                                       header_file,
232                                                       current_fun->str,
233                                                       &all_yield_funs,
234                                                       false,
235                                                       false,
236                                                       debug,
237                                                       only_yielding_funs,
238                                                       &only_yielding_funs_tree,
239                                                       static_aux_funs);
240           current_fun = current_fun->next;
241         }
242         current_fun = funs_to_yield_frec.head;
243         while(current_fun != NULL){
244           tree = ast_get_ast_with_yieldified_function(tree,
245                                                       header_file,
246                                                       current_fun->str,
247                                                       &all_yield_funs,
248                                                       true,
249                                                       true,
250                                                       debug,
251                                                       only_yielding_funs,
252                                                       &only_yielding_funs_tree,
253                                                       static_aux_funs);
254           current_fun = current_fun->next;
255         }
256         ast_add_yield_code_generated_define(tree, debug);
257         ast_add_yield_code_generated_define(header_file, debug);
258         if(only_yielding_funs){
259           ast_add_yield_code_generated_define(only_yielding_funs_tree, debug);
260         }
261         if(header_file_name != NULL){
262           ycf_string_printable_buffer* b = ycf_string_printable_buffer_new();
263             ycf_node_print(header_file, b);
264           str_to_file(header_file_name, b->buffer);
265         }
266         if(only_yielding_funs){
267           tree = only_yielding_funs_tree;
268         }
269         if(output_file_name != NULL){
270           ycf_string_printable_buffer* b = ycf_string_printable_buffer_new();
271           ycf_node_print(tree, b);
272           str_to_file(output_file_name, b->buffer);
273         } else {
274             ycf_node_print(tree, NULL);
275         }
276       }
277     }
278   }
279   return 0;
280 }
281 
is_help_option(char * string)282 bool is_help_option(char* string) {
283 return
284   ycf_string_is_equal("-h", string) ||
285   ycf_string_is_equal("--h", string) ||
286   ycf_string_is_equal("-help", string) ||
287   ycf_string_is_equal("--help", string);
288 }
289 
main(int argc,char * argv[])290 int main( int argc, char* argv[] )
291 {
292   bool log_max_mem_usage = false;
293   bool use_gc = false;
294   char * log_max_mem_usage_file = NULL;
295   int i = 1;
296   if (argc == 1) {
297     print_help_text_and_exit(argv[0], 0);
298   }
299   while(i < argc &&
300         (ycf_string_is_equal("-use_gc", argv[i]) ||
301          ycf_string_is_equal("-log_max_mem_usage", argv[i]) ||
302          ycf_string_is_equal("-print_gc_info", argv[i]) ||
303          is_help_option(argv[i]))) {
304     if (is_help_option(argv[i])) {
305       print_help_text_and_exit(argv[0], 0);
306     } else if (ycf_string_is_equal("-use_gc", argv[i])) {
307       use_gc = true;
308       i++;
309     } else if(ycf_string_is_equal("-print_gc_info", argv[i])) {
310       scgc_enable_print_gc_info();
311       i++;
312     } else if(ycf_string_is_equal(argv[i], "-log_max_mem_usage")) {
313       ycf_enable_memory_tracking();
314       log_max_mem_usage = true;
315       i++;
316       log_max_mem_usage_file = (char*)argv[i];
317       i++;
318     }
319   }
320   int nr_of_params_to_remove =  i - 1;
321   int ret;
322   if (!use_gc) {
323     ret = ycf_main(argc - nr_of_params_to_remove ,
324                        argv + nr_of_params_to_remove);
325   } else {
326     ycf_enable_gc();
327     ret = scgc_start_gced_code(ycf_main,
328                                    argc - nr_of_params_to_remove,
329                                    argv + nr_of_params_to_remove,
330                                    ycf_raw_malloc,
331                                    ycf_free);
332   }
333   if(log_max_mem_usage){
334     ycf_malloc_log(log_max_mem_usage_file, "all");
335   }
336   return ret;
337 }
338