构建ast输出
This commit is contained in:
parent
a97ed72b67
commit
93e7edaae8
|
@ -3,7 +3,7 @@
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)$(Platform)\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
<LocalDebuggerWorkingDirectory>$(SolutionDir)$(Platform)\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
||||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||||
<LocalDebuggerCommandArguments>--path "D:\手作小说\科学+修仙+创造世界" --html --dest E:\</LocalDebuggerCommandArguments>
|
<LocalDebuggerCommandArguments>--path "D:\手作小说\科学+修仙+创造世界" --dest E:\</LocalDebuggerCommandArguments>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<LocalDebuggerCommandArguments>--path "D:\手作小说\科学+修仙+创造世界"</LocalDebuggerCommandArguments>
|
<LocalDebuggerCommandArguments>--path "D:\手作小说\科学+修仙+创造世界"</LocalDebuggerCommandArguments>
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
using namespace example_novel;
|
using namespace example_novel;
|
||||||
using namespace printer;
|
using namespace printer;
|
||||||
|
using namespace lib_parse;
|
||||||
|
|
||||||
Access::Access(std::shared_ptr<const ast_gen::ElementAccess> handle)
|
Access::Access(std::shared_ptr<const ast_gen::ElementAccess> handle)
|
||||||
:access_handle(handle) {}
|
:access_handle(handle) {}
|
||||||
|
@ -532,3 +533,141 @@ QString printer::tools_printer::volumes_paint(const QList<std::shared_ptr<StoryV
|
||||||
|
|
||||||
return QString("graph scale{ %1 \n %2}").arg(clusters_description).arg(arrows_link);
|
return QString("graph scale{ %1 \n %2}").arg(clusters_description).arg(arrows_link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void printer::AstGenerate::append_tokens(QDomElement _elm, std::shared_ptr<const ast_gen::SyntaxElement> inst) {
|
||||||
|
auto dom_tokens = doc.createElement(u8"tokens");
|
||||||
|
_elm.appendChild(dom_tokens);
|
||||||
|
|
||||||
|
for (auto& token : inst->selfTokens()) {
|
||||||
|
auto dom_token = doc.createElement(u8"token");
|
||||||
|
dom_tokens.appendChild(dom_token);
|
||||||
|
|
||||||
|
dom_token.setAttribute(u8"text", token->token()->content());
|
||||||
|
dom_token.setAttribute(u8"row", token->token()->row());
|
||||||
|
dom_token.setAttribute(u8"col", token->token()->column());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printer::AstGenerate::AstGenerate()
|
||||||
|
{
|
||||||
|
auto procs = doc.createProcessingInstruction("xml", "version='1.0'");
|
||||||
|
doc.appendChild(procs);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString printer::AstGenerate::content() const
|
||||||
|
{
|
||||||
|
return doc.toString(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
VisitMode printer::AstGenerate::mode() const {
|
||||||
|
return VisitMode::FirstParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool printer::AstGenerate::visit(std::shared_ptr<const ast_gen::ElementAccess> syntax_element) {
|
||||||
|
switch ((NovelNode)syntax_element->element()->typeMark()) {
|
||||||
|
case NovelNode::GlobalElement:{
|
||||||
|
auto body = doc.createElement(u8"ast");
|
||||||
|
doc.appendChild(body);
|
||||||
|
element_stack.append(body);
|
||||||
|
}break;
|
||||||
|
case NovelNode::Document: break;
|
||||||
|
case NovelNode::StoryDefine:{
|
||||||
|
while (element_stack.last().tagName() != u8"ast") {
|
||||||
|
element_stack.takeLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto current_ast = element_stack.last();
|
||||||
|
auto story_node = std::dynamic_pointer_cast<const example_novel::StoryDefine>(syntax_element->element());
|
||||||
|
auto dom_story = doc.createElement(u8"story");
|
||||||
|
current_ast.appendChild(dom_story);
|
||||||
|
element_stack.append(dom_story);
|
||||||
|
|
||||||
|
dom_story.setAttribute(u8"name", story_node->name());
|
||||||
|
dom_story.setAttribute(u8"file-path", story_node->filePath());
|
||||||
|
dom_story.setAttribute(u8"sort", story_node->sort());
|
||||||
|
|
||||||
|
append_tokens(dom_story, story_node);
|
||||||
|
}break;
|
||||||
|
case NovelNode::FragmentDefine: {
|
||||||
|
while (element_stack.last().tagName() != u8"story") {
|
||||||
|
element_stack.takeLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto current_story = element_stack.last();
|
||||||
|
auto fragment_node = std::dynamic_pointer_cast<const example_novel::FragmentDefine>(syntax_element->element());
|
||||||
|
auto dom_fragment = doc.createElement(u8"fragment");
|
||||||
|
current_story.appendChild(dom_fragment);
|
||||||
|
element_stack.append(dom_fragment);
|
||||||
|
|
||||||
|
dom_fragment.setAttribute(u8"name", fragment_node->name());
|
||||||
|
dom_fragment.setAttribute(u8"file-path", fragment_node->filePath());
|
||||||
|
|
||||||
|
append_tokens(dom_fragment, fragment_node);
|
||||||
|
}break;
|
||||||
|
case NovelNode::TextSection:{
|
||||||
|
auto current_text = element_stack.last();
|
||||||
|
auto text_node = std::dynamic_pointer_cast<const example_novel::TextSection>(syntax_element->element());
|
||||||
|
auto dom_text = doc.createElement(u8"text-section");
|
||||||
|
current_text.appendChild(dom_text);
|
||||||
|
|
||||||
|
dom_text.setAttribute(u8"text", text_node->content());
|
||||||
|
dom_text.setAttribute(u8"file-path", text_node->filePath());
|
||||||
|
|
||||||
|
append_tokens(dom_text, text_node);
|
||||||
|
}break;
|
||||||
|
case NovelNode::FragmentRefer:{
|
||||||
|
while (element_stack.last().tagName() != u8"article" && element_stack.last().tagName() != u8"story") {
|
||||||
|
element_stack.takeLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto current_pnode = element_stack.last();
|
||||||
|
auto refer_node = std::dynamic_pointer_cast<const example_novel::FragmentRefers>(syntax_element->element());
|
||||||
|
auto dom_refer = doc.createElement(u8"refer");
|
||||||
|
element_stack.append(dom_refer);
|
||||||
|
current_pnode.appendChild(dom_refer);
|
||||||
|
|
||||||
|
dom_refer.setAttribute(u8"story", refer_node->storyRefer());
|
||||||
|
dom_refer.setAttribute(u8"fragment", refer_node->fragmentRefer());
|
||||||
|
dom_refer.setAttribute(u8"file-path", refer_node->filePath());
|
||||||
|
|
||||||
|
append_tokens(dom_refer, refer_node);
|
||||||
|
}break;
|
||||||
|
case NovelNode::VolumeDefine:{
|
||||||
|
while (element_stack.last().tagName() != u8"ast") {
|
||||||
|
element_stack.takeLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto current_ast = element_stack.last();
|
||||||
|
auto volume_node = std::dynamic_pointer_cast<const example_novel::VolumeDefine>(syntax_element->element());
|
||||||
|
auto dom_volume = doc.createElement(u8"volume");
|
||||||
|
current_ast.appendChild(dom_volume);
|
||||||
|
element_stack.append(dom_volume);
|
||||||
|
|
||||||
|
dom_volume.setAttribute(u8"name", volume_node->name());
|
||||||
|
dom_volume.setAttribute(u8"file-path", volume_node->filePath());
|
||||||
|
|
||||||
|
append_tokens(dom_volume, volume_node);
|
||||||
|
}break;
|
||||||
|
case NovelNode::ArticleDefine:{
|
||||||
|
while (element_stack.last().tagName() != u8"volume") {
|
||||||
|
element_stack.takeLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto current_volume = element_stack.last();
|
||||||
|
auto article_node = std::dynamic_pointer_cast<const example_novel::ArticleDefine>(syntax_element->element());
|
||||||
|
auto dom_article = doc.createElement(u8"article");
|
||||||
|
current_volume.appendChild(dom_article);
|
||||||
|
element_stack.append(dom_article);
|
||||||
|
|
||||||
|
dom_article.setAttribute(u8"name", article_node->name());
|
||||||
|
dom_article.setAttribute(u8"file-path", article_node->filePath());
|
||||||
|
|
||||||
|
append_tokens(dom_article, article_node);
|
||||||
|
}break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -157,4 +157,21 @@ namespace printer {
|
||||||
QString storylines_paint(const QList<std::shared_ptr<StoryLine>> &lines);
|
QString storylines_paint(const QList<std::shared_ptr<StoryLine>> &lines);
|
||||||
QString volumes_paint(const QList<std::shared_ptr<StoryVolume>> &vols, const QList<std::shared_ptr<StoryLine>> &lines);
|
QString volumes_paint(const QList<std::shared_ptr<StoryVolume>> &vols, const QList<std::shared_ptr<StoryLine>> &lines);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AstGenerate : public lib_parse::TreeVisitor {
|
||||||
|
private:
|
||||||
|
QDomDocument doc;
|
||||||
|
QList<QDomElement> element_stack;
|
||||||
|
|
||||||
|
void append_tokens(QDomElement _elm, std::shared_ptr<const ast_gen::SyntaxElement> inst);
|
||||||
|
|
||||||
|
public:
|
||||||
|
AstGenerate();
|
||||||
|
|
||||||
|
QString content() const;
|
||||||
|
|
||||||
|
// ͨ¹ý TreeVisitor ¼Ì³Ð
|
||||||
|
lib_parse::VisitMode mode() const override;
|
||||||
|
bool visit(std::shared_ptr<const ast_gen::ElementAccess> syntax_element) override;
|
||||||
|
};
|
||||||
}
|
}
|
|
@ -54,7 +54,7 @@ int main(int argc, char* argv[]) {
|
||||||
auto args = std::get<1>(parse_result);
|
auto args = std::get<1>(parse_result);
|
||||||
auto src_dir = std::dynamic_pointer_cast<args_parse::FloatArgvPack>(args_mode[1]);
|
auto src_dir = std::dynamic_pointer_cast<args_parse::FloatArgvPack>(args_mode[1]);
|
||||||
auto dst_dir = std::dynamic_pointer_cast<args_parse::FloatArgvPack>(args_mode[2]);
|
auto dst_dir = std::dynamic_pointer_cast<args_parse::FloatArgvPack>(args_mode[2]);
|
||||||
auto fmt_opt = std::dynamic_pointer_cast<args_parse::FloatOption>(args_mode[3]);
|
auto html_opt = std::dynamic_pointer_cast<args_parse::FloatOption>(args_mode[3]);
|
||||||
|
|
||||||
auto source_dir = QDir(src_dir->value());
|
auto source_dir = QDir(src_dir->value());
|
||||||
if (!source_dir.exists()) {
|
if (!source_dir.exists()) {
|
||||||
|
@ -66,7 +66,7 @@ int main(int argc, char* argv[]) {
|
||||||
if (!target_output.isEmpty() && QDir(target_output).exists()) {
|
if (!target_output.isEmpty() && QDir(target_output).exists()) {
|
||||||
destination_dir = QDir(target_output);
|
destination_dir = QDir(target_output);
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
std::cout << "编译指定的生成目录不存在,重置为:" << destination_dir.absolutePath().toLocal8Bit().data() << std::endl;
|
std::cout << "编译指定的生成目录不存在,重置为:" << destination_dir.absolutePath().toLocal8Bit().data() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +76,7 @@ int main(int argc, char* argv[]) {
|
||||||
try {
|
try {
|
||||||
auto parser = std::make_shared<NovelParser>();
|
auto parser = std::make_shared<NovelParser>();
|
||||||
access_ptr = parser->parse(files);
|
access_ptr = parser->parse(files);
|
||||||
|
qDebug() << u8"%±àÒë³É¹¦£º" << destination_dir.absoluteFilePath(u8"index.html");
|
||||||
}
|
}
|
||||||
catch (lib_syntax::SyntaxException* e) {
|
catch (lib_syntax::SyntaxException* e) {
|
||||||
qDebug().noquote() << e->message();
|
qDebug().noquote() << e->message();
|
||||||
|
@ -89,7 +90,7 @@ int main(int argc, char* argv[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fmt_opt->value().toInt() == 1 && access_ptr) {
|
if (html_opt->value().toInt() == 1 && access_ptr) {
|
||||||
QTime time_stamp = QTime::currentTime();
|
QTime time_stamp = QTime::currentTime();
|
||||||
printer::tools_printer tool;
|
printer::tools_printer tool;
|
||||||
tool.build_fragments(access_ptr);
|
tool.build_fragments(access_ptr);
|
||||||
|
@ -246,8 +247,13 @@ int main(int argc, char* argv[]) {
|
||||||
auto current_stamp = QTime::currentTime();
|
auto current_stamp = QTime::currentTime();
|
||||||
qDebug() << QString(u8"html构建消耗时间:%1 ms。").arg(time_stamp.msecsTo(current_stamp));
|
qDebug() << QString(u8"html构建消耗时间:%1 ms。").arg(time_stamp.msecsTo(current_stamp));
|
||||||
}
|
}
|
||||||
|
else if (access_ptr) {
|
||||||
qDebug() << u8"编译成功:" << destination_dir.absoluteFilePath(u8"index.html");
|
lib_parse::VisitorControl control;
|
||||||
|
auto visitor = std::make_shared<printer::AstGenerate>();
|
||||||
|
control.visitWith(access_ptr, visitor);;
|
||||||
|
auto dom_result = visitor->content();
|
||||||
|
qDebug().noquote() << dom_result;
|
||||||
|
}
|
||||||
}break;
|
}break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -42,7 +42,7 @@ std::shared_ptr<const ast_gen::ElementAccess> NovelParser::parse(const QFileInfo
|
||||||
forst_root.append(std::get<0>(exprs_result));
|
forst_root.append(std::get<0>(exprs_result));
|
||||||
}
|
}
|
||||||
auto current_stamp = QTime::currentTime();
|
auto current_stamp = QTime::currentTime();
|
||||||
qDebug() << QString(u8"词法解析+语法解析消耗时间:%1 ms。").arg(time_stamp.msecsTo(current_stamp));
|
qDebug().noquote() << QString(u8"%词法解析+语法解析消耗时间:%1 ms。").arg(time_stamp.msecsTo(current_stamp));
|
||||||
|
|
||||||
time_stamp = QTime::currentTime();
|
time_stamp = QTime::currentTime();
|
||||||
QList<std::shared_ptr<ast_gen::SyntaxElement>> docs_node;
|
QList<std::shared_ptr<ast_gen::SyntaxElement>> docs_node;
|
||||||
|
@ -55,7 +55,7 @@ std::shared_ptr<const ast_gen::ElementAccess> NovelParser::parse(const QFileInfo
|
||||||
auto x_root = NovalSyntax::tidy(context, docs_node);
|
auto x_root = NovalSyntax::tidy(context, docs_node);
|
||||||
auto novel_accesstree = std::make_shared<ast_gen::ElementAccess>(x_root);
|
auto novel_accesstree = std::make_shared<ast_gen::ElementAccess>(x_root);
|
||||||
current_stamp = QTime::currentTime();
|
current_stamp = QTime::currentTime();
|
||||||
qDebug() << QString(u8"程序结构重建消耗时间:%1 ms。").arg(time_stamp.msecsTo(current_stamp));
|
qDebug().noquote() << QString(u8"%程序结构重建消耗时间:%1 ms。").arg(time_stamp.msecsTo(current_stamp));
|
||||||
|
|
||||||
return analyzer_ref->validCheckWith(novel_accesstree);
|
return analyzer_ref->validCheckWith(novel_accesstree);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "libparse.h"
|
#include "libparse.h"
|
||||||
|
|
||||||
using namespace lib_parse;
|
using namespace lib_parse;
|
||||||
|
using namespace ast_gen;
|
||||||
|
|
||||||
CheckException::CheckException(const QString& msg) : msg_store(msg) {}
|
CheckException::CheckException(const QString& msg) : msg_store(msg) {}
|
||||||
|
|
||||||
|
@ -10,12 +11,41 @@ Analyzer::Analyzer(const QList<std::shared_ptr<const CheckProvider> >& providers
|
||||||
|
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
std::shared_ptr<const ast_gen::ElementAccess> Analyzer::validCheckWith(std::shared_ptr<const ast_gen::ElementAccess> root) const {
|
std::shared_ptr<const ElementAccess> Analyzer::validCheckWith(std::shared_ptr<const ElementAccess> root) const {
|
||||||
for (auto& v : check_providers){
|
for (auto& v : check_providers){
|
||||||
QTime time_stamp = QTime::currentTime();
|
QTime time_stamp = QTime::currentTime();
|
||||||
v->validCheck(root);
|
v->validCheck(root);
|
||||||
auto current_stamp = QTime::currentTime();
|
auto current_stamp = QTime::currentTime();
|
||||||
qDebug() << QString(u8"校验器:%2 消耗时间:%1 ms。").arg(time_stamp.msecsTo(current_stamp)).arg(v->name());
|
qDebug().noquote() << QString(u8"%УÑéÆ÷£º%2 ÏûºÄʱ¼ä£º%1 ms¡£").arg(time_stamp.msecsTo(current_stamp)).arg(v->name());
|
||||||
}
|
}
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VisitorControl::visitWith(std::shared_ptr<const ElementAccess> syntax_elm, std::shared_ptr<TreeVisitor> visitor) {
|
||||||
|
switch (visitor->mode()) {
|
||||||
|
case VisitMode::FirstParent: {
|
||||||
|
if (visitor->visit(syntax_elm)) {
|
||||||
|
for (auto& e : syntax_elm->children()) {
|
||||||
|
visitWith(e, visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}break;
|
||||||
|
case VisitMode::LastParent:{
|
||||||
|
bool exc_continue = true;
|
||||||
|
for (auto& e : syntax_elm->children()) {
|
||||||
|
if(!visitWith(e, visitor)){
|
||||||
|
exc_continue = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(exc_continue)
|
||||||
|
visitor->visit(syntax_elm);
|
||||||
|
|
||||||
|
return exc_continue;
|
||||||
|
}break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -42,4 +42,32 @@ namespace lib_parse {
|
||||||
|
|
||||||
std::shared_ptr<const ast_gen::ElementAccess> validCheckWith(std::shared_ptr<const ast_gen::ElementAccess> root) const;
|
std::shared_ptr<const ast_gen::ElementAccess> validCheckWith(std::shared_ptr<const ast_gen::ElementAccess> root) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class VisitMode {
|
||||||
|
FirstParent, // 先序遍历
|
||||||
|
LastParent, // 后序遍历
|
||||||
|
};
|
||||||
|
|
||||||
|
class TreeVisitor {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* 获取访问器的遍历模式.
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
*/
|
||||||
|
virtual VisitMode mode() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对语法树执行节点遍历.
|
||||||
|
*
|
||||||
|
* \param syntax_element 当前访问节点
|
||||||
|
* \return 是否继续执行遍历
|
||||||
|
*/
|
||||||
|
virtual bool visit(std::shared_ptr<const ast_gen::ElementAccess> syntax_element) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LIBPARSE_EXPORT VisitorControl {
|
||||||
|
public:
|
||||||
|
bool visitWith(std::shared_ptr<const ast_gen::ElementAccess> syntax_elm, std::shared_ptr<TreeVisitor> visitor);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue