File: State.cpp

package info (click to toggle)
storm-lang 0.7.4-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 52,004 kB
  • sloc: ansic: 261,462; cpp: 140,405; sh: 14,891; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (180 lines) | stat: -rw-r--r-- 5,282 bytes parent folder | download | duplicates (3)
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
#include "stdafx.h"
#include "State.h"
#include "Parser.h"

namespace storm {
	namespace syntax {
		namespace earley {

			StatePtr::StatePtr() : step(-1), index(-1) {}

			StatePtr::StatePtr(Nat step, Nat index) : step(step), index(index) {}

			void StatePtr::toS(StrBuf *to) const {
				*to << S("(") << step << S(", ") << index << S(")");
			}

			wostream &operator <<(wostream &to, StatePtr p) {
				return to << L"(" << p.step << L", " << p.index << L")";
			}

			State::State() : from(0) {}

			State::State(ProductionIter pos, Nat from) : pos(pos), from(from) {}

			State::State(ProductionIter pos, Nat from, StatePtr prev)
				: pos(pos), from(from), prev(prev) {}

			State::State(ProductionIter pos, Nat from, StatePtr prev, StatePtr completed)
				: pos(pos), from(from), prev(prev), completed(completed) {}

			void State::toS(StrBuf *to) const {
				*to << S("{") << pos << S(", ") << from << S(", ") << prev << S(", ") << completed << S("}");
			}

			wostream &operator <<(wostream &to, State s) {
				return to << L"{" << s.pos << L", " << s.from << L", " << s.prev << L", " << s.completed << L"}";
			}

			StateSet::StateSet() : chunks(null) {
				stateArrayType = StormInfo<State>::handle(engine()).gcArrayType;
			}

			void StateSet::push(Parser *parser, const State &s) {
				if (!s.valid())
					return;

				// TODO: Optimize this somehow. A lot of time is spent here!
				Nat chunkCount = chunks ? Nat(chunks->filled) : 0;
				for (nat c = 0; c < chunkCount; c++) {
					GcArray<State> *chunk = chunks->v[c];
					Nat cnt = Nat(chunk->filled);
					for (nat i = 0; i < cnt; i++) {
						State &old = chunk->v[i];
						if (old == s) {
							// Generated this state alreadly, shall we update it?

							// Keep the largest in a lexiographic ordering.
							if (execOrder(parser, s, old) != before)
								return;

							chunk->v[i] = s;
							return;
						}
					}
				}

				// Push the new state somewhere.
				GcArray<State> *last = null;
				if (chunks == null) {
					ensure(1);
					last = chunks->v[0];
				} else {
					last = chunks->v[chunks->filled - 1];
				}

				if (last->filled >= chunkSize) {
					ensure(Nat(chunks->filled + 1));
					last = chunks->v[chunks->filled - 1];
				}

				last->v[last->filled++] = s;
			}

			void StateSet::ensure(Nat n) {
				// Need to resize the array?
				if (chunks == null || chunks->count < n) {
					Nat newCount = 1;
					if (chunks)
						newCount = 2 * Nat(chunks->count);
					newCount = max(n, newCount);

					GcArray<GcArray<State> *> *old = chunks;
					chunks = runtime::allocArray<GcArray<State> *>(engine(), &pointerArrayType, newCount);
					if (old) {
						memcpy(chunks->v, old->v, sizeof(void *)*old->count);
						chunks->filled = old->filled;
					}
				}

				// Make sure all entries are filled.
				while (chunks->filled < n) {
					chunks->v[chunks->filled++] = runtime::allocArray<State>(engine(), stateArrayType, chunkSize);
				}
			}

			void StateSet::push(Parser *parser, ProductionIter pos, Nat from) {
				push(parser, pos, from, StatePtr(), StatePtr());
			}

			void StateSet::push(Parser *parser, ProductionIter pos, Nat from, StatePtr prev) {
				push(parser, pos, from, prev, StatePtr());
			}

			void StateSet::push(Parser *parser, ProductionIter pos, Nat from, StatePtr prev, StatePtr completed) {
				if (!pos.valid())
					return;

				push(parser, State(pos, from, prev, completed));
			}

			StateSet::Order StateSet::execOrder(Parser *parser, const StatePtr &aPtr, const StatePtr &bPtr) const {
				// Invalid states have no ordering.
				if (aPtr == StatePtr() || bPtr == StatePtr())
					return none;

				// Same state, realize that quickly!
				if (aPtr == bPtr)
					return none;

				return execOrder(parser, parser->state(aPtr), parser->state(bPtr));
			}

			StateSet::Order StateSet::execOrder(Parser *parser, const State &a, const State &b) const {
				// Check which has the highest priority.
				if (a.priority() != b.priority())
					return (a.priority() > b.priority()) ? before : after;

				// If they are different productions and noone has a higher priority than the other, the
				// ordering is undefined.
				if (a.production() != b.production())
					return none;

				// Order them lexiographically to see which has the highest priority!
				StateArray aStates(engine());
				prevCompleted(parser, a, aStates);
				StateArray bStates(engine());
				prevCompleted(parser, b, bStates);

				nat to = min(aStates.count(), bStates.count());
				for (nat i = 0; i < to; i++) {
					Order order = execOrder(parser, aStates[i], bStates[i]);
					if (order != none)
						return order;
				}

				// Pick the longer one in case they are equal so far. This makes * and + greedy.
				if (aStates.count() > bStates.count()) {
					return before;
				} else if (aStates.count() < bStates.count()) {
					return after;
				}

				// The rules are equal as far as we are concerned.
				return none;
			}

			void StateSet::prevCompleted(Parser *parser, const State &from, StateArray &to) const {
				to.clear();

				// Note: the first state is never completed, so we skip that.
				for (const State *at = &from; at->prev != StatePtr(); at = &parser->state(at->prev)) {
					to.push(at->completed);
				}

				to.reverse();
			}

		}
	}
}