Compare commits

..

2 Commits

Author SHA1 Message Date
codeboss 93e7edaae8 构建ast输出 2024-06-22 23:19:14 +08:00
codeboss a97ed72b67 添加启动参数解析库 2024-06-22 18:53:51 +08:00
19 changed files with 739 additions and 79 deletions

View File

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{1FF80476-26C9-42FB-BFF6-D587C4941964}</ProjectGuid>
<Keyword>QtVS_v304</Keyword>
<WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">10.0</WindowsTargetPlatformVersion>
<QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
<Import Project="$(QtMsBuild)\qt_defaults.props" />
</ImportGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
<QtInstall>5.12.11_msvc2017_64</QtInstall>
<QtModules>core</QtModules>
<QtBuildConfig>debug</QtBuildConfig>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
<QtInstall>5.12.11_msvc2017_64</QtInstall>
<QtModules>core</QtModules>
<QtBuildConfig>release</QtBuildConfig>
</PropertyGroup>
<Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
<Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
</Target>
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="Shared" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(QtMsBuild)\Qt.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(QtMsBuild)\Qt.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>ARGSPARSER_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>ARGSPARSER_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="argsparser_global.h" />
<ClInclude Include="argsparser.h" />
<ClCompile Include="argsparser.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
<Import Project="$(QtMsBuild)\qt.targets" />
</ImportGroup>
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Form Files">
<UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
<Extensions>ui</Extensions>
</Filter>
<Filter Include="Translation Files">
<UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
<Extensions>ts</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="argsparser_global.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClCompile Include="argsparser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClInclude Include="argsparser.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<QtTouchProperty>
</QtTouchProperty>
</PropertyGroup>
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<QtTouchProperty>
</QtTouchProperty>
</PropertyGroup>
</Project>

135
ArgsParser/argsparser.cpp Normal file
View File

