1 #include <string.h>
2 #include <stdlib.h>
3 
4 #include "main.h"
5 #include "nmtbl.h"
6 #include "token.h"
7 #include "trnod.h"
8 #include "util.h"
9 
10 extern int zzparse();
11 
load_predefined()12 static void load_predefined()
13 {
14     b_ring::add_cur(nm_entry::add("integer", TKN_IDENT),
15 				  symbol::s_type,
16 				  &integer_type);
17     b_ring::add_cur(nm_entry::add("real", TKN_IDENT),
18 				  symbol::s_type,
19 				  &real_type);
20     b_ring::add_cur(nm_entry::add("boolean", TKN_IDENT),
21 				  symbol::s_type,
22 				  &bool_type);
23     b_ring::add_cur(nm_entry::add("char", TKN_IDENT),
24 				  symbol::s_type,
25 				  &char_type);
26     b_ring::add_cur(nm_entry::add("text", TKN_IDENT),
27 				  symbol::s_type,
28 				  &text_type);
29     b_ring::add_cur(nm_entry::add("zero_terminated_string", TKN_IDENT),
30 		    nm_entry::add("char*", TKN_IDENT),
31 				  symbol::s_type,
32 				  &string_type);
33     b_ring::add_cur(nm_entry::add("true", TKN_IDENT),
34 				  symbol::s_const,
35 				  &bool_type);
36     b_ring::add_cur(nm_entry::add("false", TKN_IDENT),
37 				  symbol::s_const,
38 				  &bool_type);
39     b_ring::add_cur(nm_entry::add("nil", TKN_IDENT),
40 				  symbol::s_const,
41 				  &void_type);
42     if (hp_pascal) {
43         nm_entry::add("addr", TKN_ADDR);
44     }
45     if (turbo_pascal) {
46 	b_ring::add_cur(nm_entry::add("pointer", TKN_IDENT),
47 			symbol::s_type,
48 			&pointer_type);
49 	b_ring::add_cur(nm_entry::add("pchar", TKN_IDENT),
50 			symbol::s_type,
51 			&string_type);
52 	b_ring::add_cur(nm_entry::add("longint", TKN_IDENT),
53 			symbol::s_type,
54 			&longint_type);
55 	b_ring::add_cur(nm_entry::add("double", TKN_IDENT),
56 			symbol::s_type,
57 			&double_type);
58 	b_ring::add_cur(nm_entry::add("untyped_file", TKN_IDENT),
59 			symbol::s_type,
60 			&text_type);
61 	nested_comments = TRUE;
62     }
63 }
64 
load_keywords()65 static void load_keywords()
66 {
67     for (int tag = 0; tag < TKN_LAST; tag ++ )  {
68 	if (token::token_cat[tag] == CAT_ID ||
69 	    token::token_cat[tag] == CAT_KWD)
70 	{
71 	    nm_entry::add(token::token_name[tag], tag);
72 	}
73     }
74 }
75 
76 #define MAX_NAME_LEN 1024
77 
load_configuration(char * name)78 static void load_configuration(char* name) {
79     FILE* cfg = fopen(name, "r");
80     if (cfg != NULL) {
81 	char buf[MAX_NAME_LEN];
82 
83 	while (fscanf(cfg, "%s", buf) == 1) {
84 	    if (strcmp(buf, "#begin(reserved)") == 0) {
85 		while (fscanf(cfg, "%s", buf) == 1
86 		       && strcmp(buf, "#end(reserved)") != 0)
87 		{
88 		    nm_entry::add(buf, TKN_RESERVED);
89                 }
90 	    } else if(strcmp(buf, "#begin(macro)") == 0) {
91 		while (fscanf(cfg, "%s", buf) == 1
92 		       && strcmp(buf, "#end(macro)") != 0)
93 		{
94 		    nm_entry::add(buf, TKN_IDENT)->flags |= nm_entry::macro;
95 		}
96 	    } else if(strcmp(buf, "#begin(library)") == 0) {
97 		while (fscanf(cfg, "%s", buf) == 1
98 		       && strcmp(buf, "#end(library)") != 0)
99 		{
100 		    b_ring::global_b_ring.add(nm_entry::add(buf, TKN_IDENT),
101 					      symbol::s_dummy,
102 					      NULL);
103 		}
104 	    } else if(strcmp(buf, "#begin(rename)") == 0) {
105 		while (fscanf(cfg, "%s", buf) == 1
106 		       && strcmp(buf, "#end(rename)") != 0)
107 		{
108 		    nm_entry* nm_old = nm_entry::add(buf, TKN_IDENT);
109 		    fscanf(cfg, "%s", buf);
110 		    nm_entry* nm_new = nm_entry::add(buf, TKN_IDENT);
111 		    rename_item::add(nm_new, nm_old);
112 		}
113 	    }
114 	}
115 	fclose(cfg);
116 	if (turbo_pascal) { // sizeof is builtin Pascal function
117 	    nm_entry* nm_sizeof = nm_entry::find("sizeof");
118 	    if (nm_sizeof) {
119 		*nm_sizeof->text = 'S';
120 	    }
121 	}
122     } else {
123 	fprintf(stderr, "Can't open configuration file '%s'\n",
124 		name);
125     }
126 }
127 
128 
129 char *i_path;
130 char *input_file;
131 char *output_file;
132 char *output_suf;
133 char *prog_path;
134 bool  output_not_existed_hdr;
135 bool  no_array_assign_operator;
136 bool  language_c;
137 bool  compile_system_library;
138 bool  pio_init;
139 bool  use_call_graph;
140 bool  short_set;
141 bool  unsigned_comparison;
142 bool  small_enum;
143 bool  nological;
144 bool  turbo_pascal;
145 bool  use_c_strings;
146 bool  extern_vars;
147 bool  preserve_case;
148 bool  nested_comments;
149 bool  copy_array;
150 bool  comment_tags;
151 bool  use_namespaces;
152 bool  smart_union;
153 bool  no_index_decrement;
154 bool  ignore_preprocessor_directives;
155 bool  hp_pascal;
156 bool  do_not_use_enums;
157 char* pascall;
158 char path_sep;
159 
160 FILE *call_graph_file;
161 
scan_opt(int argc,char ** argv)162 static void scan_opt (int argc, char **argv) {
163     int i;
164     unsigned j;
165     bool found;
166 
167     static struct opt_str {
168 	bool *flag;
169 	char **value;
170 	char *str;
171         char *defval;
172 	char *comment;
173     } opt[] = {
174 
175 //      Add command options to this table:
176 
177 	{ NULL, &i_path, "-I", ".",
178 #ifdef _WIN32
179 	  "Include path (semicolon separated directory list)" },
180 #else
181 	  "Include path (colon separated directory list)" },
182 #endif
183 	{ NULL, &input_file, "-in", NULL,
184 	  "Input pascal file" },
185 	{ NULL, &output_file, "-out", NULL,
186 	  "Output C/C++ file" },
187 	{ NULL, &output_suf, "-suf", ".cxx",
188 	  "Output C/C++ file suffix" },
189 	{ &language_c, NULL, "-c", NULL,
190 	  "Translate into ANSI C" },
191 	{ &no_array_assign_operator, NULL, "-assign", NULL,
192 	  "Do not use assignment operators for array" },
193 	{ &use_call_graph, NULL, "-analyze", NULL,
194 	  "Analyze call graph to find non-recursive functions" },
195 	{ &short_set, NULL, "-intset", NULL,
196 	  "Use integer types for short sets of enumerations" },
197 	{ &pio_init, NULL, "-init", NULL,
198 	  "Call pio_initialize() function from main()" },
199 	{ &small_enum, NULL, "-smallenum", NULL,
200 	  "Use for enumerated types as small bytes as possible" },
201 	{ &unsigned_comparison, NULL, "-unsigned", NULL,
202 	  "Generate correct code for sign/unsigned comparisons" },
203 	{ &output_not_existed_hdr, NULL, "-h", NULL,
204 	  "Output only not existed header files" },
205 	{ &turbo_pascal, NULL, "-turbo", NULL,
206 	  "Convert Turbo Pascal" },
207 	{ &hp_pascal, NULL, "-hp", NULL,
208 	  "Convert HP64000 Pascal" },
209 	{ &use_c_strings, NULL, "-cstring", NULL,
210 	  "Use char* type for string fields in records and arrays" },
211 	{ &nological, NULL, "-nological", NULL,
212 	  "Use | and & instead of || and && for boolean operations" },
213 	{ &extern_vars, NULL, "-extern", NULL,
214 	  "Declare all variables from included files as \"EXTERN\"" },
215 	{ &preserve_case, NULL, "-preserve", NULL,
216 	  "Preserve case of identifiers" },
217 	{ &nested_comments, NULL, "-nested", NULL,
218 	  "Nested comments: (* {} *)" },
219 	{ &copy_array, NULL, "-copy", NULL,
220 	  "Always make a copy of array passed by value" },
221 	{ &comment_tags, NULL, "-comment_tags", NULL,
222 	  "Place in comments tags of Pascal variant records" },
223 	{ &smart_union, NULL, "-smartunion", NULL,
224 	  "Convert variant records with empty fixed part to unions" },
225 	{ &use_namespaces, NULL, "-namespace", NULL,
226 	  "Place Turbo Pascal units in separate namespaces" },
227 	{ &no_index_decrement, NULL, "-0based", NULL,
228 	  "Assume all arrays are zero based" },
229 	{ &ignore_preprocessor_directives, NULL, "-ignore_directives", NULL,
230 	  "Ignore all lines started with '$' character" },
231 	{ &do_not_use_enums, NULL, "-no_enums", NULL,
232 	  "Do not use enums for integer constants" },
233 	{ NULL, &pascall, "-pascall", "",
234 	  "Specify modifier (pascal,WINAPI...) for converted functions" }
235 
236     };
237     for (j = 0; j < (sizeof(opt)/sizeof(opt_str)); j++) {
238 	if (opt[j].value != NULL) {
239  	    *opt[j].value = opt[j].defval;
240         }
241 	if (opt[j].flag != NULL) {
242 	    *(opt[j].flag) = FALSE; // Switch off flags
243         }
244     }
245     for (i = 1; i < argc; i++) { // Skipping program name
246 	if (argv[i][0] != '-') {
247 	    if (input_file != NULL) {
248 		fprintf(stderr, "Only one input file name is accepted\n");
249 		goto Help;
250 	    }
251 	    input_file = argv[i];
252 	    continue;
253 	}
254 	found = FALSE;
255 	for (j = 0; j < (sizeof(opt)/sizeof(opt_str)); j++) {
256 	    if (strcmp (opt[j].str, argv[i]) == 0) {
257 		if (opt[j].flag != NULL) {
258 	            *(opt[j].flag) = TRUE;
259                 }
260 		if (opt[j].value != NULL) {
261 		    i++;
262 		    if (i >= argc) {
263 			fprintf(stderr, "Value for option '%s' is not specified\n", opt[j].str);
264 			goto Help;
265 		    }
266 		    *opt[j].value = argv[i];
267 		}
268 		found = TRUE;
269 		break;
270 	    }
271 	}
272 	if (!found) {
273  	  Help:
274 	    fprintf (stderr, "Pascal to C/C++ converter. Version "VERSION"\n"
275 			     "Available options are:\n");
276 
277 	    for (j = 0; j < (sizeof(opt)/sizeof(opt_str)); j++ ) {
278 		if (opt[j].defval != NULL) {
279 		    char buf[256];
280 		    sprintf(buf, "%s [%s]", opt[j].str, opt[j].defval);
281 		    fprintf(stderr, "\t%-12s", buf);
282  		} else {
283 		    fprintf(stderr, "\t%-12s", opt[j].str);
284 		}
285 	   	fprintf(stderr, "%s\n", opt[j].comment);
286 	    }
287 	    exit (1);
288 	}
289 	pio_init = TRUE;
290     }
291     if (input_file == NULL) {
292 	goto Help;
293     }
294 #ifdef _WIN32
295     char* p = strrchr(argv[0], '\\');
296     prog_path = (p != NULL) ? dprintf("%.*s", p + 1 - argv[0], argv[0]) : (char*)"";
297     path_sep = ';';
298 #else
299 #ifdef __EMX__
300     char* p = strrchr(_fnslashify(argv[0]), '/');
301     prog_path = (p != NULL) ? dprintf("%.*s", p + 1 - argv[0], argv[0]) : (char*)"";
302 #else
303     char* p = strrchr(argv[0], '/');
304     prog_path = (p != NULL) ? dprintf("%.*s", p + 1 - argv[0], argv[0]) : (char*)"";
305 #endif
306     path_sep = ':';
307 #endif
308     i_path = dprintf("%s%c%s", i_path, path_sep, prog_path);
309 }
310 
main(int argc,char * argv[])311 int main(int argc, char* argv[])
312 {
313     scan_opt (argc, argv);
314 
315     if (input_file == NULL) {
316 	fputs("Input file was not specified\n", stderr);
317         exit(1);
318     }
319     if (output_file == NULL) {
320 	char* ext = strrchr(input_file, '.');
321         int file_name_len = ext ? ext - input_file : strlen(input_file);
322 	if (language_c) output_suf = ".c";
323 	output_file = dprintf("%.*s%s", file_name_len, input_file, output_suf);
324     }
325     load_predefined();
326     load_keywords();
327     load_configuration(dprintf("%s%s", prog_path, CONFIG_FILE));
328 
329     if (hp_pascal) {
330         nested_comments = 1;
331         ignore_preprocessor_directives = 1;
332     }
333     if (use_call_graph) {
334 	call_graph_file = fopen(CALL_GRAPH_FILE, "a");
335 	FILE* f = fopen(RECURSIVE_PROC_FILE, "r");
336 	if (f != NULL) {
337 	    char name[256];
338 	    while (fscanf(f, "%s", name) == 1) {
339 		nm_entry::add(name, TKN_IDENT)->flags |= nm_entry::recursive;
340 	    }
341 	    fclose(f);
342 	}
343     }
344 
345     compile_system_library = TRUE;
346 #ifdef PREFIX
347     token::input(turbo_pascal
348 		 ? (char *) PREFIX "/share/ptoc/tptoc.pas"
349 		 : (char *) PREFIX "/share/ptoc/ptoc.pas");
350 #else
351     token::input(dprintf("%s%s", prog_path,
352  			 turbo_pascal ? "tptoc.pas" : "ptoc.pas"));
353 #endif
354     zzparse();
355 
356     compile_system_library = FALSE;
357     token::reset();
358     token::input(input_file);
359     zzparse();
360 
361     token::output(output_file);
362 
363     if (call_graph_file) {
364 	fclose(call_graph_file);
365     }
366     return 0;
367 }
368 
369 
370