blob: eb48cd00926d17aa2d13da48b1ee387f5b7bc01b [file] [log] [blame]
Mark Slee31985722006-05-24 21:45:31 +00001/**
2 * thrift - a lightweight cross-language rpc/serialization tool
3 *
4 * This file contains the main compiler engine for Thrift, which invokes the
5 * scanner/parser to build the thrift object tree. The interface generation
Mark Sleef5377b32006-10-10 01:42:59 +00006 * code for each language lives in a file by the language name under the
7 * generate/ folder, and all parse structures live in parse/
Mark Slee31985722006-05-24 21:45:31 +00008 *
9 * @author Mark Slee <mcslee@facebook.com>
10 */
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <stdarg.h>
15#include <string>
Mark Sleef0712dc2006-10-25 19:03:57 +000016#include <sys/types.h>
17#include <sys/stat.h>
Mark Slee31985722006-05-24 21:45:31 +000018
Mark Sleef0712dc2006-10-25 19:03:57 +000019// Careful: must include globals first for extern definitions
Mark Slee31985722006-05-24 21:45:31 +000020#include "globals.h"
21
22#include "main.h"
23#include "parse/t_program.h"
Mark Sleef0712dc2006-10-25 19:03:57 +000024#include "parse/t_scope.h"
Mark Slee31985722006-05-24 21:45:31 +000025#include "generate/t_cpp_generator.h"
Mark Sleeb15a68b2006-06-07 06:46:24 +000026#include "generate/t_java_generator.h"
Mark Slee6e536442006-06-30 18:28:50 +000027#include "generate/t_php_generator.h"
Mark Sleefc89d392006-09-04 00:04:39 +000028#include "generate/t_py_generator.h"
Mark Slee6d7d5952007-01-27 01:44:22 +000029#include "generate/t_rb_generator.h"
Mark Slee0e0ff7e2007-01-18 22:59:59 +000030#include "generate/t_xsd_generator.h"
Mark Slee31985722006-05-24 21:45:31 +000031
32using namespace std;
33
Mark Sleef5377b32006-10-10 01:42:59 +000034/**
35 * Global program tree
36 */
Mark Slee31985722006-05-24 21:45:31 +000037t_program* g_program;
38
Mark Sleef5377b32006-10-10 01:42:59 +000039/**
Mark Sleef0712dc2006-10-25 19:03:57 +000040 * Global types
41 */
42
43t_type* g_type_void;
44t_type* g_type_string;
Mark Sleeb6200d82007-01-19 19:14:36 +000045t_type* g_type_slist;
Mark Sleef0712dc2006-10-25 19:03:57 +000046t_type* g_type_bool;
47t_type* g_type_byte;
48t_type* g_type_i16;
49t_type* g_type_i32;
50t_type* g_type_i64;
51t_type* g_type_double;
52
53/**
54 * Global scope
55 */
56t_scope* g_scope;
57
58/**
59 * Parent scope to also parse types
60 */
61t_scope* g_parent_scope;
62
63/**
64 * Prefix for putting types in parent scope
65 */
66string g_parent_prefix;
67
68/**
69 * Parsing pass
70 */
71PARSE_MODE g_parse_mode;
72
73/**
74 * Current directory of file being parsed
75 */
76string g_curdir;
77
78/**
79 * Current file being parsed
80 */
81string g_curpath;
82
83/**
Martin Kraemer32c66e12006-11-09 00:06:36 +000084 * Search path for inclusions
85 */
Mark Slee2329a832006-11-09 00:23:30 +000086vector<string> g_incl_searchpath;
Martin Kraemer32c66e12006-11-09 00:06:36 +000087
88/**
Mark Sleef5377b32006-10-10 01:42:59 +000089 * Global debug state
90 */
Mark Slee31985722006-05-24 21:45:31 +000091int g_debug = 0;
92
Mark Sleef5377b32006-10-10 01:42:59 +000093/**
Mark Sleef0712dc2006-10-25 19:03:57 +000094 * Warning level
95 */
96int g_warn = 1;
97
98/**
99 * Verbose output
100 */
101int g_verbose = 0;
102
103/**
Mark Sleef5377b32006-10-10 01:42:59 +0000104 * Global time string
105 */
Mark Slee31985722006-05-24 21:45:31 +0000106char* g_time_str;
107
Mark Slee31985722006-05-24 21:45:31 +0000108/**
Mark Sleef0712dc2006-10-25 19:03:57 +0000109 * Flags to control code generation
110 */
111bool gen_cpp = false;
112bool gen_java = false;
Mark Slee6d7d5952007-01-27 01:44:22 +0000113bool gen_rb = false;
Mark Sleef0712dc2006-10-25 19:03:57 +0000114bool gen_py = false;
Mark Slee0e0ff7e2007-01-18 22:59:59 +0000115bool gen_xsd = false;
Mark Sleef0712dc2006-10-25 19:03:57 +0000116bool gen_php = false;
117bool gen_phpi = false;
118bool gen_recurse = false;
119
120/**
Mark Slee31985722006-05-24 21:45:31 +0000121 * Report an error to the user. This is called yyerror for historical
122 * reasons (lex and yacc expect the error reporting routine to be called
123 * this). Call this function to report any errors to the user.
124 * yyerror takes printf style arguments.
125 *
126 * @param fmt C format string followed by additional arguments
127 */
128void yyerror(char* fmt, ...) {
129 va_list args;
130 fprintf(stderr,
Mark Sleef0712dc2006-10-25 19:03:57 +0000131 "[ERROR:%s:%d] (last token was '%s')\n",
132 g_curpath.c_str(),
Mark Slee31985722006-05-24 21:45:31 +0000133 yylineno,
134 yytext);
Mark Slee31985722006-05-24 21:45:31 +0000135
136 va_start(args, fmt);
137 vfprintf(stderr, fmt, args);
138 va_end(args);
139
140 fprintf(stderr, "\n");
141}
142
143/**
144 * Prints a debug message from the parser.
145 *
146 * @param fmt C format string followed by additional arguments
147 */
148void pdebug(char* fmt, ...) {
149 if (g_debug == 0) {
150 return;
151 }
152 va_list args;
Mark Slee30152872006-11-28 01:24:07 +0000153 printf("[PARSE:%d] ", yylineno);
Mark Sleef0712dc2006-10-25 19:03:57 +0000154 va_start(args, fmt);
155 vprintf(fmt, args);
156 va_end(args);
157 printf("\n");
158}
159
160/**
161 * Prints a verbose output mode message
162 *
163 * @param fmt C format string followed by additional arguments
164 */
165void pverbose(char* fmt, ...) {
166 if (g_verbose == 0) {
167 return;
168 }
169 va_list args;
170 va_start(args, fmt);
171 vprintf(fmt, args);
172 va_end(args);
173}
174
175/**
176 * Prints a warning message
177 *
178 * @param fmt C format string followed by additional arguments
179 */
180void pwarning(int level, char* fmt, ...) {
181 if (g_warn < level) {
182 return;
183 }
184 va_list args;
185 printf("[WARNING:%s:%d] ", g_curpath.c_str(), yylineno);
Mark Slee31985722006-05-24 21:45:31 +0000186 va_start(args, fmt);
187 vprintf(fmt, args);
188 va_end(args);
189 printf("\n");
190}
191
192/**
193 * Prints a failure message and exits
194 *
195 * @param fmt C format string followed by additional arguments
196 */
Mark Slee30152872006-11-28 01:24:07 +0000197void failure(const char* fmt, ...) {
Mark Slee31985722006-05-24 21:45:31 +0000198 va_list args;
Mark Sleef0712dc2006-10-25 19:03:57 +0000199 fprintf(stderr, "[FAILURE:%s:%d] ", g_curpath.c_str(), yylineno);
Mark Slee31985722006-05-24 21:45:31 +0000200 va_start(args, fmt);
201 vfprintf(stderr, fmt, args);
202 va_end(args);
203 printf("\n");
204 exit(1);
205}
206
207/**
Mark Sleef0712dc2006-10-25 19:03:57 +0000208 * Converts a string filename into a thrift program name
209 */
210string program_name(string filename) {
211 string::size_type slash = filename.rfind("/");
212 if (slash != string::npos) {
213 filename = filename.substr(slash+1);
214 }
215 string::size_type dot = filename.rfind(".");
216 if (dot != string::npos) {
217 filename = filename.substr(0, dot);
218 }
219 return filename;
220}
221
222/**
223 * Gets the directory path of a filename
224 */
225string directory_name(string filename) {
226 string::size_type slash = filename.rfind("/");
227 // No slash, just use the current directory
228 if (slash == string::npos) {
229 return ".";
230 }
231 return filename.substr(0, slash);
232}
233
234/**
235 * Finds the appropriate file path for the given filename
236 */
237string include_file(string filename) {
238 // Absolute path? Just try that
Martin Kraemer32c66e12006-11-09 00:06:36 +0000239 if (filename[0] == '/') {
240 // Realpath!
241 char rp[PATH_MAX];
242 if (realpath(filename.c_str(), rp) == NULL) {
243 pwarning(0, "Cannot open include file %s\n", filename.c_str());
244 return std::string();
245 }
246
247 // Stat this files
248 struct stat finfo;
249 if (stat(rp, &finfo) == 0) {
250 return rp;
251 }
252 } else { // relative path, start searching
253 // new search path with current dir global
254 vector<string> sp = g_incl_searchpath;
255 sp.insert(sp.begin(), g_curdir);
256
257 // iterate through paths
258 vector<string>::iterator it;
259 for (it = sp.begin(); it != sp.end(); it++) {
260 string sfilename = *(it) + "/" + filename;
261
262 // Realpath!
263 char rp[PATH_MAX];
264 if (realpath(sfilename.c_str(), rp) == NULL) {
265 continue;
266 }
267
268 // Stat this files
269 struct stat finfo;
270 if (stat(rp, &finfo) == 0) {
271 return rp;
272 }
273 }
Mark Sleef0712dc2006-10-25 19:03:57 +0000274 }
275
Mark Sleef0712dc2006-10-25 19:03:57 +0000276 // Uh oh
277 pwarning(0, "Could not find include file %s\n", filename.c_str());
278 return std::string();
279}
280
281/**
Mark Slee31985722006-05-24 21:45:31 +0000282 * Diplays the usage message and then exits with an error code.
283 */
284void usage() {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000285 fprintf(stderr, "Usage: thrift [options] file\n");
286 fprintf(stderr, "Options:\n");
Mark Slee2329a832006-11-09 00:23:30 +0000287 fprintf(stderr, " -cpp Generate C++ output files\n");
288 fprintf(stderr, " -java Generate Java output files\n");
289 fprintf(stderr, " -php Generate PHP output files\n");
290 fprintf(stderr, " -phpi Generate PHP inlined files\n");
291 fprintf(stderr, " -py Generate Python output files\n");
ccheeverf53b5cf2007-02-05 20:33:11 +0000292 fprintf(stderr, " -rb Generate Ruby output files\n");
293 fprintf(stderr, " -xsd Generate XSD output files\n");
Mark Slee227ac2c2007-03-07 05:46:50 +0000294 fprintf(stderr, " -I dir Add a directory to the list of directories \n");
295 fprintf(stderr, " searched for include directives\n");
Mark Slee2329a832006-11-09 00:23:30 +0000296 fprintf(stderr, " -nowarn Suppress all compiler warnings (BAD!)\n");
297 fprintf(stderr, " -strict Strict compiler warnings on\n");
298 fprintf(stderr, " -v[erbose] Verbose mode\n");
299 fprintf(stderr, " -r[ecurse] Also generate included files\n");
300 fprintf(stderr, " -debug Parse debug trace to stdout\n");
Mark Slee31985722006-05-24 21:45:31 +0000301 exit(1);
302}
303
304/**
Mark Slee30152872006-11-28 01:24:07 +0000305 * You know, when I started working on Thrift I really thought it wasn't going
306 * to become a programming language because it was just a generator and it
307 * wouldn't need runtime type information and all that jazz. But then we
308 * decided to add constants, and all of a sudden that means runtime type
309 * validation and inference, except the "runtime" is the code generator
310 * runtime. Shit. I've been had.
311 */
312void validate_const_rec(std::string name, t_type* type, t_const_value* value) {
313 if (type->is_void()) {
314 throw "type error: cannot declare a void const: " + name;
315 }
316
317 if (type->is_base_type()) {
318 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
319 switch (tbase) {
320 case t_base_type::TYPE_STRING:
321 if (value->get_type() != t_const_value::CV_STRING) {
322 throw "type error: const \"" + name + "\" was declared as string";
323 }
324 break;
325 case t_base_type::TYPE_BOOL:
326 if (value->get_type() != t_const_value::CV_INTEGER) {
327 throw "type error: const \"" + name + "\" was declared as bool";
328 }
329 break;
330 case t_base_type::TYPE_BYTE:
331 if (value->get_type() != t_const_value::CV_INTEGER) {
332 throw "type error: const \"" + name + "\" was declared as byte";
333 }
334 break;
335 case t_base_type::TYPE_I16:
336 if (value->get_type() != t_const_value::CV_INTEGER) {
337 throw "type error: const \"" + name + "\" was declared as i16";
338 }
339 break;
340 case t_base_type::TYPE_I32:
341 if (value->get_type() != t_const_value::CV_INTEGER) {
342 throw "type error: const \"" + name + "\" was declared as i32";
343 }
344 break;
345 case t_base_type::TYPE_I64:
346 if (value->get_type() != t_const_value::CV_INTEGER) {
347 throw "type error: const \"" + name + "\" was declared as i64";
348 }
349 break;
350 case t_base_type::TYPE_DOUBLE:
351 if (value->get_type() != t_const_value::CV_INTEGER &&
352 value->get_type() != t_const_value::CV_DOUBLE) {
353 throw "type error: const \"" + name + "\" was declared as double";
354 }
355 break;
356 default:
357 throw "compiler error: no const of base type " + tbase + name;
358 }
359 } else if (type->is_enum()) {
360 if (value->get_type() != t_const_value::CV_INTEGER) {
361 throw "type error: const \"" + name + "\" was declared as enum";
362 }
363 } else if (type->is_struct() || type->is_xception()) {
364 if (value->get_type() != t_const_value::CV_MAP) {
365 throw "type error: const \"" + name + "\" was declared as struct/xception";
366 }
367 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
368 vector<t_field*>::const_iterator f_iter;
369
370 const map<t_const_value*, t_const_value*>& val = value->get_map();
371 map<t_const_value*, t_const_value*>::const_iterator v_iter;
372 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
373 if (v_iter->first->get_type() != t_const_value::CV_STRING) {
374 throw "type error: " + name + " struct key must be string";
375 }
376 t_type* field_type = NULL;
377 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
378 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
379 field_type = (*f_iter)->get_type();
380 }
381 }
382 if (field_type == NULL) {
383 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
384 }
385
386 validate_const_rec(name + "." + v_iter->first->get_string(), field_type, v_iter->second);
387 }
388 } else if (type->is_map()) {
389 t_type* k_type = ((t_map*)type)->get_key_type();
390 t_type* v_type = ((t_map*)type)->get_val_type();
391 const map<t_const_value*, t_const_value*>& val = value->get_map();
392 map<t_const_value*, t_const_value*>::const_iterator v_iter;
393 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
394 validate_const_rec(name + "<key>", k_type, v_iter->first);
395 validate_const_rec(name + "<val>", v_type, v_iter->second);
396 }
397 } else if (type->is_list() || type->is_set()) {
398 t_type* e_type;
399 if (type->is_list()) {
400 e_type = ((t_list*)type)->get_elem_type();
401 } else {
402 e_type = ((t_set*)type)->get_elem_type();
403 }
404 const vector<t_const_value*>& val = value->get_list();
405 vector<t_const_value*>::const_iterator v_iter;
406 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
407 validate_const_rec(name + "<elem>", e_type, *v_iter);
408 }
409 }
410}
411
412/**
413 * Check the type of the parsed const information against its declared type
414 */
415void validate_const_type(t_const* c) {
416 validate_const_rec(c->get_name(), c->get_type(), c->get_value());
417}
418
419/**
Mark Slee7ff32452007-02-01 05:26:18 +0000420 * Check the type of a default value assigned to a field.
421 */
422void validate_field_value(t_field* field, t_const_value* cv) {
423 validate_const_rec(field->get_name(), field->get_type(), cv);
424}
425
426/**
Mark Sleef0712dc2006-10-25 19:03:57 +0000427 * Parses a program
428 */
429void parse(t_program* program, t_program* parent_program) {
430 // Get scope file path
431 string path = program->get_path();
432
433 // Set current dir global, which is used in the include_file function
434 g_curdir = directory_name(path);
435 g_curpath = path;
436
437 // Open the file
438 yyin = fopen(path.c_str(), "r");
439 if (yyin == 0) {
440 failure("Could not open input file: \"%s\"", path.c_str());
441 }
442
443 // Create new scope and scan for includes
444 pverbose("Scanning %s for includes\n", path.c_str());
445 g_parse_mode = INCLUDES;
446 g_program = program;
447 g_scope = program->scope();
Mark Slee30152872006-11-28 01:24:07 +0000448 try {
Mark Slee36bfa2e2007-01-19 20:09:51 +0000449 yylineno = 1;
Mark Slee30152872006-11-28 01:24:07 +0000450 if (yyparse() != 0) {
451 failure("Parser error during include pass.");
452 }
453 } catch (string x) {
454 failure(x.c_str());
Mark Sleef0712dc2006-10-25 19:03:57 +0000455 }
456 fclose(yyin);
457
458 // Recursively parse all the include programs
459 vector<t_program*>& includes = program->get_includes();
460 vector<t_program*>::iterator iter;
461 for (iter = includes.begin(); iter != includes.end(); ++iter) {
462 parse(*iter, program);
463 }
464
465 // Parse the program the file
466 g_parse_mode = PROGRAM;
467 g_program = program;
468 g_scope = program->scope();
469 g_parent_scope = (parent_program != NULL) ? parent_program->scope() : NULL;
470 g_parent_prefix = program->get_name() + ".";
471 g_curpath = path;
472 yyin = fopen(path.c_str(), "r");
473 if (yyin == 0) {
474 failure("Could not open input file: \"%s\"", path.c_str());
475 }
476 pverbose("Parsing %s for types\n", path.c_str());
Mark Slee36bfa2e2007-01-19 20:09:51 +0000477 yylineno = 1;
Mark Sleef0712dc2006-10-25 19:03:57 +0000478 if (yyparse() != 0) {
479 failure("Parser error during types pass.");
480 }
481 fclose(yyin);
482}
483
484/**
485 * Generate code
486 */
487void generate(t_program* program) {
488 // Oooohh, recursive code generation, hot!!
489 if (gen_recurse) {
490 const vector<t_program*>& includes = program->get_includes();
491 for (size_t i = 0; i < includes.size(); ++i) {
492 generate(includes[i]);
493 }
494 }
495
496 // Generate code!
497 try {
498 pverbose("Program: %s\n", program->get_path().c_str());
499
500 if (gen_cpp) {
501 pverbose("Generating C++\n");
502 t_cpp_generator* cpp = new t_cpp_generator(program);
503 cpp->generate_program();
504 delete cpp;
505 }
506
507 if (gen_java) {
508 pverbose("Generating Java\n");
509 t_java_generator* java = new t_java_generator(program);
510 java->generate_program();
511 delete java;
512 }
513
514 if (gen_php) {
515 pverbose("Generating PHP\n");
516 t_php_generator* php = new t_php_generator(program, false);
517 php->generate_program();
518 delete php;
519 }
520
521 if (gen_phpi) {
522 pverbose("Generating PHP-inline\n");
523 t_php_generator* phpi = new t_php_generator(program, true);
524 phpi->generate_program();
525 delete phpi;
526 }
527
528 if (gen_py) {
529 pverbose("Generating Python\n");
530 t_py_generator* py = new t_py_generator(program);
531 py->generate_program();
532 delete py;
533 }
Mark Slee0e0ff7e2007-01-18 22:59:59 +0000534
Mark Slee6d7d5952007-01-27 01:44:22 +0000535 if (gen_rb) {
536 pverbose("Generating Ruby\n");
537 t_rb_generator* rb = new t_rb_generator(program);
538 rb->generate_program();
539 delete rb;
540 }
541
Mark Slee0e0ff7e2007-01-18 22:59:59 +0000542 if (gen_xsd) {
543 pverbose("Generating XSD\n");
544 t_xsd_generator* xsd = new t_xsd_generator(program);
545 xsd->generate_program();
546 delete xsd;
547 }
548
Mark Sleef0712dc2006-10-25 19:03:57 +0000549 } catch (string s) {
550 printf("Error: %s\n", s.c_str());
551 } catch (const char* exc) {
552 printf("Error: %s\n", exc);
553 }
554
555}
556
557/**
Mark Sleef5377b32006-10-10 01:42:59 +0000558 * Parse it up.. then spit it back out, in pretty much every language. Alright
559 * not that many languages, but the cool ones that we care about.
Mark Slee31985722006-05-24 21:45:31 +0000560 */
561int main(int argc, char** argv) {
562 int i;
Mark Sleef5377b32006-10-10 01:42:59 +0000563
Mark Sleeb15a68b2006-06-07 06:46:24 +0000564 // Setup time string
565 time_t now = time(NULL);
566 g_time_str = ctime(&now);
Mark Slee31985722006-05-24 21:45:31 +0000567
Mark Sleef0712dc2006-10-25 19:03:57 +0000568 // Check for necessary arguments, you gotta have at least a filename and
569 // an output language flag
Mark Sleeb15a68b2006-06-07 06:46:24 +0000570 if (argc < 2) {
571 usage();
572 }
Mark Slee31985722006-05-24 21:45:31 +0000573
Mark Sleef5377b32006-10-10 01:42:59 +0000574 // Hacky parameter handling... I didn't feel like using a library sorry!
Mark Slee31985722006-05-24 21:45:31 +0000575 for (i = 1; i < argc-1; i++) {
Mark Sleefdbee812006-09-27 18:50:48 +0000576 char* arg;
Mark Slee2329a832006-11-09 00:23:30 +0000577
Mark Sleefdbee812006-09-27 18:50:48 +0000578 arg = strtok(argv[i], " ");
579 while (arg != NULL) {
Mark Slee2329a832006-11-09 00:23:30 +0000580 // Treat double dashes as single dashes
Mark Slee52cb2232006-11-10 22:32:07 +0000581 if (arg[0] == '-' && arg[1] == '-') {
Mark Slee2329a832006-11-09 00:23:30 +0000582 ++arg;
583 }
584
585 if (strcmp(arg, "-debug") == 0) {
Mark Sleefdbee812006-09-27 18:50:48 +0000586 g_debug = 1;
Mark Slee2329a832006-11-09 00:23:30 +0000587 } else if (strcmp(arg, "-nowarn") == 0) {
Mark Sleef0712dc2006-10-25 19:03:57 +0000588 g_warn = 0;
Mark Slee2329a832006-11-09 00:23:30 +0000589 } else if (strcmp(arg, "-strict") == 0) {
Mark Sleef0712dc2006-10-25 19:03:57 +0000590 g_warn = 2;
Mark Slee2329a832006-11-09 00:23:30 +0000591 } else if (strcmp(arg, "-v") == 0 || strcmp(arg, "-verbose") == 0 ) {
Mark Sleef0712dc2006-10-25 19:03:57 +0000592 g_verbose = 1;
Mark Slee2329a832006-11-09 00:23:30 +0000593 } else if (strcmp(arg, "-r") == 0 || strcmp(arg, "-recurse") == 0 ) {
Mark Sleef0712dc2006-10-25 19:03:57 +0000594 gen_recurse = true;
Mark Slee2329a832006-11-09 00:23:30 +0000595 } else if (strcmp(arg, "-cpp") == 0) {
Mark Sleefdbee812006-09-27 18:50:48 +0000596 gen_cpp = true;
Mark Slee2329a832006-11-09 00:23:30 +0000597 } else if (strcmp(arg, "-java") == 0) {
Mark Sleefdbee812006-09-27 18:50:48 +0000598 gen_java = true;
Mark Slee2329a832006-11-09 00:23:30 +0000599 } else if (strcmp(arg, "-php") == 0) {
Mark Sleefdbee812006-09-27 18:50:48 +0000600 gen_php = true;
Mark Slee2329a832006-11-09 00:23:30 +0000601 } else if (strcmp(arg, "-phpi") == 0) {
Mark Sleef5377b32006-10-10 01:42:59 +0000602 gen_phpi = true;
Mark Slee2329a832006-11-09 00:23:30 +0000603 } else if (strcmp(arg, "-py") == 0) {
Mark Sleefdbee812006-09-27 18:50:48 +0000604 gen_py = true;
Mark Slee6d7d5952007-01-27 01:44:22 +0000605 } else if (strcmp(arg, "-rb") == 0) {
606 gen_rb = true;
Mark Slee0e0ff7e2007-01-18 22:59:59 +0000607 } else if (strcmp(arg, "-xsd") == 0) {
608 gen_xsd = true;
Martin Kraemer32c66e12006-11-09 00:06:36 +0000609 } else if (strcmp(arg, "-I") == 0) {
610 // An argument of "-I\ asdf" is invalid and has unknown results
611 arg = argv[++i];
612
613 if (arg == NULL) {
614 fprintf(stderr, "!!! Missing Include directory");
615 usage();
616 }
617 g_incl_searchpath.push_back(arg);
Mark Sleefdbee812006-09-27 18:50:48 +0000618 } else {
619 fprintf(stderr, "!!! Unrecognized option: %s\n", arg);
620 usage();
621 }
622
623 // Tokenize more
624 arg = strtok(NULL, " ");
Mark Slee31985722006-05-24 21:45:31 +0000625 }
626 }
627
Mark Sleef0712dc2006-10-25 19:03:57 +0000628 // You gotta generate something!
Mark Slee6d7d5952007-01-27 01:44:22 +0000629 if (!gen_cpp && !gen_java && !gen_php && !gen_phpi && !gen_py && !gen_rb && !gen_xsd) {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000630 fprintf(stderr, "!!! No output language(s) specified\n\n");
631 usage();
632 }
Mark Sleef0712dc2006-10-25 19:03:57 +0000633
634 // Real-pathify it
635 char rp[PATH_MAX];
636 if (realpath(argv[i], rp) == NULL) {
637 failure("Could not open input file: %s", argv[i]);
Mark Slee31985722006-05-24 21:45:31 +0000638 }
Mark Sleef0712dc2006-10-25 19:03:57 +0000639 string input_file(rp);
640
Mark Sleef5377b32006-10-10 01:42:59 +0000641 // Instance of the global parse tree
Mark Sleef0712dc2006-10-25 19:03:57 +0000642 t_program* program = new t_program(input_file);
643
644 // Initialize global types
645 g_type_void = new t_base_type("void", t_base_type::TYPE_VOID);
646 g_type_string = new t_base_type("string", t_base_type::TYPE_STRING);
Mark Sleeb6200d82007-01-19 19:14:36 +0000647 g_type_slist = new t_base_type("string", t_base_type::TYPE_STRING);
648 ((t_base_type*)g_type_slist)->set_string_list(true);
Mark Sleef0712dc2006-10-25 19:03:57 +0000649 g_type_bool = new t_base_type("bool", t_base_type::TYPE_BOOL);
650 g_type_byte = new t_base_type("byte", t_base_type::TYPE_BYTE);
651 g_type_i16 = new t_base_type("i16", t_base_type::TYPE_I16);
652 g_type_i32 = new t_base_type("i32", t_base_type::TYPE_I32);
653 g_type_i64 = new t_base_type("i64", t_base_type::TYPE_I64);
654 g_type_double = new t_base_type("double", t_base_type::TYPE_DOUBLE);
Mark Sleee8540632006-05-30 09:24:40 +0000655
Mark Sleef5377b32006-10-10 01:42:59 +0000656 // Parse it!
Mark Sleef0712dc2006-10-25 19:03:57 +0000657 parse(program, NULL);
Mark Slee31985722006-05-24 21:45:31 +0000658
Mark Sleef0712dc2006-10-25 19:03:57 +0000659 // Generate it!
660 generate(program);
Mark Sleeb15a68b2006-06-07 06:46:24 +0000661
Mark Sleef0712dc2006-10-25 19:03:57 +0000662 // Clean up. Who am I kidding... this program probably orphans heap memory
663 // all over the place, but who cares because it is about to exit and it is
664 // all referenced and used by this wacky parse tree up until now anyways.
Mark Sleeb15a68b2006-06-07 06:46:24 +0000665
Mark Sleef0712dc2006-10-25 19:03:57 +0000666 delete program;
667 delete g_type_void;
668 delete g_type_string;
669 delete g_type_bool;
670 delete g_type_byte;
671 delete g_type_i16;
672 delete g_type_i32;
673 delete g_type_i64;
674 delete g_type_double;
Mark Slee31985722006-05-24 21:45:31 +0000675
676 // Finished
Mark Slee31985722006-05-24 21:45:31 +0000677 return 0;
678}