blob: 9a8e29ee6098b48b6f2b0ab5735ee4c5fb86518f [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>
16
Mark Sleef5377b32006-10-10 01:42:59 +000017// Careful: must include globals first here for extern/global definitions
Mark Slee31985722006-05-24 21:45:31 +000018#include "globals.h"
19
20#include "main.h"
21#include "parse/t_program.h"
22#include "generate/t_cpp_generator.h"
Mark Sleeb15a68b2006-06-07 06:46:24 +000023#include "generate/t_java_generator.h"
Mark Slee6e536442006-06-30 18:28:50 +000024#include "generate/t_php_generator.h"
Mark Sleefc89d392006-09-04 00:04:39 +000025#include "generate/t_py_generator.h"
Mark Slee31985722006-05-24 21:45:31 +000026
27using namespace std;
28
Mark Sleef5377b32006-10-10 01:42:59 +000029/**
30 * Global program tree
31 */
Mark Slee31985722006-05-24 21:45:31 +000032t_program* g_program;
33
Mark Sleef5377b32006-10-10 01:42:59 +000034/**
35 * Global debug state
36 */
Mark Slee31985722006-05-24 21:45:31 +000037int g_debug = 0;
38
Mark Sleef5377b32006-10-10 01:42:59 +000039/**
40 * Global time string
41 */
Mark Slee31985722006-05-24 21:45:31 +000042char* g_time_str;
43
Mark Slee31985722006-05-24 21:45:31 +000044/**
45 * Report an error to the user. This is called yyerror for historical
46 * reasons (lex and yacc expect the error reporting routine to be called
47 * this). Call this function to report any errors to the user.
48 * yyerror takes printf style arguments.
49 *
50 * @param fmt C format string followed by additional arguments
51 */
52void yyerror(char* fmt, ...) {
53 va_list args;
54 fprintf(stderr,
55 "\n!!! Error: line %d (last token was '%s')",
56 yylineno,
57 yytext);
58 fprintf(stderr, "\n!!! ");
59
60 va_start(args, fmt);
61 vfprintf(stderr, fmt, args);
62 va_end(args);
63
64 fprintf(stderr, "\n");
65}
66
67/**
68 * Prints a debug message from the parser.
69 *
70 * @param fmt C format string followed by additional arguments
71 */
72void pdebug(char* fmt, ...) {
73 if (g_debug == 0) {
74 return;
75 }
76 va_list args;
77 printf("[Parse] ");
78 va_start(args, fmt);
79 vprintf(fmt, args);
80 va_end(args);
81 printf("\n");
82}
83
84/**
85 * Prints a failure message and exits
86 *
87 * @param fmt C format string followed by additional arguments
88 */
89void failure(char* fmt, ...) {
90 va_list args;
91 fprintf(stderr, "\n!!! Failure: ");
92 va_start(args, fmt);
93 vfprintf(stderr, fmt, args);
94 va_end(args);
95 printf("\n");
96 exit(1);
97}
98
99/**
100 * Diplays the usage message and then exits with an error code.
101 */
102void usage() {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000103 fprintf(stderr, "Usage: thrift [options] file\n");
104 fprintf(stderr, "Options:\n");
Mark Slee9cb7c612006-09-01 22:17:45 +0000105 fprintf(stderr, " --cpp Generate C++ output files\n");
106 fprintf(stderr, " --java Generate Java output files\n");
107 fprintf(stderr, " --php Generate PHP output files\n");
108 fprintf(stderr, " --phpi Generate PHP inlined files\n");
Mark Sleefc89d392006-09-04 00:04:39 +0000109 fprintf(stderr, " --py Generate Python output files\n");
110 fprintf(stderr, " --debug Print parse debugging to standard output\n");
Mark Slee31985722006-05-24 21:45:31 +0000111 exit(1);
112}
113
114/**
Mark Sleef5377b32006-10-10 01:42:59 +0000115 * Parse it up.. then spit it back out, in pretty much every language. Alright
116 * not that many languages, but the cool ones that we care about.
Mark Slee31985722006-05-24 21:45:31 +0000117 */
118int main(int argc, char** argv) {
119 int i;
Mark Sleef5377b32006-10-10 01:42:59 +0000120
Mark Sleeb15a68b2006-06-07 06:46:24 +0000121 bool gen_cpp = false;
122 bool gen_java = false;
Mark Sleefc89d392006-09-04 00:04:39 +0000123 bool gen_py = false;
Mark Slee6e536442006-06-30 18:28:50 +0000124 bool gen_php = false;
Mark Sleef5377b32006-10-10 01:42:59 +0000125 bool gen_phpi = false;
Mark Sleeb15a68b2006-06-07 06:46:24 +0000126
127 // Setup time string
128 time_t now = time(NULL);
129 g_time_str = ctime(&now);
Mark Slee31985722006-05-24 21:45:31 +0000130
131 // Check for necessary arguments
Mark Sleeb15a68b2006-06-07 06:46:24 +0000132 if (argc < 2) {
133 usage();
134 }
Mark Slee31985722006-05-24 21:45:31 +0000135
Mark Sleef5377b32006-10-10 01:42:59 +0000136 // Hacky parameter handling... I didn't feel like using a library sorry!
Mark Slee31985722006-05-24 21:45:31 +0000137 for (i = 1; i < argc-1; i++) {
Mark Sleefdbee812006-09-27 18:50:48 +0000138 char* arg;
139 arg = strtok(argv[i], " ");
140 while (arg != NULL) {
141 if (strcmp(arg, "--debug") == 0) {
142 g_debug = 1;
143 } else if (strcmp(arg, "--cpp") == 0) {
144 gen_cpp = true;
145 } else if (strcmp(arg, "--java") == 0) {
146 gen_java = true;
147 } else if (strcmp(arg, "--php") == 0) {
148 gen_php = true;
Mark Sleefdbee812006-09-27 18:50:48 +0000149 } else if (strcmp(arg, "--phpi") == 0) {
Mark Sleef5377b32006-10-10 01:42:59 +0000150 gen_phpi = true;
Mark Sleefdbee812006-09-27 18:50:48 +0000151 } else if (strcmp(arg, "--py") == 0) {
152 gen_py = true;
153 } else {
154 fprintf(stderr, "!!! Unrecognized option: %s\n", arg);
155 usage();
156 }
157
158 // Tokenize more
159 arg = strtok(NULL, " ");
Mark Slee31985722006-05-24 21:45:31 +0000160 }
161 }
162
Mark Sleef5377b32006-10-10 01:42:59 +0000163 if (!gen_cpp && !gen_java && !gen_php && !gen_phpi && !gen_py) {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000164 fprintf(stderr, "!!! No output language(s) specified\n\n");
165 usage();
166 }
167
Mark Slee31985722006-05-24 21:45:31 +0000168 // Open input file
169 char* input_file = argv[i];
170 yyin = fopen(input_file, "r");
171 if (yyin == 0) {
172 failure("Could not open input file: \"%s\"", input_file);
173 }
174
175 // Extract program name by dropping directory and .thrift from filename
176 string name = input_file;
177 string::size_type slash = name.rfind("/");
178 if (slash != string::npos) {
179 name = name.substr(slash+1);
180 }
181 string::size_type dot = name.find(".");
182 if (dot != string::npos) {
183 name = name.substr(0, dot);
184 }
185
Mark Sleef5377b32006-10-10 01:42:59 +0000186 // Instance of the global parse tree
Mark Slee31985722006-05-24 21:45:31 +0000187 g_program = new t_program(name);
Mark Sleee8540632006-05-30 09:24:40 +0000188
Mark Sleef5377b32006-10-10 01:42:59 +0000189 // Parse it!
Mark Slee31985722006-05-24 21:45:31 +0000190 if (yyparse() != 0) {
191 failure("Parser error.");
192 }
193
194 // Generate code
195 try {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000196 if (gen_cpp) {
197 t_cpp_generator* cpp = new t_cpp_generator();
198 cpp->generate_program(g_program);
199 delete cpp;
200 }
201
202 if (gen_java) {
203 t_java_generator* java = new t_java_generator();
204 java->generate_program(g_program);
205 delete java;
206 }
207
Mark Slee6e536442006-06-30 18:28:50 +0000208 if (gen_php) {
Mark Sleef5377b32006-10-10 01:42:59 +0000209 t_php_generator* php = new t_php_generator(false);
Mark Slee6e536442006-06-30 18:28:50 +0000210 php->generate_program(g_program);
211 delete php;
212 }
Mark Sleefc89d392006-09-04 00:04:39 +0000213
Mark Sleef5377b32006-10-10 01:42:59 +0000214 if (gen_phpi) {
215 t_php_generator* phpi = new t_php_generator(true);
216 phpi->generate_program(g_program);
217 delete phpi;
218 }
219
Mark Sleefc89d392006-09-04 00:04:39 +0000220 if (gen_py) {
221 t_py_generator* py = new t_py_generator();
222 py->generate_program(g_program);
223 delete py;
224 }
Mark Sleef5377b32006-10-10 01:42:59 +0000225
Mark Sleee8540632006-05-30 09:24:40 +0000226 } catch (string s) {
227 printf("Error: %s\n", s.c_str());
Mark Slee31985722006-05-24 21:45:31 +0000228 } catch (const char* exc) {
229 printf("Error: %s\n", exc);
230 }
231
232 // Clean up
233 delete g_program;
234
235 // Finished
Mark Slee31985722006-05-24 21:45:31 +0000236 return 0;
237}