diff --git a/kdev-pg/kdev-pg-code-gen.cpp b/kdev-pg/kdev-pg-code-gen.cpp index 6216e56..4db60e0 100644 --- a/kdev-pg/kdev-pg-code-gen.cpp +++ b/kdev-pg/kdev-pg-code-gen.cpp @@ -1,1269 +1,1269 @@ /* This file is part of kdev-pg-qt Copyright (C) 2005 Roberto Raggi Copyright (C) 2006 Jakob Petsovits Copyright (C) 2010 Jonathan Schmidt-Dominé This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kdev-pg-code-gen.h" #include #include #include #include #include "kdev-pg-pretty-printer.h" namespace KDevPG { extern QTextStream checkOut; void generateConditionFromStrings(QStringList &tokens, bool zerop, QTextStream& out) { tokens.sort(); bool initial = true; foreach (const QString &token, tokens) { if (!initial) out << endl << "|| "; out << "yytoken == Token_" << token; initial = false; } if (initial && zerop) out << "true /*epsilon*/"; } void generateCondition(const World::NodeSet& s, QTextStream& out) { if(s.size() == 0 || (s.size() == 1 && nodeCast(*s.begin()) != nullptr)) { out << "true /*epsilon*/"; return; } Model::Node *item = globalSystem.zero(); QStringList tokens; World::NodeSet::const_iterator it = s.begin(); while (it != s.end()) { item = *it; ++it; if (Model::TerminalItem *t = nodeCast(item)) tokens << t->mName; } generateConditionFromStrings(tokens, false, out); } void generateTestCondition(Model::Node *node, QTextStream& out) { if(node->kind == Model::NodeKindTerminal) { QStringList tokens; tokens << ((Model::TerminalItem*)node)->mName; generateConditionFromStrings(tokens, false, out); } else { World::NodeSet& s = globalSystem.first(node); generateCondition(s, out); } } QString generateParserCall(Model::NonTerminalItem *node, int catch_id, QTextStream& out) { static int __id = 0; static char __var[1024]; QString symbol_name = node->mSymbol->mName; QString capSymbolName = node->mSymbol->mCapitalizedName; if (globalSystem.generateAst) { sprintf(__var, "__node_%d", __id); ++__id; - out << capSymbolName << "Ast *" << __var << " = 0;" << endl + out << capSymbolName << "Ast *" << __var << " = nullptr;" << endl << "if (!parse" << capSymbolName << "(&" << __var; if (!node->mArguments.isEmpty()) out << ", " << node->mArguments; out << "))" << endl; } else { out << "if (!parse" << capSymbolName << "(" << node->mArguments << "))" << endl; } if (!catch_id) { out << "{" << endl; if (globalSystem.needStateManagement) out << "if (!mBlockErrors) {" << endl; out << "expectedSymbol(AstNode::" << capSymbolName << "Kind" << ", QStringLiteral(\"" << symbol_name << "\")" << ");" << endl; if (globalSystem.needStateManagement) out << "}" << endl; out << "return false;" << endl << "}" << endl; } else { out << "{ goto __catch_" << catch_id << "; }" << endl; } return __var; } void generateTokenTest(Model::TerminalItem *node, int catch_id, QTextStream& out) { out << "if (yytoken != Token_" << node->mName << ")" << endl; if (!catch_id) { out << "{" << endl; if (globalSystem.needStateManagement) out << "if (!mBlockErrors) {" << endl; out << "expectedToken(yytoken, Token_" << node->mName << ", QStringLiteral(\"" << node->mDescription << "\"));" << endl; if (globalSystem.needStateManagement) out << "}" << endl; out << "return false;" << endl << "}" << endl; } else { out << "goto __catch_" << catch_id << ";" << endl; } } void generateRecovery(Model::Node *node, int catch_id, QTextStream& out) { World::NodeSet s = globalSystem.follow(node); Model::Node *item = globalSystem.zero(); out << "if (try_startToken_" << catch_id << " == tokenStream->index() - 1 && yytoken != Token_EOF)" << endl << "yylex();" << endl << endl; out << "while (yytoken != Token_EOF"; World::NodeSet::iterator it = s.begin(); while (it != s.end()) { item = *it; ++it; if (Model::TerminalItem *t = nodeCast(item)) out << endl << "&& yytoken != Token_" << t->mName; } out << ")" << endl << "{ yylex(); }" << endl; } void CodeGenerator::operator()(Model::Node *node) { mEvolve = nodeCast(node); Q_ASSERT(mEvolve != nullptr); visitNode(node); } void CodeGenerator::visitZero(Model::ZeroItem *node) { Q_UNUSED(node); // out << " /* nothing to do */" << endl; } void CodeGenerator::visitSymbol(Model::SymbolItem *node) { Q_UNUSED(node); // out << " /* nothing to do */" << endl; } void CodeGenerator::visitNonTerminal(Model::NonTerminalItem *node) { generateParserCall(node, mCurrentCatchId, out); } void CodeGenerator::visitTerminal(Model::TerminalItem *node) { generateTokenTest(node, mCurrentCatchId, out); out << "yylex();" << endl << endl; } void CodeGenerator::visitPlus(Model::PlusItem *node) { out << "do {" << endl; visitNode(node->mItem); out << "} while ("; generateTestCondition(node, out); out << ");" << endl; } void CodeGenerator::visitStar(Model::StarItem *node) { out << "while ("; generateTestCondition(node, out); out << ") {" << endl; visitNode(node->mItem); out << "}" << endl; } void CodeGenerator::visitAction(Model::ActionItem *node) { DefaultVisitor::visitAction(node); out << node->mCode; } void CodeGenerator::visitCondition(Model::ConditionItem *node) { DefaultVisitor::visitCondition(node); } void CodeGenerator::visitAlternative(Model::AlternativeItem *node) { QList top_level_nodes; QStack working_list; working_list.push(node->mRight); working_list.push(node->mLeft); while (!working_list.empty()) { Model::Node *n = working_list.top(); working_list.pop(); if (Model::AlternativeItem *a = nodeCast(n)) { working_list.push(a->mRight); working_list.push(a->mLeft); } else { top_level_nodes.push_back(n); } } QList::iterator it = top_level_nodes.begin(); while (it != top_level_nodes.end()) { Model::Node *n = *it; ++it; Model::ConditionItem *cond = nodeCast(n); out << "if ("; if (cond) out << "("; generateTestCondition(n, out); if (cond) out << ") && (" << cond->mCode << ")"; out << ") {" << endl; visitNode(n); out << "}"; if (it != top_level_nodes.end()) out << "else "; else { out << "else {" << endl; if (!mCurrentCatchId) out << "return false;" << endl; else out << "goto __catch_" << mCurrentCatchId << ";"; out << "}" << endl; } } } void CodeGenerator::visitCons(Model::ConsItem *node) { DefaultVisitor::visitCons(node); } void CodeGenerator::visitEvolve(Model::EvolveItem *node) { out << "if ("; Model::ConditionItem *cond = nodeCast(node->mItem); if (cond) out << "("; generateTestCondition(node, out); if (reducesToEpsilon(node->mItem)) { out << " || "; generateCondition(globalSystem.follow(node->mSymbol), out); } if (cond) out << ") && (" << cond->mCode << ")"; out << ") {" << endl; GenerateLocalDeclarations gen_locals(out, mNames); gen_locals(node->mItem); out << node->mCode; visitNode(node->mItem); if (globalSystem.start.contains(node->mSymbol)) out << "if (Token_EOF != yytoken) { return false; }" << endl; out << "}" << endl; } void CodeGenerator::visitTryCatch(Model::TryCatchItem *node) { static int tryCatch_counter = 0; int previous_catch_id = setCatchId(++tryCatch_counter); if (node->mCatchItem) // node is a try/rollback block { out << "bool blockErrors_" << mCurrentCatchId << " = blockErrors(true);" << endl; } out << "qint64 try_startToken_" << mCurrentCatchId << " = tokenStream->index() - 1;" << endl; if (!node->mUnsafe) { out << "ParserState *try_startState_" << mCurrentCatchId << " = copyCurrentState();" << endl; } out << "{" << endl; visitNode(node->mTryItem); out << "}" << endl; if (node->mCatchItem) { out << "blockErrors(blockErrors_" << mCurrentCatchId << ");" << endl; } if (!node->mUnsafe) { out << "if (try_startState_" << mCurrentCatchId << ")" << endl << "delete try_startState_" << mCurrentCatchId << ";" << endl << endl; } out << "if (false) // the only way to enter here is using goto" << endl << "{" << endl << "__catch_" << mCurrentCatchId << ":" << endl; if (!node->mUnsafe) { out << "if (try_startState_" << mCurrentCatchId << ")" << endl << "{" << endl << "restoreState(try_startState_" << mCurrentCatchId << ");" << endl << "delete try_startState_" << mCurrentCatchId << ";" << endl << "}" << endl; } if (!node->mCatchItem) { generateRecovery(node, mCurrentCatchId, out); setCatchId(previous_catch_id); } else { out << "blockErrors(blockErrors_" << mCurrentCatchId << ");" << endl << "rewind(try_startToken_" << mCurrentCatchId << ");" << endl << endl; setCatchId(previous_catch_id); visitNode(node->mCatchItem); } out << "}" << endl << endl; } int CodeGenerator::setCatchId(int catch_id) { int previous = mCurrentCatchId; mCurrentCatchId = catch_id; return previous; } void CodeGenerator::visitAlias(Model::AliasItem *node) { Q_UNUSED(node); Q_ASSERT(0); // ### not implemented yet } void CodeGenerator::visitAnnotation(Model::AnnotationItem *node) { if (!globalSystem.generateAst) { // checkOut << "** WARNING annotation ignored" << endl; visitNode(node->mItem); return; } if (Model::TerminalItem *t = nodeCast(node->mItem)) { generateTokenTest(t, mCurrentCatchId, out); if (node->mDeclaration->mIsSequence) { QString target; if (node->mDeclaration->mStorageType == Model::VariableDeclarationItem::StorageAstMember) target += "(*yynode)->"; target += node->mDeclaration->mName; target += "Sequence"; out << target << " = snoc(" << target << ", " << "tokenStream->index() - 1, memoryPool);" << endl << "yylex();" << endl << endl; } else { if (node->mDeclaration->mStorageType == Model::VariableDeclarationItem::StorageAstMember) out << "(*yynode)->"; out << node->mDeclaration->mName << " = tokenStream->index() - 1;" << endl << "yylex();" << endl << endl; } } else if (Model::NonTerminalItem *nt = nodeCast(node->mItem)) { QString __var = generateParserCall(nt, mCurrentCatchId, out); bool check_startToken = false; World::Environment::iterator it = globalSystem.env.find(nt->mSymbol); while (it != globalSystem.env.end()) { Model::EvolveItem *e = (*it); if (it.key() != nt->mSymbol) break; ++it; Model::VariableDeclarationItem *current_decl = e->mDeclarations; while (current_decl) { if ((current_decl->mDeclarationType == Model::VariableDeclarationItem::DeclarationArgument) && (current_decl->mVariableType != Model::VariableDeclarationItem::TypeVariable)) { check_startToken = true; break; } current_decl = current_decl->mNext; } } if (check_startToken == true) { check_startToken = false; Model::VariableDeclarationItem *current_decl = mEvolve->mDeclarations; while (current_decl) { if ((current_decl->mStorageType == Model::VariableDeclarationItem::StorageTemporary) && (current_decl->mVariableType != Model::VariableDeclarationItem::TypeVariable) && (current_decl->mDeclarationType == Model::VariableDeclarationItem::DeclarationArgument)) { check_startToken = true; break; } current_decl = current_decl->mNext; } } if (check_startToken == true) { out << "if (" << __var << "->startToken < (*yynode)->startToken)" << endl << "(*yynode)->startToken = " << __var << "->startToken;" << endl; } QString target; if (node->mDeclaration->mStorageType == Model::VariableDeclarationItem::StorageAstMember) target += "(*yynode)->"; target += node->mDeclaration->mName; if (node->mDeclaration->mIsSequence) { target += "Sequence"; out << target << " = " << "snoc(" << target << ", " << __var << ", memoryPool);" << endl << endl; } else { out << target << " = " << __var << ";" << endl << endl; } } else Q_ASSERT(0); // ### not supported } void CodeGenerator::visitOperator(Model::OperatorItem *node) { out << "bool expectOperator = false;" << "while(true) {" << "if(expectOperator) {" << " "; const QString capNode = capitalized(node->mName); const QString nodeType = capNode + "Ast"; const QString baseNameC = node->mBase->mSymbol->mCapitalizedName; const QString baseType = baseNameC + "Ast"; Model::NonTerminalItem ntItem; ntItem.mSymbol = mSym; ntItem.kind = Model::NodeKindNonTerminal; { QTextStream argStr(&ntItem.mArguments); GenerateRecursiveDelegation del(argStr); } bool printElse = false; for(auto i = node->mPost.begin(); i != node->mPost.end(); ++i) { if(printElse) out << "else "; printElse = true; out << "if("; generateTestCondition(i->op.mTok, out); if(i->op.mCond.size() != 0) out << " && " << i->op.mCond; out << ") { const unsigned int priority = " << i->priority << ";"; out << i->op.mCode; - out << "AstNode *last = 0; bool br = false;"; + out << "AstNode *last = nullptr; bool br = false;"; out << "while(priority < opStack.last().p + " << i->left << ") {"; out << "if(opStack.size() == 1) {" "if(last)\n" "opStack.last().n->endToken = last->endToken;" "last = opStack.last().n;" "opStack.pop_back();" "opStack.push_front(OperatorStackItem((*yynode) = create(last), -2));" "(*yynode)->endToken = last->endToken + 1;" "(*yynode)->startToken = last->startToken;" "br = true; break; } else {" "AstNode *olast = last;" "last = opStack.last().n;\n" "if(olast)\nlast->endToken = olast->endToken;" "opStack.pop_back(); }}"; out << "if(!br) { " "opStack.last().n->endToken = last->endToken;" << "AstNode*& ref = opStack.last().n->kind == AstNode::Binary" << capNode << "Kind && ((Binary" << nodeType << "*)opStack.last().n)->second ? ((Binary" << nodeType << "*)opStack.last().n)->second : ((Binary" << nodeType << "*)opStack.last().n)->first;\n" << "opStack.push_back(OperatorStackItem(ref = create(last), -2));" "ref->endToken = last->endToken + 1;" "ref->startToken = last->startToken;" "} yylex(); }"; } for(auto i = node->mBin.begin(); i != node->mBin.end(); ++i) { if(printElse) out << "else "; printElse = true; out << "if("; generateTestCondition(i->op.mTok, out); if(i->op.mCond.size() != 0) out << " && " << i->op.mCond; out << ") { const unsigned int priority = " << i->priority << ";"; out << i->op.mCode; - out << "AstNode *last = 0; bool br = false;"; + out << "AstNode *last = nullptr; bool br = false;"; out << "while(priority < opStack.last().p + " << i->left << ") {"; out << "if(opStack.size() == 1) {" "if(last)\n" "opStack.last().n->endToken = last->endToken;" "last = opStack.last().n;\n" "opStack.pop_back();" "opStack.push_front(OperatorStackItem((*yynode) = create(last), priority));" "(*yynode)->startToken = last->startToken;" "br = true; break; } else {" "AstNode *olast = last;" "last = opStack.last().n;\n" "if(olast)\nlast->endToken = olast->endToken;" "opStack.pop_back(); }}"; out << "if(!br) { " "opStack.last().n->endToken = last->endToken;" << "AstNode*& ref = " "opStack.last().n->kind == AstNode::Ternary" << capNode << "Kind" " ? (((Ternary" << nodeType << "*)opStack.last().n)->third" " ? ((Ternary" << nodeType << "*)opStack.last().n)->third" " : (((Ternary" << nodeType << "*)opStack.last().n)->second" " ? ((Ternary" << nodeType << "*)opStack.last().n)->second" " : ((Ternary" << nodeType << "*)opStack.last().n)->first ))" " : opStack.last().n->kind == AstNode::Binary" << capNode << "Kind" " && ((Binary" << nodeType << "*)opStack.last().n)->second" " ? ((Binary" << nodeType << "*)opStack.last().n)->second" " : ((Binary" << nodeType << "*)opStack.last().n)->first;\n" << "opStack.push_back(OperatorStackItem(ref = create(last), priority)); ref->startToken = last->startToken; } expectOperator = false; yylex(); }"; } for(auto i = node->mTern.begin(); i != node->mTern.end(); ++i) { if(printElse) out << "else "; printElse = true; out << "if("; generateTestCondition(i->first.mTok, out); if(i->first.mCond.size() != 0) out << " && " << i->first.mCond; out << ") { const unsigned int priority = " << i->priority << ";"; out << i->first.mCode; - out << "AstNode *last = 0; bool br = false;"; + out << "AstNode *last = nullptr; bool br = false;"; out << "while(priority < opStack.last().p + " << i->left << ") {"; out << "if(opStack.size() == 1) {" "if(last)\n" "opStack.last().n->endToken = last->endToken;" "last = opStack.last().n;\n" "opStack.pop_back();" "opStack.push_front(OperatorStackItem((*yynode) = create(last), priority));" "(*yynode)->startToken = last->startToken;" "yylex();"; QString __var = generateParserCall(&ntItem, mCurrentCatchId, out); out << "if(!("; generateTestCondition(i->second.mTok, out); if(i->second.mCond.size() != 0) out << " && " << i->second.mCond; out << ")) return false;" "((Ternary" << nodeType << "*)*yynode)->second = " << __var << ";br = true; break; } else {" "AstNode *olast = last;" "last = opStack.last().n;\n" "if(olast)\nlast->endToken = olast->endToken;" "opStack.pop_back(); }}"; out << "if(!br) { " "opStack.last().n->endToken = last->endToken;" << "AstNode*& ref = " "opStack.last().n->kind == AstNode::Ternary" << capNode << "Kind" " ? (((Ternary" << nodeType << "*)opStack.last().n)->third" " ? ((Ternary" << nodeType << "*)opStack.last().n)->third" " : (((Ternary" << nodeType << "*)opStack.last().n)->second" " ? ((Ternary" << nodeType << "*)opStack.last().n)->second" " : ((Ternary" << nodeType << "*)opStack.last().n)->first ))" " : opStack.last().n->kind == AstNode::Binary" << capNode << "Kind" " && ((Binary" << nodeType << "*)opStack.last().n)->second" " ? ((Binary" << nodeType << "*)opStack.last().n)->second" " : ((Binary" << nodeType << "*)opStack.last().n)->first;\n" << "opStack.push_back(OperatorStackItem(ref = create(last), priority)); ref->startToken = last->startToken; } expectOperator = false; yylex(); }"; } out << "else "; out << "break;"; out << "} else {"; printElse = false; for(auto i = node->mPre.begin(); i != node->mPre.end(); ++i) { if(printElse) out << "else "; printElse = true; out << "if("; generateTestCondition(i->op.mTok, out); if(i->op.mCond.size() != 0) out << " && " << i->op.mCond; out << ") { const unsigned int priority = " << i->priority << ";"; out << i->op.mCode << "Prefix" << nodeType << " *node = create();" "if(opStack.empty())\n" "(*yynode) = node;" "else" "{\n" "void *last = opStack.last().n;" - "if(reinterpret_cast(last)->first == 0)\n" + "if(reinterpret_cast(last)->first == nullptr)\n" "reinterpret_cast(last)->first = node;" - "else if(reinterpret_cast(last)->second == 0)\n" + "else if(reinterpret_cast(last)->second == nullptr)\n" "reinterpret_cast(last)->second = node;" "else\n" "reinterpret_cast(last)->third = node;" "}" "opStack.push_back(OperatorStackItem(node, priority));" "node->startToken = tokenStream->index() - 1;" "yylex();" "}" << endl; } for(auto i = node->mParen.begin(); i != node->mParen.end(); ++i) { if(printElse) out << "else "; printElse = true; out << "if("; generateTestCondition(i->first.mTok, out); if(i->first.mCond.size() != 0) out << " && " << i->first.mCond; out << ") { yylex();" "if("; generateTestCondition(mSym, out); out << ") {"; QString __var = generateParserCall(&ntItem, mCurrentCatchId, out); out << "if(!("; generateTestCondition(i->second.mTok, out); if(i->second.mCond.size() != 0) out << " && " << i->second.mCond; out << ")) {" "return false;" "}" "--" << __var << "->startToken;" "++" << __var << "->endToken;" "yylex();"; #define PUSH_UNARY \ out << "\ if(!opStack.isEmpty())\ {\ void *last = opStack.last().n;\ - if(reinterpret_cast(last)->first == 0)\n\ + if(reinterpret_cast(last)->first == nullptr)\n\ reinterpret_cast(last)->first = " << __var << ";" << endl; \ - out << "else if(reinterpret_cast(last)->second == 0)\n\ + out << "else if(reinterpret_cast(last)->second == nullptr)\n\ reinterpret_cast(last)->second = " << __var << ";\ else\nreinterpret_cast(last)->third = " << __var << ";}\ else\n\ (*yynode) = " << __var << ";\ opStack.push_back(OperatorStackItem(" << __var << ", -2));"; PUSH_UNARY out << "expectOperator = true; } else\nreturn false; }"; } if(printElse) out << "else "; out << "if("; generateTestCondition(node->mBase->mSymbol, out); out << ") { "; QString __var = generateParserCall(node->mBase, mCurrentCatchId, out); PUSH_UNARY #undef PUSH_UNARY out << "expectOperator = true; }"; out << "else" "{" "expectedSymbol(AstNode::" << capNode << "Kind" ", \"" << node->mName << "\");return false;" "} } }"; /// @TODO Further: empty binary operator } void GenerateForwardParserRule::operator()(QPair const &__it) { Model::SymbolItem *sym = __it.second; out << "bool" << " " << "parse" << sym->mCapitalizedName << "("; GenerateParseMethodSignature gen_signature(out, nullptr); gen_signature(sym); out << ");" << endl; } void GenerateParserRule::operator()(QPair const &__it) { mNames.clear(); Model::SymbolItem *sym = __it.second; CodeGenerator cg(out, &mNames, sym); out << "bool Parser::parse" << sym->mCapitalizedName << "("; GenerateParseMethodSignature gen_signature(out, &mNames); gen_signature(sym); out << ")" << endl << "{" << endl; if (globalSystem.generateAst) { if(isOperatorSymbol(sym)) out << "QVector opStack;" << endl; else { out << "*yynode = create<" << sym->mCapitalizedName << "Ast" << ">();" << endl << endl << "(*yynode)->startToken = tokenStream->index() - 1;" << endl; //Generate initialization for this ast nodes token-members using -1 as invalid value GenerateTokenVariableInitialization gentokenvar( out ); gentokenvar(sym); out << endl; } } World::Environment::iterator it = globalSystem.env.find(sym); GenerateLocalDeclarations gen_locals(out, &mNames); while (it != globalSystem.env.end()) { Model::EvolveItem *e = (*it); if (it.key() != sym) break; ++it; gen_locals(e->mDeclarations); } it = globalSystem.env.find(sym); bool initial = true; while (it != globalSystem.env.end()) { Model::EvolveItem *e = (*it); if (it.key() != sym) break; ++it; if (!initial) out << "else "; cg(e); initial = false; } out << "else" << endl << "{ return false; }" << endl << endl; if (globalSystem.generateAst) { if(isOperatorSymbol(sym)) { - out << "AstNode *olast, *last = 0;" + out << "AstNode *olast, *last = nullptr;" "while(!opStack.empty())\n" "{" "olast = last;" "last = opStack.last().n;" "if(olast)\n" "last->endToken = olast->endToken;" "opStack.pop_back();" "}" << endl; } else { out << "(*yynode)->endToken = tokenStream->index() - 2;" << endl << endl; } } out << "return true;" << endl << "}" << endl << endl; } void GenerateLocalDeclarations::operator()(Model::Node *node) { visitNode(node); } void GenerateLocalDeclarations::visitVariableDeclaration(Model::VariableDeclarationItem *node) { // normal declarations for local variables if (node->mStorageType == Model::VariableDeclarationItem::StorageTemporary && node->mDeclarationType == Model::VariableDeclarationItem::DeclarationLocal) { if ((mNames == nullptr) || mNames->find(node->mName) == mNames->end()) { GenerateVariableDeclaration gen_var_decl(out); gen_var_decl(node); if (node->mVariableType == Model::VariableDeclarationItem::TypeToken || node->mVariableType == Model::VariableDeclarationItem::TypeNode || node->mIsSequence) { out << " = 0"; } out << ";" << endl << endl; if (mNames != nullptr) mNames->insert(node->mName); } } // for argument member nodes and tokens, check if their index precedes the current one else if (node->mStorageType == Model::VariableDeclarationItem::StorageAstMember && node->mDeclarationType == Model::VariableDeclarationItem::DeclarationArgument && globalSystem.generateAst) { QString sequence_suffix = (node->mIsSequence) ? "Sequence" : ""; out << "(*yynode)->" << node->mName << sequence_suffix << " = " << node->mName << sequence_suffix << ";" << endl; if (node->mVariableType != Model::VariableDeclarationItem::TypeVariable) { QString argument_startToken = node->mName; if (node->mIsSequence) argument_startToken += "Sequence->front()->element"; if (node->mVariableType == Model::VariableDeclarationItem::TypeNode) argument_startToken += "->startToken"; out << "if ("; // check that the variable is not null if (node->mVariableType == Model::VariableDeclarationItem::TypeNode || node->mIsSequence) { out << node->mName << sequence_suffix << " && "; } out << argument_startToken << " < (*yynode)->startToken)" << endl << "(*yynode)->startToken = " << argument_startToken << ";" << endl << endl; } } DefaultVisitor::visitVariableDeclaration(node); } void GenerateParseMethodSignature::operator()(Model::SymbolItem* sym) { if (globalSystem.generateAst) { out << sym->mCapitalizedName << "Ast **yynode"; firstParameter = false; } World::Environment::iterator it = globalSystem.env.find(sym); if (it != globalSystem.env.end()) { // this creates the method signature using just the first of // possibly multiple rules with the same name. Model::EvolveItem *e = (*it); if (e->mDeclarations) visitNode(e->mDeclarations); } } void GenerateRecursiveDelegation::operator()(Model::SymbolItem* node) { World::Environment::iterator it = globalSystem.env.find(node); if (it != globalSystem.env.end()) { // this creates the method signature using just the first of // possibly multiple rules with the same name. Model::EvolveItem *e = (*it); Model::VariableDeclarationItem *decl = e->mDeclarations; GenerateVariableDeclaration vd(out); while(decl) { vd(decl); decl = decl->mNext; } } } void GenerateParseMethodSignature::visitVariableDeclaration(Model::VariableDeclarationItem *node) { if (node->mDeclarationType == Model::VariableDeclarationItem::DeclarationArgument) { if (globalSystem.generateAst || (node->mStorageType != Model::VariableDeclarationItem::StorageAstMember)) { if (firstParameter) firstParameter = false; else out << ", "; GenerateVariableDeclaration gen_var_decl(out); gen_var_decl(node); if (mNames != nullptr) mNames->insert(node->mName); } } DefaultVisitor::visitVariableDeclaration(node); } template void GenerateVariableDeclaration::operator()(Model::VariableDeclarationItem *node) { if(printType) { if (node->mIsSequence) out << "const KDevPG::ListNode<"; if (node->mVariableType == Model::VariableDeclarationItem::TypeToken) out << "qint64 "; else if (node->mVariableType == Model::VariableDeclarationItem::TypeNode) { out << node->mCapitalizedType << "Ast *"; }else if (node->mVariableType == Model::VariableDeclarationItem::TypeVariable) out << node->mType << " "; else Q_ASSERT(0); // ### not supported if (node->mIsSequence) out << "> *"; } if(printName) { out << node->mName; if (node->mIsSequence) out << "Sequence"; } } void GenerateMemberCode::operator()(Settings::MemberItem* m) { if ((mKindMask & m->mMemberKind) != 0) { if (m->mMemberKind == Settings::MemberItem::PublicDeclaration) out << "public:" << endl; else if (m->mMemberKind == Settings::MemberItem::ProtectedDeclaration) out << "protected:" << endl; else if (m->mMemberKind == Settings::MemberItem::PrivateDeclaration) out << "private:" << endl; out << m->mCode << endl; } } void GenerateParserDeclarations::operator()() { out << "class " << globalSystem.exportMacro << " Parser : "; if(!globalSystem.parserBaseClass.isEmpty()) out << "public " << globalSystem.parserBaseClass << ", "; out << "public TokenTypeWrapper\n{" << "public:" << endl << "typedef " << globalSystem.tokenStream << "::Token Token;" << endl << globalSystem.tokenStream << " *tokenStream;" << endl << "int yytoken;" << endl; if(globalSystem.needOperatorStack) out << "struct OperatorStackItem{AstNode *n; int unsigned p;" "inline OperatorStackItem(AstNode *n, int unsigned p)\n" ": n(n), p(p)\n{}\n" "inline OperatorStackItem()\n{}\n" "inline OperatorStackItem(const OperatorStackItem& o)\n" ": n(o.n), p(o.p)\n" "{}\n};" << endl; out << endl << "inline Token LA(qint64 k = 1) const" << endl << "{ qint64 idx = tokenStream->index() - 1 + k - 1; qint64 oldidx = tokenStream->index(); tokenStream->rewind(tokenStream->size()); while(idx >= tokenStream->size()) tokenStream->read(); tokenStream->rewind(oldidx); return tokenStream->at(idx); }" << endl << "inline int yylex() {" << endl << "yytoken = tokenStream->read().kind; return yytoken;" << endl << "}" << endl << "inline void rewind(qint64 index) {" << endl << "tokenStream->rewind(index);" << endl << "yylex();" << endl << "}" << endl << endl; out << "// token stream" << endl << "void setTokenStream(" << globalSystem.tokenStream << " *s)" << endl << "{ tokenStream = s; }" << endl << endl; out << "// error handling" << endl << "void expectedSymbol(int kind, const QString& name);" << endl << "void expectedToken(int kind, qint64 token, const QString& name);" << endl << endl << "bool mBlockErrors;" << endl << "inline bool blockErrors(bool block) {" << endl << "bool previous = mBlockErrors;" << endl << "mBlockErrors = block;" << endl << "return previous;" << endl << "}" << endl; out << endl; if (globalSystem.generateAst) { out << "// memory pool" << endl << "typedef KDevPG::MemoryPool memoryPoolType;" << endl << endl << "KDevPG::MemoryPool *memoryPool;" << endl << "void setMemoryPool(KDevPG::MemoryPool *p)" << endl << "{ memoryPool = p; }" << endl << "template " << endl << "inline T *create()" << endl << "{" << endl << "T *node = new (memoryPool->allocate(sizeof(T))) T();" << endl << "node->kind = T::KIND;" << endl << "return node;" << endl << "}" << endl << "template " << endl << "inline T *create(AstNode *u)" << endl << "{" << endl << "T *node = new (memoryPool->allocate(sizeof(T))) T(u);" << endl << "node->kind = T::KIND;" << endl << "return node;" << endl << "}" << endl << endl; } if (globalSystem.parserclassMembers.declarations.empty() == false) { out << "// user defined declarations:" << endl; GenerateMemberCode gen(out, Settings::MemberItem::PublicDeclaration | Settings::MemberItem::ProtectedDeclaration | Settings::MemberItem::PrivateDeclaration); for( QList::iterator it = globalSystem.parserclassMembers.declarations.begin(); it != globalSystem.parserclassMembers.declarations.end(); ++it ) { gen(*it); } out << endl << "public:" << endl; } if (globalSystem.needStateManagement) { out << "// The copyCurrentState() and restoreState() methods are only declared" << endl << "// if you are using try blocks in your grammar, and have to be" << endl << "// implemented by yourself, and you also have to define a" << endl << "// \"struct ParserState\" inside a %parserclass directive." << endl << endl << "// This method should create a new ParserState object and return it," << endl << "// or return 0 if no state variables need to be saved." << endl << "ParserState *copyCurrentState();" << endl << endl << "// This method is only called for ParserState objects != 0" << endl << "// and should restore the parser state given as argument." << endl << "void restoreState(ParserState *state);" << endl; } out << "Parser() {" << endl; if (globalSystem.generateAst) { - out << "memoryPool = 0;" << endl; + out << "memoryPool = nullptr;" << endl; } - out << "tokenStream = 0;" << endl + out << "tokenStream = nullptr;" << endl << "yytoken = Token_EOF;" << endl << "mBlockErrors = false;" << endl; if (globalSystem.parserclassMembers.constructorCode.empty() == false) { out << endl << "// user defined constructor code:" << endl; GenerateMemberCode gen(out, Settings::MemberItem::ConstructorCode); for(QList::iterator it = globalSystem.parserclassMembers.constructorCode.begin(); it != globalSystem.parserclassMembers.constructorCode.end(); ++it ) { gen(*it); } } out << "}" << endl << endl; out << "virtual ~Parser() {"; if (globalSystem.parserclassMembers.destructorCode.empty() == false) { out << endl << "// user defined destructor code:" << endl; GenerateMemberCode gen(out, Settings::MemberItem::DestructorCode); for(QList::iterator it = globalSystem.parserclassMembers.destructorCode.begin(); it != globalSystem.parserclassMembers.destructorCode.end(); ++it ) { gen(*it); } } out << "}" << endl << endl; GenerateForwardParserRule genfwdparserrule(out); for( World::SymbolSet::iterator it = globalSystem.symbols.begin(); it != globalSystem.symbols.end(); ++it ) { genfwdparserrule(qMakePair(it.key(), *it)); } out << "};" << endl; } void GenerateParserBits::operator()() { GenerateParserRule gen(out); for( World::SymbolSet::iterator it = globalSystem.symbols.begin(); it != globalSystem.symbols.end(); ++it ) { gen(qMakePair(it.key(), *it)); } } void GenerateTokenVariableInitialization::operator()(Model::SymbolItem* sym) { World::Environment::iterator it = globalSystem.env.find(sym); if (it != globalSystem.env.end()) { // this creates the method signature using just the first of // possibly multiple rules with the same name. Model::EvolveItem *e = (*it); if (e->mItem) visitNode(e->mItem); } } void GenerateTokenVariableInitialization::visitVariableDeclaration(Model::VariableDeclarationItem *node) { if( node->mVariableType == Model::VariableDeclarationItem::TypeToken ) { if( !node->mIsSequence ) out << "(*yynode)->" << node->mName << " = -1;" << endl; } } void GenerateTokenTexts::operator()() { out << "switch (token) {" << endl; for(World::TerminalSet::iterator it = globalSystem.terminals.begin(); it != globalSystem.terminals.end(); ++it ) { Model::TerminalItem* t = *it; out << " case TokenTypeWrapper::Token_" << t->mName << ":" << endl; QString text = t->mDescription; text.replace('\\', "\\\\").replace('"', "\\\""); out << " return QStringLiteral(\"" << text << "\");" << endl; } out << " default:" << endl; out << " return QStringLiteral(\"unknown token\");" << endl; out << "}" << endl; } } // namespace KDevPG diff --git a/kdev-pg/kdev-pg-debug-visitor-gen.cpp b/kdev-pg/kdev-pg-debug-visitor-gen.cpp index 7ca7613..deb964d 100644 --- a/kdev-pg/kdev-pg-debug-visitor-gen.cpp +++ b/kdev-pg/kdev-pg-debug-visitor-gen.cpp @@ -1,200 +1,200 @@ /* This file is part of kdev-pg-qt Copyright (C) 2006 Alexander Dymo This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kdev-pg-debug-visitor-gen.h" #include "kdev-pg.h" #include namespace KDevPG { void GenerateDebugVisitor::operator()() { // the debug visitor class is header-only, thus we don't need an export macro here out << "class DebugVisitor: public DefaultVisitor {" << endl << "public:" << endl; out << "DebugVisitor("<< globalSystem.tokenStream << " *str, const QString& content = QString())" << endl; out << " : m_str(str), m_indent(0), m_content(content) {}" << endl; GenerateDebugVisitorRule gen(out); for( World::SymbolSet::iterator it = globalSystem.symbols.begin(); it != globalSystem.symbols.end(); ++it ) { gen(qMakePair(it.key(), *it)); } out << "private:" << endl; out << "void printToken(const AstNode *node, const QString &mType, const QString &mName = QString())" << endl; out << "{" << endl; out << " KDevPG::TokenStream::Token startToken;" << endl; out << " KDevPG::TokenStream::Token endToken;" << endl; out << " qint64 line, column;" << endl; out << " const bool isValidStartToken = (0 <= node->startToken && node->startToken < m_str->size());" << endl; out << " QString startTokenString;" << endl; out << " if (isValidStartToken) {" << endl; out << " startToken = m_str->at(node->startToken);" << endl; out << " m_str->startPosition(node->startToken, &line, &column);" << endl; out << " startTokenString = QString::number(startToken.begin) + QLatin1String(\", \") + QString::number(line) + QLatin1String(\", \") + QString::number(column);" << endl; out << " } else {" << endl; out << " startTokenString = QLatin1String(\"invalid token index: \") + QString::number(node->startToken);" << endl; out << " }" << endl; out << " const bool isValidEndToken = (0 <= node->endToken && node->endToken < m_str->size());" << endl; out << " QString endTokenString;" << endl; out << " if (isValidEndToken) {" << endl; out << " endToken = m_str->at(node->endToken);" << endl; out << " m_str->startPosition(node->endToken, &line, &column);" << endl; out << " endTokenString = QString::number(endToken.begin) + QLatin1String(\", \") + QString::number(line) + QLatin1String(\", \") + QString::number(column);" << endl; out << " } else {" << endl; out << " endTokenString = QLatin1String(\"invalid token index: \") + QString::number(node->endToken);" << endl; out << " }" << endl; out << " QString tokenString;" << endl; out << " if (!m_content.isEmpty() && isValidStartToken && isValidEndToken) {" << endl; out << " const int begin = startToken.begin;" << endl; out << " const int end = endToken.end;" << endl; out << " if (end-begin > 30) {" << endl; out << " tokenString = m_content.mid(begin, 10);" << endl; out << " tokenString += QStringLiteral(\" ...\");" << endl; out << " tokenString += QStringLiteral(\"%1 more\").arg(end-begin-20);" << endl; out << " tokenString += QStringLiteral(\"... \");" << endl; out << " tokenString += m_content.midRef(end-10, 10);" << endl; out << " }" << endl; out << " else {" << endl; out << " tokenString = m_content.mid(begin, end-begin+1);" << endl; out << " }" << endl; out << " tokenString.replace('\\n', QStringLiteral(\"\\\\n\"));" << endl; out << " tokenString.replace('\\r', QStringLiteral(\"\\\\r\"));" << endl; out << " }" << endl; out << " qDebug() <<" << " QString(QString().fill(QLatin1Char(' '), m_indent) +" << " mName + QLatin1String(!mName.isEmpty() ? \"->\" : \"\") + mType +" << " QLatin1Char('[') + startTokenString + QLatin1String(\"] --- [\") + endTokenString + QLatin1String(\"] \")).toUtf8().constData()" << " << tokenString;" << endl; out << "}" << endl; out << globalSystem.tokenStream << " *m_str;" << endl; out << "int m_indent;" << endl; out << "QString m_content;" << endl; out << "};" << endl; } void GenerateDebugVisitorRule::operator()(QPair const &__it) { Model::SymbolItem *sym = __it.second; mNames.clear(); bool has_members = false; HasMemberNodes hms(has_members); hms(sym); #define O1(name) \ - out << "virtual void visit" << name \ + out << "void visit" << name \ << "(" << name << "Ast *" << "node" \ - << ") {" << endl; + << ") override {" << endl; #define O2(name) \ out << "printToken(node, QStringLiteral(\"" << name << "\"));" << endl; #define O3(name) \ out << "++m_indent;"; \ \ out << "DefaultVisitor::visit" << name \ << "(" << "node" \ << ");" << endl; \ \ out << "m_indent--;"; \ \ out << "}" << endl << endl; if(isOperatorSymbol(sym)) { O1("Prefix" + sym->mCapitalizedName) O2("prefix-" + sym->mName) O3("Prefix" + sym->mCapitalizedName) O1("Postfix" + sym->mCapitalizedName) O2("postfix-" + sym->mName) O3("Postfix" + sym->mCapitalizedName) O1("Binary" + sym->mCapitalizedName) O2("binary-" + sym->mName) O3("Binary" + sym->mCapitalizedName) O1("Ternary" + sym->mCapitalizedName) O2("ternary-" + sym->mName) O3("Ternary" + sym->mCapitalizedName) } else { O1(sym->mCapitalizedName) O2(sym->mName) World::Environment::iterator it = globalSystem.env.find(sym); while (it != globalSystem.env.end()) { Model::EvolveItem *e = (*it); if (it.key() != sym) break; ++it; visitNode(e); } O3(sym->mCapitalizedName) } #undef O3 #undef O2 #undef O1 } void GenerateDebugVisitorRule::visitVariableDeclaration(Model::VariableDeclarationItem *node) { do { if (node->mStorageType != Model::VariableDeclarationItem::StorageAstMember) break; if (node->mVariableType != Model::VariableDeclarationItem::TypeNode) break; // nothing to do if (mNames.find(node->mName) != mNames.end()) break; QString base_type = node->mCapitalizedType + "Ast*"; if (node->mIsSequence) { out << "if (" << "node->" << node->mName << "Sequence" << ") {" << "const KDevPG::ListNode<" << base_type << "> *__it = " << "node->" << node->mName << "Sequence" << "->front()" << ", *__end = __it;" << endl << "do {" << endl << "printToken(__it->element, QStringLiteral(\"" << node->mType << "\"), QStringLiteral(\"" << node->mName << "[]\"));" << endl << "__it = __it->next;" << endl << "} while (__it != __end);" << endl << "}" << endl; } else { out << "if (node->" << node->mName << ") printToken(node->" << node->mName << ", QStringLiteral(\"" << node->mType << "\"), QStringLiteral(\"" << node->mName << "\"));" << endl; } mNames.insert(node->mName); } while(false); DefaultVisitor::visitVariableDeclaration(node); } } diff --git a/kdev-pg/kdev-pg-default-visitor-gen.cpp b/kdev-pg/kdev-pg-default-visitor-gen.cpp index 8f07eb3..080cc3e 100644 --- a/kdev-pg/kdev-pg-default-visitor-gen.cpp +++ b/kdev-pg/kdev-pg-default-visitor-gen.cpp @@ -1,65 +1,65 @@ /* This file is part of kdev-pg-qt Copyright (C) 2005 Roberto Raggi Copyright (C) 2006 Jakob Petsovits Copyright (C) 2010 Jonathan Schmidt-Dominé This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kdev-pg-default-visitor-gen.h" #include "kdev-pg.h" #include namespace KDevPG { void GenerateDefaultVisitor::operator()() { out << "class " << globalSystem.exportMacro << " " << name << ": public Visitor {" << endl << "public:" << endl; GenerateDefaultVisitorRule gen(out); for( World::SymbolSet::iterator it = globalSystem.symbols.begin(); it != globalSystem.symbols.end(); ++it ) { gen(qMakePair(it.key(), *it)); } out << "};" << endl; } void GenerateDefaultVisitorRule::operator()(QPair const &__it) { Model::SymbolItem *sym = __it.second; #define O(name) \ - out << "virtual void visit" << name << "(" << name << "Ast *node);" << endl; + out << "void visit" << name << "(" << name << "Ast *node) override;" << endl; if(isOperatorSymbol(sym)) { O("Prefix" + sym->mCapitalizedName) O("Postfix" + sym->mCapitalizedName) O("Binary" + sym->mCapitalizedName) O("Ternary" + sym->mCapitalizedName) } else O(sym->mCapitalizedName) #undef O } } diff --git a/kdev-pg/kdev-pg-serialize-visitor-gen.cpp b/kdev-pg/kdev-pg-serialize-visitor-gen.cpp index 88ba1fe..ff78863 100644 --- a/kdev-pg/kdev-pg-serialize-visitor-gen.cpp +++ b/kdev-pg/kdev-pg-serialize-visitor-gen.cpp @@ -1,225 +1,225 @@ /* This file is part of kdev-pg-qt Copyright (C) 2005 Roberto Raggi Copyright (C) 2006 Jakob Petsovits Copyright (C) 2006 Adam Treat This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kdev-pg-serialize-visitor-gen.h" #include "kdev-pg.h" namespace KDevPG { void GenerateSerializeVisitor::operator()() { out << "class " << globalSystem.exportMacro << " Serialize: public DefaultVisitor {" << endl << "public:" << endl; out << "static void read(KDevPG::MemoryPool *p," << endl << "AstNode *node, QIODevice* i) { " << endl << "Serialize(p, node, i); " << endl << "}" << endl << endl; out << "static void write(AstNode *node, QIODevice* o) { " << endl << "Serialize(node, o); " << endl << "}" << endl << endl; out << "private:" << endl; out << "Serialize(KDevPG::MemoryPool *p," << endl << "AstNode *node, QIODevice* i) : in(i) {" << endl << "memoryPool = p;" << endl << "if ( !node )" << endl << "node = create<" << (*globalSystem.start.begin())->mCapitalizedName << "Ast>();" << endl << "visitNode( node );" << endl << "}" << endl << endl; out << "Serialize(AstNode *node, QIODevice *o) : out(o) {" << endl << "visitNode( node );" << endl << "}" << endl << endl; out << "QDataStream in;" << endl; out << "QDataStream out;" << endl << endl; out << "// memory pool" << endl << "typedef KDevPG::MemoryPool memoryPoolType;" << endl << "KDevPG::MemoryPool *memoryPool;" << endl << "template " << endl << "inline T *create() {" << endl << "T *node = new (memoryPool->allocate(sizeof(T))) T();" << endl << "node->kind = T::KIND;" << endl << "return node;" << endl << "}" << endl; out << "template " << endl << "void handleListNode(const KDevPG::ListNode *t, E *e) {" << endl << "if (in) {" << endl //list in << "bool b;" << endl << "in >> b;" << endl << "if (b) {" << endl << "qint64 count;" << endl << "in >> count;" << endl << "for ( qint64 i = 0; i < count; ++i ) {" << endl << " e = create();" << endl // FIXME: what about token << " t = KDevPG::snoc(t, e, memoryPool);" << endl << "}" << endl << "}" << endl //end list in << "} else if (out) {" << endl //list out <<"if (t) {" << endl << "out << true;" << endl << "out << t->count();" << endl << "} else {" << endl << "out << false;" << endl << "}" << endl << endl //end list out << "}" << endl << "}" << endl << endl; out << "template " << endl << "void handleAstNode(T *t) {" << endl << "if (in) {" << endl //ast in << "bool b;" << endl << "in >> b;" << endl << "if (b) {" << endl << "t = create();" << endl << "in >> t->startToken;" << endl << "in >> t->endToken;" << endl << "}" << endl //end ast in << "} else if (out) {" << endl //ast out << "if (t) {" << endl << "bool b = true;" << endl << "out << true;" << endl << "out << t->startToken;" << endl << "out << t->endToken;" << endl << "} else {" << endl << "out << false;" << endl << "}" << endl << endl //end ast out << "}" << endl << "}" << endl << endl; out << "template " << endl << "void handleVariable(T *t) {" << endl << "if (in) {" << endl << "in >> t;" << endl << "} else if (out) {" << endl << "out << t;" << endl << "}" << endl << "}" << endl << endl; GenerateSerializeVisitorRule gen(out); for( World::SymbolSet::iterator it = globalSystem.symbols.begin(); it != globalSystem.symbols.end(); ++it ) { gen(qMakePair(it.key(), *it)); } out << "};" << endl; } void GenerateSerializeVisitorRule::operator()(QPair const &__it) { mNames.clear(); mVariableDeclarations.clear(); Model::SymbolItem *sym = __it.second; bool has_members = false; HasMemberNodes hms(has_members); hms(sym); - out << "virtual void visit" << sym->mCapitalizedName + out << "void visit" << sym->mCapitalizedName << "(" << sym->mCapitalizedName << "Ast *" << "node" - << ") {" << endl; + << ") override {" << endl; Model::EvolveItem *e = globalSystem.searchRule(sym); visitNode(e); out << "DefaultVisitor::visit" << sym->mCapitalizedName << "(" << "node" << ");" << endl; out << "}" << endl << endl; } void GenerateSerializeVisitorRule::visitVariableDeclaration(Model::VariableDeclarationItem *node) { do { if (node->mStorageType != Model::VariableDeclarationItem::StorageAstMember) break; if (mNames.find(node->mName) != mNames.end()) break; QString ext = ( node->mVariableType == Model::VariableDeclarationItem::TypeNode ? "Ast" : ""); QString type = node->mType + ext; QString name = node->mName; if (node->mVariableType == Model::VariableDeclarationItem::TypeToken) type = "qint64"; if (node->mIsSequence) { out << "{" << endl << type << " *e = 0;" << endl << "handleListNode(node->" << name << "Sequence, e);" << endl << "}" << endl; } else if (node->mVariableType == Model::VariableDeclarationItem::TypeNode) { out << "handleAstNode(node->" << name << ");" << endl; } else if (node->mVariableType == Model::VariableDeclarationItem::TypeVariable || node->mVariableType == Model::VariableDeclarationItem::TypeToken) { out << "handleVariable(&node->" << name << ");" << endl; } else { Q_ASSERT(0); // every variable type must be supported } mNames.insert(node->mName); mVariableDeclarations.push_back(node); } while(false); DefaultVisitor::visitVariableDeclaration(node); } }