/** * \file stefan.cpp * \brief Stefan's Main Program * \author Stefan Reuther */ INTERFACE: IMPLEMENTATION: #include #include #include #include #include #include // perror #include #include #include #include #include #include "except.h" #include "source.h" #include "annotator.h" #include "symbol_table.h" #include "scope.h" #include "namespace.h" #include "annotation.h" #ifdef USE_BACKTRACER # include "debug.h" #endif #undef USE_REALLOC static /*const*/ char cpp_name[] = "cpp"; static std::vector prepro_args; static std::vector input_files; class Program_from_fd : public Opencxx::Program { }; static bool change_alloc(char*& buffer, std::size_t olds, std::size_t news) { using namespace std; char* p = new char[news]; if (!p) return false; memcpy(p, buffer, olds > news ? news : olds); delete[] buffer; buffer = p; return true; } PUBLIC Program_from_fd::Program_from_fd(/*const*/ char* filename, int fd) : Program(filename) { std::size_t buf_size = 10240; std::size_t amount_read = 0; bool verbose = Symbol_table::has_dump_flag('V'); #ifdef USE_REALLOC buf = static_cast(std::malloc(buf_size)); #else buf = new char[buf_size]; #endif if (verbose) std::cout << " allocated " << buf_size << " bytes at " << (void*)buf << "\n"; ssize_t n; while ((n = read(fd, buf + amount_read, buf_size - amount_read)) > 0) { amount_read += n; if (amount_read >= buf_size) { // FIXME: error checking #ifdef USE_REALLOC buf_size *= 2; char* p = static_cast(realloc(buf, buf_size)); if (!p) compile_error("out of memory"); #else std::size_t old_size = buf_size; buf_size *= 2; if (!change_alloc(buf, old_size, buf_size)) compile_error("out of memory"); #endif if (verbose) std::cout << " allocated " << buf_size << " bytes at " << (void*)buf << "\n"; } } if (n < 0) std::perror("read"); } PUBLIC Program_from_fd::~Program_from_fd() { std::free(buf); } static bool process(/*const*/ char* file_name) { std::size_t len = std::strlen(file_name); if (len >= 3 && (std::memcmp(file_name + len - 3, ".ii", 3) == 0 || std::memcmp(file_name + len - 2, ".i", 2) == 0)) { if (Symbol_table::has_dump_flag('v')) std::cout << "Parsing...\n"; Source::instance().parse(file_name); return true; } else { int pipe_fd[2]; if (pipe(pipe_fd) < 0) { std::perror("pipe"); return false; } int pid = fork(); if (pid < 0) { std::perror("fork"); return false; } if (pid == 0) { /* Child */ std::vector exec_args; exec_args.push_back(cpp_name); for (std::size_t i = 0; i < prepro_args.size(); ++i) exec_args.push_back(prepro_args[i]); exec_args.push_back(file_name); exec_args.push_back(0); dup2(pipe_fd[1], 1); close(pipe_fd[1]); /* Library DR 69 says vectors must be continguous */ execvp(cpp_name, &exec_args[0]); std::perror(cpp_name); std::exit(255); } /* Parent */ close(pipe_fd[1]); Opencxx::Program* prog = new Program_from_fd(file_name, pipe_fd[0]); close(pipe_fd[0]); wait(0); if (Symbol_table::has_dump_flag('v')) std::cout << "Parsing...\n"; Source::instance().parse(file_name, prog); return true; } } static void init_default_symbols(Abstract_scope* s) { s->add_function_decl(s_Extern, 0, make_unary_function_type(size_type, void_type.make_pointer_type()), Symbol_name(Symbol_name::NEW_OPERATOR_NAME, s, Symbol_name::k_Alloc)); s->add_function_decl(s_Extern, 0, make_unary_function_type(size_type, void_type.make_pointer_type()), Symbol_name(Symbol_name::ANEW_OPERATOR_NAME, s, Symbol_name::k_Alloc)); s->add_function_decl(s_Extern, 0, make_unary_function_type(void_type.make_pointer_type(), void_type), Symbol_name(Symbol_name::DELETE_OPERATOR_NAME, s, Symbol_name::k_Alloc)); s->add_function_decl(s_Extern, 0, make_unary_function_type(void_type.make_pointer_type(), void_type), Symbol_name(Symbol_name::ADELETE_OPERATOR_NAME, s, Symbol_name::k_Alloc)); } int main (int argc, char** argv) { #ifdef USE_BACKTRACER initDebug(); #endif try { /* Ugly option parser */ bool reading = true; while (*++argv) { char* p = *argv; if (reading && *p == '-') { if (p[1] == 0) { input_files.push_back("-"); } else if (p[1] == '-' && p[2] == 0) { reading = false; } else { switch(p[1]) { case 'd': Symbol_table::dump_flags = &p[1]; break; case 'D': case 'I': case 'U': prepro_args.push_back(p); break; case 'S': std::cout.setf(std::cout.unitbuf); break; default: std::cerr << "unrecognized option: " << p << "\n"; return 1; } } } else { input_files.push_back(p); } } if (input_files.empty()) { std::cerr << "No input files.\n"; return 1; } /* Process all files */ Namespace_scope* nss = new Namespace_scope(0, std::string()); init_default_symbols(nss); for (unsigned i = 0; i < input_files.size(); ++i) { if (Symbol_table::has_dump_flag('v')) std::cout << "Reading " << input_files[i] << "...\n"; if (! process(input_files[i])) continue; if (Symbol_table::has_dump_flag('v')) std::cout << "Starting annotator run...\n"; Annotator reader(&Source::instance(), nss); reader.visit(); if (Symbol_table::has_dump_flag('v')) std::cout << "Filling in symbol names...\n"; for (Symbol_table::Sym_it i = Symbol_table::get_instance().begin(); i != Symbol_table::get_instance().end(); ++i) if (Function_symbol* fsym = dynamic_cast(i->second.untag)) fsym->fill_in_mangled_names(false); if (Symbol_table::has_dump_flag('t')) { Symbol_table::get_instance().dump(std::cout); } if (Symbol_table::has_dump_flag('s')) { std::cout << "Semantics of translation unit:\n"; print_annotated_tree(std::cout, "# ", reader.get_output(), Symbol_table::has_dump_flag('c')); std::cout << "\n"; } } } catch(std::exception& e) { std::cerr << "error[E]: " << e.what() << "\n"; return 1; } catch(std::string& s) { std::cerr << "error[S]: " << s << "\n"; return 1; } catch(const char* c) { std::cerr << "error[PC]: " << c << "\n"; return 1; } catch(...) { std::cerr << "unknown flying object.\n"; return 1; } if (Compile_error::had_errors) { std::cerr << "compilation had errors.\n"; return 1; } }