diff options
| author | Roland Reichwein <mail@reichwein.it> | 2020-10-26 15:38:54 +0100 | 
|---|---|---|
| committer | Roland Reichwein <mail@reichwein.it> | 2020-10-26 15:38:54 +0100 | 
| commit | ce77838c4f32b9dc237f0c4b17d1f1e1741254d4 (patch) | |
| tree | f8b987e81bd94bff0a4035ddfe75d344664ece10 | |
| parent | addbdf3cf71c6d332bdf86a101a7df544fe5a9a2 (diff) | |
Added ProgramOpts
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | cpp.cpp | 23 | ||||
| -rw-r--r-- | cpp.h | 2 | ||||
| -rw-r--r-- | mcc.cpp | 22 | ||||
| -rw-r--r-- | programopts.cpp | 84 | ||||
| -rw-r--r-- | programopts.h | 24 | 
6 files changed, 146 insertions, 10 deletions
| @@ -71,6 +71,7 @@ PROGSRC=\      grammer.cpp \      lexer.cpp \      minicc.cpp \ +    programopts.cpp  TESTSRC=\      tests/test-cpp.cpp \ @@ -13,9 +13,12 @@  #include <functional>  #include <unordered_set>  #include <unordered_map> +#include <filesystem>  using namespace Gram; +namespace fs = std::filesystem; +  CPP::CPP(){}  CPP::~CPP(){} @@ -227,15 +230,27 @@ std::vector<Gram::TreeNode> CPP::analysis(const std::vector<Token>& tokens)  namespace {   CPP::map_type map_translation_unit { -  //{"top-level-declaration-seq", [](){}}, -  {"top-level-declaration-seq/top-level-declaration/declaration/function-definition", [](){}}, +  {"/translation-unit/top-level-declaration-seq/top-level-declaration/declaration/function-definition", [](){}},   };  } // anonymous namespace -void CPP::traverse(index_t node_id, map_type& map) +void CPP::traverse(index_t node_id, map_type& map, fs::path parent_path)  { - // TODO + fs::path current_path{parent_path / m_nodes[node_id].type}; +  + // execute callbacks + auto it{map.find(current_path.generic_string())}; + if (it != map.end()) { +  std::cout << "DEBUG: Found " << current_path << std::endl; + } + + // recurse tree + for (const auto& child_id: m_nodes[node_id].child_ids) { +  if (ChildIdIsNode(child_id)) { +   traverse(child_id, map, current_path); +  } + }  }  // Phase 7.c: Translate @@ -40,6 +40,6 @@ private:   std::vector<Token> m_charTokens; // result of phase 3   std::vector<Gram::TreeNode> m_nodes; // result of phase 7.b - void traverse(index_t node_id, map_type& map); + void traverse(index_t node_id, map_type& map, fs::path parent_path = "/");  }; @@ -5,6 +5,7 @@  #include "cpp.h"  #include "elf.h"  #include "file.h" +#include "programopts.h"  #include <iostream> @@ -12,23 +13,33 @@ using namespace std::string_literals;  namespace { -void usage() { - std::cout << "Usage: mcc <translation_unit>" << std::endl; -} + void usage() { +  std::cout << "Usage: mcc <translation_unit>" << std::endl; + }  }  int main(int argc, char* argv[])  { + // Processing of options in lambdas: each do return true iff parameter was consumed + std::map<std::string, std::function<bool(const std::string&)>> option_prefixes{ +  {"-h", [&](const std::string& parameter) -> bool { usage(); return false; }}, + }; +   try {    CPP cpp; -  if (argc != 2) { +  ProgramOpts options(argc, argv, option_prefixes); +  options.process(); + +  std::vector<std::string> parameters {options.nonOptionArguments()}; + +  if (parameters.size() != 1) {     usage();     return 1;    } -  fs::path in_filename{argv[1]}; +  fs::path in_filename{parameters[0]};    fs::path out_filename{in_filename.parent_path() / in_filename.stem()};    if (in_filename == out_filename) @@ -48,3 +59,4 @@ int main(int argc, char* argv[])   return 0;  } + diff --git a/programopts.cpp b/programopts.cpp new file mode 100644 index 0000000..aee8b05 --- /dev/null +++ b/programopts.cpp @@ -0,0 +1,84 @@ +#include "programopts.h" + +#include <algorithm> +#include <iterator> + +using namespace std::string_literals; + +namespace { + struct PrefixCmp + { +  bool operator()(const std::string& lhs, const std::string& rhs) const +  { +   return !(lhs.starts_with(rhs) || rhs.starts_with(lhs)) && lhs < rhs; +  } + }; +} + +struct ProgramOpts::impl +{ + int m_argc; + char** m_argv; + std::string m_programName; + std::vector<std::string> m_parameters; + std::map<std::string, std::function<bool(const std::string&)>, PrefixCmp> m_option_prefixes; +}; + +ProgramOpts::ProgramOpts(int argc, char* argv[], std::map<std::string, std::function<bool(const std::string&)>>& option_prefixes): + m_pimpl(std::make_unique<impl>()) +{ + m_pimpl->m_argc = argc; + m_pimpl->m_argv = argv; + if (m_pimpl->m_argc >= 1) +  m_pimpl->m_programName = m_pimpl->m_argv[0]; + //std::copy(option_prefixes.begin(), option_prefixes.end(), std::inserter(m_pimpl->m_option_prefixes, std::next(m_pimpl->m_option_prefixes.begin()))); +} + +ProgramOpts::~ProgramOpts() +{ +} + +void ProgramOpts::process() +{ + for (size_t i = 1; i < m_pimpl->m_argc; i++) { +  std::string arg{ m_pimpl->m_argv[i] }; +  if (arg.size() == 0) +   throw std::runtime_error("Empty option #"s + std::to_string(i)); + +  if (arg[0] != '-') { // non-option parameter +   m_pimpl->m_parameters.push_back(arg); +  } else { +   auto prefix_iterator = m_pimpl->m_option_prefixes.find(arg); +   if (prefix_iterator == m_pimpl->m_option_prefixes.end()) +    throw std::runtime_error("Unknown option: "s + arg); +   auto& [prefix, f] = *prefix_iterator; +   std::string optional_parameter; +   bool parameter_provided{ false }; + +   if (prefix.size() < arg.size()) { +    optional_parameter = arg.substr(prefix.size()); +   } else { +    if (i < m_pimpl->m_argc - 1) +     optional_parameter = m_pimpl->m_argv[i + 1]; +    if (optional_parameter.size() > 0 && optional_parameter[0] == '-') +     optional_parameter = ""; +    else +     parameter_provided = true; +   } +   bool parameter_consumed = f(optional_parameter); // call the function from the map +   if (parameter_provided && parameter_consumed) +    i++; // skip parameter +  } + } +} + +std::string ProgramOpts::programName() +{ + return m_pimpl->m_programName; +} + +std::vector<std::string> ProgramOpts::nonOptionArguments() +{ + return m_pimpl->m_parameters; +} + diff --git a/programopts.h b/programopts.h new file mode 100644 index 0000000..af706f7 --- /dev/null +++ b/programopts.h @@ -0,0 +1,24 @@ +// Parse command line options of program + +#pragma once + +#include <functional> +#include <map> +#include <memory> +#include <string> +#include <vector> + +class ProgramOpts +{ +public: + // Processing of options in lambdas: each do return true iff parameter was consumed + ProgramOpts(int argc, char* argv[], std::map<std::string, std::function<bool(const std::string&)>>& option_prefixes); + ~ProgramOpts(); + void process(); // must be called to run functions per option, given to ctor + std::string programName(); + std::vector<std::string> nonOptionArguments(); +private: + struct impl; + std::unique_ptr<impl> m_pimpl; +}; + | 
