File: Parser.h

package info (click to toggle)
storm-lang 0.7.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • 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 (234 lines) | stat: -rw-r--r-- 7,532 bytes parent folder | download
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
#pragma once
#include "Compiler/NamedThread.h"
#include "Compiler/Exception.h"
#include "Core/Array.h"
#include "Node.h"
#include "InfoNode.h"
#include "Rule.h"
#include "Production.h"
#include "ParserBackend.h"

namespace storm {
	namespace syntax {
		STORM_PKG(core.lang);

#ifdef DEBUG
		extern bool parserDebug;
#endif

		// Default parser to use in the system. earley or glr
#define DEFAULT_PARSER glr

		/**
		 * Base class for the templated parser in Storm. In Storm, Parser<T> is to be
		 * instantiated. This is not possible from C++ as the syntax types are not present in
		 * C++. Therefore, the interface differs a bit (C++ loses some type safety compared to
		 * Storm).
		 *
		 * TODO: Make it possible to parse things on other threads than the compiler thread.
		 */
		class ParserBase : public ObjectOn<Compiler> {
			STORM_CLASS;
		protected:
			// Create. Create via Parser from C++ as the type has to be set properly for this to work.
			ParserBase(ParserBackend *backend);

			// Create an InfoParser.
			ParserBase(Rule *root, ParserBackend *backend);

			// Common parts from the constructors.
			void init(Rule *root, ParserBackend *backend);

			// Internal function called from Storm to create a parser.
			friend void createParser(void *mem, ParserBackend *backend);

		public:
			// Add a package containing syntax definitions (not recursive).
			void STORM_FN addSyntax(Package *pkg);
			void STORM_FN addSyntax(Array<Package *> *pkg);

			// Add a package contining syntax, possibly ignoring exports.
			void STORM_FN addSyntax(Package *pkg, Bool useExports);
			void STORM_FN addSyntax(Array<Package *> *pkg, Bool useExports);

			// Does this parser contain the same syntax as 'o'?
			Bool STORM_FN sameSyntax(ParserBase *o);

			// Get the root rule.
			virtual Rule *STORM_FN root() const;

			// Parse a string. Returns 'true' if we found some match.
			Bool STORM_FN parse(Str *str, Url *file);
			Bool STORM_FN parse(Str *str, Url *file, Str::Iter start);
			virtual Bool STORM_FN parse(Str *str, Url *file, Str::Iter start, Str::Iter end);

			// Clear all parse-related information. Included packages are retained.
			virtual void STORM_FN clear();

			/**
			 * Operations on the last parse.
			 */

			// Found any errors? If Str::Iter is not end, this is always true. Note that even if we
			// have an error, it could be possible to extract a tree!
			Bool STORM_FN hasError() const;

			// Is it possible to extract a syntax tree? (equivalent to the return value of 'parse').
			Bool STORM_FN hasTree() const;

			// Return an iterator after the last matched character, or the start of the string if no
			// match could be made.
			Str::Iter STORM_FN matchEnd() const;

			// Get the error (present if 'hasError' is true).
			SyntaxError *STORM_FN error() const;

			// Throw error if it is present.
			void STORM_FN throwError() const;

			// Get the error message.
			Str *STORM_FN errorMsg() const;

			// Get the syntax tree. Only for C++, in Storm we know the exact subtype we will generate!
			Node *tree() const;

			// Get the generic syntax tree.
			InfoNode *STORM_FN infoTree() const;

			// Output.
			virtual void STORM_FN toS(StrBuf *to) const;


			/**
			 * Performance inspection:
			 */

			// Get the number of states used.
			Nat STORM_FN stateCount() const;

			// Get the number of bytes used.
			Nat STORM_FN byteCount() const;

		protected:
			// Call 'parseApprox'. Only available from 'InfoParser'.
			inline InfoErrors parseApprox(Str *str, Url *file, Str::Iter start, Str::Iter end, MAYBE(InfoInternal *) context) {
				return use->parseApprox(root(), str, file, start, end, context);
			}

