From 74267ebd5b823cf3b19a7026f279d385ede1619f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=8E=89=E5=AE=87=E6=B8=85=E9=9F=B3?= <2422523675@qq.com>
Date: Sun, 6 Nov 2022 08:37:50 +0800
Subject: [PATCH] =?UTF-8?q?RTTI=E8=AF=AD=E6=B3=95=E9=93=BE=E6=9E=84?=
=?UTF-8?q?=E5=BB=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 5 +
.qmake.stash | 22 ++
DesParser/DesParser.pro | 41 +++
DesParser/DesParser.vcxproj | 234 +++++++++++++++
DesParser/DesParser.vcxproj.filters | 129 ++++++++
DesParser/DesParser.vcxproj.user | 4 +
DesParser/DesParser_zh_CN.ts | 3 +
DesParser/Design.md | 88 ++++++
DesParser/LexicalBase.cpp | 134 +++++++++
DesParser/LexicalBase.h | 76 +++++
DesParser/ParseFrame.cpp | 107 +++++++
DesParser/ParseFrame.h | 30 ++
DesParser/StoryChainDocumentParser.cpp | 380 +++++++++++++++++++++++
DesParser/StoryChainDocumentParser.h | 193 ++++++++++++
DesParser/StoryUnitDocumentParser.cpp | 331 +++++++++++++++++++++
DesParser/StoryUnitDocumentParser.h | 168 +++++++++++
DesParser/SyntaxBase.cpp | 133 +++++++++
DesParser/SyntaxBase.h | 344 +++++++++++++++++++++
DesParser/WordsPeak.cpp | 49 +++
DesParser/WordsPeak.h | 39 +++
DesParser/XSyntaxBase.cpp | 370 +++++++++++++++++++++++
DesParser/XSyntaxBase.h | 254 ++++++++++++++++
DesParser/comndef.h | 18 ++
DesParser/example.storychain | 8 +
DesParser/main.cpp | 33 ++
QtNovelDesc.pro | 5 +
QtNovelDesc.pro.user | 397 +++++++++++++++++++++++++
QtNovelDesc.sln | 31 ++
WordsIDE/WordsIDE.pro | 26 ++
WordsIDE/WordsIDE.vcxproj | 205 +++++++++++++
WordsIDE/WordsIDE.vcxproj.filters | 93 ++++++
WordsIDE/WordsIDE.vcxproj.user | 4 +
WordsIDE/WordsIDE_zh_CN.ts | 3 +
WordsIDE/main.cpp | 23 ++
WordsIDE/mainwindow.cpp | 11 +
WordsIDE/mainwindow.h | 14 +
36 files changed, 4005 insertions(+)
create mode 100644 .gitignore
create mode 100644 .qmake.stash
create mode 100644 DesParser/DesParser.pro
create mode 100644 DesParser/DesParser.vcxproj
create mode 100644 DesParser/DesParser.vcxproj.filters
create mode 100644 DesParser/DesParser.vcxproj.user
create mode 100644 DesParser/DesParser_zh_CN.ts
create mode 100644 DesParser/Design.md
create mode 100644 DesParser/LexicalBase.cpp
create mode 100644 DesParser/LexicalBase.h
create mode 100644 DesParser/ParseFrame.cpp
create mode 100644 DesParser/ParseFrame.h
create mode 100644 DesParser/StoryChainDocumentParser.cpp
create mode 100644 DesParser/StoryChainDocumentParser.h
create mode 100644 DesParser/StoryUnitDocumentParser.cpp
create mode 100644 DesParser/StoryUnitDocumentParser.h
create mode 100644 DesParser/SyntaxBase.cpp
create mode 100644 DesParser/SyntaxBase.h
create mode 100644 DesParser/WordsPeak.cpp
create mode 100644 DesParser/WordsPeak.h
create mode 100644 DesParser/XSyntaxBase.cpp
create mode 100644 DesParser/XSyntaxBase.h
create mode 100644 DesParser/comndef.h
create mode 100644 DesParser/example.storychain
create mode 100644 DesParser/main.cpp
create mode 100644 QtNovelDesc.pro
create mode 100644 QtNovelDesc.pro.user
create mode 100644 QtNovelDesc.sln
create mode 100644 WordsIDE/WordsIDE.pro
create mode 100644 WordsIDE/WordsIDE.vcxproj
create mode 100644 WordsIDE/WordsIDE.vcxproj.filters
create mode 100644 WordsIDE/WordsIDE.vcxproj.user
create mode 100644 WordsIDE/WordsIDE_zh_CN.ts
create mode 100644 WordsIDE/main.cpp
create mode 100644 WordsIDE/mainwindow.cpp
create mode 100644 WordsIDE/mainwindow.h
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3267c59
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+WordsIDE/release/
+WordsIDE/debug/
+DesParser/release/
+DesParser/debug/
+.vs/
diff --git a/.qmake.stash b/.qmake.stash
new file mode 100644
index 0000000..4a812db
--- /dev/null
+++ b/.qmake.stash
@@ -0,0 +1,22 @@
+QMAKE_CXX.QT_COMPILER_STDCXX = 199711L
+QMAKE_CXX.QMAKE_MSC_VER = 1916
+QMAKE_CXX.QMAKE_MSC_FULL_VER = 191627048
+QMAKE_CXX.COMPILER_MACROS = \
+ QT_COMPILER_STDCXX \
+ QMAKE_MSC_VER \
+ QMAKE_MSC_FULL_VER
+QMAKE_CXX.INCDIRS = \
+ "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\VC\\Tools\\MSVC\\14.16.27023\\ATLMFC\\include" \
+ "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\VC\\Tools\\MSVC\\14.16.27023\\include" \
+ "C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.6.1\\include\\um" \
+ "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.22621.0\\ucrt" \
+ "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.22621.0\\shared" \
+ "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.22621.0\\um" \
+ "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.22621.0\\winrt" \
+ "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.22621.0\\cppwinrt"
+QMAKE_CXX.LIBDIRS = \
+ "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\VC\\Tools\\MSVC\\14.16.27023\\ATLMFC\\lib\\x64" \
+ "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\VC\\Tools\\MSVC\\14.16.27023\\lib\\x64" \
+ "C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.6.1\\lib\\um\\x64" \
+ "C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.22621.0\\ucrt\\x64" \
+ "C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.22621.0\\um\\x64"
diff --git a/DesParser/DesParser.pro b/DesParser/DesParser.pro
new file mode 100644
index 0000000..f294186
--- /dev/null
+++ b/DesParser/DesParser.pro
@@ -0,0 +1,41 @@
+QT -= gui
+
+CONFIG += c++11 console
+CONFIG -= app_bundle
+
+# You can make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+ LexicalBase.cpp \
+ ParseFrame.cpp \
+ StoryChainDocumentParser.cpp \
+ StoryUnitDocumentParser.cpp \
+ SyntaxBase.cpp \
+ WordsPeak.cpp \
+ XSyntaxBase.cpp \
+ main.cpp
+
+TRANSLATIONS += \
+ DesParser_zh_CN.ts
+CONFIG += lrelease
+CONFIG += embed_translations
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
+
+HEADERS += \
+ LexicalBase.h \
+ ParseFrame.h \
+ StoryChainDocumentParser.h \
+ StoryUnitDocumentParser.h \
+ SyntaxBase.h \
+ WordsPeak.h \
+ XSyntaxBase.h \
+ comndef.h
+
+DISTFILES += \
+ example.storychain
diff --git a/DesParser/DesParser.vcxproj b/DesParser/DesParser.vcxproj
new file mode 100644
index 0000000..ebdd48b
--- /dev/null
+++ b/DesParser/DesParser.vcxproj
@@ -0,0 +1,234 @@
+
+
+
+
+ Release
+ x64
+
+
+ Debug
+ x64
+
+
+
+ {CDBA4FCE-9275-3B08-87C8-B4473EB323EA}
+ DesParser
+ QtVS_v304
+ 10.0.22621.0
+ 10.0.22621.0
+ $(MSBuildProjectDirectory)\QtMsBuild
+
+
+
+ v141
+ release\
+ false
+ NotSet
+ Application
+ release\
+ DesParser
+
+
+ v141
+ debug\
+ false
+ NotSet
+ Application
+ debug\
+ DesParser
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ debug\
+ debug\
+ DesParser
+ true
+
+
+ release\
+ release\
+ DesParser
+ true
+ false
+
+
+ 5.12.11_msvc2017_64
+ core
+
+
+ 5.12.11_msvc2017_64
+ core
+
+
+
+
+
+
+ GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;release;%(AdditionalIncludeDirectories)
+ -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)
+ release\
+ false
+ None
+ 4577;4467;%(DisableSpecificWarnings)
+ Sync
+ release\
+ MaxSpeed
+ _CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_NO_DEBUG;NDEBUG;%(PreprocessorDefinitions)
+ false
+
+
+ MultiThreadedDLL
+ true
+ true
+ Level3
+ true
+
+
+ %(AdditionalDependencies)
+ %(AdditionalLibraryDirectories)
+ "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)
+ true
+ false
+ true
+ false
+ $(OutDir)\DesParser.exe
+ true
+ Console
+ true
+
+
+ Unsigned
+ None
+ 0
+
+
+ _CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_NO_DEBUG;QT_CORE_LIB;%(PreprocessorDefinitions)
+
+
+ qmake_qmake_qm_files
+ default
+ Rcc'ing %(Identity)...
+ $(Configuration)
+ qrc_%(Filename).cpp
+
+
+
+
+ GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;debug;%(AdditionalIncludeDirectories)
+ -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)
+ debug\
+ false
+ ProgramDatabase
+ 4577;4467;%(DisableSpecificWarnings)
+ Sync
+ debug\
+ Disabled
+ _CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;%(PreprocessorDefinitions)
+ false
+ MultiThreadedDebugDLL
+ true
+ true
+ Level3
+ true
+
+
+ %(AdditionalDependencies)
+ %(AdditionalLibraryDirectories)
+ "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)
+ true
+ true
+ true
+ $(OutDir)\DesParser.exe
+ true
+ Console
+ true
+
+
+ Unsigned
+ None
+ 0
+
+
+ _CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions)
+
+
+ qmake_qmake_qm_files
+ default
+ Rcc'ing %(Identity)...
+ $(Configuration)
+ qrc_%(Filename).cpp
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Document
+ true
+ $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)
+ cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >debug\moc_predefs.h
+ Generate moc_predefs.h
+ debug\moc_predefs.h;%(Outputs)
+
+
+ Document
+ $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)
+ cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >release\moc_predefs.h
+ Generate moc_predefs.h
+ release\moc_predefs.h;%(Outputs)
+ true
+
+
+
+
+ DesParser_zh_CN.ts;%(AdditionalInputs)
+ $(QTDIR)\bin\lrelease.exe DesParser_zh_CN.ts -qm release\DesParser_zh_CN.qm
+ lrelease
+ release\DesParser_zh_CN.qm;%(Outputs)
+ DesParser_zh_CN.ts;%(AdditionalInputs)
+ $(QTDIR)\bin\lrelease.exe DesParser_zh_CN.ts -qm debug\DesParser_zh_CN.qm
+ lrelease
+ debug\DesParser_zh_CN.qm;%(Outputs)
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DesParser/DesParser.vcxproj.filters b/DesParser/DesParser.vcxproj.filters
new file mode 100644
index 0000000..c425f8a
--- /dev/null
+++ b/DesParser/DesParser.vcxproj.filters
@@ -0,0 +1,129 @@
+
+
+
+
+ {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}
+ cpp;c;cxx;moc;h;def;odl;idl;res;
+
+
+ {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}
+ cpp;c;cxx;moc;h;def;odl;idl;res;
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}
+ qrc;*
+ false
+
+
+ {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}
+ qrc;*
+ false
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}
+ ts;xlf
+ false
+
+
+ {639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}
+ ts;xlf
+ false
+
+
+ {B83CAF91-C7BF-462F-B76C-EA11631F866C}
+ *
+ false
+
+
+ {B83CAF91-C7BF-462F-B76C-EA11631F866C}
+ *
+ false
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Generated Files
+
+
+ Generated Files
+
+
+
+
+ Translation Files
+
+
+
+
+ Distribution Files
+
+
+
\ No newline at end of file
diff --git a/DesParser/DesParser.vcxproj.user b/DesParser/DesParser.vcxproj.user
new file mode 100644
index 0000000..be25078
--- /dev/null
+++ b/DesParser/DesParser.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/DesParser/DesParser_zh_CN.ts b/DesParser/DesParser_zh_CN.ts
new file mode 100644
index 0000000..630fd35
--- /dev/null
+++ b/DesParser/DesParser_zh_CN.ts
@@ -0,0 +1,3 @@
+
+
+
diff --git a/DesParser/Design.md b/DesParser/Design.md
new file mode 100644
index 0000000..95527cf
--- /dev/null
+++ b/DesParser/Design.md
@@ -0,0 +1,88 @@
+#源代码格式
+## 设计目标
+
+## 格式定义
+xxxx.storychain
+```
+#脉络:脉络定义0
+{
+ 描述文字涉及到新灵脉@{灵脉|龙虎灵脉}
+ #节点:节点名称
+ {
+ 描述文字
+ }
+}
+
+#脉络:脉络定义
+{
+ 描述数字
+ #节点:节点名称
+ {
+ 描述文字@{武器|钧天剑}
+ }
+}
+```
+
+# 编译产物(中间代码)
+## 设计目标
+* 脱离具体的表现形式,使用语法树的结构组织整个内容结构
+* 通用化内容形式,实际优化平台
+
+## 格式定义
+### 故事脉络定义:单纯的时间顺序
+-- *.storychain -- *.wsco ---------
+```
+
+ description-text
+ description-text
+ description-text
+ description-text
+
+```
+
+### 故事单元定义:组织不同情节,构成完整的故事单元,引入不同顺序排列机制
+-- *.storyunit -- *.wsuo ---------
+```
+
+ description-text
+
+
+ description-text
+
+
+
+ description-text
+
+
+
+ description-text
+
+
+
+
+
+ 顺序脉络
+
+
+
+
+
+
+
+
+
+
+```
+
+### 故事板定义,从整体的角度上对所有故事情节进行组织,基于不同的类型进行进行叙述
+-- *.storyboard -- *.wsbo ---------
+```
+
+ description-text
+
+
+
+
+
+
+```
\ No newline at end of file
diff --git a/DesParser/LexicalBase.cpp b/DesParser/LexicalBase.cpp
new file mode 100644
index 0000000..5c47e70
--- /dev/null
+++ b/DesParser/LexicalBase.cpp
@@ -0,0 +1,134 @@
+#include "LexicalBase.h"
+#include
+
+using namespace Lex;
+
+LexicalBase::LexicalBase(QList seqence, const QString UnknownToken)
+ : unknown_token(UnknownToken), lexical_seq(seqence)
+{
+ empty_seq << '\t' << '\b' << ' ' << '\r' << EOF;
+}
+
+typedef int lexunit_index;
+typedef int match_start;
+
+QList LexicalBase::push(int row, int col, const QChar w)
+{
+ QList result;
+
+ QString remains = "";
+ if (!empty_seq.contains(w)) {
+ code_acc << XChar(w, row, col);
+ if (w != '\n')
+ return result;
+ }
+ else {
+ if (!code_acc.size())
+ return result;
+ }
+
+ for (auto c : code_acc)
+ remains += c.value();
+
+ auto mid_result = lexical_parse(remains);
+ for (auto &r : mid_result) {
+ auto char_start = code_acc[r.index_at_segment];
+ r.StartRow = char_start.row();
+ r.StartCol = char_start.col();
+ auto char_end = code_acc[r.index_at_segment + r.Text.length() - 1];
+ r.EndRow = char_end.row();
+ r.EndCol = char_end.col();
+ }
+
+ code_acc.clear();
+ return mid_result;
+}
+
+QList LexicalBase::lexical_parse(const QString & segment)
+{
+ // 获取匹配词法分析
+ QList result;
+ QList> match_results;
+ int lex_index = -1;
+ for (auto lex : lexical_seq) {
+ lex_index++;
+ QRegExp exp(lex.RegExpression);
+ auto match_index = exp.indexIn(segment);
+ if (match_index != -1)
+ match_results.append(std::make_tuple(match_index, lex_index));
+ }
+
+ // 没有匹配结果,返回未定义
+ if (!match_results.size())
+ {
+ LexResult rst;
+ rst.index_at_segment = 0;
+ rst.Token = this->unknown_token;
+ rst.Text = segment;
+ result << rst;
+ return result;
+ }
+
+ // 获取“匹配索引”,“词法优先级”获取最佳匹配结果,最小
+ std::tuple min_elm = std::make_tuple(INT32_MAX, INT32_MAX);
+ for (auto item : match_results) {
+ if (std::get<0>(item) < std::get<0>(min_elm))
+ min_elm = item;
+ else if (std::get<0>(item) == std::get<0>(min_elm) &&
+ std::get<1>(item) < std::get<1>(min_elm))
+ min_elm = item;
+ }
+
+ // 发现无效匹配局部,标记前部为未知
+ if (std::get<0>(min_elm) != 0) {
+ LexResult rst;
+ rst.index_at_segment = 0;
+ rst.Token = this->unknown_token;
+ rst.Text = segment.mid(0, std::get<0>(min_elm));
+ result << rst;
+ }
+
+ // 重新匹配,获取完全匹配信息
+ auto lex_unit = lexical_seq[std::get<1>(min_elm)];
+ QRegExp exp(lex_unit.RegExpression);
+ auto match_start = exp.indexIn(segment);
+ auto match_len = exp.matchedLength();
+
+ // 获取匹配词法分析结果
+ LexResult rst;
+ rst.Token = lex_unit.TokenType;
+ rst.Text = segment.mid(match_start, match_len);
+ rst.index_at_segment = match_start;
+ result << rst;
+
+ // 迭代匹配剩余字符串
+ auto last = segment.mid(match_start + match_len);
+ if(last.length()){
+ auto xrst = lexical_parse(last);
+ for (auto &t : xrst)
+ t.index_at_segment += match_start;
+ result.append(xrst);
+ }
+
+
+ // 返回结果
+ return result;
+}
+
+XChar::XChar(QChar c, int row, int col)
+ : value_store(c), row_index(row), col_index(col) {}
+
+QChar XChar::value() const
+{
+ return value_store;
+}
+
+int XChar::row() const
+{
+ return row_index;
+}
+
+int XChar::col() const
+{
+ return col_index;
+}
diff --git a/DesParser/LexicalBase.h b/DesParser/LexicalBase.h
new file mode 100644
index 0000000..7e573ee
--- /dev/null
+++ b/DesParser/LexicalBase.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include
+#include
+
+namespace Lex {
+ class LexicalBase;
+
+ /**
+ * 解析基准定义单元.
+ */
+ struct LexUnit
+ {
+ QString TokenType; // Token字符
+ QString RegExpression; // 词法解析表达式
+ };
+
+ /**
+ * 词法分析结果.
+ */
+ struct LexResult
+ {
+ QString Token; // Token字符
+ QString Text; // 内容
+ int StartRow, StartCol, EndRow, EndCol; // 波及范围
+
+ friend class LexicalBase;
+ private:
+ int index_at_segment;
+ };
+
+ /**
+ * 字符提取富信息单元.
+ */
+ class XChar
+ {
+ public:
+ explicit XChar(QChar c, int row, int col);
+ QChar value() const;
+ int row() const;
+ int col() const;
+
+ private:
+ QChar value_store;
+ int row_index, col_index;
+ };
+
+ /**
+ * 基础词法分析器.
+ */
+ class LexicalBase
+ {
+ public:
+ explicit LexicalBase(QList seqence, const QString UnknownToken);
+ virtual ~LexicalBase() = default;
+
+ /**
+ * 词法分析器累积解析单个字符流.
+ *
+ * \param row 行
+ * \param col 列
+ * \param w 字符
+ * \return 累积适配结果,空累积,
+ */
+ QList push(int row, int col, const QChar w);
+
+ private:
+ QString unknown_token;
+ QList empty_seq;
+
+ QList code_acc;
+ QList lexical_seq;
+
+ QList lexical_parse(const QString &segment);
+ };
+}
\ No newline at end of file
diff --git a/DesParser/ParseFrame.cpp b/DesParser/ParseFrame.cpp
new file mode 100644
index 0000000..e65dfb4
--- /dev/null
+++ b/DesParser/ParseFrame.cpp
@@ -0,0 +1,107 @@
+#include "ParseFrame.h"
+#include "WordsPeak.h"
+
+using namespace Parse;
+using namespace Lex;
+
+Parse::ParseFrame::ParseFrame() {}
+
+QList Parse::ParseFrame::analysis(DocCore*doc, const QString & path)
+{
+ ForwardStream stream;
+ if (stream.initSource(path))
+ return QList();
+
+ LexicalBase token_s(this->token_seqs, this->unknown_token);
+
+ QList lex_seqence;
+ std::tuple temp;
+ while ((std::get<2>(temp = stream.read())) != EOF)
+ {
+ auto results = token_s.push(
+ std::get<0>(temp),
+ std::get<1>(temp),
+ std::get<2>(temp));
+
+ lex_seqence.append(results);
+ }
+
+ for (auto it : cascade_parsers)
+ it->docActive(doc);
+
+ QList xrets;
+ do {
+ QList nodes;
+ auto rst = inner_parse(lex_seqence, cascade_parsers, nodes);
+ if (rst == ParseResult::Failed)
+ lex_seqence.removeFirst();
+
+ xrets.append(nodes);
+ } while (lex_seqence.size());
+
+ return xrets;
+}
+
+void Parse::ParseFrame::appendTokensDefine(QList seqs, const QString & unknown_token)
+{
+ this->unknown_token = unknown_token;
+ token_seqs.append(seqs);
+}
+
+void Parse::ParseFrame::appendParser(SyntaxParser * u)
+{
+ cascade_parsers << u;
+}
+
+Parse::ParseResult Parse::ParseFrame::inner_parse(QList &lex_seqence, QList parsers, QList &nodes_out)
+{
+ QList nodes;
+
+ // 遍历解析器,获取匹配
+ for (auto it : parsers) {
+ if (!it->applied(lex_seqence))
+ continue;
+
+ it->reset();
+ for (;;) {
+ // 在当前层级解析标记序列
+ ParseResult result = it->parse(lex_seqence);
+ auto node = it->currNode();
+ if (node && !nodes.contains(node))
+ nodes << node;
+
+
+ switch (result) {
+ case ParseResult::SelfManipulate:
+ // 进入下一个循环,继续使用本解析器解析
+ break;
+
+ case ParseResult::EnterNext: {
+ // 移交解析任务给成员解析器
+ ChildCheck:
+ QList tlist;
+ auto child_parsers = it->children();
+ auto rst = inner_parse(lex_seqence, child_parsers, tlist);
+ // 一个成员解析器完成全部解析任务,继续核对下一个解析器
+ if (rst == ParseResult::Completed)
+ goto ChildCheck;
+ // 成员解析器无法处理,返回父解析器
+ }break;
+
+ case ParseResult::Completed:
+ // 本解析器处理解析完成
+ nodes_out.append(nodes);
+ return ParseResult::Completed;
+
+ case ParseResult::Failed:
+ auto token = lex_seqence.first();
+ auto word = new Words(it->docRef()->unknowns(), it->docRef(), token.Text, token.StartRow, token.StartCol);
+ it->docRef()->append(word);
+ lex_seqence.removeFirst();
+ break;
+ }
+ }
+ }
+
+ return ParseResult::Failed;
+}
diff --git a/DesParser/ParseFrame.h b/DesParser/ParseFrame.h
new file mode 100644
index 0000000..38c6219
--- /dev/null
+++ b/DesParser/ParseFrame.h
@@ -0,0 +1,30 @@
+#pragma once
+#include
+#include
+#include "SyntaxBase.h"
+
+namespace Parse
+{
+ /**
+ * 基础解析器框架.
+ */
+ class ParseFrame
+ {
+ public:
+ explicit ParseFrame();
+ virtual ~ParseFrame() = default;
+
+ QList analysis(DocCore *doc, const QString &path);
+
+ protected:
+ void appendTokensDefine(QList seqs, const QString &unknown_token);
+ void appendParser(SyntaxParser* u);
+
+ private:
+ QString unknown_token;
+ QList token_seqs;
+ QList cascade_parsers;
+
+ Parse::ParseResult Parse::ParseFrame::inner_parse(QList &lex_seqence, QList parsers, QList &nodes_out);
+ };
+}
diff --git a/DesParser/StoryChainDocumentParser.cpp b/DesParser/StoryChainDocumentParser.cpp
new file mode 100644
index 0000000..15fa9d8
--- /dev/null
+++ b/DesParser/StoryChainDocumentParser.cpp
@@ -0,0 +1,380 @@
+#include "StoryChainDocumentParser.h"
+
+using namespace Parse;
+using namespace Lex;
+using namespace Syntax;
+using namespace Syntax::Defines;
+
+// storychain 解析器================================================
+NodeStoryChainParser::NodeStoryChainParser(ProjectCore *core)
+ : XSyntaxBase("文学脉络"), pjt_ref(core)
+{
+ auto rule = addRule("文学脉络定义", 0, [this](const QList &seqs, int cnt)->ParseResult
+ {
+ auto nmidx = cnt - 1, defidx = cnt - 2;
+
+ // 构建语法节点
+ auto storychain = new NodeStoryChain(this->docRef(), seqs[nmidx].Text);
+ this->refocusNode(storychain);
+
+ // 收集词语
+ auto words0 = new Words(storychain, this->docRef(), seqs[defidx].Text, seqs[defidx].StartRow, seqs[defidx].StartCol);
+ auto words1 = new Words(storychain, this->docRef(), seqs[nmidx].Text, seqs[nmidx].StartRow, seqs[nmidx].StartCol);
+ docRef()->append(words0);
+ docRef()->append(words1);
+
+ return ParseResult::SelfManipulate;
+ });
+ rule->addExpression("脉络定义基础", { Elm("{脉络定义}"), Elm("{描述文本}", true) });
+ rule->addExpression("脉络定义拓展", { Elm("{换行符}"), Elm("{换行符}"), Exp("脉络定义基础", true)});
+
+
+
+ rule = addRule("脉络成分解析", 1, [this](const QList &seqs, int cnt)->ParseResult
+ {
+ auto nmidx = cnt - 1;
+
+ // 获取语法节点
+ auto storychain = this->currNode();
+
+ // 收集词语
+ auto word = new Words(storychain, docRef(), seqs[nmidx].Text, seqs[nmidx].StartRow, seqs[nmidx].StartCol);
+ docRef()->append(word);
+
+ return ParseResult::EnterNext;
+ });
+ rule->addExpression("基础脉络界限", { Elm("{左界限}", true) });
+ rule->addExpression("拓展脉络界限", { Elm("{换行符}"), Elm("{换行符}"), Exp("基础脉络界限", true) });
+
+
+
+ rule = addRule("完成脉络解析", 2, [this](const QList &seqs, int cnt)->ParseResult
+ {
+ auto nmidx = cnt - 1;
+
+ // 获取语法节点
+ auto storychain = this->currNode();
+
+ // 收集词语
+ auto word = new Words(storychain, docRef(), seqs[nmidx].Text, seqs[nmidx].StartRow, seqs[nmidx].StartCol);
+ docRef()->append(word);
+
+ return ParseResult::Completed;
+ });
+ rule->addExpression("基础脉络跳出", { Elm("{右界限}", true) });
+ rule->addExpression("拓展脉络跳出", { Elm("{换行符}"), Elm("{换行符}"), Exp("基础脉络跳出", true) });
+
+ addChild(QList() << new NodeStoryPointParser(this) << new NodeStoryChainDesGroupParser(this));
+}
+
+ProjectCore * NodeStoryChainParser::project() const
+{
+ return pjt_ref;
+}
+
+// storypoint解析器=================================================
+NodeStoryPointParser::NodeStoryPointParser(NodeStoryChainParser *chain)
+ : XSyntaxBase("脉络驻点"), parent_parser(chain)
+{
+ auto rule = addRule("脉络驻点定义", 0, [this](const QList &seqs, int c)->ParseResult {
+ auto nmidx = c - 1, defidx = c - 2;
+
+ // 语法节点定义
+ auto node = this->storyChainParser()->currNode();
+ auto storypoint = new NodeStoryPoint(static_cast(node), seqs[nmidx].Text);
+ node->appendChild(storypoint);
+ this->refocusNode(storypoint);
+
+ // 词语收集
+ auto word0 = new Words(storypoint, node->document(), seqs[defidx].Text, seqs[defidx].StartRow, seqs[defidx].StartCol);
+ auto word1 = new Words(storypoint, node->document(), seqs[nmidx].Text, seqs[nmidx].StartRow, seqs[nmidx].StartCol);
+ node->document()->append(word0);
+ node->document()->append(word1);
+
+ return ParseResult::SelfManipulate;
+ });
+ rule->addExpression("基础节点定义", { Elm("{节点定义}"), Elm("{描述文本}", true) });
+ rule->addExpression("拓展节点定义", { Elm("{换行符}"), Elm("{换行符}"), Exp("基础节点定义", true) });
+
+
+
+ rule = addRule("节点成分解析", 1, [this](const QList &seqs, int cnt)->ParseResult
+ {
+ auto nmidx = cnt - 1;
+ auto word = new Words(this->currNode(), this->storyChainParser()->docRef(), seqs[nmidx].Text, seqs[nmidx].StartRow, seqs[nmidx].StartCol);
+ this->docRef()->append(word);
+
+ return ParseResult::EnterNext;
+ });
+ rule->addExpression("基础节点界限", { Elm("{左界限}", true) });
+ rule->addExpression("拓展节点界限", { Elm("{换行符}"), Elm("{换行符}"), Exp("基础节点界限", true) });
+
+
+
+ rule = addRule("完成节点解析", 2, [this](const QList &seqs, int cnt)->ParseResult
+ {
+ auto nmidx = cnt - 1;
+ auto word = new Words(this->currNode(), this->storyChainParser()->docRef(), seqs[nmidx].Text, seqs[nmidx].StartRow, seqs[nmidx].StartCol);
+ this->docRef()->append(word);
+
+ return ParseResult::Completed;
+ });
+ rule->addExpression("基础节点跳出", { Elm("{右界限}", true) });
+ rule->addExpression("拓展节点跳出", { Elm("{换行符}"), Elm("{换行符}"), Exp("基础节点跳出", true) });
+
+ addChild(QList() << new NodeStoryChainDesGroupParser(this));
+}
+
+NodeStoryChainParser * NodeStoryPointParser::storyChainParser() const
+{
+ return parent_parser;
+}
+
+DocCore * NodeStoryPointParser::docRef() const
+{
+ return this->storyChainParser()->docRef();
+}
+
+
+
+
+NodeStoryChain::NodeStoryChain(DocCore * doc, const QString & name)
+ : doc_store(doc), name_store(name)
+{
+}
+
+QString NodeStoryChain::srcPath() const
+{
+ return doc_store->filePath();
+}
+
+QString NodeStoryChain::name() const
+{
+ return name_store;
+}
+
+DocCore * NodeStoryChain::document() const
+{
+ return doc_store;
+}
+
+int NodeStoryChain::typeValue() const
+{
+ return NODE_STORYCHAIN;
+}
+
+DesNode * NodeStoryChain::parent() const
+{
+ return nullptr;
+}
+
+void NodeStoryChain::appendChild(DesNode * ins)
+{
+ children_nodes.append(ins);
+}
+
+QList NodeStoryChain::children() const
+{
+ return children_nodes;
+}
+
+bool NodeStoryChain::check(QList& reasons) const
+{
+ return false;
+}
+
+QString NodeStoryChain::toString() const
+{
+ auto desc_string = QString(depth(), ' ') + "#脉络 " + name() + " {";
+ for (auto it : children())
+ desc_string += "\n"+ QString(depth(), ' ') + it->toString();
+ desc_string +="\n"+ QString(depth(), ' ') + "}";
+
+ return desc_string;
+}
+
+NodeStoryPoint::NodeStoryPoint(NodeStoryChain * chain, const QString & name)
+ : chain_store(chain), name_store(name)
+{
+}
+
+NodeStoryChain * NodeStoryPoint::storyChain() const
+{
+ return chain_store;
+}
+
+DocCore * NodeStoryPoint::document() const
+{
+ return chain_store->document();
+}
+
+int NodeStoryPoint::typeValue() const
+{
+ return NODE_STORYPOINT;
+}
+
+DesNode * NodeStoryPoint::parent() const
+{
+ return chain_store;
+}
+
+void NodeStoryPoint::appendChild(DesNode * ins)
+{
+ children_nodes.append(ins);
+}
+
+QList NodeStoryPoint::children() const
+{
+ return children_nodes;
+}
+
+bool NodeStoryPoint::check(QList& reasons) const
+{
+ return false;
+}
+
+QString NodeStoryPoint::toString() const
+{
+ QString desc_string = "";
+ desc_string += QString(depth(), ' ') + "#节点 " + name() + " {";
+ for (auto it : children())
+ desc_string += "\n" + QString(depth(), ' ') + it->toString();
+ desc_string += "\n"+QString(depth(), ' ') + "}";
+
+ return desc_string;
+}
+
+QString NodeStoryPoint::name() const
+{
+ return this->name_store;
+}
+
+NodeStoryDesGroup::NodeStoryDesGroup(DesNode * parent_refer)
+ : parent_refer(parent_refer)
+{
+}
+
+DocCore * NodeStoryDesGroup::document() const
+{
+ return parent_refer->document();
+}
+
+int NodeStoryDesGroup::typeValue() const
+{
+ return NODE_DESCRIPTION_GROUP;
+}
+
+DesNode * NodeStoryDesGroup::parent() const
+{
+ return parent_refer;
+}
+
+void NodeStoryDesGroup::appendChild(DesNode * ins)
+{
+ children_nodes << ins;
+}
+
+QList NodeStoryDesGroup::children() const
+{
+ return children_nodes;
+}
+
+bool NodeStoryDesGroup::check(QList& reasons) const
+{
+ return false;
+}
+
+QString NodeStoryDesGroup::toString() const
+{
+ QString desc = QString(depth(), ' ') ;
+ for (auto it : children())
+ desc += it->toString() + " ";
+
+ return desc;
+}
+
+NodeStoryDesBlock::NodeStoryDesBlock(NodeStoryDesGroup * parent_node, const QString &text)
+ : parent_refer(parent_node), text_block(text)
+{
+}
+
+DocCore * NodeStoryDesBlock::document() const
+{
+ return parent_refer->document();
+}
+
+int NodeStoryDesBlock::typeValue() const
+{
+ return NODE_DESCRIPTION_BLOCK;
+}
+
+DesNode * NodeStoryDesBlock::parent() const
+{
+ return parent_refer;
+}
+
+void NodeStoryDesBlock::appendChild(DesNode * ins)
+{
+}
+
+QList NodeStoryDesBlock::children() const
+{
+ return QList();
+}
+
+bool NodeStoryDesBlock::check(QList& reasons) const
+{
+ return false;
+}
+
+QString NodeStoryDesBlock::toString() const
+{
+ return text_block;
+}
+
+
+NodeStoryChainDesGroupParser::NodeStoryChainDesGroupParser(XSyntaxBase * pparser)
+ : XSyntaxBase("描述块"), parent_parser(pparser)
+{
+ auto rule = addRule("提取文本", 0, [this, pparser](const QList &seqs, int cnt)->ParseResult {
+ auto curr_node = new NodeStoryDesGroup(pparser->currNode());
+ refocusNode(curr_node);
+ pparser->currNode()->appendChild(curr_node);
+
+ for (auto idx = 0; idx < cnt; ++idx)
+ if (seqs[idx].Token != "{换行符}") {
+ auto node_blk = new NodeStoryDesBlock(curr_node, seqs[idx].Text);
+ curr_node->appendChild(node_blk);
+ auto word = new Words(node_blk, docRef(), seqs[idx].Text, seqs[idx].StartRow, seqs[idx].StartCol);
+ docRef()->append(word);
+ }
+
+ return ParseResult::Completed;
+ });
+ rule->addExpression("基础提取文本", { Elm("{描述文本}"), Elm("{描述文本}", true) });
+ rule->addExpression("拓展提取文本", { Elm("{换行符}") , Elm("{换行符}") , Exp("基础提取文本", true) });
+
+
+ rule = addRule("完成提取", 1, [this](const QList &seqs, int cnt)->ParseResult {
+ refocusNode(nullptr);
+ return ParseResult::Completed;
+ });
+ rule->addExpression("基础文本提取跳出", { Elm("{换行符}", true) });
+}
+
+
+StoryChainDocumentParser::StoryChainDocumentParser(ProjectCore * pjt)
+{
+ appendTokensDefine({
+ {"{脉络定义}","#脉络"},
+ {"{节点定义}", "#节点"},
+ {"{描述文本}", "[^#@\\{\\}\\n]+"},
+ {"{左界限}","\\{"},
+ {"{右界限}","\\}"},
+ {"{换行符}","\\n"},
+ {"{引用符}", "@"},
+ }, "{无法识别}");
+
+ auto chain_parser = new NodeStoryChainParser(pjt);
+ appendParser(chain_parser);
+}
diff --git a/DesParser/StoryChainDocumentParser.h b/DesParser/StoryChainDocumentParser.h
new file mode 100644
index 0000000..85c73fb
--- /dev/null
+++ b/DesParser/StoryChainDocumentParser.h
@@ -0,0 +1,193 @@
+#pragma once
+
+/**
+ * StoryChain文件定义.
+ */
+#include
+#include
+#include "ParseFrame.h"
+#include "XSyntaxBase.h"
+#include "comndef.h"
+
+
+namespace Parse
+{
+ class NodeStoryPoint;
+
+ /**
+ * 故事脉络节点定义.
+ */
+ class NodeStoryChain : public NamedNode
+ {
+ public:
+ /**
+ * 构建一个新的脉络节点.
+ *
+ * \param src_path 源文件路径
+ */
+ explicit NodeStoryChain(DocCore *doc, const QString &name);
+ virtual ~NodeStoryChain() = default;
+
+ /**
+ * 获取此解析节点关联的源文件路径.
+ *
+ * \return 路径字符串
+ */
+ virtual QString srcPath() const;
+
+
+ // 通过 NamedNode 继承
+ inline virtual int depth() const override {
+ return 0;
+ }
+ virtual QString name() const override;
+ virtual DocCore * document() const override;
+ virtual int typeValue() const override;
+ virtual DesNode * parent() const override;
+ virtual void appendChild(DesNode * ins) override;
+ virtual QList children() const override;
+ virtual bool check(QList& reasons) const override;
+ virtual QString toString() const override;
+
+ private:
+ DocCore *const doc_store;
+ QString name_store;
+ QList children_nodes;
+ };
+
+ /**
+ * 故事脉络定制解析器.
+ */
+ class NodeStoryChainParser : public Syntax::XSyntaxBase
+ {
+ public:
+ NodeStoryChainParser(ProjectCore *core);
+ virtual ~NodeStoryChainParser() = default;
+
+ ProjectCore* project() const;
+
+ private:
+ ProjectCore *pjt_ref;
+ };
+
+ /**
+ * 故事节点.
+ */
+ class NodeStoryPoint : public NamedNode
+ {
+ public:
+ explicit NodeStoryPoint(NodeStoryChain *chain, const QString &name);
+ virtual ~NodeStoryPoint() = default;
+
+ /**
+ * 获取此解析节点依附的脉络节点
+ *
+ * \return 脉络节点
+ */
+ virtual NodeStoryChain* storyChain() const;
+
+ // 通过 NamedNode 继承
+ inline virtual int depth() const override {
+ return chain_store->depth() + 1;
+ }
+ virtual DocCore * document() const override;
+ virtual int typeValue() const override;
+ virtual DesNode * parent() const override;
+ virtual void appendChild(DesNode * ins) override;
+ virtual QList children() const override;
+ virtual bool check(QList& reasons) const override;
+ virtual QString toString() const override;
+ virtual QString name() const override;
+
+ private:
+ NodeStoryChain *const chain_store;
+ QString name_store;
+ QList children_nodes;
+ };
+
+ /**
+ * 故事节点定制解析器.
+ */
+ class NodeStoryPointParser : public Syntax::XSyntaxBase
+ {
+ public:
+ explicit NodeStoryPointParser(NodeStoryChainParser *chain);
+ virtual ~NodeStoryPointParser() = default;
+
+ NodeStoryChainParser* storyChainParser() const;
+ virtual DocCore* docRef() const override;
+
+ private:
+ NodeStoryChainParser *const parent_parser;
+ };
+
+ /**
+ * 节点描述内容节点.
+ */
+ class NodeStoryDesGroup : public DesNode
+ {
+ public:
+ NodeStoryDesGroup(DesNode *parent_refer);
+ virtual ~NodeStoryDesGroup() = default;
+
+ // 通过 DesNode 继承
+ inline virtual int depth() const override {
+ return parent_refer->depth() + 1;
+ }
+ virtual DocCore * document() const override;
+ virtual int typeValue() const override;
+ virtual DesNode * parent() const override;
+ virtual void appendChild(DesNode * ins) override;
+ virtual QList children() const override;
+ virtual bool check(QList& reasons) const override;
+ virtual QString toString() const override;
+
+ private:
+ DesNode *const parent_refer;
+ QList children_nodes;
+ };
+
+ class NodeStoryChainDesGroupParser : public Syntax::XSyntaxBase
+ {
+ public:
+ explicit NodeStoryChainDesGroupParser(XSyntaxBase *pparser);
+ virtual ~NodeStoryChainDesGroupParser() = default;
+
+ private:
+ XSyntaxBase *const parent_parser;
+ };
+
+ /**
+ * 描述内容文字块.
+ */
+ class NodeStoryDesBlock : public DesNode
+ {
+ public:
+ explicit NodeStoryDesBlock(NodeStoryDesGroup *parent_node, const QString &text);
+ virtual ~NodeStoryDesBlock() = default;
+
+ // 通过 DesNode 继承
+ inline virtual int depth() const override {
+ return parent_refer->depth() + 1;
+ }
+ virtual DocCore * document() const override;
+ virtual int typeValue() const override;
+ virtual DesNode * parent() const override;
+ virtual void appendChild(DesNode * ins) override;
+ virtual QList children() const override;
+ virtual bool check(QList& reasons) const override;
+ virtual QString toString() const override;
+
+ private:
+ DesNode *const parent_refer;
+ QString text_block;
+ };
+
+ class StoryChainDocumentParser : public ParseFrame
+ {
+ public:
+ StoryChainDocumentParser(ProjectCore *pjt);
+ virtual ~StoryChainDocumentParser() = default;
+ };
+}
+
diff --git a/DesParser/StoryUnitDocumentParser.cpp b/DesParser/StoryUnitDocumentParser.cpp
new file mode 100644
index 0000000..4434724
--- /dev/null
+++ b/DesParser/StoryUnitDocumentParser.cpp
@@ -0,0 +1,331 @@
+#include "StoryUnitDocumentParser.h"
+
+using namespace Parse;
+using namespace Lex;
+using namespace Syntax;
+using namespace Syntax::Defines;
+
+NodeStoryUnit::NodeStoryUnit(DocCore * doc, const QString & name)
+ : doc_ref(doc), name_store(name)
+{
+}
+
+QString NodeStoryUnit::name() const
+{
+ return name_store;
+}
+
+DocCore * NodeStoryUnit::document() const
+{
+ return doc_ref;
+}
+
+int NodeStoryUnit::typeValue() const
+{
+ return NODE_STORYUNIT;
+}
+
+DesNode * NodeStoryUnit::parent() const
+{
+ return nullptr;
+}
+
+void NodeStoryUnit::appendChild(DesNode * ins)
+{
+ children_nodes << ins;
+}
+
+QList NodeStoryUnit::children() const
+{
+ return children_nodes;
+}
+
+bool NodeStoryUnit::check(QList& reasons) const
+{
+ return false;
+}
+
+QString NodeStoryUnit::toString() const
+{
+ QString rets = "#单元 " + name_store + "{";
+ for (auto it : children_nodes)
+ rets += "\n" + it->toString();
+ rets += "\n}";
+ return rets;
+}
+
+
+NodeStoryFragment::NodeStoryFragment(NodeStoryUnit * unit, const QString & name)
+ : unit_ins(unit), name_store(name)
+{
+}
+
+DocCore * NodeStoryFragment::document() const
+{
+ return unit_ins->document();
+}
+
+int NodeStoryFragment::typeValue() const
+{
+ return NODE_STORYFRAGMENT;
+}
+
+DesNode * NodeStoryFragment::parent() const
+{
+ return unit_ins;
+}
+
+void NodeStoryFragment::appendChild(DesNode * ins)
+{
+ children_nodes << ins;
+}
+
+QList NodeStoryFragment::children() const
+{
+ return children_nodes;
+}
+
+bool NodeStoryFragment::check(QList& reasons) const
+{
+ return false;
+}
+
+QString NodeStoryFragment::toString() const
+{
+ QString rets = QString(depth(), ' ') + name() + "{";
+ for (auto cin : children_nodes)
+ rets += "\n" + QString(depth(), ' ') + cin->toString();
+ return rets + "}";
+}
+
+QString NodeStoryFragment::name() const
+{
+ return name_store;
+}
+
+
+NodeStoryPointReference::NodeStoryPointReference(DesNode * parent, const QString & chain, const QString & point)
+ : parent_ins(parent), chain_name(chain), point_name(point) {}
+
+DocCore * NodeStoryPointReference::document() const
+{
+ return parent_ins->document();
+}
+
+int NodeStoryPointReference::typeValue() const
+{
+ return NODE_POINTREFERENCE;
+}
+
+DesNode * NodeStoryPointReference::parent() const
+{
+ return parent_ins;
+}
+
+void NodeStoryPointReference::appendChild(DesNode * ins) {}
+
+QList NodeStoryPointReference::children() const
+{
+ return QList();
+}
+
+bool NodeStoryPointReference::check(QList& reasons) const
+{
+ return false;
+}
+
+QString NodeStoryPointReference::toString() const
+{
+ return QString("{@节点 @%1 @%2}").arg(chain_name).arg(point_name);
+}
+
+NodeStoryFragmentComment::NodeStoryFragmentComment(DesNode * parent,
+ const QString &order, const QString & name)
+ : parent_ins(parent), order_name(order), name_store(name)
+{
+}
+
+QString NodeStoryFragmentComment::order() const
+{
+ return order_name;
+}
+
+DocCore * NodeStoryFragmentComment::document() const
+{
+ return parent_ins->document();
+}
+
+int NodeStoryFragmentComment::typeValue() const
+{
+ return NODE_ORDEREDCOMMENT;
+}
+
+DesNode * NodeStoryFragmentComment::parent() const
+{
+ return parent_ins;
+}
+
+void NodeStoryFragmentComment::appendChild(DesNode * ins)
+{
+ children_nodes << ins;
+}
+
+QList NodeStoryFragmentComment::children() const
+{
+ return children_nodes;
+}
+
+bool NodeStoryFragmentComment::check(QList& reasons) const
+{
+ return false;
+}
+
+QString NodeStoryFragmentComment::toString() const
+{
+ auto xrets = QString(depth(), ' ') + "#注解 " + name() + "{";
+ for (auto it : children_nodes)
+ xrets += "\n" + QString(depth(), ' ') + it->toString();
+ xrets += "\n" + QString(depth(), ' ') + "}";
+
+ return xrets;
+}
+
+QString NodeStoryFragmentComment::name() const
+{
+ return name_store;
+}
+
+NodeStoryUnitParser::NodeStoryUnitParser(ProjectCore * core)
+ : XSyntaxBase("故事单元"), pjt_core(core)
+{
+ auto rule = addRule("进入单元解析", 0, [this](const QList &seqs, int cnt)->ParseResult {
+ auto nmidx = cnt - 1, defidx = cnt - 2;;
+
+ auto node = new NodeStoryUnit(this->docRef(), seqs[nmidx].Text);
+ this->refocusNode(node);
+
+ auto word0 = new Words(node, docRef(), seqs[defidx].Text, seqs[defidx].StartRow, seqs[defidx].StartCol);
+ auto word1 = new Words(node, docRef(), seqs[nmidx].Text, seqs[nmidx].StartRow, seqs[nmidx].StartCol);
+ docRef()->append(word0);
+ docRef()->append(word1);
+
+ return ParseResult::SelfManipulate;
+ });
+ rule->addExpression("基础单元解析", { Elm("{单元定义}"), Elm("描述文本", true) });
+ rule->addExpression("拓展单元解析", { Elm("{换行符}"),Elm("{换行符}"), Exp("基础单元解析", true) });
+
+ rule = addRule("单元成分解析", 1, [this](const QList &seqs, int cnt)->ParseResult {
+ auto node = currNode();
+
+ auto word = new Words(node, docRef(), seqs[cnt - 1].Text, seqs[cnt - 1].StartRow, seqs[cnt - 1].StartCol);
+ docRef()->append(word);
+
+ return ParseResult::EnterNext;
+ });
+ rule->addExpression("基础单元成分解析", { Elm("{左界限}", true) });
+ rule->addExpression("拓展单元成分解析", { Elm("{换行符}"), Elm("{换行符}"), Exp("基础单元成分解析", true) });
+
+ rule = addRule("跳出单元成分解析", 2, [this](const QList &seqs, int cnt)->ParseResult {
+ auto node = currNode();
+
+ auto word = new Words(node, docRef(), seqs[cnt - 1].Text, seqs[cnt - 1].StartRow, seqs[cnt - 1].StartCol);
+ docRef()->append(word);
+
+ return ParseResult::Completed;
+ });
+ rule->addExpression("基础跳出单元解析", { Elm("{右界限}", true) });
+ rule->addExpression("拓展跳出单元解析", { Elm("{换行符}"),Elm("{换行符}"),Exp("基础跳出单元解析", true) });
+}
+
+ProjectCore * NodeStoryUnitParser::project() const
+{
+ return pjt_core;
+}
+
+StoryUnitDocumentParser::StoryUnitDocumentParser(ProjectCore * ins)
+{
+ appendTokensDefine({
+ {"{单元定义}", "#单元"},
+ {"{情节定义}", "#情节"},
+ {"{注解定义}", "#注解"},
+ {"{描述文本}", "[^#@\\{\\}\\n]+"},
+ {"{左界限}", "\\{"},
+ {"{右界限}", "\\}"},
+ {"{换行符}", "\\n"},
+ {"{节点引用}", "\\{@节点"},
+ }, "{无法识别}");
+
+ auto chain_parser = new NodeStoryUnitParser(ins);
+ appendParser(chain_parser);
+}
+
+NodeStoryFragmentParser::NodeStoryFragmentParser(NodeStoryUnitParser * pparser)
+ : XSyntaxBase("故事情节"), parent_parser(pparser)
+{
+ auto rule = addRule("进入情节解析", 0, [this](const QList &seqs, int cnt)->ParseResult {
+ auto nmidx = cnt - 1, defidx = cnt - 2;;
+
+ auto parent_parser = nodeStoryUnitParser();
+ auto node = new NodeStoryFragment(static_cast(parent_parser->currNode()), seqs[nmidx].Text);
+ this->refocusNode(node);
+
+ auto word0 = new Words(node, docRef(), seqs[defidx].Text, seqs[defidx].StartRow, seqs[defidx].StartCol);
+ auto word1 = new Words(node, docRef(), seqs[nmidx].Text, seqs[nmidx].StartRow, seqs[nmidx].StartCol);
+ docRef()->append(word0);
+ docRef()->append(word1);
+
+ return ParseResult::SelfManipulate;
+ });
+
+ rule->addExpression("基础情节解析", { Elm("{情节定义}"), Elm("描述文本", true) });
+ rule->addExpression("拓展情节解析", { Elm("{换行符}"),Elm("{换行符}"), Exp("基础情节解析", true) });
+
+ rule = addRule("情节成分解析", 1, [this](const QList &seqs, int cnt)->ParseResult {
+ auto node = currNode();
+
+ auto word = new Words(node, docRef(), seqs[cnt - 1].Text, seqs[cnt - 1].StartRow, seqs[cnt - 1].StartCol);
+ docRef()->append(word);
+
+ return ParseResult::EnterNext;
+ });
+ rule->addExpression("基础情节成分解析", { Elm("{左界限}", true) });
+ rule->addExpression("拓展情节成分解析", { Elm("{换行符}"), Elm("{换行符}"), Exp("基础情节成分解析", true) });
+
+ rule = addRule("跳出情节成分解析", 2, [this](const QList &seqs, int cnt)->ParseResult {
+ auto node = currNode();
+
+ auto word = new Words(node, docRef(), seqs[cnt - 1].Text, seqs[cnt - 1].StartRow, seqs[cnt - 1].StartCol);
+ docRef()->append(word);
+
+ return ParseResult::Completed;
+ });
+ rule->addExpression("基础跳出情节解析", { Elm("{右界限}", true) });
+ rule->addExpression("拓展跳出情节解析", { Elm("{换行符}"),Elm("{换行符}"),Exp("基础跳出情节解析") });
+}
+
+NodeStoryUnitParser * NodeStoryFragmentParser::nodeStoryUnitParser() const
+{
+ return parent_parser;
+}
+
+DocCore * NodeStoryFragmentParser::docRef() const
+{
+ return parent_parser->docRef();
+}
+
+NodeStoryUnitDesGroupParser::NodeStoryUnitDesGroupParser(XSyntaxBase * parent)
+ : XSyntaxBase("描述块"), parent_parser(parent)
+{
+ auto rule = addRule("进入描述块解析", 0, [](const QList &seqs, int cnt)->ParseResult {
+ return ParseResult::EnterNext;
+ });
+ rule->addExpression("::基础引用定义", { Elm("{节点引用}"),Elm("{描述文本}1"), Elm("{描述文本}2"), Elm("{右界限}", true) });
+ rule->addExpression("::基础文本块定义", {Elm("{描述文本}"), Elm("{描述文本}", true) });
+ rule->addExpression("::文本块混合定义x", { Exp("::基础引用定义"), Exp("::基础引用定义", true), Exp("::基础文本块定义", true), Exp("::基础引用定义")});
+ rule->addExpression("::拓展文本块x", { Elm("{换行符}"),Elm("{换行符}"), Exp("::基础引用定义")});
+ rule->addExpression("::文本块混合定义y", {Exp("::文本块混合定义"), Exp("::文本块混合定义x", true)} );
+ rule->addExpression("::文本块混合定义y", {Exp("::文本块混合定义"), Exp("::文本块混合定义x", true)} );
+
+
+ rule->resetFinal(MatchStatus::OnlyForm);
+}
diff --git a/DesParser/StoryUnitDocumentParser.h b/DesParser/StoryUnitDocumentParser.h
new file mode 100644
index 0000000..947f741
--- /dev/null
+++ b/DesParser/StoryUnitDocumentParser.h
@@ -0,0 +1,168 @@
+#pragma once
+
+#include "XSyntaxBase.h"
+#include "ParseFrame.h"
+
+namespace Parse {
+ /**
+ * 故事单元.
+ */
+ class NodeStoryUnit : public NamedNode
+ {
+ public:
+ explicit NodeStoryUnit(DocCore *doc, const QString &name);
+ virtual ~NodeStoryUnit() = default;
+
+ // 通过 NamedNode
+ virtual QString name() const;
+
+ // 通过 DesNode 继承
+ inline virtual int depth() const override {
+ return 0;
+ }
+ virtual DocCore * document() const override;
+ virtual int typeValue() const override;
+ virtual DesNode * parent() const override;
+ virtual void appendChild(DesNode * ins) override;
+ virtual QList children() const override;
+ virtual bool check(QList& reasons) const override;
+ virtual QString toString() const override;
+
+ private:
+ DocCore *doc_ref;
+ QString name_store;
+
+ QList children_nodes;
+ };
+
+ /** 故事单元解析器 */
+ class NodeStoryUnitParser : public Syntax::XSyntaxBase
+ {
+ public:
+ NodeStoryUnitParser(ProjectCore *core);
+
+ ProjectCore* project() const;
+
+ private:
+ ProjectCore *const pjt_core;
+ };
+
+ /**
+ * 故事情节节点.
+ */
+ class NodeStoryFragment : public NamedNode
+ {
+ public:
+ explicit NodeStoryFragment(NodeStoryUnit* unit, const QString &name);
+ virtual ~NodeStoryFragment() = default;
+
+ // 通过 NamedNode 继承
+ inline virtual int depth() const override {
+ return unit_ins->depth() + 1;
+ }
+ virtual DocCore * document() const override;
+ virtual int typeValue() const override;
+ virtual DesNode * parent() const override;
+ virtual void appendChild(DesNode * ins) override;
+ virtual QList children() const override;
+ virtual bool check(QList& reasons) const override;
+ virtual QString toString() const override;
+ virtual QString name() const override;
+
+ private:
+ NodeStoryUnit *const unit_ins;
+ QString name_store;
+
+ QList children_nodes;
+ };
+
+ /**
+ * 故事情节解析器.
+ */
+ class NodeStoryFragmentParser : public Syntax::XSyntaxBase
+ {
+ public:
+ NodeStoryFragmentParser(NodeStoryUnitParser *pparser);
+
+ NodeStoryUnitParser * nodeStoryUnitParser() const;
+ DocCore * docRef() const;
+
+ private:
+ NodeStoryUnitParser *const parent_parser;
+ };
+
+ /**
+ * 故事脉络节点引用.
+ */
+ class NodeStoryPointReference : public DesNode
+ {
+ public:
+ explicit NodeStoryPointReference(DesNode *parent, const QString &chain, const QString &point);
+ virtual ~NodeStoryPointReference() = default;
+
+ // 通过 DesNode 继承
+ inline virtual int depth() const override {
+ return parent_ins->depth() + 1;
+ }
+ virtual DocCore * document() const override;
+ virtual int typeValue() const override;
+ virtual DesNode * parent() const override;
+ virtual void appendChild(DesNode * ins) override;
+ virtual QList children() const override;
+ virtual bool check(QList& reasons) const override;
+ virtual QString toString() const override;
+
+ private:
+ DesNode *const parent_ins;
+ QString chain_name;
+ QString point_name;
+ };
+
+ class NodeStoryUnitDesGroupParser : public Syntax::XSyntaxBase
+ {
+ public:
+ NodeStoryUnitDesGroupParser(Syntax::XSyntaxBase * parent);
+
+ private:
+ Syntax::XSyntaxBase *const parent_parser;
+ };
+
+ /**
+ * 故事情节有序注释,单独解析
+ */
+ class NodeStoryFragmentComment : public NamedNode
+ {
+ public:
+ NodeStoryFragmentComment(DesNode *parent, const QString &order, const QString &name);
+ virtual ~NodeStoryFragmentComment() = default;
+
+ QString order() const;
+
+ // 通过 NamedNode 继承
+ inline virtual int depth() const override
+ {
+ return parent_ins->depth() + 1;
+ }
+ virtual DocCore * document() const override;
+ virtual int typeValue() const override;
+ virtual DesNode * parent() const override;
+ virtual void appendChild(DesNode * ins) override;
+ virtual QList children() const override;
+ virtual bool check(QList& reasons) const override;
+ virtual QString toString() const override;
+ virtual QString name() const override;
+ private:
+ DesNode *const parent_ins;
+ QString name_store;
+ QString order_name;
+
+ QList children_nodes;
+ };
+
+
+ class StoryUnitDocumentParser : public ParseFrame
+ {
+ public:
+ StoryUnitDocumentParser(ProjectCore *ins);
+ };
+}
\ No newline at end of file
diff --git a/DesParser/SyntaxBase.cpp b/DesParser/SyntaxBase.cpp
new file mode 100644
index 0000000..d2333d0
--- /dev/null
+++ b/DesParser/SyntaxBase.cpp
@@ -0,0 +1,133 @@
+#include "SyntaxBase.h"
+#include
+
+using namespace Parse;
+using namespace Lex;
+
+class Unknown : public DesNode
+{
+public:
+ explicit Unknown(DocCore *ins)
+ : doc_store(ins) {}
+
+ // 通过 DesNode 继承
+ virtual int depth() const override
+ {
+ return 0;
+ }
+ virtual DocCore * document() const override
+ {
+ return doc_store;
+ }
+ virtual int typeValue() const override
+ {
+ return NODE_UNKNOWNHOST;
+ }
+ virtual DesNode * parent() const override
+ {
+ return nullptr;
+ }
+ virtual void appendChild(DesNode * ins) override
+ {
+ }
+ virtual QList children() const override
+ {
+ return QList();
+ }
+ virtual bool check(QList& reasons) const override
+ {
+ return true;
+ }
+ virtual QString toString() const override
+ {
+ return QString();
+ }
+private:
+ DocCore *const doc_store;
+};
+
+Parse::Words::Words(DesNode* host, DocCore *doc, const QString & value, int row, int col)
+ : value_store(value), row_store(row), col_store(col)
+{
+}
+
+int Parse::Words::row() const
+{
+ return row_store;
+}
+
+int Parse::Words::column() const
+{
+ return col_store;
+}
+
+int Parse::Words::length() const
+{
+ return value_store.length();
+}
+
+DesNode * Parse::Words::host() const
+{
+ return desnode_store;
+}
+
+DocCore * Parse::Words::doc() const
+{
+ return docpresent_store;
+}
+
+QString Parse::Words::toString() const
+{
+ return value_store;
+}
+
+Parse::DocCore::DocCore(ProjectCore * core, const QString & path)
+ : core_store(core), file_path_store(path), unknown_host(new Unknown(this))
+{
+}
+
+DesNode * Parse::DocCore::unknowns() const
+{
+ return unknown_host;
+}
+
+ProjectCore * Parse::DocCore::project() const
+{
+ return core_store;
+}
+
+void Parse::DocCore::rename(const QString & new_name)
+{
+ file_path_store = new_name;
+}
+
+QString Parse::DocCore::filePath() const
+{
+ return file_path_store;
+}
+
+QString Parse::DocCore::fileName() const
+{
+ return QFileInfo(file_path_store).fileName();
+}
+
+void Parse::DocCore::clear()
+{
+ nodes_store.clear();
+}
+
+int Parse::DocCore::append(Words * ins)
+{
+ nodes_store << ins;
+
+ return 0;
+}
+
+Words * Parse::DocCore::getWords(int row, int col) const
+{
+ for (auto it : nodes_store)
+ if (it->row() == row && it->column() <= col && it->column() + it->length() >= col)
+ return it;
+
+ return nullptr;
+}
diff --git a/DesParser/SyntaxBase.h b/DesParser/SyntaxBase.h
new file mode 100644
index 0000000..7f78010
--- /dev/null
+++ b/DesParser/SyntaxBase.h
@@ -0,0 +1,344 @@
+#pragma once
+
+#include
+#include
+#include
+#include "LexicalBase.h"
+#include "comndef.h"
+
+namespace Parse
+{
+ class NamedNode;
+ class DocCore;
+ class ProjectCore;
+ class DesNode;
+
+ /**
+ * 词语块,可以通过文档未知直接获取.
+ */
+ class Words
+ {
+ public:
+ explicit Words(DesNode* host, DocCore *doc, const QString &value, int row, int col);
+ virtual ~Words() = default;
+
+ /**
+ * 起始行位置.
+ *
+ * \return
+ */
+ virtual int row() const;
+
+ /**
+ * 起始列位置.
+ *
+ * \return
+ */
+ virtual int column() const;
+
+ /**
+ * 次愉快长度.
+ *
+ * \return 字符数量
+ */
+ virtual int length() const;
+
+ /**
+ * 获取依托节点,悬空节点返回nullptr.
+ *
+ * \return
+ */
+ virtual DesNode* host() const;
+
+ /**
+ * 隶属文档实例.
+ *
+ * \return 实例
+ */
+ virtual DocCore* doc() const;
+
+ /**
+ * 获取文本内容.
+ *
+ * \return
+ */
+ virtual QString toString() const;
+
+ private:
+ QString value_store;
+ int row_store, col_store;
+ DesNode *desnode_store;
+ DocCore *docpresent_store;
+ };
+
+ /**
+ * 描述性的节点,如文本节点和引用节点.
+ */
+ class DesNode
+ {
+ public:
+ virtual ~DesNode() = default;
+
+ /**
+ * 节点树深度,根节点深度为0
+ *
+ * \return
+ */
+ virtual int depth() const = 0;
+ /**
+ * 承载文档源实例.
+ *
+ * \return
+ */
+ virtual DocCore* document() const = 0;
+
+ /**
+ * 类型标记.
+ *
+ * \return 标记值
+ */
+ virtual int typeValue() const = 0;
+
+ /**
+ * 获取该节点的父节点.
+ *
+ * \return 父节点实例
+ */
+ virtual DesNode* parent() const = 0;
+
+ /**
+ * 添加子节点
+ *
+ * \param ins 节点实例
+ */
+ virtual void appendChild(DesNode *ins) = 0;
+
+ /**
+ * 获取所有子节点
+ *
+ * \return 子节点集合
+ */
+ virtual QList children() const = 0;
+
+ /**
+ * 检查项目错误.
+ *
+ * \return true,没有错误
+ */
+ virtual bool check(QList &reasons) const = 0;
+
+ /**
+ * 返回本节点的代表文本内容.
+ *
+ * \return 文本内容
+ */
+ virtual QString toString() const = 0;
+ };
+
+ /**
+ * 声明描述节点.
+ */
+ class NamedNode : public DesNode
+ {
+ public:
+ virtual ~NamedNode() = default;
+
+ /**
+ * 获取此节点的名称.
+ *
+ * \return 名称字符串
+ */
+ virtual QString name() const = 0;
+
+ };
+
+
+ /**
+ * 文档实例.
+ */
+ class DocCore
+ {
+ public:
+ explicit DocCore(ProjectCore* core, const QString &path);
+ virtual ~DocCore() = default;
+
+ /**
+ * 无法识别的节点归并.
+ *
+ * \return
+ */
+ DesNode* unknowns() const;
+
+ /**
+ * 项目实例.
+ *
+ * \return
+ */
+ ProjectCore* project() const;
+
+ /**
+ * 重命名指向文件.
+ *
+ * \param new_name 新路径
+ */
+ void rename(const QString &new_name);
+
+ /**
+ * 源文件路径.
+ *
+ * \return
+ */
+ QString filePath() const;
+
+ /**
+ * 文件名.
+ *
+ * \return
+ */
+ QString fileName() const;
+
+ /**
+ * 清除所有的词语节点和内容节点.
+ */
+ void clear();
+
+ /**
+ * 对文档实例添加节点实例.
+ *
+ * \param ins 节点实例
+ * \return 0 - 添加成功
+ */
+ int append(Words *ins);
+
+
+ /**
+ * 通过位置获取词语.
+ *
+ * \param row 行位置
+ * \param col 列位置
+ * \return 字符号
+ */
+ Words* getWords(int row, int col) const;
+
+ private:
+ DesNode *const unknown_host;
+ ProjectCore *const core_store;
+ QString file_path_store;
+ QList nodes_store;
+ };
+
+ /**
+ * 项目实例.
+ */
+ class ProjectCore
+ {
+ private:
+ QString name_store;
+
+ public:
+ explicit ProjectCore(const QString &name);
+ virtual ~ProjectCore();
+
+ /**
+ * 获取文档内存实例,如果不存在指定实例,则新建实例.
+ *
+ * \param file_path 文档路径
+ * \return 实例
+ */
+ virtual DocCore* queryDocument(const QString &file_path) const;
+ virtual void replaceDocument(DocCore *ins);
+
+ virtual DesNode* queryChain(const QString & name) const;
+ virtual DesNode* queryPoint(NamedNode* chain, const QString &name) const;
+
+ virtual DesNode* queryUnit(const QString &name) const;
+ virtual DesNode* queryFragment(NamedNode *unit, const QString &name) const;
+
+ /**
+ * 查询指定顺序下的节点序列.
+ *
+ * \param type 序列名称
+ * \param unit 指定单元下的序列,nullptr代表全局范围
+ * \return
+ */
+ virtual QList queryFragmentsOrderby(const QString &type, NamedNode* unit = nullptr) const;
+
+ };
+
+ /**
+ * 解析结果标志.
+ */
+ enum class ParseResult
+ {
+ SelfManipulate = 1,
+ EnterNext = 2,
+ Completed = 3,
+ Failed = 4,
+ };
+
+ /**
+ * 解析器接口.
+ */
+ class SyntaxParser
+ {
+ public:
+ virtual ~SyntaxParser() = default;
+
+ /**
+ * 设置当前活动的Doc实例.
+ *
+ * \param ins
+ */
+ virtual void docActive(DocCore *ins) = 0;
+
+ /**
+ * 当前指向的文档.
+ *
+ * \return 文档实例
+ */
+ virtual DocCore* docRef() const = 0;
+ /**
+ * 适配当前解析.
+ *
+ * \param seqs
+ * \return
+ */
+ virtual bool applied(const QList& seqs) = 0;
+
+ /**
+ * 重置解析器
+ */
+ virtual void reset() = 0;
+
+ /**
+ * 针对性的解析当前Token序列,对已经解析过的序列做摘除处理,返回下一步可能用到的解析器列表。
+ *
+ * \param seqs 标记序列
+ * \param next_ps 下一步需要用到的解析器
+ * \return 解析操作类型
+ */
+ virtual ParseResult parse(QList& seqs)= 0;
+
+ /**
+ * 子解析器集合.
+ *
+ * \return
+ */
+ virtual QList children() const = 0;
+
+ /**
+ * 当前聚焦的节点.
+ *
+ * \return
+ */
+ virtual DesNode* currNode() const = 0;
+
+ public:
+ /**
+ * 设置子元素解析器,内部元素解析器集合.
+ *
+ * \param parsers 解析器集合
+ */
+ virtual void addChild(QList parsers) = 0;
+ };
+}
diff --git a/DesParser/WordsPeak.cpp b/DesParser/WordsPeak.cpp
new file mode 100644
index 0000000..b74c767
--- /dev/null
+++ b/DesParser/WordsPeak.cpp
@@ -0,0 +1,49 @@
+#include "WordsPeak.h"
+#include
+
+using namespace Parse;
+
+ForwardStream::ForwardStream() :file_target(nullptr), text_input(nullptr),
+current_line(""), current_row(-1), current_col(0) {}
+
+ForwardStream::~ForwardStream() {
+ if (file_target)
+ delete file_target;
+ if (text_input)
+ delete text_input;
+}
+
+int ForwardStream::initSource(const QString & path)
+{
+ if (file_target)
+ delete file_target;
+ if (text_input)
+ delete text_input;
+
+ if (!QFile(path).exists())
+ return -1;
+
+ file_target = new QFile(path);
+ if (!file_target->open(QIODevice::ReadOnly | QIODevice::Text))
+ return -2;
+
+ text_input = new QTextStream(file_target);
+ return 0;
+}
+
+std::tuple Parse::ForwardStream::read()
+{
+ if (current_col >= current_line.length()) {
+ if (!text_input->atEnd()) {
+ current_row++;
+ current_col = 0;
+ current_line = text_input->readLine() + '\n';
+ }
+ else {
+ return std::make_tuple(-1, -1, EOF);
+ }
+ }
+
+ return std::make_tuple(current_row, current_col, current_line[current_col++]);
+}
+
diff --git a/DesParser/WordsPeak.h b/DesParser/WordsPeak.h
new file mode 100644
index 0000000..3d8c949
--- /dev/null
+++ b/DesParser/WordsPeak.h
@@ -0,0 +1,39 @@
+#pragma once
+#include
+#include
+#include
+#include
+
+namespace Parse {
+ class ForwardStream
+ {
+ public:
+ typedef int n_row;
+ typedef int n_col;
+ explicit ForwardStream();
+ virtual ~ForwardStream();
+
+ /**
+ * 初始化文件指向.
+ *
+ * \param path 源文件
+ * \return -2无法打开:-1:文件不存在,0:成功
+ */
+ int initSource(const QString &path);
+
+ /**
+ * 在文件文本流中读取一个字符.
+ *
+ * \return
+ */
+ std::tuple read();
+
+ private:
+ QFile * file_target;
+ QTextStream* text_input;
+
+ QString current_line;
+ int current_row, current_col;
+
+ };
+}
diff --git a/DesParser/XSyntaxBase.cpp b/DesParser/XSyntaxBase.cpp
new file mode 100644
index 0000000..6f0bd35
--- /dev/null
+++ b/DesParser/XSyntaxBase.cpp
@@ -0,0 +1,370 @@
+#include "XSyntaxBase.h"
+
+using namespace Parse;
+using namespace Syntax;
+using namespace Lex;
+using namespace Defines;
+
+Link::Link(const QString & alias, Element * elm)
+ : alias_name(alias), host_ins(elm), tail_mark(false) {}
+
+QString Link::aliasName() const { return alias_name; }
+
+QString Link::refer() const
+{
+ return name(this->aliasName());
+}
+
+QString Link::name(const QString & s)
+{
+ QRegExp exp("^(.*)[0-9]*$");
+ if (exp.indexIn(s) == -1)
+ return "";
+ return exp.capturedTexts()[1];
+}
+
+Element * Link::host() const { return host_ins; }
+
+bool Link::tailTest() const { return tail_mark; }
+
+void Link::markTail(bool v)
+{
+ tail_mark = v;
+}
+
+void Link::appendNext(Link * ins) { next_inss << ins; }
+
+QList Link::nextElements() const { return next_inss; }
+
+std::tuple
+Link::linkCheck(const QList& tokens, int offset) const
+{
+ // 本节点匹配失败,剩余标记长度不足
+ if (tokens.size() <= offset)
+ return std::make_tuple(false, 0);
+
+ // 节点元素匹配,获取匹配结果
+ auto rst0 = host()->elementCheck(tokens, offset);
+ if (!std::get<0>(rst0))
+ return rst0;
+
+ // 本节点匹配成功,尝试下一节点匹配,调用参数向下传递
+ for (auto inss : next_inss) {
+ auto rst1 = inss->linkCheck(tokens, offset + std::get<1>(rst0));
+
+ // 随后节点完全匹配,返回累积匹配结果
+ if (std::get<0>(rst1))
+ return std::make_tuple(true, std::get<1>(rst0) + std::get<1>(rst1));
+ }
+
+ // 解析链上的允许结尾,本节点是尾结点则成功,否则失败
+ if (tailTest())
+ return rst0;
+ else
+ return std::make_tuple(false, std::get<1>(rst0));
+}
+
+/**
+* 校验标记序列是否符合语法定义.
+*
+* \param tokens 标记序列
+* \param offset 偏移量
+* \return tuple(完全匹配指示,最大匹配长度)
+*/
+Element::Element(const QString & token)
+ : value_store(token) {}
+
+
+QString Element::name() const
+{
+ return Link::name(value_store);
+}
+
+DefType Element::type() const
+{
+ return DefType::ELEMENT;
+}
+
+std::tuple
+Element::elementCheck(const QList& tokens, int offset) const
+{
+ auto u = tokens[offset];
+
+ if (u.Token == name())
+ return std::make_tuple(true, 1);
+ return std::make_tuple(false, 0);
+}
+
+Expression::Expression(const QString & name)
+ : Element(name), name_store(name), chain_store(nullptr)
+{
+}
+
+Link * Expression::parseFlow() const
+{
+ return chain_store;
+}
+
+void Expression::resetLinks(Link * entry)
+{
+ chain_store = entry;
+}
+
+DefType Expression::type() const
+{
+ return DefType::EXPRESSION;
+}
+
+std::tuple
+Expression::elementCheck(const QList& tokens, int offset) const
+{
+ if (!chain_store)
+ return std::make_tuple(false, 0);
+
+ return chain_store->linkCheck(tokens, offset);
+}
+
+ParseRule::ParseRule(XSyntaxBase * host, const QString & rule_name, unsigned short level,
+ std::function&, int)> exc)
+ : host_ins(host), target_result(MatchStatus::Entirely), level_store(level),
+ name_store(rule_name), exc_store(exc) {}
+
+int ParseRule::level() const
+{
+ return level_store;
+}
+
+QString ParseRule::name() const
+{
+ return name_store;
+}
+
+void Syntax::ParseRule::addExpression(const QString &name, const QList &defines)
+{
+ // 生成表达式实例
+ auto exp = host_ins->get_expression(Link::name(name));
+
+ // 逐个构建表达式或者元素
+ QList link_rebuilds;
+ for(auto& def_it : defines){
+ // 校验既有元素回环
+ auto size0 = link_rebuilds.size();
+ for(auto prv_it : link_rebuilds){
+ if(prv_it->aliasName() == def_it.aliasName()){
+ link_rebuilds << prv_it;
+ break;
+ }
+ }
+
+ // 没有找到元素回环
+ if(size0 == link_rebuilds.size()){
+ Link* tins = nullptr;
+ if (def_it.type() == DefType::ELEMENT)
+ tins = new Link(def_it.aliasName(), host_ins->get_element(def_it.refer()));
+ else
+ tins = new Link(def_it.aliasName(), host_ins->get_expression(def_it.refer()));
+
+ link_rebuilds << tins;
+ }
+
+ // 标记结尾可能性
+ link_rebuilds.last()->markTail(def_it.isTail());
+ }
+
+ // 匹配链构建
+ for(auto idx=1; idxappendNext(link_rebuilds[idx]);
+ }
+
+ exp->resetLinks(link_rebuilds.first());
+ expression_list << exp;
+}
+
+std::tuple ParseRule::tokensMatch(const QList& token) const
+{
+ for (auto expx : expression_list) {
+ auto result = expx->elementCheck(token, 0);
+ if (std::get<0>(result)) {
+ return std::make_tuple(target_result, std::get<1>(result));
+ }
+ }
+ return std::make_tuple(MatchStatus::Failed, 0);
+}
+
+ParseResult ParseRule::syntaxTrigger(const QList& srcs, int count) {
+ return exc_store(srcs, count);
+}
+
+void ParseRule::resetFinal(MatchStatus target)
+{
+ this->target_result = target;
+}
+
+XSyntaxBase::XSyntaxBase(const QString & section)
+ : section_name(section), current_level(-1), current_node(nullptr) {}
+
+ParseRule * XSyntaxBase::addRule(const QString & name, unsigned short level,
+ std::function&, int)> exc)
+{
+ if (!rule_collect.contains(name)) {
+ auto rule = new ParseRule(this, name, level, exc);
+ rule_collect[name] = rule;
+ }
+ return rule_collect[name];
+}
+
+inline Expression * XSyntaxBase::get_expression(const QString & name) {
+ if (!expressions_store.contains(name)) {
+ auto u = new Expression(name);
+ expressions_store[name] = u;
+ }
+ return expressions_store[name];
+}
+
+inline Element * XSyntaxBase::get_element(const QString & name)
+{
+ if (!elements_store.contains(name)) {
+ auto u = new Element(name);
+ elements_store[name] = u;
+ }
+ return elements_store[name];
+}
+
+void XSyntaxBase::addChild(QList parsers)
+{
+ this->child_parsers.append(parsers);
+}
+
+void XSyntaxBase::docActive(DocCore * ins)
+{
+ src_ref = ins;
+ for (auto &it : children())
+ it->docActive(ins);
+}
+
+DocCore * XSyntaxBase::docRef() const
+{
+ return src_ref;
+}
+
+bool XSyntaxBase::applied(const QList& seqs)
+{
+ // 求取最小等级的parse-rule
+ ParseRule* first_rule = *rule_collect.cbegin();
+ for (auto &rule : rule_collect) {
+ if (rule->level() <= first_rule->level())
+ first_rule = rule;
+ }
+
+ // 执行准入匹配
+ for (auto &rule : rule_collect) {
+ if (rule->level() != first_rule->level())
+ continue;
+
+ auto result = rule->tokensMatch(seqs);
+ if (std::get<0>(result) != MatchStatus::Failed) {
+ current_level = rule->level();
+ return true;
+ }
+ }
+ return false;
+}
+
+void XSyntaxBase::reset()
+{
+ // 重置标记
+ current_level = INT_MAX;
+
+ for (auto &x : rule_collect)
+ if (current_level > x->level())
+ current_level = x->level();
+
+ current_node = nullptr;
+}
+
+ParseResult XSyntaxBase::parse(QList& seqs)
+{
+ // 求取符合等级的parse-rule
+ QList rules_set;
+ for (auto &rule : rule_collect) {
+ if (rule->level() >= current_level)
+ rules_set << rule;
+ }
+
+ std::tuple max_result = std::make_tuple(MatchStatus::Failed, 0, nullptr);
+ // 使用符合等级的解析规则解析
+ for (auto &rule : rules_set) {
+ auto result = rule->tokensMatch(seqs);
+ if (std::get<0>(result) != MatchStatus::Failed && current_level <= rule->level()) {
+ current_level = rule->level();
+ max_result = std::make_tuple(std::get<0>(result), std::get<1>(result), rule);
+ }
+ }
+
+ // 匹配失败
+ if (std::get<0>(max_result) == MatchStatus::Failed)
+ return ParseResult::Failed;
+ else { // 匹配成功
+ auto xresult = std::get<2>(max_result)->syntaxTrigger(seqs, std::get<1>(max_result));
+
+ if (std::get<0>(max_result) == MatchStatus::Entirely) {
+ auto count = std::get<1>(max_result);
+ while (count--)
+ seqs.removeFirst();
+ }
+
+ return xresult;
+ }
+}
+
+QList XSyntaxBase::children() const
+{
+ return child_parsers;
+}
+
+void XSyntaxBase::refocusNode(DesNode * ins)
+{
+ current_node = ins;
+}
+
+DesNode * XSyntaxBase::currNode() const
+{
+ return current_node;
+}
+
+Elm::Elm(const QString &alias_name, bool tail_mark)
+ : name_store(alias_name), tail_mark(tail_mark),
+ type_define(DefType::ELEMENT){}
+
+QString Elm::aliasName() const
+{
+ return this->name_store;
+}
+
+QString Elm::refer() const
+{
+ return Link::name(this->name_store);
+}
+
+
+bool Elm::isTail() const
+{
+ return tail_mark;
+}
+
+DefType Elm::type() const
+{
+ return type_define;
+}
+
+Exp::Exp(const QString& alias_name, bool tail_mark)
+ : Elm(alias_name, tail_mark)
+{
+ type_define = DefType::EXPRESSION;
+}
+
+DefType Exp::type() const
+{
+ return type_define;
+}
diff --git a/DesParser/XSyntaxBase.h b/DesParser/XSyntaxBase.h
new file mode 100644
index 0000000..ca9d0a9
--- /dev/null
+++ b/DesParser/XSyntaxBase.h
@@ -0,0 +1,254 @@
+#pragma once
+#include
+#include
+#include
+#include "LexicalBase.h"
+#include "SyntaxBase.h"
+
+namespace Syntax
+{
+ /**
+ *专用于定义语法树的命名空间
+ */
+ namespace Defines
+ {
+ /**
+ * @brief 元素定义类型
+ */
+ enum class DefType
+ {
+ ELEMENT,
+ EXPRESSION
+ };
+
+ /**
+ * 元素定义声明.
+ */
+ class Elm
+ {
+ public:
+ explicit Elm(const QString &alias_name, bool tail_mark = false);
+ virtual ~Elm() = default;
+
+ /**
+ * 定义名称,定义别名.
+ *
+ * \return
+ */
+ QString aliasName() const;
+ /**
+ * 引用.
+ *
+ * \return
+ */
+ QString refer() const;
+ /**
+ * 匹配类型.
+ *
+ * \return 元素或表达式
+ */
+ virtual DefType type() const;
+
+ /**
+ * 是否具有结尾标记.
+ *
+ * \return
+ */
+ bool isTail() const;
+
+ private:
+ QString name_store;
+ bool tail_mark;
+
+ protected:
+ DefType type_define;
+ };
+
+ /**
+ * 表达式定义声明.
+ */
+ class Exp : public Elm
+ {
+ public:
+ explicit Exp(const QString &alias_name, bool tail_mark = false);
+ virtual ~Exp() = default;
+
+ virtual DefType type() const override;
+ };
+ }
+
+
+ /**
+ * 校验元素,单个token校验.
+ */
+ class Element
+ {
+ public:
+ typedef bool rst_mark;
+ typedef int match_len;
+
+ explicit Element(const QString &token);
+ virtual ~Element() = default;
+
+ QString name() const;
+ virtual Defines::DefType type() const;
+
+ /**
+ * 校验标记序列是否符合语法定义.
+ *
+ * \param tokens 标记序列
+ * \param offset 偏移量
+ * \return tuple(完全匹配指示,最大匹配长度)
+ */
+ virtual std::tuple
+ elementCheck(const QList &tokens, int offset) const;
+
+ private:
+ QString value_store;
+ };
+
+ /**
+ * @brief 语法匹配调用链
+ */
+ class Link
+ {
+ public:
+ Link(const QString &alias, Element *elm);
+ virtual ~Link() = default;
+
+ static QString name(const QString &s);
+ QString aliasName() const;
+ QString refer() const;
+ Element* host() const;
+
+ bool tailTest() const;
+ void markTail(bool v);
+
+ void appendNext(Link* ins);
+ QList nextElements() const;
+
+ virtual std::tuple
+ linkCheck(const QList &tokens, int offset) const;
+
+ private:
+ QString alias_name;
+ Element *const host_ins;
+ bool tail_mark;
+
+ QList next_inss;
+ };
+
+ /**
+ * @brief 校验表达式,多个语法元素顺序校验
+ */
+ class Expression : public Element
+ {
+ public:
+ explicit Expression(const QString &name);
+ virtual ~Expression() = default;
+
+ Link* parseFlow() const;
+ void resetLinks(Link* entry);
+
+ virtual Defines::DefType type() const override;
+
+ /**
+ * 校验标记序列是否符合语法定义.
+ *
+ * \param tokens 标记序列
+ * \param offset 偏移量
+ * \return tuple(完全匹配指示,最大匹配长度)
+ */
+ virtual std::tuple
+ elementCheck(const QList &tokens, int offset) const override;
+
+ private:
+ QString name_store;
+ Link* chain_store;
+ };
+
+
+
+ class XSyntaxBase;
+ /**
+ * @brief 语法校验目标形式
+ */
+ enum class MatchStatus
+ {
+ Failed,
+ OnlyForm,
+ Entirely
+ };
+
+ /**
+ * @brief 定义解析规则,支持多范式表达式匹配
+ */
+ class ParseRule
+ {
+ public:
+ ParseRule(XSyntaxBase *host, const QString &rule_name, unsigned short level,
+ std::function&, int)>);
+ virtual ~ParseRule() = default;
+
+ int level() const;
+ QString name() const;
+
+ void addExpression(const QString &name, const QList &_defines);
+ std::tuple tokensMatch(const QList &token) const;
+ Parse::ParseResult syntaxTrigger(const QList& srcs, int count);
+
+ void resetFinal(MatchStatus target);
+
+ private:
+ XSyntaxBase *const host_ins;
+ MatchStatus target_result;
+ int level_store;
+ QString name_store;
+ QList expression_list;
+
+ std::function&, int)> exc_store;
+ };
+
+
+
+ /**
+ * 基础解析器模型.
+ */
+ class XSyntaxBase : public Parse::SyntaxParser
+ {
+ public:
+ explicit XSyntaxBase(const QString §ion);
+
+ Expression* get_expression(const QString &name);
+ Element *get_element(const QString &name);
+
+ // 通过 Parse::SyntaxParser 继承
+ virtual void docActive(Parse::DocCore *ins) override;
+ virtual Parse::DocCore *docRef() const override;
+ virtual bool applied(const QList& seqs) override;
+ virtual void reset() override;
+ virtual Parse::ParseResult parse(QList& seqs) override;
+ virtual QList children() const override;
+
+ virtual Parse::DesNode * currNode() const override;
+
+ protected:
+ ParseRule* addRule(const QString &name, unsigned short level, std::function&, int)> exc);
+ virtual void addChild(QList parsers) override;
+ void refocusNode(Parse::DesNode *ins);
+
+ private:
+ QString section_name;
+ int current_level;
+ Parse::DesNode *current_node;
+ Parse::DocCore *src_ref;
+
+ QHash elements_store;
+ QHash expressions_store;
+ QList child_parsers;
+
+ QHash rule_collect;
+ };
+
+
+}
diff --git a/DesParser/comndef.h b/DesParser/comndef.h
new file mode 100644
index 0000000..86f0978
--- /dev/null
+++ b/DesParser/comndef.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#define NODE_UNKNOWNHOST 0 // 未知
+
+#define NODE_STORYCHAIN 1 // 故事脉络
+#define NODE_STORYPOINT 2 // 故事节点
+#define NODE_DESCRIPTION_GROUP 3 // 描述集(段落)
+#define NODE_DESCRIPTION_BLOCK 4 // 描述块
+
+
+#define NODE_STORYUNIT 5 // 故事单元
+#define NODE_STORYFRAGMENT 6 // 故事情节
+#define NODE_POINTREFERENCE 7 // 节点引用
+#define NODE_ORDEREDCOMMENT 8 // 情节序列注释
+
+
+#define NODE_STORYBOARD 9 // 故事大纲
+#define NODE_FRAGMENTREFERENCE 10 // 情节引用
diff --git a/DesParser/example.storychain b/DesParser/example.storychain
new file mode 100644
index 0000000..87be63a
--- /dev/null
+++ b/DesParser/example.storychain
@@ -0,0 +1,8 @@
+#脉络 大乾国共受难主线 xcvkjzlvj
+{
+ diyigeakldfj;dl来翻案;dlfj;sl分类风
+
+#节点 初始登场{ 大乾国公府鸡飞狗跳,人字广场集训大练兵}
+ #节点 高潮迭起
+ {混乱大逃杀,初始情况混乱。人间清醒}
+}
diff --git a/DesParser/main.cpp b/DesParser/main.cpp
new file mode 100644
index 0000000..3869748
--- /dev/null
+++ b/DesParser/main.cpp
@@ -0,0 +1,33 @@
+#include
+#include
+#include
+#include
+#include "StoryChainDocumentParser.h"
+#include "ParseFrame.h"
+
+using namespace Parse;
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+ QTranslator translator;
+ const QStringList uiLanguages = QLocale::system().uiLanguages();
+ for (const QString &locale : uiLanguages) {
+ const QString baseName = "DesParser_" + QLocale(locale).name();
+ if (translator.load(":/i18n/" + baseName)) {
+ a.installTranslator(&translator);
+ break;
+ }
+ }
+
+ StoryChainDocumentParser frame(nullptr);
+
+ DocCore doc(nullptr, "D:\\Projects\\Cpp\\QtNovelDesc\\DesParser\\example.storychain");
+ auto retlist = frame.analysis(&doc, "D:\\Projects\\Cpp\\QtNovelDesc\\DesParser\\example.storychain");
+ for (auto x : qAsConst(retlist)) {
+ qDebug().noquote() << x->toString();
+ }
+
+ return a.exec();
+}
diff --git a/QtNovelDesc.pro b/QtNovelDesc.pro
new file mode 100644
index 0000000..d899226
--- /dev/null
+++ b/QtNovelDesc.pro
@@ -0,0 +1,5 @@
+TEMPLATE = subdirs
+
+SUBDIRS += \
+ DesParser \
+ WordsIDE
diff --git a/QtNovelDesc.pro.user b/QtNovelDesc.pro.user
new file mode 100644
index 0000000..e272685
--- /dev/null
+++ b/QtNovelDesc.pro.user
@@ -0,0 +1,397 @@
+
+
+
+
+
+ EnvironmentId
+ {0319cfee-d1cc-46d3-9a7c-7bdb9d8fc868}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ false
+ true
+ false
+ 0
+ true
+ true
+ 0
+ 8
+ true
+ false
+ 1
+ true
+ true
+ true
+ *.md, *.MD, Makefile
+ false
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ false
+ true
+ true
+ true
+ true
+
+
+ 0
+ true
+
+ -fno-delayed-template-parsing
+
+ true
+ Builtin.BuildSystem
+
+ true
+ true
+ Builtin.DefaultTidyAndClazy
+ 8
+
+
+
+ true
+
+
+ true
+
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ Desktop Qt 5.12.11 MSVC2017 64bit
+ Desktop Qt 5.12.11 MSVC2017 64bit
+ qt.qt5.51211.win64_msvc2017_64_kit
+ 0
+ 0
+ 1
+
+ 0
+ D:\Projects\Cpp\build-QtNovelDesc-Desktop_Qt_5_12_11_MSVC2017_64bit-Debug
+ D:/Projects/Cpp/build-QtNovelDesc-Desktop_Qt_5_12_11_MSVC2017_64bit-Debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+
+
+ D:\Projects\Cpp\build-QtNovelDesc-Desktop_Qt_5_12_11_MSVC2017_64bit-Release
+ D:/Projects/Cpp/build-QtNovelDesc-Desktop_Qt_5_12_11_MSVC2017_64bit-Release
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+
+
+ 0
+ D:\Projects\Cpp\build-QtNovelDesc-Desktop_Qt_5_12_11_MSVC2017_64bit-Profile
+ D:/Projects/Cpp/build-QtNovelDesc-Desktop_Qt_5_12_11_MSVC2017_64bit-Profile
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 0
+
+ 3
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+ dwarf
+
+ cpu-cycles
+
+
+ 250
+
+ -e
+ cpu-cycles
+ --call-graph
+ dwarf,4096
+ -F
+ 250
+
+ -F
+ true
+ 4096
+ false
+ false
+ 1000
+
+ true
+
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ kcachegrind
+ 1
+
+ 25
+
+ 1
+ true
+ false
+ true
+
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+
+ 2
+
+ Qt4ProjectManager.Qt4RunConfiguration:D:/Projects/Cpp/QtNovelDesc/WordsIDE/WordsIDE.pro
+ D:/Projects/Cpp/QtNovelDesc/WordsIDE/WordsIDE.pro
+ false
+ true
+ true
+ false
+ true
+ D:/Projects/Cpp/build-QtNovelDesc-Desktop_Qt_5_12_11_MSVC2017_64bit-Debug/WordsIDE
+
+
+ dwarf
+
+ cpu-cycles
+
+
+ 250
+
+ -e
+ cpu-cycles
+ --call-graph
+ dwarf,4096
+ -F
+ 250
+
+ -F
+ true
+ 4096
+ false
+ false
+ 1000
+
+ true
+
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ kcachegrind
+ 1
+
+ 25
+
+ 1
+ true
+ false
+ true
+
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+
+ 2
+
+ Qt4ProjectManager.Qt4RunConfiguration:D:/Projects/Cpp/QtNovelDesc/DesParser/DesParser.pro
+ D:/Projects/Cpp/QtNovelDesc/DesParser/DesParser.pro
+ false
+ true
+ true
+ false
+ true
+ D:/Projects/Cpp/build-QtNovelDesc-Desktop_Qt_5_12_11_MSVC2017_64bit-Debug/DesParser
+
+ 2
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 22
+
+
+ Version
+ 22
+
+
diff --git a/QtNovelDesc.sln b/QtNovelDesc.sln
new file mode 100644
index 0000000..8852da5
--- /dev/null
+++ b/QtNovelDesc.sln
@@ -0,0 +1,31 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.2092
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DesParser", "DesParser\DesParser.vcxproj", "{CDBA4FCE-9275-3B08-87C8-B4473EB323EA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WordsIDE", "WordsIDE\WordsIDE.vcxproj", "{E0995577-1AB9-3B93-9990-97E99093D597}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CDBA4FCE-9275-3B08-87C8-B4473EB323EA}.Debug|x64.ActiveCfg = Debug|x64
+ {CDBA4FCE-9275-3B08-87C8-B4473EB323EA}.Debug|x64.Build.0 = Debug|x64
+ {CDBA4FCE-9275-3B08-87C8-B4473EB323EA}.Release|x64.ActiveCfg = Release|x64
+ {CDBA4FCE-9275-3B08-87C8-B4473EB323EA}.Release|x64.Build.0 = Release|x64
+ {E0995577-1AB9-3B93-9990-97E99093D597}.Debug|x64.ActiveCfg = Debug|x64
+ {E0995577-1AB9-3B93-9990-97E99093D597}.Debug|x64.Build.0 = Debug|x64
+ {E0995577-1AB9-3B93-9990-97E99093D597}.Release|x64.ActiveCfg = Release|x64
+ {E0995577-1AB9-3B93-9990-97E99093D597}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ Qt5Version = 5.12.11_msvc2017_64
+ SolutionGuid = {51E35A72-306D-43E5-8155-98C6F094417C}
+ EndGlobalSection
+EndGlobal
diff --git a/WordsIDE/WordsIDE.pro b/WordsIDE/WordsIDE.pro
new file mode 100644
index 0000000..c7ebb75
--- /dev/null
+++ b/WordsIDE/WordsIDE.pro
@@ -0,0 +1,26 @@
+QT += core gui
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+CONFIG += c++11
+
+# You can make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp
+
+HEADERS += \
+ mainwindow.h
+
+TRANSLATIONS += \
+ WordsIDE_zh_CN.ts
+CONFIG += lrelease
+CONFIG += embed_translations
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
diff --git a/WordsIDE/WordsIDE.vcxproj b/WordsIDE/WordsIDE.vcxproj
new file mode 100644
index 0000000..7dc0825
--- /dev/null
+++ b/WordsIDE/WordsIDE.vcxproj
@@ -0,0 +1,205 @@
+
+
+
+
+ Release
+ x64
+
+
+ Debug
+ x64
+
+
+
+ {E0995577-1AB9-3B93-9990-97E99093D597}
+ WordsIDE
+ QtVS_v304
+ 10.0.22621.0
+ 10.0.22621.0
+ $(MSBuildProjectDirectory)\QtMsBuild
+
+
+ v141
+ release\
+ false
+ NotSet
+ Application
+ release\
+ WordsIDE
+
+
+ v141
+ debug\
+ false
+ NotSet
+ Application
+ debug\
+ WordsIDE
+
+
+
+
+
+
+
+
+
+ debug\debug\WordsIDEtruerelease\release\WordsIDEtruefalse5.12.11_msvc2017_64core;gui;widgets5.12.11_msvc2017_64core;gui;widgets
+
+
+
+ GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;release;/include;%(AdditionalIncludeDirectories)
+ -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)
+ release\
+ false
+ None
+ 4577;4467;%(DisableSpecificWarnings)
+ Sync
+ release\
+ MaxSpeed
+ _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_NO_DEBUG;NDEBUG;%(PreprocessorDefinitions)
+ false
+
+ MultiThreadedDLL
+ true
+ true
+ Level3
+ true
+
+ shell32.lib;%(AdditionalDependencies)
+ C:\openssl\lib;C:\Utils\my_sql\mysql-5.6.11-winx64\lib;C:\Utils\postgresql\pgsql\lib;%(AdditionalLibraryDirectories)
+ "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)
+ true
+ false
+ true
+ false
+ $(OutDir)\WordsIDE.exe
+ true
+ Windows
+ true
+
+
+ Unsigned
+ None
+ 0
+
+
+ _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;%(PreprocessorDefinitions)
+
+ msvc./$(Configuration)/moc_predefs.hMoc'ing %(Identity)...output$(Configuration)moc_%(Filename).cppqmake_qmake_qm_filesdefaultRcc'ing %(Identity)...$(Configuration)qrc_%(Filename).cpp
+
+
+ GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;debug;/include;%(AdditionalIncludeDirectories)
+ -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)
+ debug\
+ false
+ ProgramDatabase
+ 4577;4467;%(DisableSpecificWarnings)
+ Sync
+ debug\
+ Disabled
+ _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;%(PreprocessorDefinitions)
+ false
+ MultiThreadedDebugDLL
+ true
+ true
+ Level3
+ true
+
+ shell32.lib;%(AdditionalDependencies)
+ C:\openssl\lib;C:\Utils\my_sql\mysql-5.6.11-winx64\lib;C:\Utils\postgresql\pgsql\lib;%(AdditionalLibraryDirectories)
+ "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)
+ true
+ true
+ true
+ $(OutDir)\WordsIDE.exe
+ true
+ Windows
+ true
+
+
+ Unsigned
+ None
+ 0
+
+
+ _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions)
+
+ msvc./$(Configuration)/moc_predefs.hMoc'ing %(Identity)...output$(Configuration)moc_%(Filename).cppqmake_qmake_qm_filesdefaultRcc'ing %(Identity)...$(Configuration)qrc_%(Filename).cpp
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Document
+ true
+ $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)
+ cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >debug\moc_predefs.h
+ Generate moc_predefs.h
+ debug\moc_predefs.h;%(Outputs)
+
+
+ Document
+ $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)
+ cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >release\moc_predefs.h
+ Generate moc_predefs.h
+ release\moc_predefs.h;%(Outputs)
+ true
+
+
+
+
+
+
+ WordsIDE_zh_CN.ts;%(AdditionalInputs)
+ $(QTDIR)\bin\lrelease.exe WordsIDE_zh_CN.ts -qm release\WordsIDE_zh_CN.qm
+ lrelease
+ release\WordsIDE_zh_CN.qm;%(Outputs)
+ WordsIDE_zh_CN.ts;%(AdditionalInputs)
+ $(QTDIR)\bin\lrelease.exe WordsIDE_zh_CN.ts -qm debug\WordsIDE_zh_CN.qm
+ lrelease
+ debug\WordsIDE_zh_CN.qm;%(Outputs)
+
+
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WordsIDE/WordsIDE.vcxproj.filters b/WordsIDE/WordsIDE.vcxproj.filters
new file mode 100644
index 0000000..c199ee1
--- /dev/null
+++ b/WordsIDE/WordsIDE.vcxproj.filters
@@ -0,0 +1,93 @@
+
+
+
+
+ {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}
+ cpp;c;cxx;moc;h;def;odl;idl;res;
+
+
+ {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}
+ cpp;c;cxx;moc;h;def;odl;idl;res;
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}
+ qrc;*
+ false
+
+
+ {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}
+ qrc;*
+ false
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}
+ ts;xlf
+ false
+
+
+ {639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}
+ ts;xlf
+ false
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
+
+
+
+ Generated Files
+
+
+ Generated Files
+
+
+
+
+
+
+ Translation Files
+
+
+
+
+ Resource Files
+
+
+ Resource Files
+
+
+ Resource Files
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/WordsIDE/WordsIDE.vcxproj.user b/WordsIDE/WordsIDE.vcxproj.user
new file mode 100644
index 0000000..be25078
--- /dev/null
+++ b/WordsIDE/WordsIDE.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/WordsIDE/WordsIDE_zh_CN.ts b/WordsIDE/WordsIDE_zh_CN.ts
new file mode 100644
index 0000000..630fd35
--- /dev/null
+++ b/WordsIDE/WordsIDE_zh_CN.ts
@@ -0,0 +1,3 @@
+
+
+
diff --git a/WordsIDE/main.cpp b/WordsIDE/main.cpp
new file mode 100644
index 0000000..dad6c42
--- /dev/null
+++ b/WordsIDE/main.cpp
@@ -0,0 +1,23 @@
+#include "mainwindow.h"
+
+#include
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+
+ QTranslator translator;
+ const QStringList uiLanguages = QLocale::system().uiLanguages();
+ for (const QString &locale : uiLanguages) {
+ const QString baseName = "WordsIDE_" + QLocale(locale).name();
+ if (translator.load(":/i18n/" + baseName)) {
+ a.installTranslator(&translator);
+ break;
+ }
+ }
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/WordsIDE/mainwindow.cpp b/WordsIDE/mainwindow.cpp
new file mode 100644
index 0000000..47b43a3
--- /dev/null
+++ b/WordsIDE/mainwindow.cpp
@@ -0,0 +1,11 @@
+#include "mainwindow.h"
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+{
+}
+
+MainWindow::~MainWindow()
+{
+}
+
diff --git a/WordsIDE/mainwindow.h b/WordsIDE/mainwindow.h
new file mode 100644
index 0000000..d147190
--- /dev/null
+++ b/WordsIDE/mainwindow.h
@@ -0,0 +1,14 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = nullptr);
+ ~MainWindow();
+};
+#endif // MAINWINDOW_H