@ -0,0 +1,135 @@
#include "argsparser.h"
using namespace args_parse;
ArgvPackImpl::ArgvPackImpl(const QString& means, ParamType t) : means_store(means), type_store(t) {}
// ͨ¹ý ArgvPack ¼Ì³Ð
ParamType ArgvPackImpl::paramType() const { return type_store; }
QString ArgvPackImpl::means() const { return means_store; }
void ArgvPackImpl::setValue(const QString& v) {
this->value_store = v;
}
QString ArgvPackImpl::value() const { return value_store; }
FloatArgvPack::FloatArgvPack(const QString& key, const QString& means, bool optional) :
FloatArgvImpl(key, means, optional) {}
QString FloatArgvImpl::bindKey() const { return key_name; }
bool FloatArgvImpl::optional() const {
return optional_value;
}
int FloatArgvPack::matchLenth() const
{
return 2;
}
bool FloatArgvPack::parse(const QList<QString> args, int start)
{
auto args_t = args[start];
auto args_v = args[start + 1];
if(args_t == bindKey())
setValue(args_v);
return args_t == bindKey();
}
IndexParam::IndexParam(const QString& means) : ArgvPackImpl(means, ParamType::IndexParam) {}
int args_parse::IndexParam::matchLenth() const
{
return 1;
}
bool args_parse::IndexParam::parse(const QList<QString> args, int start)
{
setValue(args[start]);
return true;
}
FloatArgvImpl::FloatArgvImpl(const QString& key, const QString& means, bool optional)
: ArgvPackImpl(means, ParamType::FloatParam), key_name(key), optional_value(optional) {}
FloatOption::FloatOption(const QString &key, const QString &means, bool opt)
: FloatArgvImpl(key, means, opt) { setValue(u8"0"); }
int FloatOption::matchLenth() const { return 1; }
bool FloatOption::parse(const QList<QString> args, int start) {
auto args_t = args[start];
setValue(QString::number(args_t == bindKey()));
return args_t == bindKey();
}
namespace args_parse {
class MatchMode {
private:
QList<std::shared_ptr<ArgvPack>> args_mode;
int code_store;
public:
explicit MatchMode(const QList<std::shared_ptr<ArgvPack>> mode, int mode_code) :args_mode(mode), code_store(mode_code) {}
int modeCode()const {return code_store;}
QList<std::shared_ptr<ArgvPack>> result() const {return args_mode;}
bool parse(const QList<QString>& args, int argv_start, int parse_index) {
if(argv_start >= args.size())
return true;
auto parse_unit = args_mode[parse_index];
switch (parse_unit->paramType()) {
case ParamType::IndexParam: {
parse_unit->parse(args, argv_start);
return parse(args, argv_start + parse_unit->matchLenth(), parse_index + 1);
}break;
case ParamType::FloatParam: {
QList<std::shared_ptr<FloatArgvImpl>> float_parsers;
for (auto& unit : args_mode) {
if (unit->paramType() == ParamType::FloatParam)
float_parsers.append(std::dynamic_pointer_cast<FloatArgvImpl>(unit));
}
for (auto& unit : float_parsers) {
if(unit->matchLenth() + argv_start > args.size())
continue;
auto result = unit->parse(args, argv_start);
if (result)
if (parse(args, argv_start + unit->matchLenth(), parse_index + 1))
return true;
else if (!result && unit->optional())
if (parse(args, argv_start, parse_index + 1))
return true;
}
}break;
}
return false;
}
};
}
void args_parse::ArgsParser::loadMode(int mode_code, const QList<std::shared_ptr<ArgvPack>>& args_model)
{
this->match_modes.append(std::make_shared<MatchMode>(args_model, mode_code));
}
std::tuple<int, QList<std::shared_ptr<ArgvPack>>> args_parse::ArgsParser::parse(int argc, char* argv[]){
QList<QString> args_list;
for (int idx = 0; idx < argc; idx++) {
auto argv_str = QString::fromLocal8Bit(argv[idx]);
args_list.append(argv_str);
}
for (auto& minst : this->match_modes) {
if (minst->parse(args_list, 0, 0))
return std::tuple<int, QList<std::shared_ptr<ArgvPack>>>(minst->modeCode(), minst->result());
}
return std::tuple<int, QList<std::shared_ptr<ArgvPack>>>(0, QList<std::shared_ptr<ArgvPack>>());
}

124
ArgsParser/argsparser.h Normal file
View File

