blob: f75bd53e2e1f26c47cb08318eb178fe9d94bafd1 [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
6 * code for each language lives in a file by the language name.
7 *
8 * @author Mark Slee <mcslee@facebook.com>
9 */
10
11#include <stdlib.h>
12#include <stdio.h>
13#include <stdarg.h>
14#include <string>
15
16// Careful: must include globals first
17#include "globals.h"
18
19#include "main.h"
20#include "parse/t_program.h"
21#include "generate/t_cpp_generator.h"
Mark Sleeb15a68b2006-06-07 06:46:24 +000022#include "generate/t_java_generator.h"
Mark Slee6e536442006-06-30 18:28:50 +000023#include "generate/t_php_generator.h"
Mark Sleefc89d392006-09-04 00:04:39 +000024#include "generate/t_py_generator.h"
Mark Slee31985722006-05-24 21:45:31 +000025
26using namespace std;
27
28/** Global program tree */
29t_program* g_program;
30
31/** Global debug state */
32int g_debug = 0;
33
34/** Global time string */
35char* g_time_str;
36
37
38/**
39 * Report an error to the user. This is called yyerror for historical
40 * reasons (lex and yacc expect the error reporting routine to be called
41 * this). Call this function to report any errors to the user.
42 * yyerror takes printf style arguments.
43 *
44 * @param fmt C format string followed by additional arguments
45 */
46void yyerror(char* fmt, ...) {
47 va_list args;
48 fprintf(stderr,
49 "\n!!! Error: line %d (last token was '%s')",
50 yylineno,
51 yytext);
52 fprintf(stderr, "\n!!! ");
53
54 va_start(args, fmt);
55 vfprintf(stderr, fmt, args);
56 va_end(args);
57
58 fprintf(stderr, "\n");
59}
60
61/**
62 * Prints a debug message from the parser.
63 *
64 * @param fmt C format string followed by additional arguments
65 */
66void pdebug(char* fmt, ...) {
67 if (g_debug == 0) {
68 return;
69 }
70 va_list args;
71 printf("[Parse] ");
72 va_start(args, fmt);
73 vprintf(fmt, args);
74 va_end(args);
75 printf("\n");
76}
77
78/**
79 * Prints a failure message and exits
80 *
81 * @param fmt C format string followed by additional arguments
82 */
83void failure(char* fmt, ...) {
84 va_list args;
85 fprintf(stderr, "\n!!! Failure: ");
86 va_start(args, fmt);
87 vfprintf(stderr, fmt, args);
88 va_end(args);
89 printf("\n");
90 exit(1);
91}
92
93/**
94 * Diplays the usage message and then exits with an error code.
95 */
96void usage() {
Mark Sleeb15a68b2006-06-07 06:46:24 +000097 fprintf(stderr, "Usage: thrift [options] file\n");
98 fprintf(stderr, "Options:\n");
Mark Slee9cb7c612006-09-01 22:17:45 +000099 fprintf(stderr, " --cpp Generate C++ output files\n");
100 fprintf(stderr, " --java Generate Java output files\n");
101 fprintf(stderr, " --php Generate PHP output files\n");
102 fprintf(stderr, " --phpi Generate PHP inlined files\n");
Mark Sleefc89d392006-09-04 00:04:39 +0000103 fprintf(stderr, " --py Generate Python output files\n");
104 fprintf(stderr, " --debug Print parse debugging to standard output\n");
Mark Slee31985722006-05-24 21:45:31 +0000105 exit(1);
106}
107
108/**
109 * Parse it up.. then spit it back out, in pretty much every language
110 */
111int main(int argc, char** argv) {
112 int i;
Mark Sleeb15a68b2006-06-07 06:46:24 +0000113 bool gen_cpp = false;
114 bool gen_java = false;
Mark Sleefc89d392006-09-04 00:04:39 +0000115 bool gen_py = false;
Mark Slee6e536442006-06-30 18:28:50 +0000116 bool gen_php = false;
Mark Slee52f643d2006-08-09 00:03:43 +0000117 bool php_inline = false;
Mark Sleeb15a68b2006-06-07 06:46:24 +0000118
119 // Setup time string
120 time_t now = time(NULL);
121 g_time_str = ctime(&now);
Mark Slee31985722006-05-24 21:45:31 +0000122
123 // Check for necessary arguments
Mark Sleeb15a68b2006-06-07 06:46:24 +0000124 if (argc < 2) {
125 usage();
126 }
Mark Slee31985722006-05-24 21:45:31 +0000127
128 for (i = 1; i < argc-1; i++) {
Mark Slee9cb7c612006-09-01 22:17:45 +0000129 if (strcmp(argv[i], "--debug") == 0) {
Mark Slee31985722006-05-24 21:45:31 +0000130 g_debug = 1;
Mark Slee9cb7c612006-09-01 22:17:45 +0000131 } else if (strcmp(argv[i], "--cpp") == 0) {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000132 gen_cpp = true;
Mark Slee9cb7c612006-09-01 22:17:45 +0000133 } else if (strcmp(argv[i], "--java") == 0) {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000134 gen_java = true;
Mark Slee9cb7c612006-09-01 22:17:45 +0000135 } else if (strcmp(argv[i], "--php") == 0) {
Mark Slee6e536442006-06-30 18:28:50 +0000136 gen_php = true;
Mark Slee52f643d2006-08-09 00:03:43 +0000137 php_inline = false;
Mark Slee9cb7c612006-09-01 22:17:45 +0000138 } else if (strcmp(argv[i], "--phpi") == 0) {
Mark Slee52f643d2006-08-09 00:03:43 +0000139 gen_php = true;
140 php_inline = true;
Mark Sleefc89d392006-09-04 00:04:39 +0000141 } else if (strcmp(argv[i], "--py") == 0) {
142 gen_py = true;
Mark Slee31985722006-05-24 21:45:31 +0000143 } else {
144 fprintf(stderr, "!!! Unrecognized option: %s\n", argv[i]);
145 usage();
146 }
147 }
148
Mark Sleefc89d392006-09-04 00:04:39 +0000149 if (!gen_cpp && !gen_java && !gen_php && !gen_py) {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000150 fprintf(stderr, "!!! No output language(s) specified\n\n");
151 usage();
152 }
153
Mark Slee31985722006-05-24 21:45:31 +0000154 // Open input file
155 char* input_file = argv[i];
156 yyin = fopen(input_file, "r");
157 if (yyin == 0) {
158 failure("Could not open input file: \"%s\"", input_file);
159 }
160
161 // Extract program name by dropping directory and .thrift from filename
162 string name = input_file;
163 string::size_type slash = name.rfind("/");
164 if (slash != string::npos) {
165 name = name.substr(slash+1);
166 }
167 string::size_type dot = name.find(".");
168 if (dot != string::npos) {
169 name = name.substr(0, dot);
170 }
171
172 // Parse it
173 g_program = new t_program(name);
Mark Sleee8540632006-05-30 09:24:40 +0000174
Mark Slee31985722006-05-24 21:45:31 +0000175 if (yyparse() != 0) {
176 failure("Parser error.");
177 }
178
179 // Generate code
180 try {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000181 if (gen_cpp) {
182 t_cpp_generator* cpp = new t_cpp_generator();
183 cpp->generate_program(g_program);
184 delete cpp;
185 }
186
187 if (gen_java) {
188 t_java_generator* java = new t_java_generator();
189 java->generate_program(g_program);
190 delete java;
191 }
192
Mark Slee6e536442006-06-30 18:28:50 +0000193 if (gen_php) {
Mark Slee52f643d2006-08-09 00:03:43 +0000194 t_php_generator* php = new t_php_generator(php_inline);
Mark Slee6e536442006-06-30 18:28:50 +0000195 php->generate_program(g_program);
196 delete php;
197 }
Mark Sleefc89d392006-09-04 00:04:39 +0000198
199 if (gen_py) {
200 t_py_generator* py = new t_py_generator();
201 py->generate_program(g_program);
202 delete py;
203 }
Mark Sleee8540632006-05-30 09:24:40 +0000204 } catch (string s) {
205 printf("Error: %s\n", s.c_str());
Mark Slee31985722006-05-24 21:45:31 +0000206 } catch (const char* exc) {
207 printf("Error: %s\n", exc);
208 }
209
210 // Clean up
211 delete g_program;
212
213 // Finished
Mark Slee31985722006-05-24 21:45:31 +0000214 return 0;
215}