Необъяснимая ошибка в исходном коде синтаксического анализатора C ++ - PullRequest
2 голосов
/ 16 сентября 2011

Это функция, которая проверяет имя функции, введенной пользователем в интерпретатор / парсер, который я делаю, сравнивает его с массивом функций и выполняет соответствующую функцию C ++. Он работает нормально, пока пользователь вводит правильное имя функции, но интерпретатор завершается некоторой необъяснимой ошибкой времени выполнения, если нет функции с именем, введенным пользователем, даже если я запрограммировал его на вывод «Неопределенной функции» и затем продолжил цикл разбора:

void parser::eval_cmd(std::string& exp, pro::command fset[])
{
    expr = exp;
    exp_ptr = (char*) expr.c_str();

    bool found = false;

    for (int i = 0; i < (int)sizeof(fset); i++)
    {
        if (fset[i].check(expr))
        {
            found = true;
            exp_ptr = (char*)expr.c_str() + (fset[i].name.size() - 1);
            if (fset[i].cmd)
                fset[i].cmd(eval_args());
            break;
        }

    }

    if (!found) err::show(err::UNDEFINED);
}

Что именно я делаю не так?

Ответы [ 3 ]

7 голосов
/ 16 сентября 2011

То, что вы делаете неправильно, это (int)sizeof(fset).Это дает вам размер указателя в байтах, а не количество элементов в переданном массиве fset.

Вам нужен какой-то другой способ определения количества элементов в массиве, возможно, путемпередавая другой аргумент, используя std:: контейнер вместо массива или NULL-завершающий массив.

Например, слегка изменяя определение вашей функции:

void parser::eval_cmd(std::string& exp, const std::vector<pro::command>& fset)
{
    ...

    for (int i = 0; i < fset.size(); i++)
    {
        ... 

остальная часть кода остается неизменной.

EDIT : Мой лучший совет - использовать std::map<string, pro::command> и разрешить map управлять алгоритмом поиска, или std::vector<pro::comand> и использовать вышеуказанный алгоритм без изменений.Вы можете измерить производительность памяти, но я ожидаю, что единственные издержки над массивом vector - это издержки new ed массива над статическим массивом.Стандартные контейнеры, вот мой второй лучший совет:

void parser::eval_cmd(std::string& exp, pro::command fset[], size_t count)
{
    ...

    for (int i = 0; i < count; i++)
    {

Предположительно, вызывающая сторона знает (или может определить) количество элементов в массиве fset.(См. Может ли этот макрос быть преобразован в функцию? для справки.)

2 голосов
/ 16 сентября 2011

Я вижу немедленную ошибку, хотя, не видя больше кода, я не могу точно сказать, какие симптомы могут быть. Ты в цикле управления условие использует sizeof(fset): fset - указатель, поэтому значение будет всегда быть одинаковым (обычно 4 или 8, в зависимости от того, в какой вы 32 битовый или 64-битный режим). У меня fset меньше членов, тогда у вас будет неопределенное поведение, и если оно имеет больше, вы не будете проверять любой из последующие функции.

Я рекомендую использовать std::map для fset и пропустить цикл полностью.

0 голосов
/ 16 сентября 2011
..., pro::command fset[])

эквивалентно

..., pro::command *fset)

Поэтому, когда вы делаете sizeof(fset), он вычисляет sizeof(command*), а не фактическое sizeof(command). Если вы не знаете размер fset[], вы можете написать оболочку template:

template<unsigned int SIZE>  // <--- finds the sizeof fset
void parser::eval_cmd_array(std::string& exp, pro::command (&fset)[SIZE])
{
  void parser::eval_cmd(exp, fset, SIZE);  // <--- pass the size as 3rd param
}

Теперь у вас есть размер массива в вашей исходной функции;

void parser::eval_cmd(std::string& exp, pro::command fset[], unsigned int sizeof_fset)
{                                                          //^^^^^^^^^^^^^^^^^^^^^^^^^ 
 //...
   for (unsigned int i = 0; i < sizeof_fset; i++)
 //...  ^^^^^^^^ let it be unsigned :)
}
...