blob: 8d8263c1db5b9cc5068208584010d8558fdf1d57 [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"
22
23using namespace std;
24
25/** Global program tree */
26t_program* g_program;
27
28/** Global debug state */
29int g_debug = 0;
30
31/** Global time string */
32char* g_time_str;
33
34
35/**
36 * Report an error to the user. This is called yyerror for historical
37 * reasons (lex and yacc expect the error reporting routine to be called
38 * this). Call this function to report any errors to the user.
39 * yyerror takes printf style arguments.
40 *
41 * @param fmt C format string followed by additional arguments
42 */
43void yyerror(char* fmt, ...) {
44 va_list args;
45 fprintf(stderr,
46 "\n!!! Error: line %d (last token was '%s')",
47 yylineno,
48 yytext);
49 fprintf(stderr, "\n!!! ");
50
51 va_start(args, fmt);
52 vfprintf(stderr, fmt, args);
53 va_end(args);
54
55 fprintf(stderr, "\n");
56}
57
58/**
59 * Prints a debug message from the parser.
60 *
61 * @param fmt C format string followed by additional arguments
62 */
63void pdebug(char* fmt, ...) {
64 if (g_debug == 0) {
65 return;
66 }
67 va_list args;
68 printf("[Parse] ");
69 va_start(args, fmt);
70 vprintf(fmt, args);
71 va_end(args);
72 printf("\n");
73}
74
75/**
76 * Prints a failure message and exits
77 *
78 * @param fmt C format string followed by additional arguments
79 */
80void failure(char* fmt, ...) {
81 va_list args;
82 fprintf(stderr, "\n!!! Failure: ");
83 va_start(args, fmt);
84 vfprintf(stderr, fmt, args);
85 va_end(args);
86 printf("\n");
87 exit(1);
88}
89
90/**
91 * Diplays the usage message and then exits with an error code.
92 */
93void usage() {
94 fprintf(stderr, "Usage: thrift [-d] <filename>\n");
95 exit(1);
96}
97
98/**
99 * Parse it up.. then spit it back out, in pretty much every language
100 */
101int main(int argc, char** argv) {
102 int i;
103
104 // Check for necessary arguments
105 if (argc < 2) usage();
106
107 for (i = 1; i < argc-1; i++) {
108 if (strcmp(argv[i], "-d") == 0) {
109 g_debug = 1;
110 } else {
111 fprintf(stderr, "!!! Unrecognized option: %s\n", argv[i]);
112 usage();
113 }
114 }
115
116 // Setup time string
117 time_t now = time(NULL);
118 g_time_str = ctime(&now);
119
120 // Open input file
121 char* input_file = argv[i];
122 yyin = fopen(input_file, "r");
123 if (yyin == 0) {
124 failure("Could not open input file: \"%s\"", input_file);
125 }
126
127 // Extract program name by dropping directory and .thrift from filename
128 string name = input_file;
129 string::size_type slash = name.rfind("/");
130 if (slash != string::npos) {
131 name = name.substr(slash+1);
132 }
133 string::size_type dot = name.find(".");
134 if (dot != string::npos) {
135 name = name.substr(0, dot);
136 }
137
138 // Parse it
139 g_program = new t_program(name);
Mark Sleee8540632006-05-30 09:24:40 +0000140
Mark Slee31985722006-05-24 21:45:31 +0000141 if (yyparse() != 0) {
142 failure("Parser error.");
143 }
144
145 // Generate code
146 try {
147 t_cpp_generator* cpp = new t_cpp_generator();
148 cpp->generate_program(g_program);
149 delete cpp;
Mark Sleee8540632006-05-30 09:24:40 +0000150 } catch (string s) {
151 printf("Error: %s\n", s.c_str());
Mark Slee31985722006-05-24 21:45:31 +0000152 } catch (const char* exc) {
153 printf("Error: %s\n", exc);
154 }
155
156 // Clean up
157 delete g_program;
158
159 // Finished
160 printf("\nDone!\n");
161 return 0;
162}