1

Given S=>BaB, B=>b and null(B), the code is supposed to generate S=>BaB|aB|Ba|a and B=>b but it is not generating Ba i.e the output is S=>BaB|aB|a and B=>b which is not correct.

The code can generate values correctly if terminal is not in the middle for example S=>BBa, B=>b gives out S=>BBa|Ba|a and B=>b The only case not working is when a terminal is on the middle of a repeated null production

Other examples where null(B)

  1. S=>aBa ,B=>b gives out S=>aBa|aa and B=>b

  2. S=>aaB, B=>b gives out S=>aaB|aa and B=>b

grammar = ["S = B a B", "B = b"]
def remove_null_productions(grammar):
    null_productions = ["B"]
    print("Null productions: {0}".format(null_productions))
    new_productions = []

    for rule in grammar:
        if('$' in rule):
            continue
        else:
            new_productions.append(rule.split(" "))

    print("\nProductions:{0}".format(new_productions))
    for null in null_productions:

        for param in new_productions:

            if(null in param[2:]):
                temp = param[2:]
                temp.remove(null)

                if(len(temp)==0):
                    pass
                else:
                    clever_array = param[0:2]
                    for val in temp:
                        clever_array.append(val)

                    new_productions.append(clever_array)
            else:
                pass

    print("\nResultant Productions")
    for rule in new_productions:
        print(rule)
    return new_productions
remove_null_productions(grammar)

I expect the output of grammar S=>BaB and B=>b to be

Null productions: ['B']

Productions:[['S', '=', 'B', 'a', 'B'], ['B', '=', 'b']]

Resultant Productions
['S', '=', 'B', 'a', 'B']
['B', '=', 'b']
['S', '=', 'a', 'B']
['S', '=', 'B', 'a']
['S', '=', 'a']

But the output is

Null productions: ['B']

Productions:[['S', '=', 'B', 'a', 'B'], ['B', '=', 'b']]

Resultant Productions
['S', '=', 'B', 'a', 'B']
['B', '=', 'b']
['S', '=', 'a', 'B']
['S', '=', 'a']
skyridertk
  • 103
  • 1
  • 8
  • I am quite confused on the grammar generation you are doing. I do not Can you give a bit of clarification on the expected output? Given the sentence `S=BaB` what does `B=b` mean? what of `null(B)`? – Onyambu Apr 29 '19 at 23:52
  • S=>Bab is a grammar where S and B are non terminal and 'a' and 'b' are terminals. null(B) means B is null and B should be removed from rules where it is found on the RHS. If we remove a B, the original production should remain as it is, and you have to append new value after B has been removed to that same production. – skyridertk Apr 29 '19 at 23:55
  • Okay now I understand. You earlier had B=b instead of B=>b so was confused – Onyambu Apr 29 '19 at 23:56

1 Answers1

1

The problem here is that temp.remove(null) will only remove the first instance of null in temp. Thus you end up adding 'S=>aB' but not 'S=>Ba'. You need to iterate through all symbols on the right hand side and replace each instance of the null value.

Doing this naively, however, will result in repeated productions (e.g. 'S=>aB' and 'S=>Ba' will both give 'S=>a'). You can avoid this issue by using a set to keep track of tuples of the productions already generated (tuples must be used instead of lists because items in a set must be immutable). You can then check against this set to make sure that you're not appending a production that has already been added.

Here's some working code that produces the expected output for both "S=>BaB" and "S=>BBa." I've mostly kept the code the same except for modifying the logic to add new productions. I also changed null_productions to be an argument to the function so that its value can be more readily changed.

grammar = ["S = B a B", "B = b"]
def remove_null_productions(grammar, null_productions=None):
    if null_productions is None:
        null_productions = ["B"]
    print("Null productions: {0}".format(null_productions))
    new_productions = []

    seen = set()
    for rule in grammar:
        if('$' in rule):
            continue
        else:
            new_productions.append(rule.split(" "))

    print("\nProductions:{0}".format(new_productions))
    for null in null_productions:

        for param in new_productions:
            for i, word in enumerate(param):
                if i < 2:   # don't degenerate LHS
                    continue
                if word == null:
                    temp = param[:i] + param[i+1:]
                    temp_tup = tuple(temp)
                    if len(temp) > 2 and temp_tup not in seen:
                        new_productions.append(temp)
                        seen.add(temp_tup)

    print("\nResultant Productions")
    for rule in new_productions:
        print(rule)
    return new_productions


remove_null_productions(grammar)

grammar2 = ["S = B B a", "B = b"]

remove_null_productions(grammar2)

Output for grammar:

Null productions: ['B']

Productions:[['S', '=', 'B', 'a', 'B'], ['B', '=', 'b']]

Resultant Productions
['S', '=', 'B', 'a', 'B']
['B', '=', 'b']
['S', '=', 'a', 'B']
['S', '=', 'B', 'a']
['S', '=', 'a']

Output for grammar2 (i.e. 'S=>BBa'):

Null productions: ['B']

Productions:[['S', '=', 'B', 'B', 'a'], ['B', '=', 'b']]

Resultant Productions
['S', '=', 'B', 'B', 'a']
['B', '=', 'b']
['S', '=', 'B', 'a']
['S', '=', 'a']
D. Gillis
  • 670
  • 5
  • 8
  • 1
    I modified line ```if len(temp) > 0 and temp_tup not in seen``` to ```if len(temp) > 2 and temp_tup not in seen ``` so that empty rules dont get appended e.g S=>XYZ nulls(X,Y,Z) should give S=>XYZ|XZ|XY|YZ|X|Y|Z but if u put ```if len(temp) > 0 and temp_tup not in seen ``` S=>XYZ nulls(X,Y,Z) gives S=>XYZ|XZ|XY|YZ|X|Y|Z|{empty_rule} – skyridertk Apr 30 '19 at 05:18
  • 1
    I've updated my answer to not produce empty rules (with the exact same change you made). – D. Gillis Apr 30 '19 at 05:45