#include "args.hh" #include "errors.hh" #include "grammar.hh" #include "io.hh" #include "prefix_tree.hh" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { enum class CharacterClass : uint8_t { kIdentifier = 0, kLiteral = 1, }; std::vector const kCharacterClassNames( {"Identifier", "Literal"}); std::string make_define(std::string_view filename) { std::string ret; ret.reserve(filename.size()); for (char c : filename) { if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') { ret.push_back(c); } else if (c >= 'a' && c <= 'z') { ret.push_back(static_cast(c & ~0x20)); } else { ret.push_back('_'); } } return ret; } class Generator { public: bool generate(std::string_view header_name, std::string_view source_name, std::string const& ns, grammar::Grammar& grammar); }; bool Generator::generate(std::string_view header_name, std::string_view source_name, std::string const& ns, grammar::Grammar& grammar) { std::fstream header{std::string(header_name), std::fstream::trunc | std::fstream::out}; std::fstream source{std::string(source_name), std::fstream::trunc | std::fstream::out}; auto header_guard = make_define(header_name); header << "#ifndef " << header_guard << "\n" << "#define " << header_guard << "\n" << "\n" << "namespace " << ns << " {\n" << "\n"; header << "\n" << "} // namespace " << ns << "\n" << "\n" << "#endif // " << header_guard << "\n"; source << "#include \"" << header_name << "\"\n" << "\n" << "namespace " << ns << " {\n" << "\n"; source << "\n" << "} // namespace " << ns << "\n"; return true; } } // namespace int main(int argc, char** argv) { auto args = Args::create(); auto opt_help = args->option('h', "help", "display this text and exit"); auto opt_ns = args->option_argument('\0', "namespace", "ARG", "Namespace for syntax reader"); std::vector arguments; if (!args->run(argc, argv, &arguments)) { args->print_error(std::cerr); std::cerr << "Try `gen_syntax --help` for usage\n"; return 1; } if (opt_help->is_set()) { std::cout << "Usage: `gen_syntax [OPTIONS...] syntax.grammar" << " OUTPUT.hh OUTPUT.cc`\n" << "Generates a syntax reader for grammar.\n" << "\n"; args->print_help(std::cout); return 0; } if (!opt_ns->is_set()) { std::cerr << "No namespace given.\n" << "Try `gen_syntax --help` for usage\n"; return 1; } auto ns = opt_ns->argument(); if (arguments.size() != 3) { std::cerr << "Expecting three arguments. No more, no less.\n" << "Try `gen_syntax --help` for usage\n"; return 1; } auto filename = std::string(arguments[0]); auto reader = io::open(filename); if (!reader.has_value()) { std::cerr << "Unable to open " << filename << '\n'; return 1; } auto errors = src::file_errors(std::move(filename)); auto grammar = grammar::load(std::move(reader.value()), kCharacterClassNames, *errors); if (!grammar || errors->errors() > 0) return 1; Generator generator; if (!generator.generate(arguments[1], arguments[2], ns, *grammar)) return 1; return 0; }