My program is 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'),  
    (r':', 'COLON'),
]

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)

def make_hashable(value):
    """Recursively converts JSON-like objects to an immutable and hashable type."""
    if isinstance(value, list):
        return tuple(make_hashable(x) for x in value)
    elif isinstance(value, dict):
        return tuple((make_hashable(k), make_hashable(v)) for k, v in value.items())
    else:
        return value  # Integers, strings, booleans, and None are already hashable


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

    def to_json(self):
        if self.kind == "map":
            # Corrected conditional to account for empty maps
            if not self.value:  # self.value is empty
                return {"%k": self.kind, "%v": {}}  # Return an empty dictionary instead of an empty list
            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):
    # Parse the correct type based on the current token
        if not self.current_token:
            raise ParserException("Unexpected end of input")
    
        token_type, token_value = self.current_token
    
        if token_type == 'LBRACKET':
            return self.parse_list()
        elif token_type == 'LBRACE':
            return self.parse_tuple()
        elif token_type == 'LMAPBRACE':
           return self.parse_map()
        elif token_type == 'INTEGER':
           self.next_token()  # Move to the next token after parsing
           return Node('int', int(token_value))  # Convert string to integer
        elif token_type == 'ATOM':
           self.next_token()
           return Node('atom', token_value)
        elif token_type == 'BOOLEAN':
           self.next_token()
        # Convert string 'true' or 'false' to a boolean
           return Node('bool', token_value == 'true')
        elif token_type == 'KEY':
           self.next_token()
           return Node('key', token_value)
        else:
           raise ParserException(f"Unexpected token type {token_type}")

    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()  # Consume 'RBRACKET'
        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()  # Skip 'LMAPBRACE'
        map_items = []
    
        while self.current_token and self.current_token[0] != 'RBRACE':
            key = self.parse_data_literal()
        
            if self.current_token[0] not in ['ARROW', 'COLON']:
                raise ParserException(f"Expected '=>' or ':', found {self.current_token} instead")

            self.next_token()  # Skip 'ARROW' or 'COLON'
            value = self.parse_data_literal()
        
        # Serialize your key to a format that can be used in a JSON dictionary
        # This can be a string representation or a nested structure

            map_items[str(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()  # Skip 'RBRACE'
            return Node('map', map_items)

def main():
    try:
        text = 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()
which is failing many test cases and the ideal program that passes all the test cases is #!/usr/bin/env python3

import re
import sys
from collections import namedtuple
import json

'''
dataItems
  : dataItem*
  ;
dataItem
  : list
  | tuple
  | map
  | primitive
  ;
primitive
  : INT
  | ATOM
  | BOOL
  ;
list
  : '[' dataItem (',' dataItem)* ']'
  | '[' ']'
  ;
tuple
  : '{' dataItem (',' dataItem)* '}'
  | '{' '}'
  ;
map
  : '%{' keyPair (',' keyPair)* '}'
  | '%{' '}'
  ;
keyPair
  : dataItem '=>' dataItem
  | KEY dataItem
  ;
'''

################################# Parser ################################


def parse(text):
    toks = tokenize(text)
    toksIndex = 0
    tok = toks[toksIndex]
    toksIndex += 1

    def peek(kind):
        nonlocal tok
        return tok.kind == kind

    def consume(kind):
        nonlocal tok, toks, toksIndex
        if (peek(kind)):
            tok = toks[toksIndex]
            toksIndex += 1
        else:
            error(kind, text)

    def error(kind, text):
        nonlocal tok
        pos = tok.pos
        if pos >= len(text) or text[pos] == '\n': pos -= 1
        lineBegin = text.rfind('\n', 0, pos)
        if lineBegin < 0: lineBegin = 0
        lineEnd = text.find('\n', pos)
        if lineEnd < 0: lineEnd = len(text)
        line = text[lineBegin:lineEnd]
        print(f"error: expecting '{kind}' but got '{tok.kind}'",
              file=sys.stderr)
        print(line, file=sys.stderr)
        nSpace = pos - lineBegin if pos >= lineBegin else 0
        print('^'.rjust(nSpace+1), file=sys.stderr)
        sys.exit(1)

    def data_items():
        items = [];
        while is_item_start():
            items.append(data_item());
        return items

    def data_item():
        if peek('['):
            return list();
        elif peek('{'):
            return tuple();
        elif peek('%{'):
            return map();
        else:
            return primitive();

    def list():
        items = []
        consume('[')
        if is_item_start():
            items.append(data_item());
            while peek(','):
                consume(',')
                items.append(data_item())
        consume(']');
        return { '%k': 'list', '%v': items };

    def tuple():
        items = []
        consume('{')
        if is_item_start():
            items.append(data_item());
            while peek(','):
                consume(',')
                items.append(data_item())
        consume('}');
        return { '%k': 'tuple', '%v': items };

    def map():
        pairs = []
        consume('%{')
        if is_item_start() or peek('KEY'):
            pairs.append(keyValue());
            while peek(','):
                consume(',')
                pairs.append(keyValue())
        consume('}');
        return { '%k': 'map', '%v': pairs };

    def primitive():
        if peek('INT'):
            v = int(tok.lexeme.replace('_', ''));
            consume('INT');
            return { '%k': 'int', '%v': v };
        elif peek('ATOM'):
            v = tok.lexeme;
            consume('ATOM');
            return { '%k': 'atom', '%v': v };
        else:
            v = tok.lexeme == 'true';
            consume('BOOL');
            return { '%k': 'bool', '%v': v };

    def keyValue():
        key = '';
        if peek('KEY'):
            atom = ':' + tok.lexeme[0:-1];
            consume('KEY');
            key = { '%k': 'atom', '%v': atom };
        else:
            key = data_item();
            consume('=>');
        value = data_item();
        return [ key, value ];

    def is_item_start():
        return peek('ATOM') or peek('INT') or peek('BOOL') or \
               peek('[') or peek('{') or peek('%{');


    items = data_items()
    if tok.kind != 'EOF': error('EOF', text)
    return items


################################# Lexer #################################

SKIP_RE = re.compile(r'(\s+|\#.*)+')
INT_RE = re.compile(r'\d(\_?\d+)*')
ATOM_RE = re.compile(r'\:[_a-zA-Z]\w*')
KEY_RE = re.compile(r'[_a-zA-Z]\w*\:')
BOOL_RE = re.compile(r'\b(true|false)\b')
ARROW_RE = re.compile(r'\=\>')
FANCY_LBRACE_RE = re.compile(r'\%\{')

Token = namedtuple('Token', 'kind lexeme pos')

def tokenize(text, pos=0):
    toks = []
    while pos < len(text):
        m = SKIP_RE.match(text, pos)
        if m:
            pos += len(m.group())
        if pos >= len(text): break
        if m := INT_RE.match(text, pos):
            tok = Token('INT', m.group(), pos)
        elif m := ATOM_RE.match(text, pos):
            tok = Token('ATOM', m.group(), pos)
        elif m := KEY_RE.match(text, pos):
            tok = Token('KEY', m.group(), pos)
        elif m := BOOL_RE.match(text, pos):
            tok = Token('BOOL', m.group(), pos)
        elif m := ARROW_RE.match(text, pos):
            tok = Token('=>', m.group(), pos)
        elif m := FANCY_LBRACE_RE.match(text, pos):
            tok = Token('%{', m.group(), pos)
        else:
            tok = Token(text[pos], text[pos], pos)
        pos += len(tok.lexeme)
        toks.append(tok)
    toks.append(Token('EOF', '<EOF>', pos))
    return toks


################################## Main #################################

def main():
    text = sys.stdin.read()
    #print(tokenize(text))
    result = parse(text)
    print(json.dumps(result, separators=(',', ':'))) #no whitespace

if __name__ == "__main__":
    main() Make changes to my program so that it can also pass the test cases. take the reference from the ideal program and make necessary changes to my program.