@ -0,0 +1,124 @@
#pragma once
#include <memory>
#include <QString>
#include <QList>
#include <qHash>
#include <tuple>
#include "argsparser_global.h"
namespace args_parse {
/**
* .
*/
enum class ParamType {
IndexParam,
FloatParam,
};
/**
* @brief .
*/
class ArgvPack {
public:
virtual ~ArgvPack() = default;
virtual ParamType paramType() const = 0;
virtual QString means() const = 0;
virtual QString value() const = 0;
/**
* @brief .
*
* \return
*/
virtual int matchLenth() const = 0;
/**
* @brief .
*
* \param argv
* \param start
* \return
*/
virtual bool parse(const QList<QString> args, int start) = 0;
};
class ARGSPARSER_EXPORT ArgvPackImpl : public ArgvPack {
private:
QString means_store;
QString value_store;
ParamType type_store;
public:
ArgvPackImpl(const QString &means, ParamType t);
void setValue(const QString &v);
// 通过 ArgvPack 继承
ParamType paramType() const override;
QString means() const override;
QString value() const override;
};
class ARGSPARSER_EXPORT FloatArgvImpl : public ArgvPackImpl {
private:
QString key_name;
bool optional_value;
public:
explicit FloatArgvImpl(const QString& key, const QString& means, bool optional);
QString bindKey() const;
virtual bool optional() const;
};
/**
* @brief key-value解析匹配模式.
* --key value
*/
class ARGSPARSER_EXPORT FloatArgvPack : public FloatArgvImpl {
public:
explicit FloatArgvPack(const QString& key, const QString &means, bool optional = false);
virtual ~FloatArgvPack() = default;
virtual int matchLenth() const override;
bool parse(const QList<QString> args, int start) override;
};
/**
* @brief key解析匹配模式.
* --key
*/
class ARGSPARSER_EXPORT FloatOption : public FloatArgvImpl {
public:
explicit FloatOption(const QString& key, const QString& means, bool optional = false);
virtual ~FloatOption() = default;
virtual int matchLenth() const override;
bool parse(const QList<QString> args, int start) override;
};
/**
* .
*/
class ARGSPARSER_EXPORT IndexParam : public ArgvPackImpl {
public:
explicit IndexParam(const QString &means);
virtual ~IndexParam() = default;
// 通过 ArgvPackImpl 继承
int matchLenth() const override;
bool parse(const QList<QString> args, int start) override;
};
class MatchMode;
class ARGSPARSER_EXPORT ArgsParser {
private:
QList<std::shared_ptr<MatchMode>> match_modes;
public:
void loadMode(int mode_code, const QList<std::shared_ptr<ArgvPack>> &args_model);
std::tuple<int, QList<std::shared_ptr<ArgvPack>>> parse(int argc, char* argv[]);
};
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <QtCore/qglobal.h>
#ifndef BUILD_STATIC
# if defined(ARGSPARSER_LIB)
# define ARGSPARSER_EXPORT Q_DECL_EXPORT
# else
# define ARGSPARSER_EXPORT Q_DECL_IMPORT
# endif
#else
# define ARGSPARSER_EXPORT
#endif

View File

@ -26,6 +26,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决
报告20240619-1206.diagsession = 报告20240619-1206.diagsession
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ArgsParser", "ArgsParser\ArgsParser.vcxproj", "{1FF80476-26C9-42FB-BFF6-D587C4941964}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -48,6 +50,10 @@ Global
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Debug|x64.Build.0 = Debug|x64
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Release|x64.ActiveCfg = Release|x64
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Release|x64.Build.0 = Release|x64
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Debug|x64.ActiveCfg = Debug|x64
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Debug|x64.Build.0 = Debug|x64
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Release|x64.ActiveCfg = Release|x64
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -61,7 +61,7 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<IncludePath>$(SolutionDir)libToken;$(SolutionDir)libSyntax;$(SolutionDir)libParse;$(IncludePath)</IncludePath>
<IncludePath>$(SolutionDir)libToken;$(SolutionDir)libSyntax;$(SolutionDir)ArgsParser;$(SolutionDir)libParse;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath)</LibraryPath>
<TargetName>nsc</TargetName>
</PropertyGroup>
@ -72,7 +72,7 @@
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link>
<AdditionalDependencies>libToken.lib;libSyntax.lib;libParse.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libToken.lib;libSyntax.lib;libParse.lib;ArgsParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<ClCompile>
<LanguageStandard>Default</LanguageStandard>

View File

@ -3,7 +3,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)$(Platform)\$(Configuration)\</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommandArguments>--path "D:\手作小说\科学+修仙+创造世界"</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>--path "D:\手作小说\科学+修仙+创造世界" --dest E:\</LocalDebuggerCommandArguments>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerCommandArguments>--path "D:\手作小说\科学+修仙+创造世界"</LocalDebuggerCommandArguments>

View File

