Add simple command line tool to view the AST
This commit is contained in:
parent
d66d6d26af
commit
01b206d453
7 changed files with 358 additions and 60 deletions
|
|
@ -11,6 +11,8 @@
|
|||
#include <type_safe/reference.hpp>
|
||||
#include <type_safe/flag_set.hpp>
|
||||
|
||||
#include <cppast/detail/assert.hpp>
|
||||
|
||||
namespace cppast
|
||||
{
|
||||
/// The C++ standard that should be used.
|
||||
|
|
@ -24,6 +26,26 @@ namespace cppast
|
|||
cpp_latest = cpp_standard::cpp_14,
|
||||
};
|
||||
|
||||
/// \returns A human readable string representing the option,
|
||||
/// it is e.g. `c++14` for `cpp_14`.
|
||||
inline const char* to_string(cpp_standard standard) noexcept
|
||||
{
|
||||
switch (standard)
|
||||
{
|
||||
case cpp_standard::cpp_98:
|
||||
return "c++98";
|
||||
case cpp_standard::cpp_03:
|
||||
return "c++03";
|
||||
case cpp_standard::cpp_11:
|
||||
return "c++11";
|
||||
case cpp_standard::cpp_14:
|
||||
return "c++14";
|
||||
}
|
||||
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
return "ups";
|
||||
}
|
||||
|
||||
/// Other special compilation flags.
|
||||
enum class compile_flag
|
||||
{
|
||||
|
|
@ -32,31 +54,18 @@ namespace cppast
|
|||
ms_extensions, //< Enable MSVC extensions.
|
||||
ms_compatibility, //< Enable MSVC compatibility.
|
||||
|
||||
_count, //< \exclude
|
||||
_flag_set_size, //< \exclude
|
||||
};
|
||||
} // namespace cppast
|
||||
|
||||
namespace type_safe
|
||||
{
|
||||
/// Specialization of [ts::flag_set_traits]() to use [cppast::compile_flag]() with [ts::flag_set]().
|
||||
template <>
|
||||
struct flag_set_traits<cppast::compile_flag> : std::true_type
|
||||
{
|
||||
static constexpr std::size_t size() noexcept
|
||||
{
|
||||
return static_cast<std::size_t>(cppast::compile_flag::_count);
|
||||
}
|
||||
};
|
||||
} // namespace type_safe
|
||||
/// A [ts::flag_set]() of [cppast::compile_flag]().
|
||||
using compile_flags = type_safe::flag_set<compile_flag>;
|
||||
|
||||
namespace cppast
|
||||
{
|
||||
/// Base class for the configuration of a [cppast::parser]().
|
||||
class compile_config
|
||||
{
|
||||
public:
|
||||
/// \effects Sets the given C++ standard and compilation flags.
|
||||
void set_flags(cpp_standard standard, type_safe::flag_set<compile_flag> flags = {})
|
||||
void set_flags(cpp_standard standard, compile_flags flags = {})
|
||||
{
|
||||
do_set_flags(standard, flags);
|
||||
}
|
||||
|
|
@ -105,8 +114,7 @@ namespace cppast
|
|||
|
||||
private:
|
||||
/// \effects Sets the given C++ standard and compilation flags.
|
||||
virtual void do_set_flags(cpp_standard standard,
|
||||
type_safe::flag_set<compile_flag> flags) = 0;
|
||||
virtual void do_set_flags(cpp_standard standard, compile_flags flags) = 0;
|
||||
|
||||
/// \effects Adds the given path to the set of include directories.
|
||||
virtual void do_add_include_dir(std::string path) = 0;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace cppast
|
|||
}
|
||||
|
||||
private:
|
||||
void do_set_flags(cpp_standard standard, type_safe::flag_set<compile_flag> flags) override;
|
||||
void do_set_flags(cpp_standard standard, compile_flags flags) override;
|
||||
|
||||
void do_add_include_dir(std::string path) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,12 +10,22 @@ namespace cppast
|
|||
class cpp_entity;
|
||||
|
||||
/// Information about the state of a visit operation.
|
||||
enum class visitor_info
|
||||
struct visitor_info
|
||||
{
|
||||
leaf_entity, //< Callback called for a leaf entity without children.
|
||||
enum event_type
|
||||
{
|
||||
leaf_entity, //< Callback called for a leaf entity without children.
|
||||
/// If callback returns `false`, visit operation will be aborted.
|
||||
|
||||
container_entity_enter, //< Callback called for a container entity before the children.
|
||||
container_entity_exit, //< Callback called for a container entity after the children.
|
||||
container_entity_enter, //< Callback called for a container entity before the children.
|
||||
/// If callback returns `false`, none of the children will be visited,
|
||||
/// going immediately to the exit event.
|
||||
container_entity_exit, //< Callback called for a container entity after the children.
|
||||
/// If callback returns `false`, visit operation will be aborted.
|
||||
} event;
|
||||
bool
|
||||
last_child; //< True when the current entity is the last child of the visited parent entity.
|
||||
/// \notes It will always be `false` for the initial entity.
|
||||
};
|
||||
|
||||
/// \exclude
|
||||
|
|
@ -30,21 +40,19 @@ namespace cppast
|
|||
return func(e, info);
|
||||
}
|
||||
|
||||
bool visit(const cpp_entity& e, visitor_callback_t cb, void* functor);
|
||||
bool visit(const cpp_entity& e, visitor_callback_t cb, void* functor, bool last_child);
|
||||
} // namespace detail
|
||||
|
||||
/// Visits a [cppast::cpp_entity]().
|
||||
/// \effects If the given entity is a container, i.e. if it has child entities,
|
||||
/// calls `f(e, visitor_info::container_entity_enter)`.
|
||||
/// If that returns `true`, recursively calls `visit()` for all child entities,
|
||||
/// followed by a call to `f(e, visitor_info::container_entity_exit)`.
|
||||
/// If the given entity is not a container, calls `f(e, visitor_info::leave_entity)`.
|
||||
/// If the functor returns `false` for [cppast::visitor_info]() other than `container_entity_enter`,
|
||||
/// the visit operation is aborted.
|
||||
/// \effects Invokes the callback for the current entity,
|
||||
/// and any child entities.
|
||||
/// It will pass a reference to the current entity and the [cppast::visitor_info]().
|
||||
/// The return value of the callback controls the visit operation,
|
||||
/// the semantic depend on the [cppast::visitor_info::event_type]().
|
||||
template <typename Func>
|
||||
void visit(const cpp_entity& e, Func f)
|
||||
{
|
||||
detail::visit(e, &detail::visitor_callback<Func>, &f);
|
||||
detail::visit(e, &detail::visitor_callback<Func>, &f, false);
|
||||
}
|
||||
} // namespace cppast
|
||||
|
||||
|
|
|
|||
|
|
@ -58,8 +58,7 @@ libclang_compile_config::libclang_compile_config() : compile_config({})
|
|||
add_include_dir(CPPAST_LIBCLANG_SYSTEM_INCLUDE_DIR);
|
||||
}
|
||||
|
||||
void libclang_compile_config::do_set_flags(cpp_standard standard,
|
||||
type_safe::flag_set<compile_flag> flags)
|
||||
void libclang_compile_config::do_set_flags(cpp_standard standard, compile_flags flags)
|
||||
{
|
||||
switch (standard)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,58 +24,65 @@ using namespace cppast;
|
|||
namespace
|
||||
{
|
||||
template <typename T>
|
||||
bool handle_container(const cpp_entity& e, detail::visitor_callback_t cb, void* functor)
|
||||
bool handle_container(const cpp_entity& e, detail::visitor_callback_t cb, void* functor,
|
||||
bool last_child)
|
||||
{
|
||||
auto& container = static_cast<const T&>(e);
|
||||
|
||||
auto handle_children = cb(functor, container, visitor_info::container_entity_enter);
|
||||
auto handle_children =
|
||||
cb(functor, container, {visitor_info::container_entity_enter, last_child});
|
||||
if (handle_children)
|
||||
{
|
||||
for (auto& child : container)
|
||||
if (!detail::visit(child, cb, functor))
|
||||
for (auto iter = container.begin(); iter != container.end();)
|
||||
{
|
||||
auto& cur = *iter;
|
||||
++iter;
|
||||
if (!detail::visit(cur, cb, functor, iter == container.end()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return cb(functor, container, visitor_info::container_entity_exit);
|
||||
return cb(functor, container, {visitor_info::container_entity_exit, last_child});
|
||||
}
|
||||
}
|
||||
|
||||
bool detail::visit(const cpp_entity& e, detail::visitor_callback_t cb, void* functor)
|
||||
bool detail::visit(const cpp_entity& e, detail::visitor_callback_t cb, void* functor,
|
||||
bool last_child)
|
||||
{
|
||||
switch (e.kind())
|
||||
{
|
||||
case cpp_entity_kind::file_t:
|
||||
return handle_container<cpp_file>(e, cb, functor);
|
||||
return handle_container<cpp_file>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::language_linkage_t:
|
||||
return handle_container<cpp_language_linkage>(e, cb, functor);
|
||||
return handle_container<cpp_language_linkage>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::namespace_t:
|
||||
return handle_container<cpp_namespace>(e, cb, functor);
|
||||
return handle_container<cpp_namespace>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::enum_t:
|
||||
return handle_container<cpp_enum>(e, cb, functor);
|
||||
return handle_container<cpp_enum>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::class_t:
|
||||
return handle_container<cpp_class>(e, cb, functor);
|
||||
return handle_container<cpp_class>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::function_t:
|
||||
return handle_container<cpp_function>(e, cb, functor);
|
||||
return handle_container<cpp_function>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::member_function_t:
|
||||
return handle_container<cpp_member_function>(e, cb, functor);
|
||||
return handle_container<cpp_member_function>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::conversion_op_t:
|
||||
return handle_container<cpp_conversion_op>(e, cb, functor);
|
||||
return handle_container<cpp_conversion_op>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::constructor_t:
|
||||
return handle_container<cpp_constructor>(e, cb, functor);
|
||||
return handle_container<cpp_constructor>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::template_template_parameter_t:
|
||||
return handle_container<cpp_template_template_parameter>(e, cb, functor);
|
||||
return handle_container<cpp_template_template_parameter>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::alias_template_t:
|
||||
return handle_container<cpp_alias_template>(e, cb, functor);
|
||||
return handle_container<cpp_alias_template>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::variable_template_t:
|
||||
return handle_container<cpp_variable_template>(e, cb, functor);
|
||||
return handle_container<cpp_variable_template>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::function_template_t:
|
||||
return handle_container<cpp_function_template>(e, cb, functor);
|
||||
return handle_container<cpp_function_template>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::function_template_specialization_t:
|
||||
return handle_container<cpp_function_template_specialization>(e, cb, functor);
|
||||
return handle_container<cpp_function_template_specialization>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::class_template_t:
|
||||
return handle_container<cpp_class_template>(e, cb, functor);
|
||||
return handle_container<cpp_class_template>(e, cb, functor, last_child);
|
||||
case cpp_entity_kind::class_template_specialization_t:
|
||||
return handle_container<cpp_class_template_specialization>(e, cb, functor);
|
||||
return handle_container<cpp_class_template_specialization>(e, cb, functor, last_child);
|
||||
|
||||
case cpp_entity_kind::macro_definition_t:
|
||||
case cpp_entity_kind::include_directive_t:
|
||||
|
|
@ -95,7 +102,7 @@ bool detail::visit(const cpp_entity& e, detail::visitor_callback_t cb, void* fun
|
|||
case cpp_entity_kind::template_type_parameter_t:
|
||||
case cpp_entity_kind::non_type_template_parameter_t:
|
||||
case cpp_entity_kind::unexposed_t:
|
||||
return cb(functor, e, visitor_info::leaf_entity);
|
||||
return cb(functor, e, {visitor_info::leaf_entity, last_child});
|
||||
|
||||
case cpp_entity_kind::count:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ unsigned test_visit(const cppast::cpp_file& file, Func f, bool check_code = true
|
|||
{
|
||||
auto count = 0u;
|
||||
cppast::visit(file, [&](const cppast::cpp_entity& e, cppast::visitor_info info) {
|
||||
if (info == cppast::visitor_info::container_entity_exit)
|
||||
if (info.event == cppast::visitor_info::container_entity_exit)
|
||||
return true; // already handled
|
||||
|
||||
if (e.kind() == T::kind())
|
||||
|
|
|
|||
278
tool/main.cpp
278
tool/main.cpp
|
|
@ -4,6 +4,282 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
int main()
|
||||
#include <cxxopts.hpp>
|
||||
|
||||
#include <cppast/libclang_parser.hpp> // for libclang_parser, libclang_compile_config, cpp_entity,...
|
||||
#include <cppast/visitor.hpp> // for visit()
|
||||
#include <cppast/code_generator.hpp> // for generate_code()
|
||||
#include <cppast/cpp_entity_kind.hpp> // for the cpp_entity_kind definition
|
||||
#include <cppast/cpp_namespace.hpp> // for cpp_namespace
|
||||
|
||||
// print help options
|
||||
void print_help(const cxxopts::Options& options)
|
||||
{
|
||||
std::cout << options.help({"", "compilation"}) << '\n';
|
||||
}
|
||||
|
||||
// print error message
|
||||
void print_error(const std::string& msg)
|
||||
{
|
||||
std::cerr << msg << '\n';
|
||||
}
|
||||
|
||||
// prints the AST entry of a cpp_entity (base class for all entities),
|
||||
// will only print a single line
|
||||
void print_entity(std::ostream& out, const cppast::cpp_entity& e)
|
||||
{
|
||||
// print name and the kind of the entity
|
||||
out << e.name() << " (" << cppast::to_string(e.kind()) << ")";
|
||||
|
||||
if (e.kind() == cppast::cpp_entity_kind::language_linkage_t)
|
||||
// no need to print additional information for language linkages
|
||||
out << '\n';
|
||||
else if (e.kind() == cppast::cpp_entity_kind::namespace_t)
|
||||
{
|
||||
// cast to cpp_namespace
|
||||
auto& ns = static_cast<const cppast::cpp_namespace&>(e);
|
||||
// print whether or not it is inline
|
||||
if (ns.is_inline())
|
||||
out << " [inline]";
|
||||
out << '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
// print the declaration of the entity
|
||||
// it will only use a single line
|
||||
// derive from code_generator and implement various callbacks for printing
|
||||
// it will print into a std::string
|
||||
class code_generator : public cppast::code_generator
|
||||
{
|
||||
std::string str_; // the result
|
||||
bool was_newline_ = false; // whether or not the last token was a newline
|
||||
// needed for lazily printing them
|
||||
|
||||
public:
|
||||
code_generator(const cppast::cpp_entity& e)
|
||||
{
|
||||
// kickoff code generation here
|
||||
cppast::generate_code(*this, e);
|
||||
}
|
||||
|
||||
// return the result
|
||||
const std::string& str() const noexcept
|
||||
{
|
||||
return str_;
|
||||
}
|
||||
|
||||
private:
|
||||
// called at the beginning of the code generation of a container entity (i.e. one with child)
|
||||
synopsis_options on_container_begin(const cppast::cpp_entity&) override
|
||||
{
|
||||
// generate declaration only
|
||||
return synopsis_options::declaration;
|
||||
}
|
||||
|
||||
// called before code generation of a leaf entity
|
||||
synopsis_options on_leaf(const cppast::cpp_entity&) override
|
||||
{
|
||||
// generate declaration only
|
||||
return synopsis_options::declaration;
|
||||
}
|
||||
|
||||
// no need to handle indentation, as only a single line is used
|
||||
void do_indent() override
|
||||
{
|
||||
}
|
||||
void do_unindent() override
|
||||
{
|
||||
}
|
||||
|
||||
// called when a generic token sequence should be generated
|
||||
// there are specialized callbacks for various token kinds,
|
||||
// to e.g. implement syntax highlighting
|
||||
void do_write_token_seq(cppast::string_view tokens) override
|
||||
{
|
||||
if (was_newline_)
|
||||
{
|
||||
// lazily append newline as space
|
||||
str_ += ' ';
|
||||
was_newline_ = false;
|
||||
}
|
||||
// append tokens
|
||||
str_ += tokens.c_str();
|
||||
}
|
||||
|
||||
// called when a newline should be generated
|
||||
// we're lazy as it will always generate a trailing newline,
|
||||
// we don't want
|
||||
void do_write_newline() override
|
||||
{
|
||||
was_newline_ = true;
|
||||
}
|
||||
|
||||
} generator(e);
|
||||
// print generated code
|
||||
out << ": `" << generator.str() << '`' << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
// prints the AST of a file
|
||||
void print_ast(std::ostream& out, const cppast::cpp_file& file)
|
||||
{
|
||||
// print file name
|
||||
out << "AST for '" << file.name() << "':\n";
|
||||
std::string prefix; // the current prefix string
|
||||
// recursively visit file and all children
|
||||
cppast::visit(file, [&](const cppast::cpp_entity& e, cppast::visitor_info info) {
|
||||
if (e.kind() == cppast::cpp_entity_kind::file_t)
|
||||
// no need to do anything for a file
|
||||
// return value of true continues visit
|
||||
return true;
|
||||
else if (info.event == cppast::visitor_info::container_entity_exit)
|
||||
{
|
||||
// we have visited all children of a container,
|
||||
// remove prefix
|
||||
prefix.pop_back();
|
||||
prefix.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
out << prefix; // print prefix for previous entities
|
||||
// calculate next prefix
|
||||
if (info.last_child)
|
||||
{
|
||||
if (info.event == cppast::visitor_info::container_entity_enter)
|
||||
prefix += " ";
|
||||
out << "+-";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (info.event == cppast::visitor_info::container_entity_enter)
|
||||
prefix += "| ";
|
||||
out << "|-";
|
||||
}
|
||||
|
||||
print_entity(out, e);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// parse a file
|
||||
std::unique_ptr<cppast::cpp_file> parse_file(const cppast::libclang_compile_config& config,
|
||||
const cppast::diagnostic_logger& logger,
|
||||
const std::string& filename, bool fatal_error) try
|
||||
{
|
||||
// the entity index is used to resolve cross references in the AST
|
||||
// we don't need that, so it will not be needed afterwards
|
||||
cppast::cpp_entity_index idx;
|
||||
// the parser is used to parse the entity
|
||||
// there can be multiple parser implementations
|
||||
cppast::libclang_parser parser(type_safe::ref(logger));
|
||||
// parse the file
|
||||
auto file = parser.parse(idx, filename, config);
|
||||
if (fatal_error && logger.error_logged())
|
||||
return nullptr;
|
||||
return file;
|
||||
}
|
||||
catch (const cppast::libclang_error& ex)
|
||||
{
|
||||
print_error(std::string("[fatal parsing error] ") + ex.what());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
cxxopts::Options options("cppast",
|
||||
"cppast - The commandline interface to the cppast library.\n");
|
||||
// clang-format off
|
||||
options.add_options()
|
||||
("h,help", "display this help and exit")
|
||||
("version", "display version information and exit")
|
||||
("v,verbose", "be verbose when parsing")
|
||||
("fatal_errors", "abort program when a parser error occurs, instead of doing error correction")
|
||||
("file", "the file that is being parsed (last positional argument)",
|
||||
cxxopts::value<std::string>());
|
||||
options.add_options("compilation")
|
||||
("std", "set the C++ standard (c++98, c++03, c++11, c++14)",
|
||||
cxxopts::value<std::string>()->default_value(cppast::to_string(cppast::cpp_standard::cpp_latest)))
|
||||
("I,include_directory", "add directory to include search path",
|
||||
cxxopts::value<std::vector<std::string>>())
|
||||
("D,macro_definition", "define a macro on the command line",
|
||||
cxxopts::value<std::vector<std::string>>())
|
||||
("U,macro_undefinition", "undefine a macro on the command line",
|
||||
cxxopts::value<std::vector<std::string>>())
|
||||
("gnu_extensions", "enable GNU extensions (equivalent to -std=gnu++XX)")
|
||||
("msvc_extensions", "enable MSVC extensions (equivalent to -fms-extensions)")
|
||||
("msvc_compatibility", "enable MSVC compatibility (equivalent to -fms-compatibility)");
|
||||
// clang-format on
|
||||
options.parse_positional("file");
|
||||
options.parse(argc, argv);
|
||||
|
||||
if (options.count("help"))
|
||||
print_help(options);
|
||||
else if (options.count("version"))
|
||||
{
|
||||
std::cout << "cppast version 0.0\n";
|
||||
std::cout << "Copyright (C) Jonathan Müller 2017 <jonathanmueller.dev@gmail.com>\n";
|
||||
std::cout << '\n';
|
||||
std::cout << "Using libclang version " << CPPAST_CLANG_VERSION_STRING << '\n';
|
||||
}
|
||||
else if (!options.count("file") || options["file"].as<std::string>().empty())
|
||||
{
|
||||
print_error("missing file argument");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the compile config stores compilation flags
|
||||
cppast::libclang_compile_config config;
|
||||
|
||||
if (options.count("include_directory"))
|
||||
for (auto& include : options["include_directory"].as<std::vector<std::string>>())
|
||||
config.add_include_dir(include);
|
||||
if (options.count("macro_definition"))
|
||||
for (auto& macro : options["macro_definition"].as<std::vector<std::string>>())
|
||||
{
|
||||
auto equal = macro.find('=');
|
||||
auto name = macro.substr(0, equal);
|
||||
auto def = equal == std::string::npos ? macro.substr(equal + 1u) : "";
|
||||
config.define_macro(std::move(name), std::move(def));
|
||||
}
|
||||
if (options.count("macro_undefinition"))
|
||||
for (auto& name : options["macro_undefinition"].as<std::vector<std::string>>())
|
||||
config.undefine_macro(name);
|
||||
|
||||
// the compile_flags are generic flags
|
||||
cppast::compile_flags flags;
|
||||
if (options.count("gnu_extensions"))
|
||||
flags |= cppast::compile_flag::gnu_extensions;
|
||||
if (options.count("msvc_extensions"))
|
||||
flags |= cppast::compile_flag::ms_extensions;
|
||||
if (options.count("msvc_compatibility"))
|
||||
flags |= cppast::compile_flag::ms_compatibility;
|
||||
|
||||
if (options["std"].as<std::string>() == "c++98")
|
||||
config.set_flags(cppast::cpp_standard::cpp_98, flags);
|
||||
else if (options["std"].as<std::string>() == "c++03")
|
||||
config.set_flags(cppast::cpp_standard::cpp_03, flags);
|
||||
else if (options["std"].as<std::string>() == "c++11")
|
||||
config.set_flags(cppast::cpp_standard::cpp_11, flags);
|
||||
else if (options["std"].as<std::string>() == "c++14")
|
||||
config.set_flags(cppast::cpp_standard::cpp_14, flags);
|
||||
else
|
||||
{
|
||||
print_error("invalid value '" + options["std"].as<std::string>() + "' for std flag");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// the logger is used to print diagnostics
|
||||
cppast::stderr_diagnostic_logger logger;
|
||||
if (options.count("verbose"))
|
||||
logger.set_verbose(true);
|
||||
|
||||
auto file = parse_file(config, logger, options["file"].as<std::string>(),
|
||||
options.count("fatal_errors") == 1u);
|
||||
if (!file)
|
||||
return 2;
|
||||
print_ast(std::cout, *file);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue