Compare commits

...

3 Commits

Author SHA1 Message Date
codeboss d0fa2671fa 1 2024-10-02 00:03:59 +08:00
codeboss 637e7c5a23 1 2024-10-01 23:23:54 +08:00
codeboss cae32e3215 1 2024-10-01 18:17:40 +08:00
3 changed files with 297 additions and 182 deletions

View File

@ -1,4 +1,5 @@
#include "argsparser.h" #include "argsparser.h"
#include <QVariant>
using namespace args_parse; using namespace args_parse;
using namespace std; using namespace std;
@ -14,27 +15,27 @@ QString __ArgvPackImpls::means() const {
return means_store; return means_store;
} }
void __ArgvPackImpls::setValue(const QString& v) { void __ArgvPackImpls::setValue(const QVariant& v) {
this->value_store = v; this->value_store = v;
} }
QString __ArgvPackImpls::value() const { QVariant __ArgvPackImpls::value() const {
return value_store; return value_store;
} }
FloatKeyValue::FloatKeyValue(const QString& key, const QString& means, bool optional) : FloatKeyValue::FloatKeyValue(const QString& key, const QString& means, bool optional) :
__FloatArgvImpl(key, means, optional) { } __FloatArgvImpls(key, means, optional) { }
QString __FloatArgvImpl::bindKey() const { QString __FloatArgvImpls::bindKey() const {
return key_name; return key_name;
} }
bool __FloatArgvImpl::optional() const { bool __FloatArgvImpls::optional() const {
return optional_value; return optional_value;
} }
QString args_parse::FloatKeyValue::placeHolder() const { QString args_parse::FloatKeyValue::placeHolder() const {
if(optional()) if (optional())
return QString("[--%1 <%2>]").arg(bindKey(), bindKey()); return QString("[--%1 <%2>]").arg(bindKey(), bindKey());
return QString("--%1 <%2>").arg(bindKey(), bindKey()); return QString("--%1 <%2>").arg(bindKey(), bindKey());
} }
@ -46,9 +47,11 @@ int FloatKeyValue::matchLenth() const {
bool FloatKeyValue::parse(const QList<QString> args, int start) { bool FloatKeyValue::parse(const QList<QString> args, int start) {
auto args_t = args[start]; auto args_t = args[start];
auto args_v = args[start + 1]; auto args_v = args[start + 1];
if (args_t == bindKey()) if (args_t == u8"--" + bindKey()){
setValue(args_v); setValue(args_v);
return args_t == bindKey(); return true;
}
return false;
} }
IndexParam::IndexParam(const QString& place_v, const QString& means) IndexParam::IndexParam(const QString& place_v, const QString& means)
@ -67,16 +70,15 @@ bool IndexParam::parse(const QList<QString> args, int start) {
return true; return true;
} }
__FloatArgvImpl::__FloatArgvImpl(const QString& key, const QString& means, bool optional) __FloatArgvImpls::__FloatArgvImpls(const QString& key, const QString& means, bool optional)
: __ArgvPackImpls(means, ParamType::FloatParam), key_name(key), optional_value(optional) { } : __ArgvPackImpls(means, ParamType::FloatParam), key_name(key), optional_value(optional) { }
FloatOption::FloatOption(const QString& key, const QString& means, bool opt) FloatOption::FloatOption(const QString& key, const QString& means, bool opt)
: __FloatArgvImpl(key, means, opt) { : __FloatArgvImpls(key, means, opt) {
setValue(u8"0");
} }
QString args_parse::FloatOption::placeHolder() const { QString args_parse::FloatOption::placeHolder() const {
if(optional()) if (optional())
return QString("[--%1]").arg(bindKey()); return QString("[--%1]").arg(bindKey());
return QString("--%1").arg(bindKey()); return QString("--%1").arg(bindKey());
} }
@ -87,83 +89,123 @@ int FloatOption::matchLenth() const {
bool FloatOption::parse(const QList<QString> args, int start) { bool FloatOption::parse(const QList<QString> args, int start) {
auto args_t = args[start]; auto args_t = args[start];
setValue(QString::number(args_t == bindKey())); setValue(args_t == bindKey());
return args_t == bindKey(); return args_t == u8"--" + bindKey();
} }
namespace args_parse { MatchMode::MatchMode(int mode_code, const QString& mode)
class MatchMode { :_means_explain(mode), code_store(mode_code) { }
private:
QList<shared_ptr<IArgvPack>> args_mode;
int code_store;
public: /**
explicit MatchMode(const QList<shared_ptr<IArgvPack>> mode, int mode_code) * @brief
:args_mode(mode), code_store(mode_code) { } * @return
*/
/** MatchMode& args_parse::MatchMode::operator<<(std::shared_ptr<IArgvPack> unit) {
* @brief args_mode << unit;
* @return return *this;
*/
int modeCode()const {
return code_store;
}
/**
* @brief
* @return
*/
QList<shared_ptr<IArgvPack>> result() const {
return args_mode;
}
/**
* @brief
*/
bool parse(const QList<QString>& args, int argv_index, int parse_index) {
if (argv_index >= args.size())
return true;
// 获取模式匹配单元
auto parse_unit = args_mode[parse_index];
switch (parse_unit->paramType()) {
case ParamType::IndexParam:// 固定位置索引匹配
{
parse_unit->parse(args, argv_index);
// 继续匹配下一个为止
return parse(args, argv_index + parse_unit->matchLenth(), parse_index + 1);
}break;
case ParamType::FloatParam:// 浮动参数匹配
{
QList<shared_ptr<__FloatArgvImpl>> float_parsers;
for (auto& unit : args_mode) {
if (unit->paramType() == ParamType::FloatParam)
float_parsers << dynamic_pointer_cast<__FloatArgvImpl>(unit);
}
for (auto& unit : float_parsers) {
if (unit->matchLenth() + argv_index > args.size())
continue;
auto result = unit->parse(args, argv_index);
if (result)
if (parse(args, argv_index + unit->matchLenth(), parse_index + 1))
return true;
else if (!result && unit->optional())
if (parse(args, argv_index, parse_index + 1))
return true;
}
}break;
}
return false;
}
};
}
void ArgsParser::loadMode(int mode_code, const QList<shared_ptr<IArgvPack>>& args_model) {
this->match_modes.append(make_shared<MatchMode>(args_model, mode_code));
} }
tuple<int, QList<shared_ptr<IArgvPack>>> ArgsParser::parse(int argc, char* argv[]) { int MatchMode::modeCode() const {
return code_store;
}
QString args_parse::MatchMode::usageString() const {
QString usage_string;
for (auto& item : args_mode)
usage_string += item->placeHolder() + u8" ";
return usage_string;
}
QString args_parse::MatchMode::explanString() const {
QStringList sections;
sections << u8" " + _means_explain;
sections << QString(" Switch:");
for (auto& item : args_mode) {
sections << " " + item->placeHolder();
sections << " " + item->means();
}
return sections.join("\n");
}
/**
* @brief
*/
bool MatchMode::parse(const QList<QString>& args, int argv_index, int parse_index) {
if (argv_index >= args.size())
return true;
// 获取模式匹配单元
auto parse_unit = args_mode[parse_index];
switch (parse_unit->paramType()) {
case ParamType::IndexParam:// 固定位置索引匹配
{
parse_unit->parse(args, argv_index);
// 继续匹配下一个为止
return parse(args, argv_index + parse_unit->matchLenth(), parse_index + 1);
}break;
case ParamType::FloatParam:// 浮动参数匹配
{
QList<shared_ptr<__FloatArgvImpls>> float_parsers;
for (auto& unit : args_mode) {
if (unit->paramType() == ParamType::FloatParam)
float_parsers << dynamic_pointer_cast<__FloatArgvImpls>(unit);
}
for (auto& unit : float_parsers) {
if (unit->matchLenth() + argv_index > args.size())
continue;
auto result = unit->parse(args, argv_index);
if (result)
if (parse(args, argv_index + unit->matchLenth(), parse_index + 1))
return true;
else if (!result && unit->optional())
if (parse(args, argv_index, parse_index + 1))
return true;
}
}break;
}
return false;
}
std::shared_ptr<IArgvPack> args_parse::MatchMode::getUnitViaKey(const QString& key) {
for (auto& u : args_mode) {
if (u->paramType() == ParamType::FloatParam) {
auto conv = std::dynamic_pointer_cast<__FloatArgvImpls>(u);
if (conv->bindKey() == key)
return u;
}
}
return std::shared_ptr<IArgvPack>();
}
std::shared_ptr<IArgvPack> args_parse::MatchMode::getUnitViaPos(int pos) {
return args_mode[pos];
}
QString args_parse::ArgsParser::helpDoc() const {
QString help_string;
for (auto& mode : this->match_modes) {
help_string += "Usage:" + mode->usageString() + "\n";
help_string += mode->explanString() + "\n\n";
}
return help_string;
}
ArgsParser& args_parse::ArgsParser::operator<<(std::shared_ptr<MatchMode> mode) {
this->match_modes.append(mode);
return *this;
}
std::shared_ptr<MatchMode> ArgsParser::parse(int argc, char* argv[]) {
// 聚合参数数组 // 聚合参数数组
QList<QString> args_list; QList<QString> args_list;
for (int idx = 0; idx < argc; idx++) { for (int idx = 0; idx < argc; idx++) {
@ -174,8 +216,8 @@ tuple<int, QList<shared_ptr<IArgvPack>>> ArgsParser::parse(int argc, char* argv[
// 枚举模式匹配 // 枚举模式匹配
for (auto& minst : this->match_modes) { for (auto& minst : this->match_modes) {
if (minst->parse(args_list, 0, 0)) if (minst->parse(args_list, 0, 0))
return tuple<int, QList<shared_ptr<IArgvPack>>>(minst->modeCode(), minst->result()); return minst;
} }
return tuple<int, QList<shared_ptr<IArgvPack>>>(0, QList<shared_ptr<IArgvPack>>()); return std::shared_ptr<MatchMode>();
} }

View File

@ -5,6 +5,7 @@
#include <QList> #include <QList>
#include <qHash> #include <qHash>
#include <tuple> #include <tuple>
#include <QVariant>
#include "argsparser_global.h" #include "argsparser_global.h"
namespace args_parse { namespace args_parse {
@ -35,7 +36,7 @@ namespace args_parse {
*/ */
virtual QString means() const = 0; virtual QString means() const = 0;
virtual QString placeHolder() const = 0; virtual QString placeHolder() const = 0;
virtual QString value() const = 0; virtual QVariant value() const = 0;
/** /**
* @brief . * @brief .
* *
@ -55,27 +56,27 @@ namespace args_parse {
class ARGSPARSER_EXPORT __ArgvPackImpls : public IArgvPack { class ARGSPARSER_EXPORT __ArgvPackImpls : public IArgvPack {
private: private:
QString means_store; QString means_store;
QString value_store; QVariant value_store;
ParamType type_store; ParamType type_store;
public: public:
__ArgvPackImpls(const QString &means, ParamType t); __ArgvPackImpls(const QString &means, ParamType t);
void setValue(const QString &v); void setValue(const QVariant &v);
// 通过 IArgvPack 继承 // 通过 IArgvPack 继承
ParamType paramType() const override; ParamType paramType() const override;
QString means() const override; QString means() const override;
QString value() const override; QVariant value() const override;
}; };
class ARGSPARSER_EXPORT __FloatArgvImpl : public __ArgvPackImpls { class ARGSPARSER_EXPORT __FloatArgvImpls : public __ArgvPackImpls {
private: private:
QString key_name; QString key_name;
bool optional_value; bool optional_value;
public: public:
explicit __FloatArgvImpl(const QString& key, const QString& means, bool optional); explicit __FloatArgvImpls(const QString& key, const QString& means, bool optional);
QString bindKey() const; QString bindKey() const;
virtual bool optional() const; virtual bool optional() const;
@ -85,8 +86,15 @@ namespace args_parse {
* @brief key-value解析匹配模式. * @brief key-value解析匹配模式.
* --key value * --key value
*/ */
class ARGSPARSER_EXPORT FloatKeyValue : public __FloatArgvImpl { class ARGSPARSER_EXPORT FloatKeyValue : public __FloatArgvImpls {
public: public:
/**
* key-value解析单元.
*
* \param key
* \param means
* \param optional
*/
explicit FloatKeyValue(const QString& key, const QString &means, bool optional = false); explicit FloatKeyValue(const QString& key, const QString &means, bool optional = false);
virtual ~FloatKeyValue() = default; virtual ~FloatKeyValue() = default;
@ -99,8 +107,15 @@ namespace args_parse {
* @brief key解析匹配模式. * @brief key解析匹配模式.
* --key * --key
*/ */
class ARGSPARSER_EXPORT FloatOption : public __FloatArgvImpl { class ARGSPARSER_EXPORT FloatOption : public __FloatArgvImpls {
public: public:
/**
* option解析单元.
*
* \param key
* \param means
* \param optional
*/
explicit FloatOption(const QString& key, const QString& means, bool optional = false); explicit FloatOption(const QString& key, const QString& means, bool optional = false);
virtual ~FloatOption() = default; virtual ~FloatOption() = default;
@ -126,15 +141,69 @@ namespace args_parse {
bool parse(const QList<QString> args, int start) override; bool parse(const QList<QString> args, int start) override;
}; };
class MatchMode; class ARGSPARSER_EXPORT MatchMode {
private:
int code_store;
QString _means_explain;
QList<std::shared_ptr<IArgvPack>> args_mode;
public:
explicit MatchMode(int mode_code, const QString &explain);
/**
* @brief
* @return
*/
int modeCode()const;
/**
* .
*
* \return
*/
QString usageString() const;
/**
* .
*
* \return
*/
QString explanString() const;
/**
* .
*
* \param unit
* \return
*/
MatchMode& operator<<(std::shared_ptr<IArgvPack> unit);
/**
* @brief
*/
bool parse(const QList<QString>& args, int argv_index, int parse_index);
/**
* .
*
* \param key
* \return
*/
std::shared_ptr<IArgvPack> getUnitViaKey(const QString& key);
std::shared_ptr<IArgvPack> getUnitViaPos(int pos);
};
class ARGSPARSER_EXPORT ArgsParser { class ARGSPARSER_EXPORT ArgsParser {
private: private:
QList<std::shared_ptr<MatchMode>> match_modes; QList<std::shared_ptr<MatchMode>> match_modes;
public: public:
void loadMode(int mode_code, const QList<std::shared_ptr<IArgvPack>> &args_model); QString helpDoc() const;
std::tuple<int, QList<std::shared_ptr<IArgvPack>>> parse(int argc, char* argv[]); ArgsParser& operator<<(std::shared_ptr<MatchMode> mode);
std::shared_ptr<MatchMode> parse(int argc, char* argv[]);
}; };
} }

View File

@ -17,6 +17,8 @@
#include "htmlprint.h" #include "htmlprint.h"
using namespace example_novel; using namespace example_novel;
using namespace std;
using namespace args_parse;
/* /*
* nsc --help * nsc --help
@ -28,99 +30,101 @@ using namespace example_novel;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
QCoreApplication a(argc, argv); QCoreApplication a(argc, argv);
args_parse::ArgsParser args_parser; ArgsParser args_parser;
QList<std::shared_ptr<args_parse::IArgvPack>> args_mode; auto help_mode = make_shared<MatchMode>(0x000Au, u8"打印帮助信息");
args_mode << std::make_shared<args_parse::IndexParam>(u8"nsc", u8"程序名称"); args_parser << help_mode;
args_mode << std::make_shared<args_parse::FloatOption>(u8"--help", u8"帮助"); *help_mode << make_shared<IndexParam>(u8"nsc", u8"程序名称")
args_parser.loadMode(0x000Au, args_mode); << make_shared<FloatOption>(u8"help", u8"帮助");
args_mode.clear(); auto build_mode = make_shared<MatchMode>(0x000Bu, u8"执行故事线编译任务");
args_mode << std::make_shared<args_parse::IndexParam>(u8"nsc", u8"程序名称"); args_parser << build_mode;
args_mode << std::make_shared<args_parse::FloatKeyValue>(u8"--path", u8"源代码目录"); *build_mode << make_shared<IndexParam>(u8"nsc", u8"程序名称")
args_mode << std::make_shared<args_parse::FloatKeyValue>(u8"--dest", u8"生成目录"); << make_shared<FloatKeyValue>(u8"path", u8"指定源代码目录")
args_mode << std::make_shared<args_parse::FloatOption>(u8"--html", u8"生成html文件格式取代AST", true); << make_shared<FloatKeyValue>(u8"dest", u8"指定生成目录")
args_parser.loadMode(0x000Bu, args_mode); << make_shared<FloatOption>(u8"html", u8"生成html文件格式取代AST", true);
auto parse_result = args_parser.parse(argc, argv); auto p_result = args_parser.parse(argc, argv);
switch (std::get<0>(parse_result)) { if (!p_result) {
case 0xBu: { qDebug().noquote() << args_parser.helpDoc();
auto args = std::get<1>(parse_result); }
auto src_dir = std::dynamic_pointer_cast<args_parse::FloatKeyValue>(args_mode[1]); else {
auto dst_dir = std::dynamic_pointer_cast<args_parse::FloatKeyValue>(args_mode[2]); switch (p_result->modeCode()) {
auto html_opt = std::dynamic_pointer_cast<args_parse::FloatOption>(args_mode[3]); case 0xAu:
default:
qDebug().noquote() << args_parser.helpDoc();
break;
case 0xBu:
{
auto src_dir = dynamic_pointer_cast<FloatKeyValue>(p_result->getUnitViaKey(u8"path"));
auto dst_dir = dynamic_pointer_cast<FloatKeyValue>(p_result->getUnitViaKey(u8"dest"));
auto html_opt = dynamic_pointer_cast<FloatOption>(p_result->getUnitViaKey(u8"html"));
auto source_dir = QDir(src_dir->value()); auto source_dir = QDir(src_dir->value().toString());
if (!source_dir.exists()) { if (!source_dir.exists()) {
std::cout << "%编译指定的源代码目录不存在!" << std::endl; cout << "%编译指定的源代码目录不存在!" << endl;
exit(0); exit(0);
} }
auto destination_dir = QDir::current(); auto destination_dir = QDir::current();
auto target_output = dst_dir->value(); auto target_output = dst_dir->value();
if (!target_output.isEmpty() && QDir(target_output).exists()) { if (!target_output.isNull() && QDir(target_output.toString()).exists()) {
destination_dir = QDir(target_output); destination_dir = QDir(target_output.toString());
} }
else { else {
std::cout << "%编译指定的生成目录不存在,重置为:" << destination_dir.absolutePath().toLocal8Bit().data() << std::endl; cout << "%编译指定的生成目录不存在,重置为:" << destination_dir.absolutePath().toLocal8Bit().data() << endl;
}
auto files = source_dir.entryInfoList(QStringList() << "*.story");
std::shared_ptr<const ast_gen::ElementAccess> access_ptr = nullptr;
if (files.size()) {
try {
auto parser = std::make_shared<NovelParser>();
auto docs = parser->parse(files);
auto errors_list = parser->parserContext()->errors();
if (errors_list.size()) {
for (auto& err : errors_list) {
qDebug().noquote() << err;
} }
exit(0);
}
access_ptr = parser->validsApply(docs);
}
catch (lib_syntax::SyntaxException* e) {
qDebug().noquote() << e->message();
delete e;
exit(0);
}
catch (lib_parse::CheckException* e) {
qDebug().noquote() << e->message();
delete e;
exit(0);
}
}
if (html_opt->value().toInt() == 1 && access_ptr) { auto files = source_dir.entryInfoList(QStringList() << "*.story");
printer::tools_printer tool; shared_ptr<const ast_gen::ElementAccess> access_ptr = nullptr;
tool.plain_html_output(access_ptr, destination_dir); if (files.size()) {
try {
auto parser = make_shared<NovelParser>();
auto docs = parser->parse(files);
auto errors_list = parser->parserContext()->errors();
if (errors_list.size()) {
for (auto& err : errors_list) {
qDebug().noquote() << err;
}
exit(0);
}
access_ptr = parser->validsApply(docs);
}
catch (lib_syntax::SyntaxException* e) {
qDebug().noquote() << e->message();
delete e;
exit(0);
}
catch (lib_parse::CheckException* e) {
qDebug().noquote() << e->message();
delete e;
exit(0);
}
}
if (html_opt->value().toInt() == 1 && access_ptr) {
printer::tools_printer tool;
tool.plain_html_output(access_ptr, destination_dir);
}
else if (access_ptr) {
QTime time_stamp = QTime::currentTime();
lib_parse::VisitorControl control;
auto visitor = make_shared<printer::AstGenerate>(source_dir);
control.visitWith(access_ptr, visitor);;
auto dom_result = visitor->content();
QFile file(destination_dir.absoluteFilePath(u8"storyline.xast"));
if (file.open(QIODevice::Text | QIODevice::WriteOnly)) {
QTextStream tout(&file);
tout.setCodec("UTF-8");
tout << dom_result;
tout.flush();
}
auto current_stamp = QTime::currentTime();
qDebug().noquote() << QString(u8"%AST构建消耗时间%1 ms。").arg(time_stamp.msecsTo(current_stamp));
qDebug().noquote() << QString(u8"%编译成功:%1。").arg(QFileInfo(file).absoluteFilePath());
}
}break;
} }
else if (access_ptr) {
QTime time_stamp = QTime::currentTime();
lib_parse::VisitorControl control;
auto visitor = std::make_shared<printer::AstGenerate>(source_dir);
control.visitWith(access_ptr, visitor);;
auto dom_result = visitor->content();
QFile file(destination_dir.absoluteFilePath(u8"storyline.xast"));
if (file.open(QIODevice::Text | QIODevice::WriteOnly)) {
QTextStream tout(&file);
tout.setCodec("UTF-8");
tout << dom_result;
tout.flush();
}
auto current_stamp = QTime::currentTime();
qDebug().noquote() << QString(u8"%AST构建消耗时间%1 ms。").arg(time_stamp.msecsTo(current_stamp));
qDebug().noquote() << QString(u8"%编译成功:%1。").arg(QFileInfo(file).absoluteFilePath());
}
}break;
case 0xAu:
default: {
std::cout << "nsc(WsNovelStoryCompiler故事线编译器)" << std::endl;
std::cout << "版本V1.0.0" << std::endl;
std::cout << "nsc --path path-to-dir --dest path-to-output [--html]" << std::endl;
std::cout << "nsc --help" << std::endl;
}break;
} }
//return a.exec(); //return a.exec();
return 0; return 0;