blob: 878330938c7b4c83254fcfcad28cb58826a6c054 [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 Sleeb15a68b2006-06-07 06:46:24 +0000101 //fprintf(stderr, " -python Generate Python output files\n");
102 fprintf(stderr, " -d Print parse debugging to standard output\n");
Mark Slee31985722006-05-24 21:45:31 +0000103 exit(1);
104}
105
106/**
107 * Parse it up.. then spit it back out, in pretty much every language
108 */
109int main(int argc, char** argv) {
110 int i;
Mark Sleeb15a68b2006-06-07 06:46:24 +0000111 bool gen_cpp = false;
112 bool gen_java = false;
Mark Slee6e536442006-06-30 18:28:50 +0000113 bool gen_php = false;
Mark Sleeb15a68b2006-06-07 06:46:24 +0000114
115 // Setup time string
116 time_t now = time(NULL);
117 g_time_str = ctime(&now);
Mark Slee31985722006-05-24 21:45:31 +0000118
119 // Check for necessary arguments
Mark Sleeb15a68b2006-06-07 06:46:24 +0000120 if (argc < 2) {
121 usage();
122 }
Mark Slee31985722006-05-24 21:45:31 +0000123
124 for (i = 1; i < argc-1; i++) {
125 if (strcmp(argv[i], "-d") == 0) {
126 g_debug = 1;
Mark Sleeb15a68b2006-06-07 06:46:24 +0000127 } else if (strcmp(argv[i], "-cpp") == 0) {
128 gen_cpp = true;
129 } else if (strcmp(argv[i], "-java") == 0) {
130 gen_java = true;
Mark Slee6e536442006-06-30 18:28:50 +0000131 } else if (strcmp(argv[i], "-php") == 0) {
132 gen_php = true;
Mark Slee31985722006-05-24 21:45:31 +0000133 } else {
134 fprintf(stderr, "!!! Unrecognized option: %s\n", argv[i]);
135 usage();
136 }
137 }
138
Mark Slee6e536442006-06-30 18:28:50 +0000139 if (!gen_cpp && !gen_java && !gen_php) {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000140 fprintf(stderr, "!!! No output language(s) specified\n\n");
141 usage();
142 }
143
Mark Slee31985722006-05-24 21:45:31 +0000144 // Open input file
145 char* input_file = argv[i];
146 yyin = fopen(input_file, "r");
147 if (yyin == 0) {
148 failure("Could not open input file: \"%s\"", input_file);
149 }
150
151 // Extract program name by dropping directory and .thrift from filename
152 string name = input_file;
153 string::size_type slash = name.rfind("/");
154 if (slash != string::npos) {
155 name = name.substr(slash+1);
156 }
157 string::size_type dot = name.find(".");
158 if (dot != string::npos) {
159 name = name.substr(0, dot);
160 }
161
162 // Parse it
163 g_program = new t_program(name);
Mark Sleee8540632006-05-30 09:24:40 +0000164
Mark Slee31985722006-05-24 21:45:31 +0000165 if (yyparse() != 0) {
166 failure("Parser error.");
167 }
168
169 // Generate code
170 try {
Mark Sleeb15a68b2006-06-07 06:46:24 +0000171 if (gen_cpp) {
172 t_cpp_generator* cpp = new t_cpp_generator();
173 cpp->generate_program(g_program);
174 delete cpp;
175 }
176
177 if (gen_java) {
178 t_java_generator* java = new t_java_generator();
179 java->generate_program(g_program);
180 delete java;
181 }
182
Mark Slee6e536442006-06-30 18:28:50 +0000183 if (gen_php) {
184 t_php_generator* php = new t_php_generator();
185 php->generate_program(g_program);
186 delete php;
187 }
Mark Sleee8540632006-05-30 09:24:40 +0000188 } catch (string s) {
189 printf("Error: %s\n", s.c_str());
Mark Slee31985722006-05-24 21:45:31 +0000190 } catch (const char* exc) {
191 printf("Error: %s\n", exc);
192 }
193
194 // Clean up
195 delete g_program;
196
197 // Finished
Mark Slee31985722006-05-24 21:45:31 +0000198 return 0;
199}