Парсинг методом рекурсивного спуска

152
01 апреля 2018, 20:47

Привет! Это мой не первый пост по поводу парсера, но все же. Собственно, проблема такова: есть список(вектор) токенов(указателей на них) и на его основе необходимо сделать выражение(класс Expression). Давайте глянем код:

Допустим имеем выражение: 2 + 2 - 2
Expression* parse(){
    Expression* result = primary(); // Взяли, к примеру, NmberExpression(2)
    while(true){
        if(match(TokenType::PLUS){ // "Пропускаем" токен ПЛЮС, если он стоит после двойки в нашем выражении
            result = new BinaryExpression('+', result, primary());
        ... что дальше - не важно: принцип один и тот же...
}
Expression* primary(){
    return new NumberExpression(число из текущего токена);
    ... ну, либо эксепшн :D ...
}

Естественно, в моем проекте реализована логика уничтожения указателей, но она ломается на 6 строчке приведенного кода, и вы поймете почему.

Прошу не бить палками - дочитайте пост до конца. Как видите, алгоритм и логика проста: мы просто "откусываем" в класс Expression часть выражения, а остальное дальше продолжаем парсить. Давайте я подробно разберу, что происходит, чтобы подтолнуть вас к моей идее:

  • Имеем выражение 2 + 2 - 2
  • Берем первую двоечку, как Expression
  • Пропускаем плюс
  • теперь в переменную result записываем новый класс BinaryExpression, который сформирован на основе этой же переменной!

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

  1. Перелопатить программу, изменив все указатели на умные
  2. Использовать какой-то другой метод парсинга и составления AST. (Если так, то подскажите, какой именно паттерн или логику сделать, так как я не нашел ничего годного для своей задачи. Есть много разных пример на Java, Python и других языках, но там такое можно сделать, ибо оператор "new" там работает по-другому) Заранее благодарю!

P.S. если Вы не поняли, почему удаление объекта по указателю ломается, то объясняю: мы создаем новый экземпляр класса на основе существующей переменной, и теперь та самая переменная хранит этот новый экземпляр(BinaryExpression), но если мы вызовем в BinaryExpression деструктор, где происходит удаление этих 2-х Expression, которые пришли как аргументы, то вылетит ошибка о доступе к памяти, т.к. мы создали класс BinaryExpression на основе переменной, а потом эту же переменную перезаписываем, то попытка удалить указатель (тот самый первый аргумент) не закончиться успехом, т.к. это тоже самое, что написать в классе delete this;

READ ALSO
setlocale и linux

setlocale и linux

Пишу на линуксе и никогда не в код не вставляю:

175
Ошибка программы

Ошибка программы

Такие ошибки:

174
Нечитаемые символы в cout

Нечитаемые символы в cout

Вот весь код, подскажите пожалуйста на каком этапе ломается читаемость и как это исправить?

144
Запуск Gitlab Runner для C++/Qt проекта на Mac OS

Запуск Gitlab Runner для C++/Qt проекта на Mac OS

Здравствуйте! Есть задача запустить Gitlab Runner для сборки C++/Qt проекта на Mac OSЗнаю, что для сборки просто C++ проекта можно использовать Nuget и MSBuild

157