Skip to content

Instantly share code, notes, and snippets.

@dermesser
Created December 10, 2020 13:27
Show Gist options
  • Select an option

  • Save dermesser/5813ea5cca68dfe929c189bf759c4cdf to your computer and use it in GitHub Desktop.

Select an option

Save dermesser/5813ea5cca68dfe929c189bf759c4cdf to your computer and use it in GitHub Desktop.
A naive S-expr parser in python
#!/usr/bin/env python3
# Simple sexpr parser
from collections import namedtuple
Expr = namedtuple('Expr', ('children'));
OPEN = 1
CLOSE = 2
def lex(txt):
parts = []
i = 0
while i < len(txt):
if txt[i] == '(':
i += 1
parts.append(OPEN)
elif txt[i] == ')':
i += 1
parts.append(CLOSE)
elif txt[i].isspace():
i += 1
else:
j = i
while not (txt[j].isspace() or txt[j] in ('(', ')')):
j += 1
parts.append(txt[i:j])
i = j
return parts
def parse(parts):
while True:
if parts[0] == OPEN: # Paren open
children = []
i = 1
while parts[i] != CLOSE:
child, consumed = parse(parts[i:])
children.append(child)
i += consumed
return children, i+1
if parts[0] == CLOSE: # Paren close
return [], 1
else: # Atom
return parts[0], 1
def find_singletons(tree):
stons = []
for l in tree:
if type(l) is list and len(l) == 1:
stons.extend(l)
elif type(l) is list:
stons.extend(find_singletons(l))
return stons
print(parse(lex('(abc def (gh i (j)) jkl)')))
tree = parse(lex('(3 (2 Yet) (3 (2 (2 The) (2 Act)) (3 (4 (3 (2 Is) (3 (2 Still) (4 (Charming)))) (2 Here)) (2 .))))'))
print(tree)
print(find_singletons(tree))
# Prints:
# (['abc', 'def', ['gh', 'i', ['j']], 'jkl'], 12)
# (['3', ['2', 'Yet'], ['3', ['2', ['2', 'The'], ['2', 'Act']], ['3', ['4', ['3', ['2', 'Is'], ['3', ['2', 'Still'], ['4', ['Charming']]]], ['2', 'Here']], ['2', '.']]]], 55)
# ['Charming']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment