-
Notifications
You must be signed in to change notification settings - Fork 1
/
non_terminal.cs
361 lines (295 loc) · 11.5 KB
/
non_terminal.cs
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
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
namespace CUP
{
using System;
/// <summary>This class represents a non-terminal symbol in the grammar. Each
/// non terminal has a textual name, an index, and a string which indicates
/// the type of object it will be implemented with at runtime (i.e. the class
/// of object that will be pushed on the parse stack to represent it).
/// *
/// </summary>
/// <version> last updated: 11/25/95
/// </version>
/// <author> Scott Hudson
///
/// </author>
public class non_terminal:symbol
{
private void InitBlock()
{
_productions = new System.Collections.Hashtable(11);
_first_set = new terminal_set();
}
/*-----------------------------------------------------------*/
/*--- Constructor(s) ----------------------------------------*/
/*-----------------------------------------------------------*/
/// <summary>Full constructor.
/// </summary>
/// <param name="nm"> the name of the non terminal.
/// </param>
/// <param name="tp"> the type string for the non terminal.
///
/// </param>
public non_terminal(string nm, string tp):base(nm, tp)
{
InitBlock();
/* add to set of all non terminals and check for duplicates */
System.Object conflict = SupportClass.PutElement(_all, nm, this);
if (conflict != null)
(new internal_error("Duplicate non-terminal (" + nm + ") created")).crash();
/* assign a unique index */
_index = next_index++;
/* add to by_index set */
SupportClass.PutElement(_all_by_index, _index, this);
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>Constructor with default type.
/// </summary>
/// <param name="nm"> the name of the non terminal.
///
/// </param>
public non_terminal(string nm):this(nm, null)
{
InitBlock();
}
/*-----------------------------------------------------------*/
/*--- (Access to) Static (Class) Variables ------------------*/
/*-----------------------------------------------------------*/
/// <summary>Table of all non-terminals -- elements are stored using name strings
/// as the key
/// </summary>
protected internal static System.Collections.Hashtable _all = new System.Collections.Hashtable();
/// <summary>Access to all non-terminals.
/// </summary>
public static System.Collections.IEnumerator all()
{
return _all.Values.GetEnumerator();
}
/// <summary>lookup a non terminal by name string
/// </summary>
public static non_terminal find(string with_name)
{
if (with_name == null)
return null;
else
return (non_terminal) _all[with_name];
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>Table of all non terminals indexed by their index number.
/// </summary>
protected internal static System.Collections.Hashtable _all_by_index = new System.Collections.Hashtable();
/// <summary>Lookup a non terminal by index.
/// </summary>
public static non_terminal find(int indx)
{
System.Int32 the_indx = indx;
return (non_terminal) _all_by_index[the_indx];
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>Total number of non-terminals.
/// </summary>
public static int number()
{
return _all.Count;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>Static counter to assign unique indexes.
/// </summary>
protected internal static int next_index = 0;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>Static counter for creating unique non-terminal names
/// </summary>
protected internal static int next_nt = 0;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>special non-terminal for start symbol
/// </summary>
//UPGRADE_NOTE: Final was removed from the declaration of 'START_nt '. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1003"'
public static non_terminal START_nt = new non_terminal("$START");
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>flag non-terminals created to embed action productions
/// </summary>
public bool is_embedded_action = false; /* added 24-Mar-1998, CSA */
/*-----------------------------------------------------------*/
/*--- Static Methods ----------------------------------------*/
/*-----------------------------------------------------------*/
/// <summary>Method for creating a new uniquely named hidden non-terminal using
/// the given string as a base for the name (or "NT$" if null is passed).
/// </summary>
/// <param name="prefix">base name to construct unique name from.
///
/// </param>
internal static non_terminal create_new(string prefix)
{
if (prefix == null)
prefix = "NT$";
return new non_terminal(prefix + next_nt++);
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>static routine for creating a new uniquely named hidden non-terminal
/// </summary>
internal static non_terminal create_new()
{
return create_new(null);
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>Compute nullability of all non-terminals.
/// </summary>
public static void compute_nullability()
{
bool change = true;
non_terminal nt;
System.Collections.IEnumerator e;
production prod;
/* repeat this process until there is no change */
while (change)
{
/* look for a new change */
change = false;
/* consider each non-terminal */
//UPGRADE_TODO: method 'java.util.Enumeration.hasMoreElements' was converted to ' ' which has a different behavior. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1073_javautilEnumerationhasMoreElements"'
for (e = all(); e.MoveNext(); )
{
//UPGRADE_TODO: method 'java.util.Enumeration.nextElement' was converted to ' ' which has a different behavior. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1073_javautilEnumerationnextElement"'
nt = (non_terminal) e.Current;
/* only look at things that aren't already marked nullable */
if (!nt.nullable())
{
if (nt.looks_nullable())
{
nt._nullable = true;
change = true;
}
}
}
}
/* do one last pass over the productions to finalize all of them */
for (e = production.all(); e.MoveNext(); )
{
prod = (production) e.Current;
prod.set_nullable(prod.check_nullable());
}
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>Compute first sets for all non-terminals. This assumes nullability has
/// already computed.
/// </summary>
public static void compute_first_sets()
{
bool change = true;
System.Collections.IEnumerator n;
System.Collections.IEnumerator p;
non_terminal nt;
production prod;
terminal_set prod_first;
/* repeat this process until we have no change */
while (change)
{
/* look for a new change */
change = false;
/* consider each non-terminal */
for (n = all(); n.MoveNext(); )
{
nt = (non_terminal) n.Current;
/* consider every production of that non terminal */
for (p = nt.productions(); p.MoveNext(); )
{
prod = (production) p.Current;
/* get the updated first of that production */
prod_first = prod.check_first_set();
/* if this going to add anything, add it */
if (!prod_first.is_subset_of(nt._first_set))
{
change = true;
nt._first_set.add(prod_first);
}
}
}
}
}
/*-----------------------------------------------------------*/
/*--- (Access to) Instance Variables ------------------------*/
/*-----------------------------------------------------------*/
/// <summary>Table of all productions with this non terminal on the LHS.
/// </summary>
//UPGRADE_NOTE: The initialization of '_productions' was moved to method 'InitBlock'. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1005"'
protected internal System.Collections.Hashtable _productions;
/// <summary>Access to productions with this non terminal on the LHS.
/// </summary>
public virtual System.Collections.IEnumerator productions()
{
return _productions.Values.GetEnumerator();
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>Total number of productions with this non terminal on the LHS.
/// </summary>
public virtual int num_productions()
{
return _productions.Count;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>Add a production to our set of productions.
/// </summary>
public virtual void add_production(production prod)
{
/* catch improper productions */
if (prod == null || prod.lhs() == null || prod.lhs().the_symbol() != this)
throw new internal_error("Attempt to add invalid production to non terminal production table");
/* add it to the table, keyed with itself */
SupportClass.PutElement(_productions, prod, prod);
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>Nullability of this non terminal.
/// </summary>
protected internal bool _nullable;
/// <summary>Nullability of this non terminal.
/// </summary>
public virtual bool nullable()
{
return _nullable;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>First set for this non-terminal.
/// </summary>
//UPGRADE_NOTE: The initialization of '_first_set' was moved to method 'InitBlock'. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1005"'
protected internal terminal_set _first_set;
/// <summary>First set for this non-terminal.
/// </summary>
public virtual terminal_set first_set()
{
return _first_set;
}
/*-----------------------------------------------------------*/
/*--- General Methods ---------------------------------------*/
/*-----------------------------------------------------------*/
/// <summary>Indicate that this symbol is a non-terminal.
/// </summary>
public override bool is_non_term()
{
return true;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>Test to see if this non terminal currently looks nullable.
/// </summary>
protected internal virtual bool looks_nullable()
{
/* look and see if any of the productions now look nullable */
//UPGRADE_TODO: method 'java.util.Enumeration.hasMoreElements' was converted to ' ' which has a different behavior. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1073_javautilEnumerationhasMoreElements"'
for (System.Collections.IEnumerator e = productions(); e.MoveNext(); )
{
//UPGRADE_TODO: method 'java.util.Enumeration.nextElement' was converted to ' ' which has a different behavior. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1073_javautilEnumerationnextElement"'
if (((production) e.Current).check_nullable())
return true;
}
/* none of the productions can go to empty, so we are not nullable */
return false;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/// <summary>convert to string
/// </summary>
public override string ToString()
{
//UPGRADE_TODO: The equivalent in .NET for method 'java.Object.toString' may return a different value. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1043"'
return base.ToString() + "[" + index() + "]" + (nullable()?"*":"");
}
/*-----------------------------------------------------------*/
}
}