@ -4,6 +4,7 @@
using namespace example_novel;
using namespace printer;
using namespace lib_parse;
Access::Access(std::shared_ptr<const ast_gen::ElementAccess> handle)
:access_handle(handle) {}
@ -532,3 +533,141 @@ QString printer::tools_printer::volumes_paint(const QList<std::shared_ptr<StoryV
return QString("graph scale{ %1 \n %2}").arg(clusters_description).arg(arrows_link);
}
void printer::AstGenerate::append_tokens(QDomElement _elm, std::shared_ptr<const ast_gen::SyntaxElement> inst) {
auto dom_tokens = doc.createElement(u8"tokens");
_elm.appendChild(dom_tokens);
for (auto& token : inst->selfTokens()) {
auto dom_token = doc.createElement(u8"token");
dom_tokens.appendChild(dom_token);
dom_token.setAttribute(u8"text", token->token()->content());
dom_token.setAttribute(u8"row", token->token()->row());
dom_token.setAttribute(u8"col", token->token()->column());
}
}
printer::AstGenerate::AstGenerate()
{
auto procs = doc.createProcessingInstruction("xml", "version='1.0'");
doc.appendChild(procs);
}
QString printer::AstGenerate::content() const
{
return doc.toString(2);
}
VisitMode printer::AstGenerate::mode() const {
return VisitMode::FirstParent;
}
bool printer::AstGenerate::visit(std::shared_ptr<const ast_gen::ElementAccess> syntax_element) {
switch ((NovelNode)syntax_element->element()->typeMark()) {
case NovelNode::GlobalElement:{
auto body = doc.createElement(u8"ast");
doc.appendChild(body);
element_stack.append(body);
}break;
case NovelNode::Document: break;
case NovelNode::StoryDefine:{
while (element_stack.last().tagName() != u8"ast") {
element_stack.takeLast();
}
auto current_ast = element_stack.last();
auto story_node = std::dynamic_pointer_cast<const example_novel::StoryDefine>(syntax_element->element());
auto dom_story = doc.createElement(u8"story");
current_ast.appendChild(dom_story);
element_stack.append(dom_story);
dom_story.setAttribute(u8"name", story_node->name());
dom_story.setAttribute(u8"file-path", story_node->filePath());
dom_story.setAttribute(u8"sort", story_node->sort());
append_tokens(dom_story, story_node);
}break;
case NovelNode::FragmentDefine: {
while (element_stack.last().tagName() != u8"story") {
element_stack.takeLast();
}
auto current_story = element_stack.last();
auto fragment_node = std::dynamic_pointer_cast<const example_novel::FragmentDefine>(syntax_element->element());
auto dom_fragment = doc.createElement(u8"fragment");
current_story.appendChild(dom_fragment);
element_stack.append(dom_fragment);
dom_fragment.setAttribute(u8"name", fragment_node->name());
dom_fragment.setAttribute(u8"file-path", fragment_node->filePath());
append_tokens(dom_fragment, fragment_node);
}break;
case NovelNode::TextSection:{
auto current_text = element_stack.last();
auto text_node = std::dynamic_pointer_cast<const example_novel::TextSection>(syntax_element->element());
auto dom_text = doc.createElement(u8"text-section");
current_text.appendChild(dom_text);
dom_text.setAttribute(u8"text", text_node->content());
dom_text.setAttribute(u8"file-path", text_node->filePath());
append_tokens(dom_text, text_node);
}break;
case NovelNode::FragmentRefer:{
while (element_stack.last().tagName() != u8"article" && element_stack.last().tagName() != u8"story") {
element_stack.takeLast();
}
auto current_pnode = element_stack.last();
auto refer_node = std::dynamic_pointer_cast<const example_novel::FragmentRefers>(syntax_element->element());
auto dom_refer = doc.createElement(u8"refer");
element_stack.append(dom_refer);
current_pnode.appendChild(dom_refer);
dom_refer.setAttribute(u8"story", refer_node->storyRefer());
dom_refer.setAttribute(u8"fragment", refer_node->fragmentRefer());
dom_refer.setAttribute(u8"file-path", refer_node->filePath());
append_tokens(dom_refer, refer_node);
}break;
case NovelNode::VolumeDefine:{
while (element_stack.last().tagName() != u8"ast") {
element_stack.takeLast();
}
auto current_ast = element_stack.last();
auto volume_node = std::dynamic_pointer_cast<const example_novel::VolumeDefine>(syntax_element->element());
auto dom_volume = doc.createElement(u8"volume");
current_ast.appendChild(dom_volume);
element_stack.append(dom_volume);
dom_volume.setAttribute(u8"name", volume_node->name());
dom_volume.setAttribute(u8"file-path", volume_node->filePath());
append_tokens(dom_volume, volume_node);
}break;
case NovelNode::ArticleDefine:{
while (element_stack.last().tagName() != u8"volume") {
element_stack.takeLast();
}
auto current_volume = element_stack.last();
auto article_node = std::dynamic_pointer_cast<const example_novel::ArticleDefine>(syntax_element->element());
auto dom_article = doc.createElement(u8"article");
current_volume.appendChild(dom_article);
element_stack.append(dom_article);
dom_article.setAttribute(u8"name", article_node->name());
dom_article.setAttribute(u8"file-path", article_node->filePath());
append_tokens(dom_article, article_node);
}break;
default:
break;
}
return true;
}

