commit 74267ebd5b823cf3b19a7026f279d385ede1619f Author: 玉宇清音 <2422523675@qq.com> Date: Sun Nov 6 08:37:50 2022 +0800 RTTI语法链构建 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