diff --git a/include/kdev-pg-allocator.h b/include/kdev-pg-allocator.h index fe860de..7bf3b91 100644 --- a/include/kdev-pg-allocator.h +++ b/include/kdev-pg-allocator.h @@ -1,152 +1,152 @@ /* This file is part of kdev-pg Copyright 2005, 2006 Roberto Raggi Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef KDEV_PG_ALLOCATOR_H #define KDEV_PG_ALLOCATOR_H #include #include #include #include namespace KDevPG { template class Allocator { public: typedef _Tp valueType; typedef _Tp* pointer; typedef const _Tp* constPointer; typedef _Tp& reference; typedef const _Tp& constReference; typedef ::std::size_t sizeType; typedef qint64 differenceType; static const sizeType maxBlockCount = sizeType( -1); Allocator() { sBlockIndex = sizeType(-1); sCurrentIndex = 0; - sStorage = 0; - sCurrentBlock = 0; + sStorage = nullptr; + sCurrentBlock = nullptr; } ~Allocator() { - if (sStorage != 0) + if (sStorage != nullptr) { for (sizeType index = 0; index <= sBlockIndex; ++index) delete[] sStorage[index]; std::free(sStorage); } } bool contains(void* ptr) { for(sizeType i = 0; i <= sBlockIndex; ++i) if(ptr >= (void*)(sStorage[i]) && ptr < (void*)(sStorage[i] + sBlockSize)) return true; return false; } pointer address(reference __val) { return &__val; } constPointer address(constReference __val) const { return &__val; } - pointer allocate(sizeType __n, const void* = 0) + pointer allocate(sizeType __n, const void* = nullptr) { const sizeType bytes = __n * sizeof(_Tp); - if (sCurrentBlock == 0 + if (sCurrentBlock == nullptr || sBlockSize < sCurrentIndex + bytes) { ++sBlockIndex; sStorage = reinterpret_cast (std::realloc(sStorage, sizeof(char*) * (1 + sBlockIndex))); sCurrentBlock = sStorage[sBlockIndex] = reinterpret_cast (new char[sBlockSize]); std::memset(sCurrentBlock, 0, sBlockSize); sCurrentIndex = 0; } pointer p = reinterpret_cast (sCurrentBlock + sCurrentIndex); sCurrentIndex += bytes; return p; } void deallocate(pointer /*__p*/, sizeType /*__n*/) {} sizeType maxSize() const { return sizeType( -1) / sizeof(_Tp); } void contruct(pointer __p, constReference __val) { new (__p) _Tp(__val); } void destruct(pointer __p) { __p->~_Tp(); } private: template class Rebind { typedef Allocator<_Tp1> other; }; template Allocator(const Allocator<_Tp1> &/*__o*/) {} private: static const sizeType sBlockSize; sizeType sBlockIndex; sizeType sCurrentIndex; char *sCurrentBlock; char **sStorage; }; template const typename Allocator<_Tp>::sizeType Allocator<_Tp>::sBlockSize = 1 << 16; // 64K } #endif // KDEV_PG_ALLOCATOR_H diff --git a/include/kdev-pg-location-table.h b/include/kdev-pg-location-table.h index cd5b643..c176493 100644 --- a/include/kdev-pg-location-table.h +++ b/include/kdev-pg-location-table.h @@ -1,138 +1,138 @@ /* This file is part of kdev-pg Copyright 2002-2006 Roberto Raggi Copyright 2009 Milian Wolff Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ //krazy:excludeall=inline #ifndef KDEV_PG_LOCATION_TABLE_H #define KDEV_PG_LOCATION_TABLE_H #include #include // krazy:exclude=includes namespace KDevPG { class LocationTable { public: inline LocationTable(qint64 size = 1024) - : lines(0), lineCount(0), currentLine(0), lastLine(0) + : lines(nullptr), lineCount(0), currentLine(0), lastLine(0) { resize(size); lines[currentLine++] = 0; } inline ~LocationTable() { free(lines); } inline qint64 size() const { return lineCount; } void resize(qint64 size) { Q_ASSERT(size > 0); lines = (qint64*) ::realloc(lines, sizeof(qint64) * size); lineCount = size; } /** * Returns the \a line and \a column of the given \a offset in this table. */ void positionAt(qint64 offset, qint64 *line, qint64 *column) const { if ( offset < 0 ) { // invalid offset *line = -1; *column = -1; return; } else if ( offset > lines[currentLine - 1] ) { // overflow *line = currentLine - 1; *column = offset - lines[currentLine - 1]; return; } qint64 i = -1; // search relative to last line (next line and the one after that) if ( lastLine + 1 < currentLine && lines[lastLine] <= offset ) { if ( lines[lastLine + 1] > offset ) { // last matched line matches again i = lastLine; } else if ( lastLine + 2 < currentLine && lines[lastLine + 2] > offset ) { // next line relative to last matched matches i = lastLine + 1; } } if ( i == -1 ) { // fallback to binary search qint64 *it = std::lower_bound(lines, lines + currentLine, offset); Q_ASSERT(it != lines + currentLine); if (*it != offset) { --it; } *line = it - lines; *column = offset - *it; } else { *line = i; *column = offset - lines[i]; } lastLine = *line; } /** * Marks an \a offset as the character before the first one in the next line. * The positionAt() function relies on newline() being called properly. */ inline void newline(qint64 offset) { if (currentLine == lineCount) resize(currentLine * 2); lines[currentLine++] = offset+1; } inline qint64 &operator[](int index) { return lines[index]; } protected: /// An array of input buffer offsets qint64 *lines; /// The size of the allocated array qint64 lineCount; /// The index to the next index in the lines array qint64 currentLine; /// Last line as found by positionAt mutable qint64 lastLine; private: LocationTable(LocationTable const &other); void operator=(LocationTable const &other); }; } #endif // KDEV_PG_LOCATION_TABLE_H diff --git a/include/kdev-pg-memory-pool.h b/include/kdev-pg-memory-pool.h index b36a8da..132c1ea 100644 --- a/include/kdev-pg-memory-pool.h +++ b/include/kdev-pg-memory-pool.h @@ -1,106 +1,106 @@ /* This file is part of kdev-pg Copyright 2005, 2006 Roberto Raggi Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ //krazy:excludeall=inline #ifndef KDEV_PG_MEMORY_POOL #define KDEV_PG_MEMORY_POOL #include #include #include namespace KDevPG { class BlockType { public: qint64 blockSize; BlockType *chain; char *data; char *ptr; char *end; inline void init(int block_size = 256) { blockSize = block_size; - chain = 0; + chain = nullptr; data = (char*) malloc(blockSize); ptr = data; end = data + block_size; } inline void init0(int block_size = 256) { init(block_size); memset(data, '\0', block_size); } inline void destroy() { if (chain) { chain->destroy(); free(chain); } free(data); } inline void *allocate(size_t size, BlockType **right_most) { if (end < ptr + size) { // assert( size < block_size ); if (!chain) { chain = (BlockType*) malloc(sizeof(BlockType)); chain->init0(blockSize << 2); } return chain->allocate(size, right_most); } char *r = ptr; ptr += size; if (right_most) *right_most = this; return r; } }; class MemoryPool { public: BlockType blk; BlockType *rightMost; inline MemoryPool() { blk.init0(); rightMost = &blk; } inline ~MemoryPool() { blk.destroy(); } inline void *allocate(size_t size) { return rightMost->allocate(size, &rightMost); } }; } #endif diff --git a/include/kdev-pg-token-stream.h b/include/kdev-pg-token-stream.h index 906a943..31af384 100644 --- a/include/kdev-pg-token-stream.h +++ b/include/kdev-pg-token-stream.h @@ -1,262 +1,262 @@ /* This file is part of kdev-pg Copyright 2005, 2006 Roberto Raggi Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ //krazy:excludeall=inline #ifndef KDEV_PG_TOKEN_STREAM_H #define KDEV_PG_TOKEN_STREAM_H #include #include "kdev-pg-location-table.h" /* T& front() ✓ * T& back() ✓ * T& curr() → ? * * T& advance() → read() * qint64 tokenIndex() → delete * qint64 index() ✓ * T& next() → push(), push(Token) * int nextToken() → delete * T& token(index) → at() * ? more * * rewind(index) ✓ * qint64 size() ✓ * reset() ✓ * free() → clear() * * locationTable() ✓ * * startPosition(index, line, column) ✓ * endPosition(index, line, column) ✓ */ namespace KDevPG { class Token { public: int kind; qint64 begin; qint64 end; }; /** * Stores a stream of tokens and has an associated location table. * You can add tokens and traverse them (Java-style unidirectional iterator with random access). * Internal representation similar to a std::vector (capacity gets multiplied if it get exceeded). * @todo Fix inconsistencies in naming: advance vs. next vs. nextToken, token vs. nextToken */ template class TokenStreamBase { public: typedef T Token; TokenStreamBase() : mIndex(0), - mLocationTable(0) + mLocationTable(nullptr) { reset(); } ~TokenStreamBase() { if (mLocationTable) delete mLocationTable; } /** * Clears the stream. * @note It does not free the reserved memory, because usually as much memory is required as before. * @note It will not affect the location table. * @sa free */ inline void reset() { mIndex = 0; } /** * Clears the stream and frees all memory. * @note It will not affect the location table. * @sa reset */ inline void clear() { mIndex = 0; mTokenBuffer.clear(); } /** * The number of tokens in the stream. */ inline qint64 size() const { return mTokenBuffer.size(); } /** * The current position in the stream. */ inline qint64 index() const { return mIndex; } /** * Sets the position in the stream. * All tokens will be unaffected. */ inline void rewind(qint64 index) { mIndex = index; } /** * Returns the token at the specified position in the stream. */ inline T const &at(qint64 index) const { return mTokenBuffer[index]; } /** * Returns the token at the specified position in the stream. */ inline T &at(qint64 index) { return mTokenBuffer[index]; } /** * Pushes a new token to the stream. * @return The new default-initialized token (reference) */ inline T &push() { mTokenBuffer.push_back({}); return mTokenBuffer.back(); } /** * Pushes the specified token to the stream. * @return Reference to the inserted token */ inline T &push(const T& t) { mTokenBuffer.push_back(t); return mTokenBuffer.back(); } /** * Advances and returns the token at the current position. */ inline T &read() { if(mIndex == size()) { push().kind = 1000; } return mTokenBuffer[mIndex++]; } /** * Current token in the stream. */ inline T &curr() { return mTokenBuffer[mIndex]; } /** * Last token in the stream. */ inline T &back() { return mTokenBuffer.back(); } /** * First token in the stream. */ inline T &front() { return mTokenBuffer.front(); } /** * @return The associated location table. */ inline LocationTable *locationTable() { if (!mLocationTable) mLocationTable = new LocationTable(); return mLocationTable; } /** * Coordinates of the beginning of the first token. */ inline void startPosition(qint64 index, qint64 *line, qint64 *column) { if (!mLocationTable) { *line = 0; *column = 0; } else mLocationTable->positionAt(at(index).begin, line, column); } /** * Coordinate at the end of all tokens. */ inline void endPosition(qint64 index, qint64 *line, qint64 *column) { if (!mLocationTable) { *line = 0; *column = 0; } else mLocationTable->positionAt(at(index).end, line, column); } private: std::vector mTokenBuffer; qint64 mIndex; LocationTable *mLocationTable; private: TokenStreamBase(TokenStreamBase const &other); void operator = (TokenStreamBase const &other); }; class TokenStream : public TokenStreamBase { }; } #endif // KDEV_PG_TOKEN_STREAM_H diff --git a/kdev-pg/kdev-pg-ast.h b/kdev-pg/kdev-pg-ast.h index 3deaf74..b79c201 100644 --- a/kdev-pg/kdev-pg-ast.h +++ b/kdev-pg/kdev-pg-ast.h @@ -1,385 +1,385 @@ /* 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. */ #ifndef KDEV_PG_AST_H #define KDEV_PG_AST_H #include "kdev-pg-allocator.h" #include "kdev-pg-memory-pool.h" #include #include using std::vector; using std::pair; using std::make_pair; #include #include #define PG_NODE(k) \ enum { NodeKind = NodeKind##k }; namespace KDevPG { // the kdev-pg calculus namespace Model { enum NodeKind { NodeKindItem = 0, NodeKindZero = 1, NodeKindPlus = 2, NodeKindStar = 3, NodeKindSymbol = 4, NodeKindAction = 5, NodeKindAlternative = 6, NodeKindCons = 7, NodeKindEvolve = 8, NodeKindTryCatch = 9, NodeKindAlias = 10, NodeKindTerminal = 11, NodeKindNonTerminal = 12, NodeKindAnnotation = 13, NodeKindCondition = 14, NodeKindVariableDeclaration = 15, NodeKindOperator = 16, NodeKindInlinedNonTerminal = 17, NodeKindLast }; class Node { public: PG_NODE(Item) int kind; }; class ZeroItem: public Node { public: PG_NODE(Zero) }; class PlusItem: public Node { public: PG_NODE(Plus) Node *mItem; }; class StarItem: public Node { public: PG_NODE(Star) Node *mItem; }; class SymbolItem: public Node { public: PG_NODE(Symbol) QString mName; QString mCapitalizedName; }; class ActionItem: public Node { public: PG_NODE(Action) Node *mItem; QString mCode; }; class AlternativeItem: public Node { public: PG_NODE(Alternative) Node *mLeft; Node *mRight; }; class ConsItem: public Node { public: PG_NODE(Cons) Node *mLeft; Node *mRight; }; class TryCatchItem: public Node { public: PG_NODE(TryCatch) Node *mTryItem; Node *mCatchItem; // contains 0 for "catch(recover)" bool mUnsafe; }; class AliasItem: public Node { public: PG_NODE(Alias) QString mCode; SymbolItem *mSymbol; }; class InlinedNonTerminalItem: public Node { public: PG_NODE(InlinedNonTerminal) SymbolItem *mSymbol; }; class TerminalItem: public Node { public: PG_NODE(Terminal) QString mName; QString mDescription; }; class NonTerminalItem: public Node { public: PG_NODE(NonTerminal) SymbolItem *mSymbol; QString mArguments; }; class Operator { public: Node *mTok; QString mCond, mCode; }; class OperatorItem : public Node { public: PG_NODE(Operator) struct TernDescription { Operator first, second; QString left; QString priority; }; struct BinDescription { Operator op; QString left; QString priority; }; struct UnaryDescription { Operator op; QString priority; }; struct ParenDescription { Operator first, second; }; QString mName; NonTerminalItem *mBase; vector< ParenDescription > mParen; vector< TernDescription > mTern; vector< BinDescription > mBin, mPost; vector< UnaryDescription > mPre; inline void pushParen(const Operator& op1, const Operator& op2) { ParenDescription d; d.first = op1; d.second = op2; mParen.push_back(d); } inline void pushPre(const Operator& op, const QString& priority) { UnaryDescription d; d.op = op; d.priority = priority; mPre.push_back(d); } inline void pushPost(const Operator& op, const QString& left, const QString& priority) { BinDescription d; d.op = op; d.priority = priority; d.left = left; mPost.push_back(d); } inline void pushBin(const Operator& op, const QString& left, const QString& priority) { BinDescription d; d.op = op; d.left = left; d.priority = priority; mBin.push_back(d); } inline void pushTern(const Operator& op1, const Operator& op2, const QString& left, const QString& priority) { TernDescription d; d.first = op1; d.second = op2; d.left = left; d.priority = priority; mTern.push_back(d); } }; class VariableDeclarationItem: public Node { public: PG_NODE(VariableDeclaration) enum DeclarationType { DeclarationArgument, DeclarationLocal }; enum StorageType { StorageAstMember, StorageTemporary }; enum VariableType { TypeNode, TypeToken, TypeVariable }; QString mType; QString mCapitalizedType; QString mName; DeclarationType mDeclarationType; StorageType mStorageType; VariableType mVariableType; bool mIsSequence; VariableDeclarationItem *mNext; }; class AnnotationItem: public Node { public: PG_NODE(Annotation) Node *mItem; VariableDeclarationItem *mDeclaration; }; class ConditionItem: public Node { public: PG_NODE(Condition) QString mCode; Node *mItem; }; class EvolveItem: public Node { public: PG_NODE(Evolve) Node *mItem; SymbolItem *mSymbol; VariableDeclarationItem *mDeclarations; QString mCode; }; } // namespace model // configuration stuff outside the model namespace Settings { enum NodeKind { NodeKindMember = 30, NodeKindLast }; class MemberItem: public Model::Node { public: PG_NODE(Member) enum MemberKind { PublicDeclaration = 1, ProtectedDeclaration = 2, PrivateDeclaration = 4, ConstructorCode = 8, DestructorCode = 16 }; MemberKind mMemberKind; QString mCode; }; } // namespace settings template struct StripPtr { typedef T Result; }; template struct StripPtr { typedef T Result; }; template _Tp nodeCast(Model::Node *item) { if (StripPtr<_Tp>::Result::NodeKind == item->kind) return static_cast<_Tp>(item); - return 0; + return nullptr; } extern KDevPG::Allocator globalMemoryPool; template _Tp *createNode() { _Tp *node = new (globalMemoryPool.allocate(sizeof(_Tp)))_Tp(); node->kind = _Tp::NodeKind; return node; } } #endif // KDEV_PG_AST_H diff --git a/kdev-pg/kdev-pg-bnf-visitor.cpp b/kdev-pg/kdev-pg-bnf-visitor.cpp index 5575172..848b75d 100644 --- a/kdev-pg/kdev-pg-bnf-visitor.cpp +++ b/kdev-pg/kdev-pg-bnf-visitor.cpp @@ -1,311 +1,311 @@ /* This file is part of kdev-pg-qt 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-bnf-visitor.h" using namespace KDevPG; bool BnfVisitor::isInternal(Model::Node* item) { return localMemoryPool.contains(item); } template inline _Tp* BnfVisitor::localCreateNode() { _Tp *node = new (localMemoryPool.allocate(sizeof(_Tp)))_Tp(); node->kind = _Tp::NodeKind; return node; } template inline _Tp* BnfVisitor::createArray(qint64 size) { return reinterpret_cast<_Tp*>(localMemoryPool.allocate(size * sizeof(_Tp))); } template inline _Tp* BnfVisitor::getSubArray(void* mem, qint64 s) { _Tp *arr = reinterpret_cast<_Tp*>(mem); for(qint64 i = 0; i != s; ++i) arr[i].kind = _Tp::NodeKind; return arr; } KDevPG::Allocator KDevPG::BnfVisitor::localMemoryPool; QHash KDevPG::BnfVisitor::mOpStuff; QHash KDevPG::BnfVisitor::mStarStuff; QHash KDevPG::BnfVisitor::mPlusStuff; void KDevPG::BnfVisitor::visitInlinedNonTerminal(Model::InlinedNonTerminalItem* node) { Model::EvolveItem *rule = globalSystem.searchRule(node->mSymbol); preCopy(rule, node); preCopy(node->mSymbol, node); // visitNode(rule); copy(node->mSymbol, node); copy(rule, node); } void KDevPG::BnfVisitor::visitNonTerminal(Model::NonTerminalItem* node) { Model::EvolveItem *rule = globalSystem.searchRule(node->mSymbol); preCopy(rule, node); preCopy(node->mSymbol, node); // visitNode(rule); copy(node->mSymbol, node); copy(rule, node); } void KDevPG::BnfVisitor::visitPlus(Model::PlusItem* node) { if(mPlusStuff.contains(node)) { preCopy(mPlusStuff[node], node); DefaultVisitor::visitNode(mPlusStuff[node]); copy(mPlusStuff[node], node); return; } Model::ConsItem *c = localCreateNode(); Model::AlternativeItem *a = localCreateNode(); c->mLeft = node->mItem; c->mRight = a; a->mLeft = globalSystem.zero(); a->mRight = c; preCopy(c, node); DefaultVisitor::visitNode(c); mPlusStuff[node] = c; copy(c, node); } void KDevPG::BnfVisitor::visitStar(Model::StarItem* node) { if(mStarStuff.contains(node)) { preCopy(mStarStuff[node], node); DefaultVisitor::visitNode(mStarStuff[node]); copy(mStarStuff[node], node); return; } Model::ConsItem *c = localCreateNode(); Model::AlternativeItem *a = localCreateNode(); c->mLeft = node->mItem; c->mRight = a; a->mLeft = globalSystem.zero(); a->mRight = c; preCopy(a, node); DefaultVisitor::visitNode(a); mStarStuff[node] = a; copy(a, node); } void KDevPG::BnfVisitor::visitOperator(Model::OperatorItem* node) { if(mOpStuff.contains(node)) { preCopy(mOpStuff[node], node); DefaultVisitor::visitNode(mOpStuff[node]); copy(mOpStuff[node], node); } else { void *mem = localMemoryPool.allocate( (node->mPre.size() * 1 + node->mBin.size() * 2 + node->mPost.size() * 1 + node->mParen.size() * 2 + node->mTern.size() * 4) * sizeof(Model::ConsItem) + (node->mPre.size() * 1 + node->mBin.size() * 1 + node->mPost.size() * 1 + node->mParen.size() * 1 + node->mTern.size() * 1) * sizeof(Model::AlternativeItem) ); Model::ConsItem *tmpPre = getSubArray(mem, node->mPre.size()); Model::ConsItem *tmpBinRight = getSubArray(tmpPre + node->mPre.size(), node->mBin.size()); Model::ConsItem *tmpBin = getSubArray(tmpBinRight + node->mBin.size(), node->mBin.size()); Model::ConsItem *tmpPost = getSubArray(tmpBin + node->mBin.size(), node->mPost.size()); Model::ConsItem *tmpParenRight = getSubArray(tmpPost + node->mPost.size(), node->mParen.size()); Model::ConsItem *tmpParen = getSubArray(tmpParenRight + node->mParen.size(), node->mParen.size()); Model::ConsItem *tmpTern3 = getSubArray(tmpParen + node->mParen.size(), node->mTern.size()); Model::ConsItem *tmpTern2 = getSubArray(tmpTern3 + node->mTern.size(), node->mTern.size()); Model::ConsItem *tmpTern1 = getSubArray(tmpTern2 + node->mTern.size(), node->mTern.size()); Model::ConsItem *tmpTern = getSubArray(tmpTern1 + node->mTern.size(), node->mTern.size()); int i = node->mPre.size() + node->mPost.size() + node->mBin.size() + node->mTern.size() + node->mParen.size(); Model::AlternativeItem *tmp = getSubArray(tmpTern + node->mTern.size(), i); Model::Node *last = node->mBase; for(size_t j = 0; j != node->mPre.size(); ++j) { tmpPre[j].mLeft = node->mPre[j].op.mTok; tmpPre[j].mRight = tmp+0; tmpPre[j].kind = Model::NodeKindCons; --i; tmp[i].kind = Model::NodeKindAlternative; tmp[i].mRight = last; tmp[i].mLeft = tmpPre+j; last = tmp+i; } for(size_t j = 0; j != node->mPost.size(); ++j) { tmpPost[j].mLeft = tmp+0; tmpPost[j].mRight = node->mPost[j].op.mTok; tmpPost[j].kind = Model::NodeKindCons; --i; tmp[i].kind = Model::NodeKindAlternative; tmp[i].mRight = last; tmp[i].mLeft = tmpPost+j; last = tmp+i; } for(size_t j = 0; j != node->mBin.size(); ++j) { tmpBinRight[j].mLeft = node->mBin[j].op.mTok; tmpBinRight[j].mRight = tmp+0; tmpBinRight[j].kind = Model::NodeKindCons; tmpBin[j].mLeft = tmp+0; tmpBin[j].mRight = tmpBinRight+j; tmpBin[j].kind = Model::NodeKindCons; --i; tmp[i].kind = Model::NodeKindAlternative; tmp[i].mRight = last; tmp[i].mLeft = tmpBin+j; last = tmp+i; } for(size_t j = 0; j != node->mTern.size(); ++j) { tmpTern3[j].mLeft = node->mTern[j].second.mTok; tmpTern3[j].mRight = tmp+0; tmpTern3[j].kind = Model::NodeKindCons; tmpTern2[j].mLeft = tmp+0; tmpTern2[j].mRight = tmpTern3+j; tmpTern2[j].kind = Model::NodeKindCons; tmpTern1[j].mLeft = node->mTern[j].first.mTok; tmpTern1[j].mRight = tmpTern2+j; tmpTern1[j].kind = Model::NodeKindCons; tmpTern[j].mLeft = tmp+0; tmpTern[j].mRight = tmpTern1+j; tmpTern[j].kind = Model::NodeKindCons; --i; tmp[i].kind = Model::NodeKindAlternative; tmp[i].mRight = last; tmp[i].mLeft = tmpTern+j; last = tmp+i; } for(size_t j = 0; j != node->mParen.size(); ++j) { tmpParenRight[j].mLeft = tmp+0; tmpParenRight[j].mRight = node->mParen[j].second.mTok; tmpParenRight[j].kind = Model::NodeKindCons; tmpParen[j].mLeft = node->mParen[j].first.mTok; tmpParen[j].mRight = tmpParenRight+j; tmpParen[j].kind = Model::NodeKindCons; --i; tmp[i].kind = Model::NodeKindAlternative; tmp[i].mRight = last; tmp[i].mLeft = tmpParen+j; last = tmp+i; } mOpStuff[node] = last; preCopy(last, node); DefaultVisitor::visitNode(last); copy(last, node); } } void BnfVisitor::visitAnnotation(Model::AnnotationItem* node) { preCopy(node->mItem, node); KDevPG::DefaultVisitor::visitAnnotation(node); copy(node->mItem, node); } void BnfVisitor::visitCondition(Model::ConditionItem* node) { preCopy(node->mItem, node); KDevPG::DefaultVisitor::visitCondition(node); copy(node->mItem, node); } void BnfVisitor::visitAction(Model::ActionItem* node) { preCopy(node->mItem, node); KDevPG::DefaultVisitor::visitNode(node->mItem); copy(node->mItem, node); } void BnfVisitor::visitTryCatch(Model::TryCatchItem* node) { - if(node->mCatchItem == 0) + if(node->mCatchItem == nullptr) { preCopy(node->mTryItem, node); DefaultVisitor::visitNode(node->mTryItem); copy(node->mTryItem, node); } else // A little bit dirty, please do not change the layout ;) visitAlternative(reinterpret_cast(node)); } void BnfVisitor::visitEvolve(Model::EvolveItem* node) { preCopy(node, node->mSymbol); preCopy(node->mItem, node); visitNode(node->mItem); copy(node->mItem, node); copy(node, node->mSymbol); } void KDevPG::BnfVisitor::finished() { // localMemoryPool.~Allocator(); // new (&localMemoryPool) Allocator; } diff --git a/kdev-pg/kdev-pg-checker.cpp b/kdev-pg/kdev-pg-checker.cpp index ed7443c..38f91c9 100644 --- a/kdev-pg/kdev-pg-checker.cpp +++ b/kdev-pg/kdev-pg-checker.cpp @@ -1,440 +1,440 @@ /* This file is part of kdev-pg-qt Copyright (C) 2005 Roberto Raggi Copyright (C) 2006 Jakob Petsovits 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-checker.h" #include "kdev-pg-pretty-printer.h" #include "kdev-pg-bnf-visitor.h" #include //uncomment this to see debug output for follow checker // #define FOLLOW_CHECKER_DEBUG namespace KDevPG { QTextStream checkOut(stderr); int ProblemSummaryPrinter::mFirstFirstConflictCount = 0; int ProblemSummaryPrinter::mFirstFollowConflictCount = 0; int ProblemSummaryPrinter::mErrorCount = 0; void FirstFirstConflictChecker::operator()(Model::Node *node) { Model::EvolveItem *e = nodeCast(node); - Q_ASSERT(e != 0); + Q_ASSERT(e != nullptr); mSymbol = e->mSymbol; visitNode(node); } void FirstFirstConflictChecker::visitAlternative(Model::AlternativeItem *node) { DefaultVisitor::visitAlternative(node); mCheckedNode = node; check(node->mLeft, node->mRight); } void FirstFirstConflictChecker::visitInlinedNonTerminal(Model::InlinedNonTerminalItem* node) { Q_UNUSED(node); } void FirstFirstConflictChecker::check(Model::Node *left, Model::Node *right) { World::NodeSet const &left_first = globalSystem.first(left); World::NodeSet const &right_first = globalSystem.first(right); QSet U = left_first; U.intersect( right_first ); if (!U.empty()) { QTextStream& str( checkOut ); PrettyPrinter printer(str); str << "** WARNING found FIRST/FIRST conflict in " << mSymbol->mName << ":" << endl << "\tRule ``"; printer(mCheckedNode); // p(left); str << "''" << endl << "\tTerminals [" << endl; QSet::iterator it = U.begin(); while (it != U.end()) { Model::Node *n = *it++; str << "\t\t" << n; if (it != U.end()) str << ", "; str << endl; } str << "\t]" << endl << endl; ProblemSummaryPrinter::reportFirstFirstConflict(); } } void FirstFirstConflictChecker::visitEvolve(Model::EvolveItem *node) { DefaultVisitor::visitEvolve(node); World::Environment::iterator it = globalSystem.env.find(node->mSymbol); while (it != globalSystem.env.end()) { Model::SymbolItem *sym = it.key(); Model::EvolveItem *e = (*it); ++it; if (sym != node->mSymbol || node == e) continue; mCheckedNode = node; check(e, node); } } void FirstFollowConflictChecker::operator()(Model::Node *node) { Model::EvolveItem *e = nodeCast(node); - Q_ASSERT(e != 0); + Q_ASSERT(e != nullptr); mSymbol = e->mSymbol; visitNode(node); } void FirstFollowConflictChecker::check(Model::Node *node, Model::Node *sym) { if (!sym) sym = node; World::NodeSet const &first = globalSystem.first(node); World::NodeSet const &follow = globalSystem.follow(sym); QSet U = first; U.intersect(follow); if (!U.empty()) { QTextStream& str( checkOut ); PrettyPrinter p(str); str << "** WARNING found FIRST/FOLLOW conflict in " << mSymbol->mName; #ifdef FOLLOW_CHECKER_DEBUG str << "(" << (uint*)mSymbol << ")"; #endif str << ":" << endl << "\tRule ``"; p(node); #ifdef FOLLOW_CHECKER_DEBUG str << " [[" << (uint*)node << "]]"; #endif str << "''" << endl << "\tTerminals [" << endl; QSet::iterator it = U.begin(); while (it != U.end()) { Model::Node *n = *it++; if (isZero(n)) continue; str << "\t\t" << ((Model::TerminalItem*)n)->mName << ": conflicts with the FIRST set of: " << endl; FollowDepChecker(n).check(node); if (it != U.end()) str << "," << endl; } str << "\t]" << endl << endl; ProblemSummaryPrinter::reportFirstFollowConflict(); } } void FollowDepChecker::check(Model::Node *node) { //avoid cyclical follow dependency check if (mVisited.find(node) != mVisited.end()) return; mVisited.insert(node); World::FollowDep &D = globalSystem.followDep(node); QList FD = D.first.toList(); QList FLD = D.second.toList(); QTextStream& str( checkOut ); PrettyPrinter p(str); #ifdef FOLLOW_CHECKER_DEBUG str << "[["; p(node); str << " | " << (uint*)node << "]] "; str << "{" << node->kind << "}" << endl; #endif for (int i = 0; i != FD.size(); ++i) // no iterator → modifiable { if(BnfVisitor::isInternal(FD[i])) { World::NodeSet set = globalSystem.followDep(FD[i]).second; World::NodeSet set2 = globalSystem.followDep(FD[i]).first; // :-S has to be verified… for(auto jt = FD.begin(); jt != FD.end(); ++jt) { set.remove(*jt); set2.remove(*jt); } for(auto jt = set2.begin(); jt != set2.end(); ++jt) if(!BnfVisitor::isInternal(*jt)) FD.append(*jt); FD.append(set.toList()); } else { World::NodeSet first = globalSystem.first(FD[i]); #ifdef FOLLOW_CHECKER_DEBUG str << " "; #endif if (first.find(mTerminal) != first.end()) { str << "\t\t"; p(FD[i]); #ifdef FOLLOW_CHECKER_DEBUG str << " ( in \""; p(node); str << " \" )"; #endif str << ", " << endl; } } } for (int i = 0; i != FLD.size(); ++i) { if(BnfVisitor::isInternal(FLD[i])) { World::NodeSet set = globalSystem.followDep(FLD[i]).second; for(auto jt = FLD.begin(); jt != FLD.end(); ++jt) set.remove(*jt); FLD.append(set.toList()); } else { World::NodeSet first = globalSystem.first(FLD[i]); #ifdef FOLLOW_CHECKER_DEBUG str << endl << "\t\t" << "in "; p(FLD[i]); str << endl; #endif check(FLD[i]); } } } void FirstFollowConflictChecker::visitAlternative(Model::AlternativeItem *node) { DefaultVisitor::visitAlternative(node); if (isZero(node->mRight)) return; if (reducesToEpsilon(node)) check(node); } void FirstFollowConflictChecker::visitCons(Model::ConsItem *node) { DefaultVisitor::visitCons(node); if (reducesToEpsilon(node)) check(node); } void FirstFollowConflictChecker::visitPlus(Model::PlusItem *node) { DefaultVisitor::visitPlus(node); if (reducesToEpsilon(node)) check(node); } void FirstFollowConflictChecker::visitStar(Model::StarItem *node) { DefaultVisitor::visitStar(node); check(node); } void FirstFollowConflictChecker::visitInlinedNonTerminal(Model::InlinedNonTerminalItem* node) { Q_UNUSED(node); } void UndefinedSymbolChecker::visitInlinedNonTerminal(Model::InlinedNonTerminalItem* node) { if(node->mSymbol) visitSymbol(node->mSymbol); } void UndefinedSymbolChecker::operator()(Model::Node *node) { Model::EvolveItem *e = nodeCast(node); - Q_ASSERT(e != 0); + Q_ASSERT(e != nullptr); mSymbol = e->mSymbol; visitNode(node); } void UndefinedSymbolChecker::visitSymbol(Model::SymbolItem *node) { if (globalSystem.env.count(node) == 0) { checkOut << "** ERROR Undefined symbol ``" << node->mName << "'' in " << mSymbol->mName << endl; ProblemSummaryPrinter::reportError(); } } void UndefinedSymbolChecker::visitVariableDeclaration(Model::VariableDeclarationItem *node) { if (node->mVariableType != Model::VariableDeclarationItem::TypeNode) return; Model::SymbolItem *sym; QString name = node->mType; World::SymbolSet::iterator it = globalSystem.symbols.find(name); if (it == globalSystem.symbols.end()) { checkOut << "** ERROR Undefined symbol ``" << name << "'' (rule parameter declaration) in " << mSymbol->mName << endl; ProblemSummaryPrinter::reportError(); return; } else sym = (*it); if (globalSystem.env.count(sym) == 0) { checkOut << "** ERROR Undefined symbol ``" << node->mName << "'' (rule parameter declaration) in " << mSymbol->mName << endl; ProblemSummaryPrinter::reportError(); } } void UndefinedTokenChecker::visitInlinedNonTerminal(Model::InlinedNonTerminalItem* node) { Q_UNUSED(node); } void UndefinedTokenChecker::operator()(Model::Node *node) { Model::EvolveItem *e = nodeCast(node); - Q_ASSERT(e != 0); + Q_ASSERT(e != nullptr); mSymbol = e->mSymbol; visitNode(node); } void UndefinedTokenChecker::visitTerminal(Model::TerminalItem *node) { QString name = node->mName; if (globalSystem.terminals.find(name) == globalSystem.terminals.end()) { checkOut << "** ERROR Undefined token ``" << node->mName << "'' in " << mSymbol->mName << endl; ProblemSummaryPrinter::reportError(); } } void EmptyFirstChecker::operator()(Model::Node *node) { visitNode(node); } void EmptyFirstChecker::visitNonTerminal(Model::NonTerminalItem *node) { Q_UNUSED(node); } void EmptyFirstChecker::visitInlinedNonTerminal(Model::InlinedNonTerminalItem *node) { Q_UNUSED(node); } void EmptyFirstChecker::visitSymbol(Model::SymbolItem *node) { if (globalSystem.first(node).empty()) { checkOut << "** ERROR Empty FIRST set for ``" << node->mName << "''" << endl; ProblemSummaryPrinter::reportError(); } } void EmptyOperatorChecker::operator()(Model::Node *node) { visitNode(node); } void EmptyOperatorChecker::visitOperator(Model::OperatorItem *node) { if (reducesToEpsilon((node->mBase->mSymbol))) { checkOut << "** ERROR Base symbol ``" << node->mBase->mSymbol->mName << "'' for operator ``" << node->mName << "'' reduces to zero" << endl; ProblemSummaryPrinter::reportError(); } } void ProblemSummaryPrinter::operator()() { if (KDevPG::globalSystem.conflictHandling != KDevPG::World::Ignore) checkOut << (mFirstFirstConflictCount + mFirstFollowConflictCount) << " conflicts total: " << mFirstFollowConflictCount << " FIRST/FOLLOW conflicts, " << mFirstFirstConflictCount << " FIRST/FIRST conflicts." << endl; if (mErrorCount > 0) { checkOut << mErrorCount << " fatal errors found, exiting." << endl; exit(EXIT_FAILURE); } if (KDevPG::globalSystem.conflictHandling == KDevPG::World::Strict && mFirstFirstConflictCount + mFirstFollowConflictCount > 0) { checkOut << "Conflicts found, exiting." << endl; exit(EXIT_FAILURE); } } void ProblemSummaryPrinter::reportFirstFirstConflict() { ++mFirstFirstConflictCount; } void ProblemSummaryPrinter::reportFirstFollowConflict() { ++mFirstFollowConflictCount; } void ProblemSummaryPrinter::reportError() { ++mErrorCount; } } // kate: space-indent on; indent-width 2; tab-width 2; show-tabs on; diff --git a/kdev-pg/kdev-pg-checker.h b/kdev-pg/kdev-pg-checker.h index 4957cff..11b7c48 100644 --- a/kdev-pg/kdev-pg-checker.h +++ b/kdev-pg/kdev-pg-checker.h @@ -1,149 +1,149 @@ /* This file is part of kdev-pg-qt Copyright (C) 2005 Roberto Raggi Copyright (C) 2006 Jakob Petsovits 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. */ #ifndef KDEV_PG_CHECKER_H #define KDEV_PG_CHECKER_H #include "kdev-pg.h" #include "kdev-pg-default-visitor.h" /** * @file * Checks for conflicts and some errors. * TODO: split conflict-computation and conflict-message-printing */ namespace KDevPG { class EmptyFirstChecker: protected DefaultVisitor { public: void operator()(Model::Node *node); protected: virtual void visitNonTerminal(Model::NonTerminalItem *node); virtual void visitInlinedNonTerminal(Model::InlinedNonTerminalItem *node); virtual void visitSymbol(Model::SymbolItem *node); }; class EmptyOperatorChecker: protected DefaultVisitor { public: void operator()(Model::Node *node); protected: virtual void visitOperator(Model::OperatorItem *node); }; class FirstFirstConflictChecker: protected DefaultVisitor { public: void operator()(Model::Node *node); protected: void check(Model::Node *left, Model::Node *right); virtual void visitEvolve(Model::EvolveItem *node); virtual void visitAlternative(Model::AlternativeItem *node); virtual void visitInlinedNonTerminal(Model::InlinedNonTerminalItem *node); private: Model::SymbolItem *mSymbol; Model::Node *mCheckedNode; }; class FirstFollowConflictChecker: protected DefaultVisitor { public: void operator()(Model::Node *node); protected: - void check(Model::Node *node, Model::Node *sym = 0); + void check(Model::Node *node, Model::Node *sym = nullptr); virtual void visitAlternative(Model::AlternativeItem *node); virtual void visitCons(Model::ConsItem *node); virtual void visitPlus(Model::PlusItem *node); virtual void visitStar(Model::StarItem *node); virtual void visitInlinedNonTerminal(Model::InlinedNonTerminalItem *node); private: Model::SymbolItem *mSymbol; }; class FollowDepChecker { public: FollowDepChecker(Model::Node *terminal): mTerminal(terminal) {} void check(Model::Node *n); private: Model::Node *mTerminal; World::NodeSet mVisited; }; class UndefinedSymbolChecker: protected DefaultVisitor { public: void operator()(Model::Node *node); protected: virtual void visitSymbol(Model::SymbolItem *node); virtual void visitVariableDeclaration(Model::VariableDeclarationItem *node); virtual void visitInlinedNonTerminal(Model::InlinedNonTerminalItem *node); private: Model::SymbolItem *mSymbol; }; class UndefinedTokenChecker: protected DefaultVisitor { public: void operator()(Model::Node *node); protected: virtual void visitTerminal(Model::TerminalItem *node); virtual void visitInlinedNonTerminal(Model::InlinedNonTerminalItem *node); private: Model::SymbolItem *mSymbol; }; class ProblemSummaryPrinter { public: void operator()(); static void reportFirstFirstConflict(); static void reportFirstFollowConflict(); static void reportError(); private: static int mFirstFirstConflictCount; static int mFirstFollowConflictCount; static int mErrorCount; }; } #endif // KDEV_PG_CHECKER_H // kate: space-indent on; indent-width 2; tab-width 2; show-tabs on; diff --git a/kdev-pg/kdev-pg-clone-tree.cpp b/kdev-pg/kdev-pg-clone-tree.cpp index 536337b..ddc65b5 100644 --- a/kdev-pg/kdev-pg-clone-tree.cpp +++ b/kdev-pg/kdev-pg-clone-tree.cpp @@ -1,176 +1,176 @@ /* This file is part of kdev-pg-qt Copyright (C) 2005 Roberto Raggi Copyright (C) 2006 Jakob Petsovits 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-clone-tree.h" #include "kdev-pg.h" namespace KDevPG { void CloneTree::visitZero(Model::ZeroItem *node) { mTemps.push(node); } void CloneTree::visitSymbol(Model::SymbolItem *node) { mTemps.push(node); } void CloneTree::visitTerminal(Model::TerminalItem *node) { mTemps.push(node); } void CloneTree::visitNonTerminal(Model::NonTerminalItem *node) { mTemps.push(KDevPG::nonTerminal(node->mSymbol, node->mArguments)); } void CloneTree::visitInlinedNonTerminal(Model::InlinedNonTerminalItem* node) { mTemps.push(KDevPG::inlinedNonTerminal(node->mSymbol)); } void CloneTree::visitPlus(Model::PlusItem *node) { visitNode(node->mItem); Model::Node *item = mTemps.top(); mTemps.pop(); mTemps.push(KDevPG::plus(item)); } void CloneTree::visitStar(Model::StarItem *node) { visitNode(node->mItem); Model::Node *item = mTemps.top(); mTemps.pop(); mTemps.push(KDevPG::star(item)); } void CloneTree::visitAction(Model::ActionItem *node) { visitNode(node->mItem); Model::Node *item = mTemps.top(); mTemps.pop(); mTemps.push(KDevPG::action(item, node->mCode)); } void CloneTree::visitAlternative(Model::AlternativeItem *node) { visitNode(node->mLeft); Model::Node *left = mTemps.top(); mTemps.pop(); visitNode(node->mRight); Model::Node *right = mTemps.top(); mTemps.pop(); mTemps.push(KDevPG::alternative(left, right)); } void CloneTree::visitCons(Model::ConsItem *node) { visitNode(node->mLeft); Model::Node *left = mTemps.top(); mTemps.pop(); visitNode(node->mRight); Model::Node *right = mTemps.top(); mTemps.pop(); mTemps.push(KDevPG::cons(left, right)); } void CloneTree::visitEvolve(Model::EvolveItem *node) { visitNode(node->mItem); Model::Node *item = mTemps.top(); mTemps.pop(); mTemps.push(KDevPG::evolve(item, node->mSymbol, node->mDeclarations, node->mCode)); } void CloneTree::visitTryCatch(Model::TryCatchItem *node) { visitNode(node->mTryItem); Model::Node *try_item = mTemps.top(); mTemps.pop(); - Model::Node *catch_item = 0; + Model::Node *catch_item = nullptr; if (node->mCatchItem) { visitNode(node->mCatchItem); catch_item = mTemps.top(); mTemps.pop(); } mTemps.push(KDevPG::tryCatch(try_item, catch_item)); } void CloneTree::visitAlias(Model::AliasItem *node) { Q_UNUSED(node); Q_ASSERT(0); // ### not implemented yet } void CloneTree::visitAnnotation(Model::AnnotationItem *node) { visitNode(node->mItem); Model::Node *item = mTemps.top(); mTemps.pop(); mTemps.push(KDevPG::annotation(node->mDeclaration->mName, item, node->mDeclaration->mIsSequence, node->mDeclaration->mStorageType)); } void CloneTree::visitOperator(Model::OperatorItem *node) { // Should not be relevant if it gets really copied mTemps.push(node); } Model::Node *CloneTree::clone(Model::Node *node) { mTemps = QStack(); visitNode(node); Model::Node *n = mTemps.top(); mTemps.pop(); Q_ASSERT(mTemps.empty()); return n; } } diff --git a/kdev-pg/kdev-pg-code-gen.cpp b/kdev-pg/kdev-pg-code-gen.cpp index 1809ac5..4732a05 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()) != 0)) + 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 << "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 != 0); + 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 << "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 << "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 << "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" "reinterpret_cast(last)->first = node;" "else if(reinterpret_cast(last)->second == 0)\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\ reinterpret_cast(last)->first = " << __var << ";" << endl; \ out << "else if(reinterpret_cast(last)->second == 0)\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, 0); + 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;" "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 == 0) || mNames->find(node->mName) == mNames->end()) + 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 != 0) + 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 != 0) + 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 << "tokenStream = 0;" << 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-first.cpp b/kdev-pg/kdev-pg-first.cpp index d8109e2..918ed0c 100644 --- a/kdev-pg/kdev-pg-first.cpp +++ b/kdev-pg/kdev-pg-first.cpp @@ -1,139 +1,139 @@ /* 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-first.h" #include namespace KDevPG { void initializeFirst() { globalSystem.first(globalSystem.zero()).insert(globalSystem.zero()); for(auto i = globalSystem.terminals.begin(); i != globalSystem.terminals.end(); ++i) { globalSystem.first(*i).insert(*i); } } NextFirst::NextFirst(bool &changed): mChanged(changed) { } void NextFirst::operator ()(Model::Node *node) { assert(nodeCast(node)); mMergeZeroBlocked = false; visitNode(node); } bool NextFirst::blockZeroMerge(bool block) { bool old = mMergeZeroBlocked; mMergeZeroBlocked = block; return old; } void NextFirst::merge(Model::Node *__dest, Model::Node *__source, int K) { - if(__source == 0 || __dest == 0) + if(__source == nullptr || __dest == nullptr) return; World::NodeSet &dest = globalSystem.first(__dest, K); World::NodeSet &source = globalSystem.first(__source, K); for (World::NodeSet::iterator it = source.begin(); it != source.end(); ++it) { if (mMergeZeroBlocked && nodeCast(*it)) { continue; } if( !dest.contains(*it) ) { dest.insert(*it); mChanged = true; } } } void NextFirst::visitNode(Model::Node *node) { - if(node == 0) + if(node == nullptr) return; if(mVisited.contains(node)) return; mVisited.insert(node); DefaultVisitor::visitNode(node); mVisited.remove(node); } void NextFirst::visitAlternative(Model::AlternativeItem *node) { DefaultVisitor::visitAlternative(node); merge(node, node->mLeft); merge(node, node->mRight); } void NextFirst::visitCons(Model::ConsItem *node) { visitNode(node->mRight); bool zero_blocked = mMergeZeroBlocked; if (!reducesToEpsilon(node->mRight)) zero_blocked = blockZeroMerge(true); visitNode(node->mLeft); merge(node, node->mLeft); if (reducesToEpsilon(node->mLeft)) { visitNode(node->mRight); merge(node, node->mRight); } blockZeroMerge(zero_blocked); } void computeFirst() // the closure of the FIRST sets { initializeFirst(); bool changed = true; NextFirst next(changed); while (changed) { changed = false; for(QList::iterator it = globalSystem.rules.begin(); it != globalSystem.rules.end(); ++it) { next(*it); } } } } diff --git a/kdev-pg/kdev-pg-follow.cpp b/kdev-pg/kdev-pg-follow.cpp index 7eabd1f..fefe8e8 100644 --- a/kdev-pg/kdev-pg-follow.cpp +++ b/kdev-pg/kdev-pg-follow.cpp @@ -1,236 +1,236 @@ /* This file is part of kdev-pg-qt Copyright (C) 2005 Roberto Raggi Copyright (C) 2006 Jakob Petsovits Copyright (C) 2006 Alexander Dymo 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-follow.h" #include "kdev-pg-pretty-printer.h" #include //uncomment this to see debug output for follow dependency calculation // #define followDepsEP_DEBUG /* * Computing LL(k)-follow-sets */ namespace KDevPG { extern QTextStream checkOut; #ifdef FOLLOWDEP_DEBUG void DebugFollowDep(Model::Node *dest, Model::Node *dep, const QString &message) { checkOut << "=============================" << endl; PrettyPrinter p(QTextStream( stderr )); checkOut << "adding " << message << " "; p(dep); checkOut << " (" << (uint*)dep << ")"; checkOut << " to follow "; p(dest); checkOut << " (" << (uint*)dest << ")"; checkOut << "{" << dest->kind << "}"; if (dest->kind == Model::Node_kind_nonTerminal) { Model::SymbolItem *s = ((Model::NonTerminalItem*)dest)->mSymbol; if (s) checkOut << "__"; p(s); checkOut << "__"; } checkOut << endl; } void debugFirstToFollowDep(Model::Node *dest, Model::Node *dep) { DebugFollowDep(dest, dep, "first"); } void debugFollowToFollowDep(Model::Node *dest, Model::Node *dep) { DebugFollowDep(dest, dep, "follow"); } #endif // // Calculating the FOLLOW set depends on the first set being already available // and is in principle quite easy. There are only a few simple rules: // // 1. Put EOF at the end of the start rule // 2. For every rule "items -> rulename", put FOLLOW(rulename) into FOLLOW(items) // 3. For every item sequence "item1 item2", put first(item2) into FOLLOW(item1) // 4. For every rule "item1 item2 -> rulename", put FOLLOW(rulename) // into FOLLOW(item1) if item2 can derive to epsilon ("0"). // 5. Propagate the FOLLOW sets down to the symbols where appropriate. // 6. Loop for all rules until there are no changes in any FOLLOW set anymore. // NextFollow::NextFollow(bool &changed) : mChanged(changed) { Model::TerminalItem *teof = globalSystem.pushTerminal("EOF", "end of file"); for(auto i = globalSystem.rules.begin(); i != globalSystem.rules.end(); ++i) { if(globalSystem.start.contains((*i)->mSymbol)) { globalSystem.follow(*i).insert(teof); globalSystem.follow((*i)->mSymbol).insert(teof); globalSystem.follow((*i)->mItem).insert(teof); } } } void NextFollow::operator()(Model::Node *node) { Model::EvolveItem *e = nodeCast(node); - Q_ASSERT(e != 0); + Q_ASSERT(e != nullptr); mSymbol = e->mSymbol; visitNode(node); } void NextFollow::merge(Model::Node*__dest, World::NodeSet const &source) { - if (nodeCast(__dest) != 0 - || nodeCast(__dest) != 0) + if (nodeCast(__dest) != nullptr + || nodeCast(__dest) != nullptr) { return; } World::NodeSet &dest = globalSystem.follow(__dest); for (World::NodeSet::const_iterator it = source.begin(); it != source.end(); ++it) { if (Model::TerminalItem *t = nodeCast(*it)) { if( !dest.contains(t) ) { mChanged = true; dest.insert(t); } } } } void NextFollow::visitCons(Model::ConsItem *node) { merge(node->mRight, globalSystem.follow(node)); addFollowToFollowDep(node->mRight, node); merge(node->mLeft, globalSystem.first(node->mRight)); addFirstToFollowDep(node->mLeft, node->mRight); if (reducesToEpsilon(node->mRight)) { merge(node->mLeft, globalSystem.follow(node)); addFollowToFollowDep(node->mLeft, node); } DefaultVisitor::visitCons(node); } void NextFollow::visitAlternative(Model::AlternativeItem *node) { merge(node->mLeft, globalSystem.follow(node)); addFollowToFollowDep(node->mLeft, node); merge(node->mRight, globalSystem.follow(node)); addFollowToFollowDep(node->mRight, node); DefaultVisitor::visitAlternative(node); } void NextFollow::visitNode(Model::Node* node) { - if(node == 0) + if(node == nullptr) return; if(mVisited.contains(node)) return; mVisited.insert(node); KDevPG::Visitor::visitNode(node); mVisited.remove(node); } void NextFollow::preCopy(Model::Node* from, Model::Node* to) { - if(from != 0 && to != 0) + if(from != nullptr && to != nullptr) { merge(from, globalSystem.follow(to)); addFollowToFollowDep(from, to); } } void NextFollow::copy(Model::Node* from, Model::Node* to) { Q_UNUSED(from); Q_UNUSED(to); } void NextFollow::addFirstToFollowDep(Model::Node *dest, Model::Node *dep) { if (dest->kind == Model::NodeKindNonTerminal) { Model::SymbolItem *s = nodeCast(dest)->mSymbol; if (s) globalSystem.followDep(s).first.insert(dep); } else globalSystem.followDep(dest).first.insert(dep); #ifdef FOLLOWDEP_DEBUG debugFirstToFollowDep(dest, dep); #endif } void NextFollow::addFollowToFollowDep(Model::Node *dest, Model::Node *dep) { if (dest->kind == Model::NodeKindNonTerminal) { Model::SymbolItem *s = nodeCast(dest)->mSymbol; if (s) globalSystem.followDep(s).second.insert(dep); } else globalSystem.followDep(dest).second.insert(dep); #ifdef FOLLOWDEP_DEBUG debugFollowToFollowDep(dest, dep); #endif } void computeFollow() { bool changed = true; NextFollow next(changed); while (true) { for(QList::iterator it = globalSystem.rules.begin(); it != globalSystem.rules.end(); ++it) { next(*it); } if(!changed) // for the eof in the first iteration break; changed = false; } } } // kate: space-indent on; indent-width 2; tab-width 2; show-tabs on; diff --git a/kdev-pg/kdev-pg-inline-checker.cpp b/kdev-pg/kdev-pg-inline-checker.cpp index bfec6c3..4d1121b 100644 --- a/kdev-pg/kdev-pg-inline-checker.cpp +++ b/kdev-pg/kdev-pg-inline-checker.cpp @@ -1,75 +1,75 @@ /* This file is part of kdev-pg-qt 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-inline-checker.h" #include "kdev-pg-checker.h" #include namespace KDevPG { extern QTextStream checkOut; } using namespace KDevPG; void InlineChecker::operator()(Model::EvolveItem* node) { if(!mVisited.contains(node->mSymbol)) visitEvolve(node); } void InlineChecker::visitNonTerminal(Model::NonTerminalItem* node) { Q_UNUSED(node); } void InlineChecker::visitInlinedNonTerminal(Model::InlinedNonTerminalItem* node) { - if(node->mSymbol == 0) + if(node->mSymbol == nullptr) return; if(mCurrentlyVisiting.contains(node->mSymbol)) { checkOut << "** ERROR Cyclic inlining of ``" << node->mSymbol->mName << "''\n"; ProblemSummaryPrinter::reportError(); throw node->mSymbol; } if(mVisited.contains(node)) return; if(isOperatorSymbol(node->mSymbol)) { checkOut << "** ERROR Inlining of an operator expression ``" << node->mSymbol->mName << "''\n"; ProblemSummaryPrinter::reportError(); } mVisited.insert(node); mCurrentlyVisiting.insert(node->mSymbol); try { DefaultVisitor::visitInlinedNonTerminal(node); } catch(Model::SymbolItem* thrown) { checkOut << "\t\tinlined from ``" << node->mSymbol->mName << "''\n"; mCurrentlyVisiting.remove(node->mSymbol); if(node->mSymbol != thrown) throw; - node->mSymbol = 0; // avoid it in future + node->mSymbol = nullptr; // avoid it in future return; } mCurrentlyVisiting.remove(node->mSymbol); } diff --git a/kdev-pg/kdev-pg-unicode-loader.cpp b/kdev-pg/kdev-pg-unicode-loader.cpp index e7c7b1a..87677b1 100644 --- a/kdev-pg/kdev-pg-unicode-loader.cpp +++ b/kdev-pg/kdev-pg-unicode-loader.cpp @@ -1,127 +1,127 @@ /* This file is part of kdev-pg-qt * Copyright (C) 2011 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-unicode-loader.h" #include "kdev-pg.h" #include "kdev-pg-regexp.h" #include namespace KDevPG { #define SET_CHAR(str, i, x) \ { \ x = 0; \ for(; ; ++i) \ { \ x *= 16; \ if(str[i] >= 'a' && str[i] <= 'f') \ x += (str[i] - 'a' + 10); \ else if(str[i] >= 'A' && str[i] <= 'F') \ x += (str[i] - 'A' + 10); \ else if(str[i] >= '0' && str[i] <= '9') \ x += (str[i] - '0'); \ else \ break; \ } \ x /= 16; \ } void standardFormat(const QString fileName) { QMap res; QFile file(fileName); if(file.open(QIODevice::ReadOnly)) { while(!file.atEnd()) { auto line = file.readLine(); if(line.size() > 0 && line[0] != '#') { if(line[0] != '#') { int idxDotDot = line.indexOf(".."); if(idxDotDot != -1) { quint32 start; int i = 0; SET_CHAR(line, i, start) assert(i <= idxDotDot); i += 2; quint32 end = 0; int idxSemicolon = line.indexOf(';', idxDotDot + 2); SET_CHAR(line, i, end) assert(i <= idxSemicolon); QByteArray name = line.mid(idxSemicolon+1, (uint)(line.indexOf('#', idxSemicolon + 1)) - idxSemicolon - 1).trimmed().toLower(); name.replace(' ', '_'); name.replace('-', '_'); auto toInsert = GNFA::range(start, end+1); - if(globalSystem.regexpById[name] == 0) + if(globalSystem.regexpById[name] == nullptr) globalSystem.regexpById[name] = new GNFA(toInsert); else *globalSystem.regexpById[name] |= toInsert; } else { quint32 single; int i = 0; SET_CHAR(line, i, single); int idxSemicolon = line.indexOf(';', i); QByteArray name = line.mid(idxSemicolon+1, (uint)(line.indexOf('#', idxSemicolon + 1)) - idxSemicolon - 1).trimmed().toLower(); name.replace(' ', '_'); name.replace('-', '_'); auto toInsert = GNFA::character(single); - if(globalSystem.regexpById[name] == 0) + if(globalSystem.regexpById[name] == nullptr) globalSystem.regexpById[name] = new GNFA(toInsert); else *globalSystem.regexpById[name] |= toInsert; } } } } } else qFatal("** ERROR Failed to open unicode-data-file ``%s''", fileName.toUtf8().data()); } void loadUnicodeData() { static bool loaded = false; if(!loaded) { loaded = true; standardFormat(":/unidata/Blocks.txt"); standardFormat(":/unidata/PropList.txt"); standardFormat(":/unidata/DerivedCoreProperties.txt"); standardFormat(":/unidata/Scripts.txt"); standardFormat(":/unidata/ScriptExtensions.txt"); standardFormat(":/unidata/DerivedNumericType.txt"); globalSystem.regexpById["num"] = new GNFA(*globalSystem.regexpById["numeric"]); *globalSystem.regexpById["num"] |= *globalSystem.regexpById["digit"]; *globalSystem.regexpById["num"] |= *globalSystem.regexpById["decimal"]; globalSystem.regexpById["ascii-range"] = new GNFA(GNFA::range(0, 0x80)); globalSystem.regexpById["latin1-range"] = new GNFA(GNFA::range(0, 0x100)); // IndicMatraCategory and IndicSyllabicCategory: same format, but should have a prefix, names like “vowel” are confusing when used for Indian vowels only // named sequences: other format } } } diff --git a/kdev-pg/kdev-pg-visitor.cpp b/kdev-pg/kdev-pg-visitor.cpp index e6161d3..208a310 100644 --- a/kdev-pg/kdev-pg-visitor.cpp +++ b/kdev-pg/kdev-pg-visitor.cpp @@ -1,48 +1,48 @@ /* This file is part of kdev-pg-qt Copyright (C) 2005 Roberto Raggi Copyright (C) 2006 Jakob Petsovits 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-visitor.h" namespace KDevPG { Visitor::VisitorFuncPointer Visitor::sTable[Model::NodeKindLast] = { - 0, + nullptr, reinterpret_cast(&Visitor::visitZero), reinterpret_cast(&Visitor::visitPlus), reinterpret_cast(&Visitor::visitStar), reinterpret_cast(&Visitor::visitSymbol), reinterpret_cast(&Visitor::visitAction), reinterpret_cast(&Visitor::visitAlternative), reinterpret_cast(&Visitor::visitCons), reinterpret_cast(&Visitor::visitEvolve), reinterpret_cast(&Visitor::visitTryCatch), reinterpret_cast(&Visitor::visitAlias), reinterpret_cast(&Visitor::visitTerminal), reinterpret_cast(&Visitor::visitNonTerminal), reinterpret_cast(&Visitor::visitAnnotation), reinterpret_cast(&Visitor::visitCondition), reinterpret_cast(&Visitor::visitVariableDeclaration), reinterpret_cast(&Visitor::visitOperator), reinterpret_cast(&Visitor::visitInlinedNonTerminal), }; } diff --git a/kdev-pg/kdev-pg.cpp b/kdev-pg/kdev-pg.cpp index 250212f..f4990be 100644 --- a/kdev-pg/kdev-pg.cpp +++ b/kdev-pg/kdev-pg.cpp @@ -1,456 +1,456 @@ /* This file is part of kdev-pg-qt Copyright (C) 2005 Roberto Raggi Copyright (C) 2006 Jakob Petsovits 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.h" #include "kdev-pg-ast.h" namespace KDevPG { Model::ZeroItem *zero() { Model::ZeroItem *node = createNode(); return node; } Model::PlusItem *plus(Model::Node *item) { Model::PlusItem *node = createNode(); node->mItem = item; return node; } Model::StarItem *star(Model::Node *item) { Model::StarItem *node = createNode(); node->mItem = item; return node; } Model::SymbolItem *symbol(const QString& name) { Model::SymbolItem *node = createNode(); node->mName = name; node->mCapitalizedName = name; capitalize(node->mCapitalizedName); return node; } Model::ActionItem *action(Model::Node *item, const QString& code) { Model::ActionItem *node = createNode(); node->mItem = item; node->mCode = code; return node; } Model::AlternativeItem *alternative(Model::Node *left, Model::Node *right) { Model::AlternativeItem *node = createNode(); node->mLeft = left; node->mRight = right; return node; } Model::ConsItem *cons(Model::Node *left, Model::Node *right) { Model::ConsItem *node = createNode(); node->mLeft = left; node->mRight = right; return node; } Model::EvolveItem *evolve( Model::Node *item, Model::SymbolItem *symbol, Model::VariableDeclarationItem *declarations, const QString& code) { Model::EvolveItem *node = createNode(); node->mItem = item; node->mSymbol = symbol; node->mDeclarations = declarations; node->mCode = code; return node; } Model::TryCatchItem *tryCatch(Model::Node *try_item, Model::Node *catch_item) { Model::TryCatchItem *node = createNode(); node->mTryItem = try_item; node->mCatchItem = catch_item; node->mUnsafe = false; return node; } Model::AliasItem *alias(const QString& code, Model::SymbolItem *symbol) { Model::AliasItem *node = createNode(); node->mCode = code; node->mSymbol = symbol; return node; } Model::TerminalItem *terminal(const QString& name, const QString& description) { Model::TerminalItem *node = createNode(); node->mName = name; node->mDescription = description; return node; } Model::NonTerminalItem *nonTerminal(Model::SymbolItem *symbol, const QString& arguments) { Model::NonTerminalItem *node = createNode(); node->mSymbol = symbol; node->mArguments = arguments; return node; } Model::InlinedNonTerminalItem* inlinedNonTerminal(Model::SymbolItem* symbol) { Model::InlinedNonTerminalItem *node = createNode(); node->mSymbol = symbol; return node; } Model::AnnotationItem *annotation( const QString& name, Model::Node *item, bool isSequence, Model::VariableDeclarationItem::StorageType storageType) { Model::AnnotationItem *node = createNode(); node->mItem = item; Model::VariableDeclarationItem::VariableType variableType; QString type; if (Model::TerminalItem *t = nodeCast(item)) { variableType = Model::VariableDeclarationItem::TypeToken; type = t->mName; } else if (Model::NonTerminalItem *nt = nodeCast(item)) { variableType = Model::VariableDeclarationItem::TypeNode; type = nt->mSymbol->mName; } else { variableType = Model::VariableDeclarationItem::TypeVariable; // has to be set to something, or compiler gives a warning qFatal("Item must either be a terminal or a non-terminal"); Q_ASSERT(0); // ### item must either be a terminal or a nonTerminal } node->mDeclaration = variableDeclaration(Model::VariableDeclarationItem::DeclarationLocal, storageType, variableType, isSequence, name, type); return node; } Model::ConditionItem *condition(const QString& code, Model::Node *item) { Model::ConditionItem *node = createNode(); node->mCode = code; node->mItem = item; return node; } Model::VariableDeclarationItem *variableDeclaration( Model::VariableDeclarationItem::DeclarationType declarationType, Model::VariableDeclarationItem::StorageType storageType, Model::VariableDeclarationItem::VariableType variableType, bool isSequence, const QString& name, const QString& type) { Model::VariableDeclarationItem *node = createNode(); node->mName = name; node->mType = type; node->mCapitalizedType = type; capitalize(node->mCapitalizedType); node->mDeclarationType = declarationType; node->mStorageType = storageType; node->mVariableType = variableType; node->mIsSequence = isSequence; - node->mNext = 0; + node->mNext = nullptr; return node; } Settings::MemberItem *member(Settings::MemberItem::MemberKind kind, const QString& code) { Settings::MemberItem *node = createNode(); node->mMemberKind = kind; node->mCode = code; return node; } QString unescaped(const QByteArray& str) { QString ret; int cnt = 0; for(auto i = str.begin(); i < str.end(); ++i) { if(cnt++ != 0) { } if(*i == '\\') { char nxt = *++i; if(nxt == 'n') ret += '\n'; else if(nxt == 't') ret += '\t'; else if(nxt == 'f') ret += '\f'; else if(nxt == 'v') ret += '\v'; else if(nxt == 'r') ret += '\r'; else if(nxt == '0') ret += '\0'; else if(nxt == 'b') ret += '\b'; else if(nxt == 'a') ret += '\a'; else if(nxt == 'x' || nxt == 'X' || nxt == 'u' || nxt == 'U') { quint32 x = 0; for(++i; ; ++i) { x *= 16; if(i == str.end()) break; else if(*i >= 'a' && *i <= 'f') x += (*i - 'a' + 10); else if(*i >= 'A' && *i <= 'F') x += (*i - 'A' + 10); else if(*i >= '0' && *i <= '9') x += (*i - '0'); else break; } --i; x /= 16; ret += QString::fromUcs4(&x, 1); } else if(nxt == 'd' || nxt == 'D') { quint32 x = 0; for(++i; ; ++i) { x *= 10; if(i == str.end()) break; else if(*i >= '0' && *i <= '9') x += (*i - '0'); else break; } --i; x /= 10; ret += QString::fromUcs4(&x, 1); } else if(nxt == 'o' || nxt == 'O') { quint32 x = 0; for(++i; ; ++i) { x *= 8; if(i == str.end()) break; else if(*i >= '0' && *i <= '7') x += (*i - '0'); else break; } --i; x /= 8; ret += QString::fromUcs4(&x, 1); } else if(nxt == 'y' || nxt == 'Y') { quint32 x = 0; for(++i; ; ++i) { x *= 2; if(i == str.end()) break; else if(*i >= '0' && *i <= '1') x += (*i - '0'); else break; } --i; x /= 2; ret += QString::fromUcs4(&x, 1); } else ret += nxt; } else ret += *i; } return ret; } bool isOperatorSymbol(Model::SymbolItem *sym) { Model::EvolveItem *e = globalSystem.searchRule(sym); return e && e->mItem->kind == Model::OperatorItem::NodeKind; } bool reducesToEpsilon(Model::Node *node, QSet& v) { - if (node == 0) + if (node == nullptr) return true; if (v.contains(node)) return true; v.insert(node); if (Model::ConsItem *c = nodeCast(node)) { return reducesToEpsilon(c->mLeft, v) && reducesToEpsilon(c->mRight, v); } else if (nodeCast(node)) { return false; } else if (Model::AlternativeItem *a = nodeCast(node)) { return reducesToEpsilon(a->mLeft, v) || reducesToEpsilon(a->mRight, v); } else if (Model::ActionItem *a = nodeCast(node)) { if(a->mItem) return reducesToEpsilon(a->mItem, v); else return true; } else if (Model::ConditionItem *c = nodeCast(node)) { return reducesToEpsilon(c->mItem, v); } else if (Model::TryCatchItem *t = nodeCast(node)) { return reducesToEpsilon(t->mTryItem, v) || (t->mCatchItem && reducesToEpsilon(t->mCatchItem, v)); } else if (Model::AnnotationItem *a = nodeCast(node)) { return reducesToEpsilon(a->mItem, v); } else if (Model::NonTerminalItem *n = nodeCast(node)) { return reducesToEpsilon(n->mSymbol, v); } else if (Model::InlinedNonTerminalItem *n = nodeCast(node)) { return reducesToEpsilon(n->mSymbol, v); } else if (Model::SymbolItem *s = nodeCast(node)) { return globalSystem.first(s).find(globalSystem.zero()) != globalSystem.first(s).end(); // hmm } else if (Model::PlusItem *p = nodeCast(node)) { return reducesToEpsilon(p->mItem, v); } else if (nodeCast(node)) { return true; } else if (nodeCast(node)) { return true; } return false; } bool reducesToEpsilon(Model::Node *node) { QSet v; return reducesToEpsilon(node, v); } bool isZero(Model::Node *node) { if (Model::ActionItem *a = nodeCast(node)) { return isZero(a->mItem); } else if (Model::ConditionItem *c = nodeCast(node)) { return isZero(c->mItem); } else if (Model::AnnotationItem *a = nodeCast(node)) { return isZero(a->mItem); } else if (Model::PlusItem *p = nodeCast(node)) { return isZero(p->mItem); } else if (Model::StarItem *s = nodeCast(node)) { return isZero(s->mItem); } else if (nodeCast(node)) { return true; } return false; } Model::Operator *makeOperator(Model::Node *tok, const QString& cond, const QString& code) { Model::Operator *op = new Model::Operator; op->mTok = tok; op->mCond = cond; op->mCode = code; return op; } } QTextStream& operator << (QTextStream& out, KDevPG::Model::Node const *__node) { KDevPG::Model::Node *node = const_cast(__node); if (KDevPG::nodeCast(node)) return (out << "0"); else if (KDevPG::Model::SymbolItem *s = KDevPG::nodeCast(node)) return (out << s->mName); else if (KDevPG::Model::TerminalItem *t = KDevPG::nodeCast(node)) return (out << t->mName); else if (KDevPG::Model::AnnotationItem *a = KDevPG::nodeCast(node)) return (out << ((a->mDeclaration->mIsSequence) ? "#" : "") << a->mDeclaration->mName << ((a->mDeclaration->mStorageType == KDevPG::Model::VariableDeclarationItem::StorageTemporary) ? ":" : "=") << a->mItem); #if 0 else if (Model::EvolveItem *e = nodeCast(node)) return (out << "evolve:" << e->mSymbol->mName); #endif Q_ASSERT(0); return out; } diff --git a/kdev-pg/kdev-pg.h b/kdev-pg/kdev-pg.h index 6c20fb9..d6d4c0f 100644 --- a/kdev-pg/kdev-pg.h +++ b/kdev-pg/kdev-pg.h @@ -1,350 +1,350 @@ /* This file is part of kdev-pg-qt Copyright (C) 2005 Roberto Raggi Copyright (C) 2006 Jakob Petsovits 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. */ #ifndef KDEV_PG_H #define KDEV_PG_H #include "kdev-pg-ast.h" #include #include #include #include #include #include #include #include #include #include #include namespace KDevPG { class GNFA; class GDFA; void deleteNFA(GNFA*); void deleteDFA(GDFA*); Model::ZeroItem *zero(); Model::PlusItem *plus(Model::Node *item); Model::StarItem *star(Model::Node *item); Model::SymbolItem *symbol(const QString& name); Model::ActionItem *action(Model::Node *item, const QString& code); Model::AlternativeItem *alternative(Model::Node *left, Model::Node *right); Model::ConsItem *cons(Model::Node *left, Model::Node *right); Model::EvolveItem *evolve( Model::Node *item, Model::SymbolItem *symbol, Model::VariableDeclarationItem *declarations, const QString& code ); Model::TryCatchItem *tryCatch(Model::Node *try_item, Model::Node *catch_item); Model::AliasItem *alias(const QString& code, Model::SymbolItem *symbol); Model::TerminalItem *terminal(const QString& name, const QString& description); Model::NonTerminalItem *nonTerminal(Model::SymbolItem *symbol, const QString& arguments); Model::InlinedNonTerminalItem *inlinedNonTerminal(Model::SymbolItem *symbol); Model::ConditionItem *condition(const QString& code, Model::Node *item); Model::AnnotationItem *annotation( const QString& name, Model::Node *item, bool isSequence, Model::VariableDeclarationItem::StorageType storageType ); Model::VariableDeclarationItem *variableDeclaration( Model::VariableDeclarationItem::DeclarationType declarationType, Model::VariableDeclarationItem::StorageType storageType, Model::VariableDeclarationItem::VariableType variableType, bool isSequence, const QString& name, const QString& type ); bool isOperatorSymbol(Model::SymbolItem *node); Settings::MemberItem *member(Settings::MemberItem::MemberKind kind, const QString& code); Model::Operator *makeOperator(Model::Node *tok, const QString& cond, const QString& code); inline void capitalize(QString& str) { if(!str.isEmpty()) str.replace(0, 1, str.at(0).toUpper()); } inline QString capitalized(const QString& str) { QString ret(str); capitalize(ret); return ret; } QString unescaped(const QByteArray& str); class World { public: struct MemberCode { QList declarations; QList constructorCode; QList destructorCode; }; typedef QSet NodeSet; typedef QMap SymbolSet; typedef QMap TerminalSet; typedef QMultiMap Environment; typedef QMultiMap NamespaceSet; typedef QMap, NodeSet> FirstSet; typedef QMap, NodeSet> FollowSet; /**pair: list of rules whose FIRST set is used to calculate FOLLOW, list of rules whose FOLLOW set is used to calculate FOLLOW*/ typedef QPair FollowDep; /**key: rule whose FOLLOW set has a dependency on other rules' FIRST and FOLLOW, value: follow set dependency*/ typedef QMap FollowDeps; typedef QMap AstBaseClasses; World() : tokenStream("KDevPG::TokenStream"), language(), ns(), decl(), bits(), exportMacro(""), exportMacroHeader(), astCode(""), namespaceCode(""), inputStream("KDevPG::QUtf16ToUcs4Iterator"), generateAst(true), hasLexer(false), generateSerializeVisitor(false), generateDebugVisitor(false), generateTokenText(false), needStateManagement(false), needOperatorStack(false), lineNumberPolicy(FullLineNumbers), visitorTable(false), - conflictHandling(Permissive), mZero(0), + conflictHandling(Permissive), mZero(nullptr), lexerBaseClass("KDevPG::TokenStream") {} ~World() { for(auto i = regexpById.begin(); i != regexpById.end(); ++i) deleteNFA(*i); for(auto i = lexerEnvResults.begin(); i != lexerEnvResults.end(); ++i) deleteNFA(*i); for(auto i = dfaForNfa.begin(); i != dfaForNfa.end(); ++i) deleteDFA(*i); } // options QString tokenStream; QString language; QString ns; QString decl; QString bits; QString lexerBits; QString exportMacro; QString exportMacroHeader; QString astCode; QString namespaceCode; QStringList parserDeclarationHeaders; QStringList parserBitsHeaders; QStringList astHeaders; QStringList lexerDeclarationHeaders; QStringList lexerBitsHeaders; QString inputStream; bool generateAst: 1; bool hasLexer: 1; bool generateSerializeVisitor: 1; bool generateDebugVisitor: 1; bool generateTokenText: 1; bool needStateManagement: 1; bool needOperatorStack: 1; enum { BeautifulCode, CompatibilityLineNumbers, FullLineNumbers } lineNumberPolicy; bool beautifulCode: 1; bool visitorTable: 1; enum { Ignore = 0, Permissive = 1, Strict = 2 } conflictHandling: 2; Model::ZeroItem *zero() { if (!mZero) mZero = KDevPG::zero(); return mZero; } Model::TerminalItem *terminal(QString __name) { QString name = __name; TerminalSet::iterator it = terminals.find(name); if (it == terminals.end()) return KDevPG::terminal(__name, __name); return (*it); } void pushRule(Model::Node *rule) { Model::EvolveItem *e = nodeCast(rule); - Q_ASSERT(e != 0); + Q_ASSERT(e != nullptr); rules.push_back(e); } void pushParserClassMember(Model::Node *member) { Settings::MemberItem *m = nodeCast(member); - Q_ASSERT(m != 0); + Q_ASSERT(m != nullptr); if (m->mMemberKind == Settings::MemberItem::ConstructorCode) parserclassMembers.constructorCode.push_back(m); else if (m->mMemberKind == Settings::MemberItem::DestructorCode) parserclassMembers.destructorCode.push_back(m); else // public, protected or private declaration parserclassMembers.declarations.push_back(m); } void pushLexerClassMember(Model::Node *member) { Settings::MemberItem *m = nodeCast(member); - Q_ASSERT(m != 0); + Q_ASSERT(m != nullptr); if (m->mMemberKind == Settings::MemberItem::ConstructorCode) lexerclassMembers.constructorCode.push_back(m); else if (m->mMemberKind == Settings::MemberItem::DestructorCode) lexerclassMembers.destructorCode.push_back(m); else // public, protected or private declaration lexerclassMembers.declarations.push_back(m); } Model::TerminalItem *pushTerminal(QString __name, QString __description) { QString name = __name; TerminalSet::iterator it = terminals.find(name); if (it == terminals.end()) it = terminals.insert(name, KDevPG::terminal(__name, __description)); return (*it); } Model::SymbolItem *pushSymbol(QString __name) { QString name = __name; SymbolSet::iterator it = symbols.find(name); if (it == symbols.end()) { it = symbols.insert(name, KDevPG::symbol(__name)); start.insert(*it); } else start.remove(*it); return (*it); } void pushParserDeclarationHeader(QString file) { parserDeclarationHeaders << file; } void pushParserBitsHeader(QString file) { parserBitsHeaders << file; } void pushAstHeader(QString file) { astHeaders << file; } void pushLexerBitsHeader(QString file) { lexerBitsHeaders << file; } void pushLexerDeclarationHeader(QString file) { lexerDeclarationHeaders << file; } inline static bool ruleComp(Model::Node *a, Model::Node *b) { - if(a != 0 && a->kind == Model::NodeKindEvolve) + if(a != nullptr && a->kind == Model::NodeKindEvolve) a = ((Model::EvolveItem*)a)->mSymbol; - if(b != 0 && b->kind == Model::NodeKindEvolve) + if(b != nullptr && b->kind == Model::NodeKindEvolve) b = ((Model::EvolveItem*)b)->mSymbol; return a < b; } void finishedParsing() { std::sort(rules.begin(), rules.end(), &ruleComp); } Model::EvolveItem *searchRule(Model::SymbolItem *sym) { auto i = std::lower_bound(rules.begin(), rules.end(), sym, &ruleComp); if(i == rules.end() || (*i)->mSymbol != sym) - return 0; + return nullptr; return *i; } FirstSet::iterator firstBegin() { return firstSet.begin(); } FirstSet::iterator firstEnd() { return firstSet.end(); } FollowSet::iterator followBegin() { return followSet.begin(); } FollowSet::iterator followEnd() { return followSet.end(); } NodeSet &first(Model::Node *node, int K = 1) { return firstSet[qMakePair(node, K)]; } NodeSet &follow(Model::Node *node, int K = 1) { return followSet[qMakePair(node, K)]; } FollowDep &followDep(Model::Node *node) { return followDeps[node]; } FirstSet::iterator findInFirst(Model::Node *node, int K = 1) { return firstSet.find(qMakePair(node, K)); } FollowSet::iterator findInFollow(Model::Node *node, int K = 1) { return followSet.find(qMakePair(node, K)); } QSet start; Model::ZeroItem *mZero; SymbolSet symbols; TerminalSet terminals; QList rules; MemberCode parserclassMembers, lexerclassMembers; AstBaseClasses astBaseClasses; QString parserBaseClass, lexerBaseClass; QMap > lexerEnvs; QMap lexerEnvResults; QMap > lexerActions; QMap regexpById; QMap enteringCode, leavingCode; QMap dfaForNfa; Environment env; private: FirstSet firstSet; FollowSet followSet; FollowDeps followDeps; }; bool reducesToEpsilon(Model::Node *node); bool isZero(Model::Node *node); extern KDevPG::World globalSystem; extern QFile file; } QTextStream& operator << (QTextStream& out, KDevPG::Model::Node const *__node); #endif // KDEV_PG_H diff --git a/tests/benchmarks.cpp b/tests/benchmarks.cpp index 47ef59e..27239b5 100644 --- a/tests/benchmarks.cpp +++ b/tests/benchmarks.cpp @@ -1,361 +1,361 @@ /* Copyright 2009 Milian Wolff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 "benchmarks.h" #include #include #include #include #include #include "../include/kdev-pg-location-table.h" #include #include using namespace std; namespace KDevPG { class BenchmarkLocationTable : public LocationTable { public: BenchmarkLocationTable() : LocationTable(), m_lastLine(0) { /// number of lines in each table const int lines = 12500; /// every i-th line has i chars, which gets reset each \p charResetLine line. const int charResetLine = 160; tableMaxOffset = 0; for ( int i = 0; i < lines; ++i ) { tableMaxOffset += tableMaxOffset % charResetLine + 1; newline(tableMaxOffset); } } /** * Implements a bisection algorithm / binary search * for the offset. * * Should perform pretty good for any kind of usage, but potentially not * as good as positionAtWithMemory for linear access. */ void positionAtQtBisection(qint64 offset, qint64 *line, qint64 *column) const { if ( offset < 0 ) { *line = -1; *column = -1; return; } else if ( offset > lines[currentLine - 1] ) { *line = currentLine - 1; *column = offset - lines[currentLine - 1]; return; } qint64 i = -1; // search relative to last line (next line and the one after that) if ( m_lastLine + 1 < currentLine && lines[m_lastLine] <= offset ) { if ( lines[m_lastLine + 1] > offset ) { // last matched line matches again i = m_lastLine; } else if ( m_lastLine + 2 < currentLine && lines[m_lastLine + 2] > offset ) { // next line relative to last matched matches i = m_lastLine + 1; } } if ( i == -1 ) { // fallback to binary search qint64 *it = std::lower_bound(lines, lines + currentLine, offset); Q_ASSERT(it != lines + currentLine); if (*it != offset) { --it; } *line = it - lines; *column = offset - *it; } else { *line = i; *column = offset - lines[i]; } m_lastLine = *line; } /** * Uses old algorithm as written by Roberto Raggi in r687144 (kdevelop-pg/include/kdev-pg-location-table.h) */ void positionAtSTLBisection(qint64 offset, qint64 *line, qint64 *column) const { if ( offset < 0 ) { *line = -1; *column = -1; return; } else if ( offset > lines[currentLine - 1] ) { *line = currentLine - 1; *column = offset - lines[currentLine - 1]; return; } qint64 i = -1; // search relative to last line (next line and the one after that) if ( m_lastLine + 1 < currentLine && lines[m_lastLine] <= offset ) { if ( lines[m_lastLine + 1] > offset ) { // last matched line matches again i = m_lastLine; } else if ( m_lastLine + 2 < currentLine && lines[m_lastLine + 2] > offset ) { // next line relative to last matched matches i = m_lastLine + 1; } } if ( i == -1 ) { // fallback to binary search qint64 *it = std::lower_bound(lines, lines + currentLine, offset); Q_ASSERT(it != lines + currentLine); if (*it != offset) { --it; } *line = it - lines; *column = offset - *it; } else { *line = i; *column = offset - lines[i]; } m_lastLine = *line; } qint64 tableMaxOffset; private: mutable qint64 m_lastLine; }; void Benchmarks::initTestCase() { - srand ( time(NULL) ); + srand ( time(nullptr) ); } void Benchmarks::positionAt() { QFETCH(int, algorithm); QFETCH(int, access); BenchmarkLocationTable table; qint64 line; qint64 column; switch ( algorithm) { case CurrentPositionAt: { switch ( access ) { case LinearAccess: { QBENCHMARK { for ( qint64 i = 0; i < table.tableMaxOffset; i += 10 ) { table.positionAt(i, &line, &column); } } break; } case RandomAccess: { QBENCHMARK { for ( qint64 i = 0; i < table.tableMaxOffset; i += 10 ) { table.positionAt(rand() % table.tableMaxOffset, &line, &column); } } break; } default: qFatal("unexpected access type"); break; } break; } case QtBinaryPositionAt: { switch ( access ) { case LinearAccess: { QBENCHMARK { for ( qint64 i = 0; i < table.tableMaxOffset; i += 10 ) { table.positionAtQtBisection(i, &line, &column); } } break; } case RandomAccess: { QBENCHMARK { for ( qint64 i = 0; i < table.tableMaxOffset; i += 10 ) { table.positionAtQtBisection(rand() % table.tableMaxOffset, &line, &column); } } break; } default: qFatal("unexpected access type"); break; } break; } case STLBinaryPositionAt: { switch ( access ) { case LinearAccess: { QBENCHMARK { for ( qint64 i = 0; i < table.tableMaxOffset; i += 10 ) { table.positionAtSTLBisection(i, &line, &column); } } break; } case RandomAccess: { QBENCHMARK { for ( qint64 i = 0; i < table.tableMaxOffset; i += 10 ) { table.positionAtSTLBisection(rand() % table.tableMaxOffset, &line, &column); } } break; } default: qFatal("unexpected access type"); break; } break; } } } void Benchmarks::positionAt_data() { QTest::addColumn("algorithm"); QTest::addColumn("access"); QTest::newRow("current, linear") << (int) CurrentPositionAt << (int) LinearAccess; QTest::newRow("current, random") << (int) CurrentPositionAt << (int) RandomAccess; QTest::newRow("qt binary, linear") << (int) QtBinaryPositionAt << (int) LinearAccess; QTest::newRow("qt binary, random") << (int) QtBinaryPositionAt << (int) RandomAccess; QTest::newRow("stl binary, linear") << (int) STLBinaryPositionAt << (int) LinearAccess; QTest::newRow("stl binary, random") << (int) STLBinaryPositionAt << (int) RandomAccess; } void Benchmarks::verifyPositionAt() { QFETCH(int, algorithm); QFETCH(int, access); BenchmarkLocationTable table; qint64 oldLine; qint64 oldColumn; qint64 newLine; qint64 newColumn; switch ( algorithm) { case QtBinaryPositionAt: { switch ( access ) { case LinearAccess: { for ( qint64 i = 0; i < table.tableMaxOffset; i += 10 ) { table.positionAt(i, &oldLine, &oldColumn); table.positionAtQtBisection(i, &newLine, &newColumn); QCOMPARE(newLine, oldLine); QCOMPARE(newColumn, oldColumn); } // special cases // underflow table.positionAt(-5, &oldLine, &oldColumn); table.positionAtQtBisection(-5, &newLine, &newColumn); QCOMPARE(newLine, oldLine); QCOMPARE(newColumn, oldColumn); // overflow table.positionAt(table.tableMaxOffset + 10, &oldLine, &oldColumn); table.positionAtQtBisection(table.tableMaxOffset + 10, &newLine, &newColumn); QCOMPARE(newLine, oldLine); QCOMPARE(newColumn, oldColumn); break; } case RandomAccess: { for ( qint64 i = 0; i < table.tableMaxOffset; i += 10 ) { qint64 offset = rand() % table.tableMaxOffset; table.positionAt(offset, &oldLine, &oldColumn); table.positionAtQtBisection(offset, &newLine, &newColumn); QCOMPARE(newLine, oldLine); QCOMPARE(newColumn, oldColumn); } break; } default: qFatal("unexpected access type"); break; } break; } case STLBinaryPositionAt: { switch ( access ) { case LinearAccess: { for ( qint64 i = 0; i < table.tableMaxOffset; i += 10 ) { table.positionAt(i, &oldLine, &oldColumn); table.positionAtSTLBisection(i, &newLine, &newColumn); QCOMPARE(newLine, oldLine); QCOMPARE(newColumn, oldColumn); } // special cases // underflow table.positionAt(-5, &oldLine, &oldColumn); table.positionAtSTLBisection(-5, &newLine, &newColumn); QCOMPARE(newLine, oldLine); QCOMPARE(newColumn, oldColumn); // overflow table.positionAt(table.tableMaxOffset + 10, &oldLine, &oldColumn); table.positionAtSTLBisection(table.tableMaxOffset + 10, &newLine, &newColumn); QCOMPARE(newLine, oldLine); QCOMPARE(newColumn, oldColumn); break; } case RandomAccess: { for ( qint64 i = 0; i < table.tableMaxOffset; i += 10 ) { qint64 offset = rand() % table.tableMaxOffset; table.positionAt(offset, &oldLine, &oldColumn); table.positionAtSTLBisection(offset, &newLine, &newColumn); QCOMPARE(newLine, oldLine); QCOMPARE(newColumn, oldColumn); } break; } default: qFatal("unexpected access type"); break; } break; } default: qFatal("unexpected algorithm"); break; } } void Benchmarks::verifyPositionAt_data() { QTest::addColumn("algorithm"); QTest::addColumn("access"); QTest::newRow("qt binary, linear") << (int) QtBinaryPositionAt << (int) LinearAccess; QTest::newRow("qt binary, random") << (int) QtBinaryPositionAt << (int) RandomAccess; QTest::newRow("stl binary, linear") << (int) STLBinaryPositionAt << (int) LinearAccess; QTest::newRow("stl binary, random") << (int) STLBinaryPositionAt << (int) RandomAccess; } } QTEST_MAIN(KDevPG::Benchmarks)