View File

@ -157,4 +157,21 @@ namespace printer {
QString storylines_paint(const QList<std::shared_ptr<StoryLine>> &lines);
QString volumes_paint(const QList<std::shared_ptr<StoryVolume>> &vols, const QList<std::shared_ptr<StoryLine>> &lines);
};
class AstGenerate : public lib_parse::TreeVisitor {
private:
QDomDocument doc;
QList<QDomElement> element_stack;
void append_tokens(QDomElement _elm, std::shared_ptr<const ast_gen::SyntaxElement> inst);
public:
AstGenerate();
QString content() const;
// ͨ¹ý TreeVisitor ¼Ì³Ð
lib_parse::VisitMode mode() const override;
bool visit(std::shared_ptr<const ast_gen::ElementAccess> syntax_element) override;
};
}

View File

@ -11,84 +11,94 @@
#include <QTextStream>
#include <iostream>
#include <QTime>
#include <argsparser.h>
#include "novelparser.h"
#include "htmlprint.h"
using namespace example_novel;
std::function<void(std::shared_ptr<const ast_gen::ElementAccess>, int)> tnode_print =
[&](std::shared_ptr<const ast_gen::ElementAccess> node, int intend) {
auto name = node->element()->signature();
auto text = QString(intend * 2, ' ') + name;
/*for (auto& t : node->tokens()) {
text += " " + t->token()->content();
}*/
qDebug() << text;
for (auto& c_n : node->children()) {
tnode_print(c_n, intend + 1);
}
};
/*
* nsc --help
* nsc [opts] --path path-to-dir
* nsc -[pw] --path path-to-dir [--out path-to-dir]
* opts:
* -p print-struct
* p print-struct
* w print-web web页面输出格式
*/
int main(int argc, char* argv[]) {
QCoreApplication a(argc, argv);
QStringList args;
for (int idx = 0; idx < argc; idx++) {
args += QString::fromLocal8Bit(argv[idx]);
}
args_parse::ArgsParser args_parser;
QList<std::shared_ptr<args_parse::ArgvPack>> args_mode;
args_mode << std::make_shared<args_parse::IndexParam>(u8"程序名称");
args_mode << std::make_shared<args_parse::FloatOption>(u8"--help", u8"帮助");
args_parser.loadMode(0x000Au, args_mode);
// 帮助特殊用法
if (args.contains(u8"--help")) {
args_mode.clear();
args_mode << std::make_shared<args_parse::IndexParam>(u8"程序名称");
args_mode << std::make_shared<args_parse::FloatArgvPack>(u8"--path", u8"源代码目录");
args_mode << std::make_shared<args_parse::FloatArgvPack>(u8"--dest", u8"生成目录", true);
args_mode << std::make_shared<args_parse::FloatOption>(u8"--html", u8"生成html文件格式取代AST", true);
args_parser.loadMode(0x000Bu, args_mode);
auto parse_result = args_parser.parse(argc, argv);
switch (std::get<0>(parse_result))
{
case 0xAu: {
std::cout << "nsc(WsNovelStoryCompiler故事线编译器)" << std::endl;
std::cout << "版本V1.0.0" << std::endl;
std::cout << "nsc -path path-to-dir" << std::endl;
exit(0);
}
std::cout << "nsc --path path-to-dir [--dest path-to-output] [--html]" << std::endl;
}break;
case 0xBu: {
auto args = std::get<1>(parse_result);
auto src_dir = std::dynamic_pointer_cast<args_parse::FloatArgvPack>(args_mode[1]);
auto dst_dir = std::dynamic_pointer_cast<args_parse::FloatArgvPack>(args_mode[2]);
auto html_opt = std::dynamic_pointer_cast<args_parse::FloatOption>(args_mode[3]);
auto source_dir = QDir::current();
auto index = args.indexOf(u8"--path");
if (index < 0) {
std::cout << "参数错误:必须指定 --path 参数" << endl;
exit(1);
}
if (index + 1 >= args.size()) {
std::cout << "参数错误:--path 后面应该续接story文件的父文件夹路径。" << std::endl;
exit(1);
}
else {
auto tdir = QDir(args[index+1]);
if (tdir.exists()) {
source_dir = tdir;
auto source_dir = QDir(src_dir->value());
if (!source_dir.exists()) {
std::cout << "编译指定的源代码目录不存在!" << std::endl;
exit(0);
}
auto destination_dir = QDir::current();
auto target_output = dst_dir->value();
if (!target_output.isEmpty() && QDir(target_output).exists()) {
destination_dir = QDir(target_output);
}
else {
std::cout << "参数错误传入的story文件父文件夹路径无效。"<< std::endl;
exit(1);
std::cout << "编译指定的生成目录不存在,重置为:" << destination_dir.absolutePath().toLocal8Bit().data() << std::endl;
}
}
auto files = source_dir.entryInfoList(QStringList() << "*.story");
if (files.size()) {
try {
auto parser = std::make_shared<NovelParser>();
auto novel_accesstree = parser->parse(files);
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>();
access_ptr = parser->parse(files);
qDebug() << u8"%编译成功:" << destination_dir.absoluteFilePath(u8"index.html");
}
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) {
QTime time_stamp = QTime::currentTime();
printer::tools_printer tool;
tool.build_fragments(novel_accesstree);
tool.build_refers_network(novel_accesstree);
tool.build_fragments(access_ptr);
tool.build_refers_network(access_ptr);
tool.fragments_anchors_define(tool.fragment_defines.values(), QDir::current());
tool.storylines_anchors_define(tool.storyline_defines.values(), QDir::current());
tool.volumes_anchors_define(tool.volume_defines.values(), QDir::current());
tool.fragments_anchors_define(tool.fragment_defines.values(), destination_dir);
tool.storylines_anchors_define(tool.storyline_defines.values(), destination_dir);
tool.volumes_anchors_define(tool.volume_defines.values(), destination_dir);
std::function<void(std::shared_ptr<const printer::Access>)> html_output =
[](std::shared_ptr<const printer::Access> inst) {
@ -117,6 +127,7 @@ int main(int argc, char* argv[]) {
for (auto& node : tool.volume_defines)
html_output(node);
QDir::setCurrent(destination_dir.canonicalPath());
auto dot_src = tool.storylines_paint(tool.storyline_defines.values());
QFile dot_file(QDir::current().filePath(u8"relates.dot"));
if (dot_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
@ -199,7 +210,7 @@ int main(int argc, char* argv[]) {
int row_ctrl = 0;
QDomElement elm_row;
for (auto& inst_frag : tool.fragment_defines) {
if(row_ctrl++ % 4 == 0){
if (row_ctrl++ % 4 == 0) {
elm_row = doc_inst.createElement(u8"tr");
table_cube.appendChild(elm_row);
}
@ -235,18 +246,20 @@ int main(int argc, char* argv[]) {
auto current_stamp = QTime::currentTime();
qDebug() << QString(u8"html构建消耗时间%1 ms。").arg(time_stamp.msecsTo(current_stamp));
//tnode_print(novel_accesstree, 0);
qDebug() << u8"编译成功:" << QDir::current().absoluteFilePath(u8"index.html");
}
catch (lib_syntax::SyntaxException* e) {
qDebug().noquote() << e->message();
delete e;
}
catch (lib_parse::CheckException* e) {
qDebug().noquote() << e->message();
delete e;
else if (access_ptr) {
lib_parse::VisitorControl control;
auto visitor = std::make_shared<printer::AstGenerate>();
control.visitWith(access_ptr, visitor);;
auto dom_result = visitor->content();
qDebug().noquote() << dom_result;
}
}break;
default:
break;
}
return 0;
//return a.exec();
}

View File

@ -42,7 +42,7 @@ std::shared_ptr<const ast_gen::ElementAccess> NovelParser::parse(const QFileInfo
forst_root.append(std::get<0>(exprs_result));
}
auto current_stamp = QTime::currentTime();
qDebug() << QString(u8"词法解析+语法解析消耗时间:%1 ms。").arg(time_stamp.msecsTo(current_stamp));
qDebug().noquote() << QString(u8"%词法解析+语法解析消耗时间:%1 ms。").arg(time_stamp.msecsTo(current_stamp));
time_stamp = QTime::currentTime();
QList<std::shared_ptr<ast_gen::SyntaxElement>> docs_node;
@ -55,7 +55,7 @@ std::shared_ptr<const ast_gen::ElementAccess> NovelParser::parse(const QFileInfo
auto x_root = NovalSyntax::tidy(context, docs_node);
auto novel_accesstree = std::make_shared<ast_gen::ElementAccess>(x_root);
current_stamp = QTime::currentTime();
qDebug() << QString(u8"程序结构重建消耗时间:%1 ms。").arg(time_stamp.msecsTo(current_stamp));
qDebug().noquote() << QString(u8"%程序结构重建消耗时间:%1 ms。").arg(time_stamp.msecsTo(current_stamp));
return analyzer_ref->validCheckWith(novel_accesstree);
}

View File

@ -1,6 +1,7 @@
#include "libparse.h"
using namespace lib_parse;
using namespace ast_gen;
CheckException::CheckException(const QString& msg) : msg_store(msg) {}
@ -10,12 +11,41 @@ Analyzer::Analyzer(const QList<std::shared_ptr<const CheckProvider> >& providers
#include <QTime>
#include <QDebug>
std::shared_ptr<const ast_gen::ElementAccess> Analyzer::validCheckWith(std::shared_ptr<const ast_gen::ElementAccess> root) const {
std::shared_ptr<const ElementAccess> Analyzer::validCheckWith(std::shared_ptr<const ElementAccess> root) const {
for (auto& v : check_providers){
QTime time_stamp = QTime::currentTime();
v->validCheck(root);
auto current_stamp = QTime::currentTime();
qDebug() << QString(u8"校验器:%2 消耗时间:%1 ms。").arg(time_stamp.msecsTo(current_stamp)).arg(v->name());
qDebug().noquote() << QString(u8"%УÑéÆ÷£º%2 ÏûºÄʱ¼ä£º%1 ms¡£").arg(time_stamp.msecsTo(current_stamp)).arg(v->name());
}
return root;
}
bool VisitorControl::visitWith(std::shared_ptr<const ElementAccess> syntax_elm, std::shared_ptr<TreeVisitor> visitor) {
switch (visitor->mode()) {
case VisitMode::FirstParent: {
if (visitor->visit(syntax_elm)) {
for (auto& e : syntax_elm->children()) {
visitWith(e, visitor);
}
}
return true;
}break;
case VisitMode::LastParent:{
bool exc_continue = true;
for (auto& e : syntax_elm->children()) {
if(!visitWith(e, visitor)){
exc_continue = false;
break;
}
}
if(exc_continue)
visitor->visit(syntax_elm);
return exc_continue;
}break;
default:
break;
}
}

View File

@ -42,4 +42,32 @@ namespace lib_parse {
std::shared_ptr<const ast_gen::ElementAccess> validCheckWith(std::shared_ptr<const ast_gen::ElementAccess> root) const;
};
enum class VisitMode {
FirstParent, // 先序遍历
LastParent, // 后序遍历
};
class TreeVisitor {
public:
/**
* 访.
*
* \return
*/
virtual VisitMode mode() const = 0;
/**
* .
*
* \param syntax_element 访
* \return
*/
virtual bool visit(std::shared_ptr<const ast_gen::ElementAccess> syntax_element) = 0;
};
class LIBPARSE_EXPORT VisitorControl {
public:
bool visitWith(std::shared_ptr<const ast_gen::ElementAccess> syntax_elm, std::shared_ptr<TreeVisitor> visitor);
};
}

View File

@ -18,8 +18,8 @@ std::shared_ptr<const SyntaxElement> GlobalElement::appendToCache(std::shared_pt
return nullptr;
}
std::shared_ptr<const SyntaxElement> GlobalElement::getNamedNodeBy(int type, const QString& signature) const {
auto mixed_key = QString(u8"%1<%2>").arg(signature).arg(type);
std::shared_ptr<const SyntaxElement> GlobalElement::getNamedNodeBy(int paramType, const QString& signature) const {
auto mixed_key = QString(u8"%1<%2>").arg(signature).arg(paramType);
if (!node_cache.contains(mixed_key))
return nullptr;
return node_cache[mixed_key];

View File

@ -121,7 +121,7 @@ namespace ast_gen
* @return
* @throws
*/
virtual std::shared_ptr<const ast_gen::SyntaxElement> getNamedNodeBy(int type, const QString& signature) const;
virtual std::shared_ptr<const ast_gen::SyntaxElement> getNamedNodeBy(int paramType, const QString& signature) const;
virtual void addChild(std::shared_ptr<ast_gen::SyntaxElement> citem);
// ParseElement interface

View File

@ -4,8 +4,8 @@ using namespace example_novel;
using namespace lib_token;
TokenContent::TokenContent(int r, int c, const QString& t, const QString& p, std::shared_ptr<const ITokenDefine> type)
: row_n(r), col_n(c), text_n(t), path_p(p), type_def(type) {}
TokenContent::TokenContent(int r, int c, const QString& t, const QString& p, std::shared_ptr<const ITokenDefine> paramType)
: row_n(r), col_n(c), text_n(t), path_p(p), type_def(paramType) {}
QString TokenContent::file() const { return path_p; }
@ -65,7 +65,7 @@ int ReferMark::typeMark() const
QString ReferMark::regex() const { return u8"@"; }
Keywords::Keywords(const QString& val, const QString& nm, uint type_code) : value_store(val), name_store(nm), type_code(type_code) {}
Keywords::Keywords(const QString& val, const QString& nm, uint type_code) : means_store(val), name_store(nm), type_code(type_code) {}
QString Keywords::typeName() const { return name_store; }
@ -74,7 +74,7 @@ int Keywords::typeMark() const
return 0x06000000 | (0x00ffffff & type_code);
}
QString Keywords::regex() const { return value_store; }
QString Keywords::regex() const { return means_store; }
std::tuple<std::shared_ptr<const IToken>, std::shared_ptr<const IWordBase>>
Keywords::analysis(std::shared_ptr<const IWordBase> content) const {

View File

@ -18,7 +18,7 @@ namespace lib_token {
std::shared_ptr<const ITokenDefine> type_def;
public:
TokenContent(int r, int c, const QString& t, const QString& p, std::shared_ptr<const ITokenDefine> type);
TokenContent(int r, int c, const QString& t, const QString& p, std::shared_ptr<const ITokenDefine> paramType);
// WordBase interface
public:
@ -75,7 +75,7 @@ namespace example_novel {
class LIBTOKEN_EXPORT Keywords : public lib_token::ITokenDefine, public std::enable_shared_from_this<Keywords> {
private:
QString value_store, name_store;
QString means_store, name_store;
int type_code;
public: