function tokenize(string $format): array
{
    $level = 0;
    $stack = [['context' => 'text', 'text' => '', 'level' => $level]]; // context = text, start, end, tag
    $escapees = '\{?}';
    $escaped = false;

    for ($i = 0; $i < strlen($format); $i++) {
        $ch = $format[$i];
        if (strpos($escapees, $ch) !== false && $i>0 && $format[$i-1] === '\\' && !$escaped) {
            $escaped = true;
        } else {
            $escaped = false;
            if ($ch === '\\' && strlen($format) > $i+1 && strpos($escapees, $format[$i+1]) !== false) continue;
        }

        if ($ch === '{' && !$escaped) {
            stack_push($stack, ['context' => 'start', 'text' => '{', 'level' => $level++]);
            continue;
        } elseif ($ch === '}' && !$escaped) {
            stack_push($stack, ['context' => 'end', 'text' => '}', 'level' => --$level]);
            $frame = ['nested' => []];
            $compound = false;
            while (count($stack) > 0) {
                $temp = stack_pop($stack);
                /*if($temp['level'] > $level)*/ array_unshift($frame['nested'], $temp);
                $frame['text'] = $temp['text'].$frame['text'];
                if ($temp['context'] === 'start') {
                    $frame['context'] = 'tag';
                    $frame['level'] = $temp['level'];
                    break;
                }
                else $frame['context'] = 'text';
                if ($temp['context'] === 'tag') $compound = true;
            }
            if (!$compound) unset($frame['nested']);
            stack_push($stack, $frame);
            continue;
        } elseif (current($stack)['context'] === 'start') {
            stack_push($stack, ['context' => 'text', 'text' => $ch, 'level' => $level]);
            continue;
        } elseif ($stack[count($stack)-1]['context'] === 'tag') {
            stack_push($stack, ['context' => 'text', 'text' => '', 'level' => $level]);
        }

        if ($stack[key($stack)]['context'] === 'text')
            $stack[key($stack)]['text'] .= $ch;
    }
    return $stack;
}


function stack_push(array &$array, $value)
{
    $array[] = $value;
    end($array);
}

function stack_pop(array &$array)
{
    $pop = array_pop($array);
    end($array);
    return $pop;
}