48int main(
int argc,
char* argv[]) {
49 std::string input_file;
50 std::string output_file;
52 bool dump_ast =
false;
53 bool preprocess_only =
false;
54 std::vector<std::pair<std::string, std::string>> predefined_macros;
56 auto args = std::span(argv, argc);
63 for (
int i = 1; i < argc; ++i) {
64 std::string_view arg = args[i];
66 if (!arg.starts_with(
'-')) {
67 if (!input_file.empty()) {
68 std::cerr <<
"Error: Only one input file can be specified.\n";
77 std::cerr <<
"Error: -o requires an argument\n";
80 output_file = args[++i];
81 }
else if (arg ==
"-m") {
83 std::cerr <<
"Error: -m requires an argument\n";
86 std::string_view mode_str = args[++i];
87 if (mode_str ==
"single") {
89 }
else if (mode_str !=
"expr") {
90 std::cerr << std::format(
91 "Error: Invalid mode '{}'. Use 'expr' or 'single'.\n",
92 std::string(mode_str));
95 }
else if (arg ==
"-D") {
97 std::cerr <<
"Error: -D requires an argument\n";
100 std::string_view macro_def = args[++i];
101 size_t eq_pos = macro_def.find(
'=');
102 if (eq_pos != std::string_view::npos) {
103 std::string name(macro_def.substr(0, eq_pos));
104 std::string value(macro_def.substr(eq_pos + 1));
105 predefined_macros.emplace_back(std::move(name),
108 predefined_macros.emplace_back(std::string(macro_def),
"");
110 }
else if (arg ==
"--dump-ast") {
112 }
else if (arg ==
"-E") {
113 preprocess_only =
true;
115 std::cerr << std::format(
"Error: Unknown option '{}'\n",
122 if (input_file.empty()) {
123 std::cerr <<
"Error: No input file specified.\n";
128 if (preprocess_only) {
130 std::cerr <<
"Error: --dump-ast and -E cannot be used together\n";
133 if (!output_file.empty()) {
134 std::cerr <<
"Error: -o and -E cannot be used together\n";
138 if (output_file.empty()) {
139 std::cerr <<
"Error: Output file must be specified with -o\n";
145 std::ifstream in_stream(input_file);
147 std::cerr << std::format(
"Error: Cannot open input file '{}'\n",
151 std::stringstream buffer;
152 buffer << in_stream.rdbuf();
153 std::string source = buffer.str();
167 for (
const auto& [name, value] : predefined_macros) {
173 if (!preprocess_result.success) {
174 std::cerr <<
"Preprocessing errors:\n";
175 for (
const auto& error : preprocess_result.errors) {
176 std::cerr << error <<
"\n";
181 if (preprocess_only) {
182 std::cout <<
"=== Preprocessed Code ===\n";
183 std::cout << preprocess_result.source <<
"\n";
184 std::cout <<
"\n=== Macro Expansion Trace ===\n";
186 std::string expansion_info =
188 if (expansion_info.empty()) {
189 std::cout <<
"(No macro expansions)\n";
191 std::cout << expansion_info;
197 Tokenizer tokenizer(preprocess_result.source);
203 0, preprocess_result.line_map,
204 preprocess_result.library_line_count);
210 std::cout <<
"--- AST Dump ---\n"
212 <<
"--- End AST Dump ---\n";
218 std::cerr << std::format(
"Analysis errors:\n{}\n", diagnostics);
221 if (!diagnostics.empty()) {
222 std::cerr << std::format(
"Analysis warnings:\n{}\n", diagnostics);
227 std::ofstream out_stream(output_file);
229 std::cerr << std::format(
"Error: Cannot open output file '{}'\n",
233 out_stream << postfix_code <<
'\n';
235 std::cout << std::format(
"Successfully converted '{}' to '{}'\n",
236 input_file, output_file);
238 }
catch (
const std::exception& e) {
239 std::cerr << std::format(
"An error occurred: {}\n", e.what());
std::string print(const Program *program)
const Program * getAST() const
std::string formatDiagnostics() const
std::string generateCode()
static std::string formatMacroExpansions(const std::vector< LineMapping > &line_map)
std::vector< Token > tokenize()
int main(int argc, char *argv[])