Условный разбор, нестандартный подход


Условный разбор (ака читать какие-то жетоны и возвращают true или false).

Как решение это так вопрос, я написал следующий код:

bool nectar_loader::resolve_conditional( const std::function<bool(const string&)> &config_contains )
{
    bool result = true;
    // My very own recursive implementation
    /*
      - each set of parenthesis is handled recursively
      - logical AND: +
      - logical OR:  |
      - logical NOT: !
      - two bools: "result" and "current"
      - "result" keeps global result, and is modified by "+"
      - "current" keeps results for "|" and "!"
      - syntax checking for invalid
    */
    bool previous_was_operator = true;
    bool current = false; // keep track of current state
    string token;
    while( next_token(token) )
    {
        conditional_operator op;
        if( map_value(conditional_operator_map, token, op) )
        {
            if( previous_was_operator )
            {
                if( op == conditional_operator::not_op )
                    current ^= current; // negate next
                else
                {
                    syntax_error( "Conditional operators \'+\', \'|\', \')\', and \'(\' must be followed by a CONFIG string." );
                    break;
                }
            }
            else
            {
                switch(op)
                {
                    case conditional_operator::right_parenthesis:
                        // TODO: allow conditionals without outer parenthesis of the form (a+b)|(c)
                        return result;
                    case conditional_operator::left_parenthesis: // recurse
                        return resolve_conditional( config_contains );
                    case conditional_operator::plus_op:
                        result = result && current; // "current" -> "result"
                        if( !result ) // negative when an element of a "+" expression
                        current = false; // reset "current"
                        break;
                    case conditional_operator::or_op: // combine with "current"

                    case conditional_operator::not_op: // unreachable
                        throw runtime_error( "Internal logic error in nectar_loader::resolve_conditional" );
                }
            }
            previous_was_operator = true;
        }
        else if( !previous_was_operator )
        {
            syntax_error( "In a conditional all CONFIG strings must be seperated by a conditional operator \'+\', \'|\', \')\', or \'(\'." );
            break;
        }
        else // previous was operator, so now we have a CONFIG string
        {
            // check CONFIG string, and perform a logical OR
            // TODO: check effect of "!"
            current = current || config_contains(token);
        }
    }
    return result;
}

next_token() считывает следующий знак, и возвращает значение false в случае неудачи. syntax_error устанавливает глобальный статус ошибка с сообщение, которое проверено после вызова этой функции. map_value возвращает true, если маркер может быть преобразован в перечисление классов значением (поэтому, если это условный оператор, как это определено со мной). Этот алгоритм является более гибким, чем сортировочной станцией (из-за моих планов на будущее).

Я не проверял это очень хорошо, но что вы думаете?



634
3
задан 11 июня 2011 в 03:06 Источник Поделиться
Комментарии
1 ответ

Несколько замечаний:

bool nectar_loader::resolve_conditional( const std::function<bool(const string&)> &config_contains )

Я бы вообще предпочел, чтобы превратить это в шаблон, и пройти правильный тип функции (и если раньше я с std::функция вообще, использовать его только внутри магазина что-то):

template <class func> 
bool nextar_loader::resolve_conditional(func &config_contains) {

bool result = true;
// My very own recursive implementation
/*
- each set of parenthesis is handled recursively
- logical AND: +
- logical OR: |
- logical NOT: !
- two bools: "result" and "current"
- "result" keeps global result, and is modified by "+"
- "current" keeps results for "|" and "!"
- syntax checking for invalid
*/

Я бы предпочел, чтобы переместить блок комментария чуть выше заголовка функции. Я тоже предпочитаю более описательные имена, чем результат и настоящее. Учитывая их использовать, я бы считал имена более как "expression_value" и "subexpression_value".

    bool previous_was_operator = true;
bool current = false; // keep track of current state

Этот комментарий, кажется, ничего не добавляют к нашему пониманию кода. Я бы рассмотрел что-то больше похоже на: "// считать текущий суб-выражение является недопустимым, пока не разбирается." (если это правда, почему вы инициализировать его в значение false).

    string token;
while( next_token(token) )
{
conditional_operator op;
if( map_value(conditional_operator_map, token, op) )
{
if( previous_was_operator )
{
if( op == conditional_operator::not_op )
current ^= current; // negate next

Опять-таки, комментарий, кажется, делает мало, чтобы помочь в понимании код. Я бы, наверное, заявить о том, что такое выражение как в фп1 фп2 б действителен, если и только если еп2 - это унарный оператор (которого эта грамматика, видимо, поддерживает только один).

                    case conditional_operator::plus_op:
result = result && current; // "current" -> "result"

Учитывая, что вы используете его в качестве и, я бы назвал это conditional_operator::and_op (или нечто подобное). Тогда название должно отражать логический смысл оператора, не факт, что это случается (неправильно)представленные с + характер.

                        if( !result ) // negative when an element of a "+" expression
current = false; // reset "current"

Это если заявление представляется ненужным (по крайней мере для меня). Вы только привести к логическому и из текущих и результат, так что это будет верно , если и только если оба входа оказались уже правдой.

result = current = (current && result);

Так как в конечном итоге true, если и только если оба начинали правда. Если начались ложные, оба оказываются ложными.

                        break;
case conditional_operator::or_op: // combine with "current"

case conditional_operator::not_op: // unreachable
throw runtime_error( "Internal logic error in nectar_loader::resolve_conditional" );

Это выглядит скорее как баг. Вы действительно предполагаете, что or_op будет бросать исключение, как недоступный, или должен ли быть перерыв после or_op случае?

2
ответ дан 24 марта 2014 в 04:03 Источник Поделиться