Fast .slk (SYLK) file parser
I gave it a try compiling it on my machine, but there are too many things still missing, so this will be mainly based on visual inspection of the code.
Functions
I would break out various pieces of this into separate named functions. It will greatly improve readability, and likely they'll be small enough that they'll be inlined, anyway, so it probably won't hurt speed. First, reading the header line could be its own function:
bool check_SLK_header(std::fstream file)
{
    bool header_is_good = false;
    std::string line;
    if (std::getline(file, line)) {
        if (line.substr(0, 2) == &quot;ID&quot;) {
            header_is_good = true;
        }
    }
    return header_is_good;
}

I would leave printing the error message to the caller of the main function (which you haven't named, so I can't reference it). That separates out the logic of parsing the file from the display of data to the user, which is usually a good thing.
Next I would break out the various cases of the switch statement into their own functions, too. I would name them something like parse_dimensions_record() for the B case, and parse_cell_record() for the C case. I'll talk about the E case below.
Avoid Infinite Loops
This pattern of writing an infinite loop that has some special &quot;break-out&quot; criteria hidden in the middle of it is extremely hard to read and follow. This is one of the problems with using goto, break (outside of a switch statement), continue, etc. It obscures the flow of the code. You can almost always rewrite an infinite loop better with an actual exit criteria. Here's how I'd write the parse_dimensions_record() function for the B case:
void parse_dimensions_record(const std::string&amp; line, std::vector&lt;std::vector&lt;std::string&gt;&gt;&amp; table_data)
{
    int columns = -1;
    int rows = -1;
    size_t position = 2;
    while (((columns &lt; 0) &amp;&amp; (rows &lt; 0)) &amp;&amp; (position &lt; line.size() - 1))
    {
        switch (line [ position ])
        {
            case 'X':
                columns = parse_int_part();
                break;
            case 'Y':
                rows = parse_int_part();
                break;
        }
        position++;
    }
    
    if ((columns &gt;= 0) &amp;&amp; (rows &gt;= 0))
    {
        table_data.resize(rows, std::vector&lt;std::string&gt;(columns));
    }
}

It now becomes clear that there are some edge cases that might warrant handling. First, does it make sense to have 0 columns or 0 rows? If not, you should be returning an error and stop parsing, probably, when you hit that case. If so, then you can also probably end early, as there's no point in reading the rest of the file, as there's no columns or rows to hold any data.
You also don't handle malformed data, such as an invalid specifier in the B record, for example. Is it safe to ignore those? Does it indicate a corrupted file? You probably need to return an error code and handle that case in some way.
I mentioned above that I'd talk about the E case below. Well here we are. The main loop for parsing the file isn't an infinite loop which is good, but you still don't need the goto you have in there. You can end it by just keeping around a variable that says whether you've hit the end record. Something like this:
bool hit_end = false;
while ((std::get line(stream, line)) &amp;&amp; (!hit_end)) {
    position = 2;
    
    switch (line.front()) {
        case 'B':
            parse_dimensions_record(line, table_data);
            break;
        case 'C':
            parse_cell_record(line, table_data);
            break;
        case 'E':
            hit_end = true;
            break;
        default:
            // Got some sort of invalid record here. Should probably stop parsing
            break;
    }
}

This is much easier to read and understand and avoids the various goto calls that made the other version difficult to understand.