Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use cache for recursion in grammar.py to avoid unnecessary retraversal. #162

Merged
merged 2 commits into from
Aug 4, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions src/representation/grammar.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ def __init__(self, file_name):
self.productionregex = '(?=\#)(?:\#.*$)|(?!\#)\s*(?P<production>(?:[^\'\"\|\#]+|\'.*?\'|".*?")+)'
self.productionpartsregex = '\ *([\r\n]+)\ *|([^\'"<\r\n]+)|\'(.*?)\'|"(.*?)"|(?P<subrule><[^>|\s]+>)|([<]+)'

# to speed up the recursion step
self.recursion_cache = {}

# Read in BNF grammar, set production rules, terminals and
# non-terminals.
self.read_bnf_file(file_name)
Expand Down Expand Up @@ -316,20 +319,29 @@ def check_recursion(self, cur_symbol, seen):

# Get choices of current symbol.
choices = self.rules[cur_symbol]['choices']
nt = self.non_terminals[cur_symbol]

recursive = False
for choice in choices:
for sym in choice['choice']:
# Recurse over choices.
recursive_symbol = self.check_recursion(sym["symbol"], seen)
recursive = recursive or recursive_symbol
# T is always non-recursive so no need to care about them
if sym["type"] == "NT":
# Check the cache, no need to traverse the same subtree multiple times
if sym["symbol"] in self.recursion_cache:
# Grab previously calculated value
recursion_result = self.recursion_cache[sym["symbol"]]
else:
# Traverse subtree
recursion_result = self.check_recursion(sym["symbol"], seen)
# Add result to cache for future runs
self.recursion_cache[sym["symbol"]] = recursion_result

recursive = recursive or recursion_result

# Set recursive properties.
nt['recursive'] = recursive
self.non_terminals[cur_symbol]['recursive'] = recursive
seen.remove(cur_symbol)

return nt['recursive']
return recursive

def set_arity(self):
"""
Expand Down