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