def parse_chars(bels: list, errors: Errors) -> Tuple[CharLocs, Errors]:
pstack, qstack, nested_pstack = [], [], []<EOL>parens, nested_parens, quotes, commas = {}, {}, {}, {}<EOL>notquoted_flag = True<EOL>for i, c in enumerate(bels):<EOL><INDENT>prior_char = i - <NUM_LIT:1><EOL>if c == '<STR_LIT:">' and bels[prior_char] != "<STR_LIT:\\>" and len(qstack) == <NUM_LIT:0>:<EOL><INDENT>qstack.append(i)<EOL>notquoted_flag = False<EOL><DEDENT>elif c == '<STR_LIT:">' and bels[prior_char] != "<STR_LIT:\\>":<EOL><INDENT>quotes[qstack.pop()] = i<EOL>notquoted_flag = True<EOL><DEDENT>elif c == '<STR_LIT:">' and bels[prior_char] == "<STR_LIT:\\>" and len(qstack) == <NUM_LIT:0>:<EOL><INDENT>errors.append(<EOL>(<EOL>"<STR_LIT>",<EOL>f"<STR_LIT>",<EOL>(i - <NUM_LIT:1>, i - <NUM_LIT:1>),<EOL>)<EOL>)<EOL><DEDENT>elif notquoted_flag and c == "<STR_LIT:(>" and bels[prior_char] == "<STR_LIT:U+0020>":<EOL><INDENT>if len(nested_pstack) > <NUM_LIT:1>:<EOL><INDENT>errors.append(<EOL>(<EOL>"<STR_LIT>",<EOL>f"<STR_LIT>",<EOL>(i, i),<EOL>)<EOL>)<EOL><DEDENT>nested_pstack.append(i)<EOL><DEDENT>elif notquoted_flag and c == "<STR_LIT:(>" and bels[prior_char] not in ["<STR_LIT:\\>"]:<EOL><INDENT>pstack.append(i)<EOL><DEDENT>elif notquoted_flag and c == "<STR_LIT:)>" and bels[prior_char] != "<STR_LIT:\\>":<EOL><INDENT>if len(pstack):<EOL><INDENT>if len(pstack) > <NUM_LIT:1>:<EOL><INDENT>parens[pstack.pop()] = (i, "<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>parens[pstack.pop()] = (i, "<STR_LIT>")<EOL><DEDENT><DEDENT>elif len(nested_pstack):<EOL><INDENT>nested_parens[nested_pstack.pop()] = (i, "<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>errors.append(<EOL>(<EOL>"<STR_LIT>",<EOL>f"<STR_LIT>",<EOL>(i, i),<EOL>)<EOL>)<EOL><DEDENT><DEDENT>elif notquoted_flag and c == "<STR_LIT:U+002C>" and len(qstack) == <NUM_LIT:0>:<EOL><INDENT>sparen = pstack[-<NUM_LIT:1>]<EOL>if sparen not in commas:<EOL><INDENT>commas[sparen] = [i]<EOL><DEDENT>else:<EOL><INDENT>commas[sparen].append(i)<EOL><DEDENT><DEDENT><DEDENT>while len(pstack):<EOL><INDENT>errors.append(<EOL>(<EOL>"<STR_LIT>",<EOL>f"<STR_LIT>",<EOL>(pstack[-<NUM_LIT:1>], pstack[-<NUM_LIT:1>]),<EOL>)<EOL>)<EOL>if len(pstack) > <NUM_LIT:1>:<EOL><INDENT>parens[pstack.pop()] = (-<NUM_LIT:1>, "<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>parens[pstack.pop()] = (-<NUM_LIT:1>, "<STR_LIT>")<EOL><DEDENT><DEDENT>while len(nested_pstack):<EOL><INDENT>errors.append(<EOL>(<EOL>"<STR_LIT>",<EOL>f"<STR_LIT>",<EOL>(nested_pstack[-<NUM_LIT:1>], nested_pstack[-<NUM_LIT:1>]),<EOL>)<EOL>)<EOL>nested_parens[nested_pstack.pop()] = (-<NUM_LIT:1>, "<STR_LIT>")<EOL><DEDENT>if len(qstack):<EOL><INDENT>missing_quote = qstack.pop()<EOL>errors.append(<EOL>(<EOL>"<STR_LIT>",<EOL>f"<STR_LIT>",<EOL>(missing_quote, missing_quote),<EOL>)<EOL>)<EOL><DEDENT>return (<EOL>{<EOL>"<STR_LIT>": parens,<EOL>"<STR_LIT>": nested_parens,<EOL>"<STR_LIT>": quotes,<EOL>"<STR_LIT>": commas,<EOL>},<EOL>errors,<EOL>)<EOL>
Scan BEL string to map parens, quotes, commas

    Args:
        bels: bel string as an array of characters
        errors: list of error tuples ('<type>', '<msg>')

    Returns:
        (char_locs, errors): character locations and errors