13. И ЧТО ЖЕ МЫ ВИДИМ?
Вот весь алгоритм:
int WhereToPut(const TToken & rToken)
{
assert(rToken.GetType() < eTokenTypeCount);
return g_TokenPlaces[rToken.GetType];
}
bool Pop_N_Break(const int x, const TToken & rToken1, const TToken & rToken2)
{
assert(rToken1.GetType() < eTokenTypeCount);
assert(rToken2.GetType() < eTokenTypeCount);
return g_iPriorities[rToken1.GetType()][x] >
g_iPriorities[rToken2.GetType()][x + 1];
}
В "чистом виде" (без кода обработки ошибок):
//Возьми тип токена из таблицы
return g_TokenPlaces[rToken.GetType()];
и
//Получи из таблицы приоритетов так или так
return g_iPriorities[rToken1.GetType()][х] > g_iPriorities[rToken2.GetType()][x + 1];
Как видно, алгоритм прост, как два рельса ("возьми из таблицы" и "возьми из таблицы"). И, при всей этой простоте, теперь будет несложно развивать "калькулятор" сколько угодно.
Любую новую сущность, которую надо будет поддержать, мы, вовсе не трогая алгоритма (сейчас и никогда), просто
- регистрируем во внешнем "справочнике" TTokenType ("тип токена"), а также
- заносим "место", куда следует поместить токен, во внешний справочник g_TokenPlaces[] ("места токенов") и
- задаём приоритеты токена во внешней таблице правил для функции Pop_N_Break
А идеальная функция, похоже, выглядит так: "Получи что приказано, откуда укажут".
Далее...