blob: 5cbf53e3826bf3e34770c69ba4956d3abd799569 [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 Sleefdbee812006-09-27 18:50:48 +0000129 char* arg;
130 arg = strtok(argv[i], " ");
131 while (arg != NULL) {
132 if (strcmp(arg, "--debug") == 0) {
133 g_debug = 1;
134 } else if (strcmp(arg, "--cpp") == 0) {
135 gen_cpp = true;
136 } else if (strcmp(arg, "--java") == 0) {
137 gen_java = true;
138 } else if (strcmp(arg, "--php") == 0) {
139 gen_php = true;
140 php_inline = false;
141 } else if (strcmp(arg, "--phpi") == 0) {
142 gen_php = true;
143 php_inline = true;
144 } else if (strcmp(arg, "--py") == 0) {
145 gen_py = true;
146 } else {
147 fprintf(stderr, "!!! Unrecognized option: %s\n", arg);
148 usage();
149 }
150
151 // Tokenize more
152 arg = strtok(NULL, " ");
Mark Slee31985722006-05-24 21:45:31 +0000153 }
154 }
155
Mark Sleefc89d392006-09-04 00:04:39 +0000156 if (!gen_cpp && !gen_java && !gen_php && !gen_py) {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000157 fprintf(stderr, "!!! No output language(s) specified\n\n");
158 usage();
159 }
160
Mark Slee31985722006-05-24 21:45:31 +0000161 // Open input file
162 char* input_file = argv[i];
163 yyin = fopen(input_file, "r");
164 if (yyin == 0) {
165 failure("Could not open input file: \"%s\"", input_file);
166 }
167
168 // Extract program name by dropping directory and .thrift from filename
169 string name = input_file;
170 string::size_type slash = name.rfind("/");
171 if (slash != string::npos) {
172 name = name.substr(slash+1);
173 }
174 string::size_type dot = name.find(".");
175 if (dot != string::npos) {
176 name = name.substr(0, dot);
177 }
178
179 // Parse it
180 g_program = new t_program(name);
Mark Sleee8540632006-05-30 09:24:40 +0000181
Mark Slee31985722006-05-24 21:45:31 +0000182 if (yyparse() != 0) {
183 failure("Parser error.");
184 }
185
186 // Generate code
187 try {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000188 if (gen_cpp) {
189 t_cpp_generator* cpp = new t_cpp_generator();
190 cpp->generate_program(g_program);
191 delete cpp;
192 }
193
194 if (gen_java) {
195 t_java_generator* java = new t_java_generator();
196 java->generate_program(g_program);
197 delete java;
198 }
199
Mark Slee6e536442006-06-30 18:28:50 +0000200 if (gen_php) {
Mark Slee52f643d2006-08-09 00:03:43 +0000201 t_php_generator* php = new t_php_generator(php_inline);
Mark Slee6e536442006-06-30 18:28:50 +0000202 php->generate_program(g_program);
203 delete php;
204 }
Mark Sleefc89d392006-09-04 00:04:39 +0000205
206 if (gen_py) {
207 t_py_generator* py = new t_py_generator();
208 py->generate_program(g_program);
209 delete py;
210 }
Mark Sleee8540632006-05-30 09:24:40 +0000211 } catch (string s) {
212 printf("Error: %s\n", s.c_str());
Mark Slee31985722006-05-24 21:45:31 +0000213 } catch (const char* exc) {
214 printf("Error: %s\n", exc);
215 }
216
217 // Clean up
218 delete g_program;
219
220 // Finished
Mark Slee31985722006-05-24 21:45:31 +0000221 return 0;
222}