import json
import re
import sys

token_patterns = [
(r’#[^\n]‘, None),
(r’\s+‘, None),
(r’[‘, ‘LBRACKET’),
(r’]‘, ‘RBRACKET’),
(r’{‘, ‘LBRACE’),
(r’}‘, ‘RBRACE’),
(r’%{‘, ‘LMAPBRACE’),
(r’=>‘, ‘ARROW’),
(r’,‘, ‘COMMA’),
(r’(true|false)‘, ‘BOOLEAN’),
(r’(0|[1-9][0-9_])‘, ‘INTEGER’),
(r’:[A-Za-z_]\w*‘, ‘ATOM’),
(r’[A-Za-z_]\w*‘, ‘KEY’),
]

regex_parts = [f’(?P<{name}>{pattern})’ if name else f’(?:{pattern})’ for pattern, name in token_patterns]
token_regex = ‘|’.join(regex_parts)
token_re = re.compile(token_regex)

class TokenizerException(Exception): pass


class ParserException(Exception): pass


def tokenize(text):
pos = 0
while pos < len(text):
match = token_re.match(text, pos)
if not match:
raise TokenizerException(f’Illegal character {text[pos]!r} at index {pos}‘)
pos = match.end()
if match.lastgroup:
yield match.lastgroup, match.group(match.lastgroup)


class Node:
def init(self, kind, value):
self.kind = kind
self.value = value

def to_json(self):
if self.kind == “map”:
return {“%k”: self.kind, “%v”: {k.to_json()[“%v”]: v.to_json() for k, v in self.value}}
elif self.kind == “list”:
return {“%k”: self.kind, “%v”: [item.to_json() for item in self.value]}
else:
return {“%k”: self.kind, “%v”: self.value}


class Parser:
def init(self, tokens):
self.tokens = iter(tokens)
self.current_token = None
self.next_token()

def next_token(self):
try:
self.current_token = next(self.tokens)
except StopIteration:
self.current_token = None

def parse(self):
result = self.parse_sentence()
if self.current_token is not None:
raise ParserException(‘Unexpected token at the end’)
return result

def parse_sentence(self):
nodes = []
while self.current_token is not None:
node = self.parse_data_literal()
nodes.append(node)
if self.current_token and self.current_token[0] in {‘COMMA’, ‘COLON’, ‘ARROW’}:
self.next_token()
return nodes

def parse_data_literal(self):
if self.current_token[0] == ‘LBRACKET’:
return self.parse_list()
elif self.current_token[0] == ‘LBRACE’:
return self.parse_tuple()
elif self.current_token[0] == ‘LMAPBRACE’:
return self.parse_map()
elif self.current_token[0] == ‘INTEGER’:
value = int(self.current_token[1])
self.next_token()
return Node(‘int’, value)
elif self.current_token[0] == ‘ATOM’:
value = self.current_token[1]
self.next_token()
return Node(‘atom’, value)
elif self.current_token[0] == ‘BOOLEAN’:
value = self.current_token[1] == ‘true’
self.next_token()
return Node(‘bool’, value)
elif self.current_token[0] == ‘KEY’:
value = self.current_token[1]
self.next_token()
if self.current_token and self.current_token[0] == ‘COLON’:
self.next_token()
return Node(‘key’, value)
return Node(‘string’, value)
else:
raise ParserException(f’Unexpected token {self.current_token[1]}’)

def parse_list(self):
self.next_token()
items = []
while self.current_token and self.current_token[0] != ‘RBRACKET’:
item = self.parse_data_literal()
items.append(item)
if self.current_token and self.current_token[0] == ‘COMMA’:
self.next_token()
if not self.current_token or self.current_token[0] != ‘RBRACKET’:
raise ParserException(‘List not properly terminated with ]’)
self.next_token()
return Node(‘list’, items)

def parse_tuple(self):
items = []
self.next_token()
while self.current_token is not None and self.current_token[0] != ‘RBRACE’:
items.append(self.parse_data_literal())
if self.current_token and self.current_token[0] == ‘COMMA’:
self.next_token()
if self.current_token is None or self.current_token[0] != ‘RBRACE’:
raise ParserException(‘Tuple not properly terminated with }’)
self.next_token()
return Node(‘tuple’, [item.to_json() for item in items])

def parse_map(self):
self.next_token()
map_items = {}
while self.current_token and self.current_token[0] != ‘RBRACE’:

if self.current_token[0] not in {‘ATOM’, ‘KEY’}:
raise ParserException(f’Expected map key, found {self.current_token}‘)

key = self.current_token[1] if self.current_token[0] == ‘ATOM’ else ‘:{}’.format(self.current_token[1])
self.next_token()

if self.current_token and self.current_token[0] not in {‘ARROW’, ‘COLON’}:
raise ParserException(f’Expected “=>” or “:”, found {self.current_token}’)
self.next_token()

value = self.parse_data_literal()
map_items[key] = value
if self.current_token and self.current_token[0] == ‘COMMA’:
self.next_token()
if not self.current_token or self.current_token[0] != ‘RBRACE’:
raise ParserException(‘Map not properly terminated with }’)
self.next_token()
return Node(‘map’, map_items)

def main():
try:
sys.stdin.read()

tokens = list(tokenize(text))

if not tokens:
print(json.dumps([]))
else:
parser = Parser(tokens)
result = parser.parse()

json_output = json.dumps([node.to_json() for node in result], separators=(‘,’, ‘:’))
print(json_output)
except TokenizerException as e:
sys.stderr.write(str(e) + ‘\n’)
except ParserException as e:
sys.stderr.write(str(e) + ‘\n’)


if name == ‘main’:
main()
I want you to write make.sh and run.sh programs for the above program. Build program using sh make.sh. Use run.sh to Run some tests. Do not set up run.sh script to run interpeter files directly.