blob: 6a7faf8c16edd375c45f5713f0e4d34c2bda88ff [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 Slee31985722006-05-24 21:45:31 +000024
25using namespace std;
26
27/** Global program tree */
28t_program* g_program;
29
30/** Global debug state */
31int g_debug = 0;
32
33/** Global time string */
34char* g_time_str;
35
36
37/**
38 * Report an error to the user. This is called yyerror for historical
39 * reasons (lex and yacc expect the error reporting routine to be called
40 * this). Call this function to report any errors to the user.
41 * yyerror takes printf style arguments.
42 *
43 * @param fmt C format string followed by additional arguments
44 */
45void yyerror(char* fmt, ...) {
46 va_list args;
47 fprintf(stderr,
48 "\n!!! Error: line %d (last token was '%s')",
49 yylineno,
50 yytext);
51 fprintf(stderr, "\n!!! ");
52
53 va_start(args, fmt);
54 vfprintf(stderr, fmt, args);
55 va_end(args);
56
57 fprintf(stderr, "\n");
58}
59
60/**
61 * Prints a debug message from the parser.
62 *
63 * @param fmt C format string followed by additional arguments
64 */
65void pdebug(char* fmt, ...) {
66 if (g_debug == 0) {
67 return;
68 }
69 va_list args;
70 printf("[Parse] ");
71 va_start(args, fmt);
72 vprintf(fmt, args);
73 va_end(args);
74 printf("\n");
75}
76
77/**
78 * Prints a failure message and exits
79 *
80 * @param fmt C format string followed by additional arguments
81 */
82void failure(char* fmt, ...) {
83 va_list args;
84 fprintf(stderr, "\n!!! Failure: ");
85 va_start(args, fmt);
86 vfprintf(stderr, fmt, args);
87 va_end(args);
88 printf("\n");
89 exit(1);
90}
91
92/**
93 * Diplays the usage message and then exits with an error code.
94 */
95void usage() {
Mark Sleeb15a68b2006-06-07 06:46:24 +000096 fprintf(stderr, "Usage: thrift [options] file\n");
97 fprintf(stderr, "Options:\n");
98 fprintf(stderr, " -cpp Generate C++ output files\n");
99 fprintf(stderr, " -java Generate Java output files\n");
Mark Slee6e536442006-06-30 18:28:50 +0000100 fprintf(stderr, " -php Generate PHP output files\n");
Mark Slee52f643d2006-08-09 00:03:43 +0000101 fprintf(stderr, " -phpi Generate PHP inlined files\n");
Mark Sleeb15a68b2006-06-07 06:46:24 +0000102 //fprintf(stderr, " -python Generate Python output files\n");
103 fprintf(stderr, " -d Print parse debugging to standard output\n");
Mark Slee31985722006-05-24 21:45:31 +0000104 exit(1);
105}
106
107/**
108 * Parse it up.. then spit it back out, in pretty much every language
109 */
110int main(int argc, char** argv) {
111 int i;
Mark Sleeb15a68b2006-06-07 06:46:24 +0000112 bool gen_cpp = false;
113 bool gen_java = false;
Mark Slee6e536442006-06-30 18:28:50 +0000114 bool gen_php = false;
Mark Slee52f643d2006-08-09 00:03:43 +0000115 bool php_inline = false;
Mark Sleeb15a68b2006-06-07 06:46:24 +0000116
117 // Setup time string
118 time_t now = time(NULL);
119 g_time_str = ctime(&now);
Mark Slee31985722006-05-24 21:45:31 +0000120
121 // Check for necessary arguments
Mark Sleeb15a68b2006-06-07 06:46:24 +0000122 if (argc < 2) {
123 usage();
124 }
Mark Slee31985722006-05-24 21:45:31 +0000125
126 for (i = 1; i < argc-1; i++) {
127 if (strcmp(argv[i], "-d") == 0) {
128 g_debug = 1;
Mark Sleeb15a68b2006-06-07 06:46:24 +0000129 } else if (strcmp(argv[i], "-cpp") == 0) {
130 gen_cpp = true;
131 } else if (strcmp(argv[i], "-java") == 0) {
132 gen_java = true;
Mark Slee6e536442006-06-30 18:28:50 +0000133 } else if (strcmp(argv[i], "-php") == 0) {
134 gen_php = true;
Mark Slee52f643d2006-08-09 00:03:43 +0000135 php_inline = false;
136 } else if (strcmp(argv[i], "-phpi") == 0) {
137 gen_php = true;
138 php_inline = true;
Mark Slee31985722006-05-24 21:45:31 +0000139 } else {
140 fprintf(stderr, "!!! Unrecognized option: %s\n", argv[i]);
141 usage();
142 }
143 }
144
Mark Slee6e536442006-06-30 18:28:50 +0000145 if (!gen_cpp && !gen_java && !gen_php) {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000146 fprintf(stderr, "!!! No output language(s) specified\n\n");
147 usage();
148 }
149
Mark Slee31985722006-05-24 21:45:31 +0000150 // Open input file
151 char* input_file = argv[i];
152 yyin = fopen(input_file, "r");
153 if (yyin == 0) {
154 failure("Could not open input file: \"%s\"", input_file);
155 }
156
157 // Extract program name by dropping directory and .thrift from filename
158 string name = input_file;
159 string::size_type slash = name.rfind("/");
160 if (slash != string::npos) {
161 name = name.substr(slash+1);
162 }
163 string::size_type dot = name.find(".");
164 if (dot != string::npos) {
165 name = name.substr(0, dot);
166 }
167
168 // Parse it
169 g_program = new t_program(name);
Mark Sleee8540632006-05-30 09:24:40 +0000170
Mark Slee31985722006-05-24 21:45:31 +0000171 if (yyparse() != 0) {
172 failure("Parser error.");
173 }
174
175 // Generate code
176 try {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000177 if (gen_cpp) {
178 t_cpp_generator* cpp = new t_cpp_generator();
179 cpp->generate_program(g_program);
180 delete cpp;
181 }
182
183 if (gen_java) {
184 t_java_generator* java = new t_java_generator();
185 java->generate_program(g_program);
186 delete java;
187 }
188
Mark Slee6e536442006-06-30 18:28:50 +0000189 if (gen_php) {
Mark Slee52f643d2006-08-09 00:03:43 +0000190 t_php_generator* php = new t_php_generator(php_inline);
Mark Slee6e536442006-06-30 18:28:50 +0000191 php->generate_program(g_program);
192 delete php;
193 }
Mark Sleee8540632006-05-30 09:24:40 +0000194 } catch (string s) {
195 printf("Error: %s\n", s.c_str());
Mark Slee31985722006-05-24 21:45:31 +0000196 } catch (const char* exc) {
197 printf("Error: %s\n", exc);
198 }
199
200 // Clean up
201 delete g_program;
202
203 // Finished
Mark Slee31985722006-05-24 21:45:31 +0000204 return 0;
205}