@@ -294,7 +294,16 @@ def is_done(self):
294
294
return self .top () == self .head () == HASH
295
295
296
296
def match (self ):
297
- """Attempts a match move and returns the corresponding new instantaneous description."""
297
+ """Performs a match move.
298
+
299
+ If the top of the stack is ε, it will be removed and the tape head will be left unchanged.
300
+
301
+ Raises:
302
+ ValueError: If the top of the stack and tape head symbol are not equal.
303
+ Returns:
304
+ A new updated instantaneous description.
305
+ """
306
+ # the stack and tape can never be empty
298
307
if (self .top () == ε ) or (self .top () in self .G .T and self .top () == self .head ()):
299
308
c = copy (self )
300
309
c .stack = copy (c .stack )
@@ -305,14 +314,24 @@ def match(self):
305
314
raise ValueError ('The top of the stack and tape head symbol are not equal.' )
306
315
307
316
def predict (self , P ):
308
- """Attempts a prediction move, given the specified production, and returns the corresponding new instantaneous description."""
317
+ """Performs a prediction move, given the specified production.
318
+
319
+ If the production is an epsilon production, the stack will be left unchanged.
320
+
321
+ Args:
322
+ P (:class:`~liblet.grammar.Production`): The production to predict.
323
+ Raises:
324
+ ValueError: If the production does not belong to the grammar, or if the lhs does not correspond to the top of the stack.
325
+ Returns:
326
+ A new updated instantaneous description.
327
+ """
309
328
if P in self .G .P and self .top () == P .lhs :
310
329
c = copy (self )
311
330
c .stack = copy (c .stack )
312
331
c .stack .pop ()
313
332
c .steps += (P ,)
314
- for X in reversed ( P . rhs ):
315
- if ε != X :
333
+ if not P . is_epsilon ( ):
334
+ for X in reversed ( P . rhs ) :
316
335
c .stack .push (X )
317
336
return c
318
337
raise ValueError ('The top of the stack does not correspond to the production lhs.' )
@@ -337,17 +356,45 @@ def is_done(self):
337
356
"""Returns `True` if the computation is done, that is if the stack contains the a tree rooted in G.S and the head is at the tape end."""
338
357
return len (self .stack ) == 1 and len (self .tape ) == self .head_pos and self .top () == self .G .S
339
358
340
- def shift (self ):
341
- """Performs a shift move and returns the corresponding new instantaneous description."""
359
+ def shift (self , consume = True ):
360
+ """Performs a shift move.
361
+
362
+ If the top of the stack is ε, it will be removed before shifting.
363
+
364
+ Args:
365
+ consume (bool): If `True`, the head position is increased so that the symbol under the tape head is consumed.
366
+ Otherwise, the head does not move and an ε is pushed. The default is `True`.
367
+
368
+ Returns:
369
+ A new updated instantaneous description.
370
+ """
342
371
c = copy (self )
343
- c .stack .push (Tree (c .head ()))
344
- c .head_pos += 1
372
+ if self .stack and self .top () == ε :
373
+ c .stack .pop ()
374
+ if consume :
375
+ if self .head_pos < len (self .tape ):
376
+ c .stack .push (Tree (c .head ()))
377
+ c .head_pos += 1
378
+ else :
379
+ raise ValueError ('The head is already at the end of the tape.' )
380
+ else :
381
+ c .stack .push (Tree (ε ))
345
382
return c
346
383
347
384
def reduce (self , P ):
348
- """Attempts a reduce move, given the specified production, and returns the corresponding new instantaneous description."""
385
+ """Performs a reduce move, given the specified production.
386
+
387
+ Args:
388
+ P (:class:`~liblet.grammar.Production`): The production to reduce.
389
+ Raises:
390
+ ValueError: If the production does not belong to the grammar, if the rhs does not correspond to the symbols on the stack or the stack is empty.
391
+ Returns:
392
+ A new updated instantaneous description.
393
+ """
349
394
if P not in self .G .P :
350
395
raise ValueError ('The production does not belong to the grammar.' )
396
+ if not self .stack :
397
+ raise ValueError ('The stack is empty.' )
351
398
c = copy (self )
352
399
children = [c .stack .pop () for _ in P .rhs ][::- 1 ]
353
400
if tuple (t .root for t in children ) != P .rhs :
0 commit comments