1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
|
#pragma once
#include "Core/Object.h"
#include "Core/GcArray.h"
#include "Core/PODArray.h"
#include "Syntax.h"
#include "Compiler/Syntax/InfoErrors.h"
namespace storm {
namespace syntax {
namespace glr {
STORM_PKG(lang.bnf.glr);
class TreeStore;
extern const Nat countMask;
extern const Nat errorMask;
extern const Nat posMask;
inline Nat read(TreeStore *src, Nat pos);
inline void write(TreeStore *src, Nat pos, Nat val);
/**
* Easy acces to an array of children from a TreeNode.
*/
class TreeArray {
STORM_VALUE;
public:
// Does this array exist?
inline Bool STORM_FN exists() const { return ptr != 0; }
inline operator bool() const { return ptr != 0; }
// Get number of elements.
inline Nat STORM_FN count() const {
return cnt;
}
// Any elements?
inline Bool STORM_FN any() const { return count() > 0; }
inline Bool STORM_FN empty() const { return count() == 0; }
// Get element #n.
inline Nat STORM_FN operator[] (Nat i) const {
return read(src, ptr + i + 2);
}
// Set element #n.
inline void STORM_FN set(Nat i, Nat v) const {
write(src, ptr + i + 2, v);
}
// Get the reduced production.
inline Nat STORM_FN production() const {
return read(src, ptr + 1);
}
private:
friend class TreeNode;
inline TreeArray(TreeStore *in, Nat pos) {
src = in;
ptr = pos;
cnt = read(src, ptr) & ~countMask;
}
// Access to data. Might be null.
TreeStore *src;
// Starting point of this node.
Nat ptr;
// Cached element count.
Nat cnt;
};
/**
* Easy access to a tree node stored in TreeStore somewhere.
*/
class TreeNode {
STORM_VALUE;
public:
// Get a 'pointer' to this node.
inline Nat STORM_FN id() const {
return ptr;
}
// Get the starting position of this node.
inline Nat STORM_FN pos() const {
return read(src, ptr) & posMask;
}
// Set the starting position of this node.
inline void STORM_FN pos(Nat v) const {
v &= posMask;
v |= read(src, ptr) & ~posMask;
return write(src, ptr, v);
}
// Is this a leaf node (ie. no children?).
inline Bool STORM_FN leaf() const {
Nat first = read(src, ptr);
return (first & countMask) == 0;
}
// Get the child array.
inline TreeArray STORM_FN children() const {
Nat first = read(src, ptr);
if ((first & countMask) == 0)
return TreeArray(src, 0);
Nat offset = 1;
offset += (first & errorMask) != 0;
Nat pos = read(src, ptr + offset);
if (pos & countMask) {
return TreeArray(src, ptr + offset);
} else {
return TreeArray(src, pos);
}
}
// Get the number of errors encountered to reach this node.
inline InfoErrors STORM_FN errors() const {
if ((read(src, ptr) & errorMask) == 0)
return infoSuccess();
else
return InfoErrors::fromData(read(src, ptr + 1));
}
// Replace the contents of this node with another. This is only doable if both this
// and the other tree node have children. Unable to set 'errors' in some cases.
void STORM_FN replace(const TreeNode &other);
// Get the production.
inline Nat STORM_FN production() const {
return children().production();
}
private:
friend class TreeStore;
// Create with a 'pointer' to the first entry used by this node.
inline TreeNode(TreeStore *in, Nat pos) {
src = in;
ptr = pos;
}
// Access to data.
TreeStore *src;
// Starting point of this node.
Nat ptr;
};
/**
* Batch allocation of tree nodes. Note: Element #0 is always empty (acts as the null pointer).
*
* This is just an array of Nat elements. The classes TreeNode and TreeArray just read
* from here. Nodes are stored as follows (one entry per item):
* - position this node started in the input string. If msb of the position is set, this node
* contains children. If the next msb is set, this node also contains an error count.
* - number of children / 'pointer' to the data array. If msb is set, then this is a count and the
* child array is allocated right here. Otherwise, this is a pointer (possibly to null, which
* equals no children) to the child array, starting with a number of children.
* - production reduced
* - pointer to child n (n times).
*
* Implements an array-like data structure where index lookup is constant time and
* growing is also (near)constant time.
*/
class TreeStore : public ObjectOn<Compiler> {
STORM_CLASS;
public:
// Create.
STORM_CTOR TreeStore(Syntax *syntax);
// Item access.
inline TreeNode at(Nat i) {
return TreeNode(this, i);
}
// Add a new terminal node and return its ID.
TreeNode push(Nat pos);
// Add a new terminal node with a specific number of encountered errors.
TreeNode push(Nat pos, InfoErrors errors);
// Add a new nonterminal with a specific number of children.
TreeNode push(Nat pos, Nat production, Nat children);
// Add a new nonterminal with a specific number of encountered errors and a specific number of children.
TreeNode push(Nat pos, Nat production, InfoErrors errors, Nat children);
// Free a node deemed unneeded.
void free(Nat node);
// Priority for tree comparisions.
enum Priority {
higher,
equal,
lower,
};
// Find out if a node has a higher priority compared to another.
Priority STORM_FN priority(Nat a, Nat b);
// See if the node 'haystack' contains node 'needle'.
Bool STORM_FN contains(Nat haystack, Nat needle);
// Size information.
inline Nat STORM_FN count() const { return size; }
inline Nat STORM_FN byteCount() const { return size*sizeof(Nat); }
/**
* Interface that TreeNode and TreeArray are supposed to use.
*/
// Low-level access.
inline Nat read(Nat i) const {
return chunks->v[chunkId(i)]->v[chunkOffset(i)];
}
inline void write(Nat i, Nat v) const {
chunks->v[chunkId(i)]->v[chunkOffset(i)] = v;
}
private:
enum {
// Bits used for each chunk.
chunkBits = 8,
// Elements per chunk. Assumed to be a power of two.
chunkSize = 1 << chunkBits,
};
// Compute the chunk id and the chunk offset.
inline Nat chunkId(Nat id) const { return id >> chunkBits; }
inline Nat chunkOffset(Nat id) const { return id & (chunkSize - 1); }
// List of all chunks.
typedef GcArray<Nat> Chunk;
GcArray<Chunk *> *chunks;
// Current number of elements.
Nat size;
// Last allocated node ptr.
Nat lastAlloc;
// Remember the syntax.
Syntax *syntax;
// Allocate room for 'n' more items.
Nat alloc(Nat n);
// Grow 'chunks'.
void grow();
// Type for storing the expanded list of children.
typedef PODArray<Nat, 40> ChildArray;
// Traverse the node 'x' and find all subtrees wrt to pseudoproductions.
void allChildren(ChildArray &out, Nat productionId, TreeNode &node);
bool addNode(ChildArray &out, Nat productionId, Nat node);
};
inline Nat read(TreeStore *src, Nat pos) {
return src->read(pos);
}
inline void write(TreeStore *src, Nat pos, Nat val) {
src->write(pos, val);
}
}
}
}
|