			// Get the raw info tree. Never throws an exception.
			inline MAYBE(InfoNode *) unsafeInfoTree() const {
				return use->infoTree();
			}

		private:
			// Backend being used.
			ParserBackend *use;

			// Private version for adding syntax.
			void addSyntaxI(Package *pkg);
		};


		/**
		 * Generic parser supporting only generating trees of InfoNodes. However, it is possible to
		 * change the root rule of this kind of parser.
		 */
		class InfoParser : public ParserBase {
			STORM_CLASS;
		public:
			// Create.
			STORM_CTOR InfoParser(Rule *rootRule);
			STORM_CTOR InfoParser(Rule *rootRule, ParserBackend *backend);

			// Create with a package and a name.
			static InfoParser *create(Package *pkg, const wchar *name);
			static InfoParser *create(Package *pkg, const wchar *name, ParserBackend *backend);

			// Set a new root.
			void STORM_FN root(Rule *rule);

			// Get the root rule.
			virtual Rule *STORM_FN root() const;

			// Parse a string regularly. We need to keep track of what is being parsed.
			using ParserBase::parse;
			virtual Bool STORM_FN parse(Str *str, Url *file, Str::Iter start, Str::Iter end);

			// Parse a syntax tree using error recovery, optionally providing a context to properly
			// resolve dependencies when parsing parts of the input. If provided, the context is the
			// node that will be the parent of the node produced by this parse. Do not use 'tree'
			// after calling this, as 'tree' assumes a complete syntax tree (not possible from
			// Storm, as 'tree' is not exposed).
			InfoErrors STORM_FN parseApprox(Str *str, Url *file);
			InfoErrors STORM_FN parseApprox(Str *str, Url *file, Str::Iter start);
			InfoErrors STORM_FN parseApprox(Str *str, Url *file, Str::Iter start, Str::Iter end);
			InfoErrors STORM_FN parseApprox(Str *str, Url *file, InfoInternal *context);
			InfoErrors STORM_FN parseApprox(Str *str, Url *file, Str::Iter start, InfoInternal *context);
			InfoErrors STORM_FN parseApprox(Str *str, Url *file, Str::Iter start, Str::Iter end, InfoInternal *context);

			// Clear.
			virtual void STORM_FN clear();

			// Get an info tree that is always filled to the end of the tree, regardless of the
			// actual length of the match.
			InfoNode *STORM_FN fullInfoTree();

		private:
			// Root rule.
			Rule *rootRule;

			// Remember the last parsed string and start position.
			Str *lastStr;
			Nat lastBeginOffset;
			Nat lastEndOffset;
		};


		/**
		 * C++ instantiation, compatible enough to pass on to Storm. This class is not visible to
		 * the preprocessor, so use ParserBase for that.
		 *
		 * Make sure to not introduce any additional data members here, as they might get lost
		 * during accidental interfacing with Storm. This class should only contain functions that
		 * completes the interface from the C++ side.
		 */
		class Parser : public ParserBase {
		public:
			// Create a parser parsing a specific type.
			static Parser *create(Rule *root);
			static Parser *create(Rule *root, ParserBackend *backend);

			// Create a parser parsing the type named 'name' in 'pkg'.
			static Parser *create(Package *pkg, const wchar *name);
			static Parser *create(Package *pkg, const wchar *name, ParserBackend *backend);

			// Transform syntax nodes. See limitations for 'transformNode<>'.
			template <class R>
			R *transform() {
				return transformNode<R>(tree());
			}

			template <class R, class P>
			R *transform(P par) {
				return transformNode<R, P>(tree(), par);
			}

		private:
			// Use 'create'.
			Parser(ParserBackend *backend);
		};


		/**
		 * Create parser backends.
		 */
		Nat STORM_FN backendCount();
		ParserBackend *STORM_FN createBackend(EnginePtr e, Nat id);


		// Declare the template. This does not match the above declaration, so use ParserBase to
		// store Parser instances in classes!
		STORM_TEMPLATE(Parser, createParser);

	}
}