442 lines
11 KiB
C++
442 lines
11 KiB
C++
#include "XSyntaxBase.h"
|
|
|
|
using namespace Parse;
|
|
using namespace Parse::Result;
|
|
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]+)[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*> Link::nextElements() const { return next_inss; }
|
|
|
|
std::tuple<Element::rst_mark, Element::match_len>
|
|
Link::linkCheck(const QList<LexResult>& 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::rst_mark, Element::match_len>
|
|
Element::elementCheck(const QList<LexResult>& 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<Element::rst_mark, Element::match_len>
|
|
Expression::elementCheck(const QList<LexResult>& 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<ParseResult(const QList<LexResult>&, int)> exc)
|
|
: enable_state(true), host_ins(host), 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 ParseRule::setEnable(bool v)
|
|
{
|
|
this->enable_state = v;
|
|
}
|
|
|
|
void Syntax::ParseRule::addExpression(const QString &name, const QList<Elm> &defines)
|
|
{
|
|
// 生成表达式实例
|
|
auto exp = host_ins->get_expression(Link::name(name));
|
|
|
|
// 逐个构建表达式或者元素
|
|
QList<Link*> 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;
|
|
}
|
|
|
|
// 标记结尾可能性
|
|
if (!link_rebuilds.last()->tailTest())
|
|
link_rebuilds.last()->markTail(def_it.isTail());
|
|
}
|
|
|
|
// 匹配链构建
|
|
for (auto idx = 1; idx < link_rebuilds.size(); ++idx) {
|
|
auto prv_it = link_rebuilds[idx - 1];
|
|
prv_it->appendNext(link_rebuilds[idx]);
|
|
}
|
|
|
|
exp->resetLinks(link_rebuilds.first());
|
|
expression_list << exp;
|
|
}
|
|
|
|
std::tuple<bool, int> ParseRule::tokensMatch(const QList<LexResult>& token) const
|
|
{
|
|
if(enable_state)
|
|
for (auto expx : expression_list) {
|
|
auto result = expx->elementCheck(token, 0);
|
|
if (std::get<0>(result)) {
|
|
return std::make_tuple(true, std::get<1>(result));
|
|
}
|
|
}
|
|
|
|
return std::make_tuple(false, 0);
|
|
}
|
|
|
|
ParseResult ParseRule::syntaxTrigger(const QList<LexResult>& srcs, int count) {
|
|
return exc_store(srcs, count);
|
|
}
|
|
|
|
XSyntaxBase::XSyntaxBase(const QString & section, MatchType type)
|
|
: target_type(type), section_name(section), current_level(INT_MAX), current_node(nullptr) {}
|
|
|
|
ParseRule * XSyntaxBase::addRule(const QString & name, unsigned short level,
|
|
std::function<ParseResult(const QList<LexResult>&, 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<SyntaxParser*> 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<LexResult>& seqs)
|
|
{
|
|
if(!seqs.size())
|
|
return false;
|
|
|
|
// 求取最小等级的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)) {
|
|
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<LexResult>& seqs)
|
|
{
|
|
if(!seqs.size())
|
|
return ParseResult::Failed;
|
|
|
|
// 求取符合等级的parse-rule
|
|
QList<ParseRule*> rules_set;
|
|
for (auto &rule : rule_collect) {
|
|
if (rule->level() >= current_level)
|
|
rules_set << rule;
|
|
}
|
|
|
|
std::tuple<bool, int, ParseRule*> max_result = std::make_tuple(false, 0, nullptr);
|
|
// 使用符合等级的解析规则解析
|
|
for (auto &rule : rules_set) {
|
|
auto result = rule->tokensMatch(seqs);
|
|
if (std::get<0>(result) && current_level <= rule->level()) {
|
|
current_level = rule->level();
|
|
max_result = std::make_tuple(true, std::get<1>(result), rule);
|
|
}
|
|
}
|
|
|
|
if (!std::get<0>(max_result)) {
|
|
if (target_type == MatchType::Outline)
|
|
return ParseResult::Completed;
|
|
return ParseResult::Failed;
|
|
}
|
|
else { // 匹配成功
|
|
if (target_type == MatchType::Outline) {
|
|
if (current_node == nullptr) {
|
|
return std::get<2>(max_result)->syntaxTrigger(seqs, std::get<1>(max_result));
|
|
}
|
|
else {
|
|
return ParseResult::Completed;
|
|
}
|
|
}
|
|
else {
|
|
auto xresult = std::get<2>(max_result)->syntaxTrigger(seqs, std::get<1>(max_result));
|
|
|
|
if (target_type == MatchType::Entirely) {
|
|
auto count = std::get<1>(max_result);
|
|
while (count--)
|
|
seqs.removeFirst();
|
|
}
|
|
return xresult;
|
|
}
|
|
}
|
|
}
|
|
|
|
QList<SyntaxParser*> XSyntaxBase::children() const
|
|
{
|
|
return child_parsers;
|
|
}
|
|
|
|
void XSyntaxBase::refocusNode(DesNode * ins)
|
|
{
|
|
current_node = ins;
|
|
}
|
|
|
|
Expression *XSyntaxBase::set_common_expression(const QString &name, const QList<Defines::Elm> &defines)
|
|
{
|
|
if (expressions_store.contains(Link::name(name)))
|
|
return nullptr;
|
|
|
|
auto ins = get_expression(Link::name(name));
|
|
// 逐个构建表达式或者元素
|
|
QList<Link*> 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(), get_element(def_it.refer()));
|
|
else
|
|
tins = new Link(def_it.aliasName(), get_expression(def_it.refer()));
|
|
|
|
link_rebuilds << tins;
|
|
}
|
|
|
|
// 标记结尾可能性
|
|
link_rebuilds.last()->markTail(def_it.isTail());
|
|
}
|
|
|
|
// 匹配链构建
|
|
for (auto idx = 1; idx < link_rebuilds.size(); ++idx) {
|
|
auto prv_it = link_rebuilds[idx - 1];
|
|
prv_it->appendNext(link_rebuilds[idx]);
|
|
}
|
|
|
|
ins->resetLinks(link_rebuilds.first());
|
|
return ins;
|
|
}
|
|
|
|
void XSyntaxBase::resetMatch(MatchType mtype)
|
|
{
|
|
this->target_type = mtype;
|
|
}
|
|
|
|
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;
|
|
}
|