Обработка ошибок в шаблоне интерпретатора

Предположим, я хочу добавить арабские числа (1 + 2) или римские числа (I + II), и я использую шаблон интерпретатора, который выглядит примерно так:

(код, полученный здесь: https://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Design_Patterns#Interpreter)

struct Expression {
virtual int interpret() = 0;
};

class ArabicNumber : public Expression {
private:
int number;
public:
ArabicNumber(int number)       { this->number = number; }
int interpret(Map variables)  { return number; }
}

class RomanNumber : public Expression {
private:
string number;
public:
RomanNumber(string number)       { this->number = number; }
int interpret(Map variables)  {
//somehow convert the roman number string to an int
}
}

class Plus : public Expression {
Expression* leftOperand;
Expression* rightOperand;
public:
Plus(Expression* left, Expression* right) {
leftOperand = left;
rightOperand = right;
}
~Plus(){
delete leftOperand;
delete rightOperand;
}

int interpret(Map variables)  {
return leftOperand->interpret(variables) + rightOperand->interpret(variables);
}
};

Как я могу убедиться, что ошибочный запрос (1 + II) обработан правильно? Единственное решение, которое я мог придумать, было как-то использовать кастинг, но это не похоже на элегантное решение. Или шаблон не должен использоваться таким образом?

Конечно, одним из вариантов будет написать две отдельные функции для этого, но мне любопытно, можно ли это сделать в одной, потому что я хотел бы использовать этот шаблон для более сложной контекстно-свободной грамматики.

Редактировать: Моя проблема также описана Вот. Я цитирую соответствующий раздел:

Однако введение языка и сопровождающей его грамматики также требует довольно обширной проверки ошибок для неправильно написанных терминов или неуместных грамматических элементов.

Так что мой главный вопрос: Как лучше спроектировать эту обширную проверку ошибок?

1

Решение

Вы действительно хотите разрешить добавлять только римские или арабские цифры, но не смешивать? Если бы микс был в порядке, ваш код просто работал бы (предполагая, что вы пишете фактический код синтаксического анализа для Roman-to-int, который вы там оставили). Если вы не хотите разрешать смешивание, вам нужно добавить шаг проверки перед вызовом интерпретации обоих аргументов в Plus ().

Например, вы могли бы dynamic_cast<ArabicNumber> оба операнда, и если один из них равен NULL, то если оба имеют значение NULL, попробуйте dynamic_cast<RomanNumber> вместо. Обычно тестирование типа класса — это запах кода, но здесь вы проверяете, так что все в порядке.

Другим подходом было бы дать каждому Expression CanBeConvertedToType() метод, затем есть оператор switch в этой функции, который проверяет константу, представляющую данный тип, типу результата данного Expression, Это было бы более безопасным для будущего, так как позволяет вам иметь разные Expression подклассы, которые возвращают один и тот же тип, без необходимости изменения кода проверки типов для проверки каждого класса, который действителен при добавлении нового класса.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]