BoldCalc (Федосов Андрей)
Разберём идейную реализацию программы BoldCalc. Конспект рассчитан на то, что Вы в процессе прочтения сами реализуете работающую программу и закрепите тем самым материал основной лекции. Можно, конечно, не глядя скопировать соответствующие части решения (а можно и скачать само решение, но зачем?). Поскольку в решении не применяется сколь-нибудь сложный алгоритм, рекомендуется убедиться, что вы поняли разбор, закрыть его и решить по-своему.
Отталкиваясь от пунктов нашего условия будем писать нашу функцию. На вход нам поступают строки, которые мы будем последовательно обрабатывать и некоторый словарь с переменными, о котором мы расскажем ниже. Перед обработкой выполним небольшое преобразование строки, а именно: удалим все пробелы методом replace(), после чего перейдём к основным этапам.
- Во-первых, нам необходимо определиться, нужно ли работать с нашей строчкой, или её обработку можно пропустить (в случае, если она является комментарием).
Затем, внимательно прочитав условие, мы можем понять, что в случае, если строка не является комментарием, то перед нами строка одного из двух типов: либо строка с присваиванием (“=”), либо обычное выражение. Определить это мы можем достаточно просто воспользовавшись методом split(). Также на этом шаге необходимо учесть, что знаков равно в такой строке должно быть не больше 1, иначе нам нужно выкинуть соответствующую ошибку.
- Двигаясь дальше по этой ветке, мы должны проверить, что с левой стороны знака находится идентификатор. В этом нам поможет достаточно простое регулярное выражение, которое должно включать в себя (согласно условию) буквы латинского алфавита и символ нижнего подчёркивания. Иначе мы также выкидываем соответствующую ошибку.
Далее нам необходимо сделать проверку выражения, стоящего с правой стороны от знака “=”, этот этап будет универсальным и подойдёт и для обработки случая строки, не содержащей присваивания.
- На этом этапе в первую очередь нам необходимо убедиться, что наше выражение не пустое,
- Затем — что в нём присутствуют только допустимые символы, а именно: буквы и разрешённые операции.
Дополнительно мы проверяем, нет ли в нашем выражении запрещённых последовательностей, таких как: “//”, “**”, правильно ли написан идентификатор и ситуации, когда “()” сразу при имени идентификатора. Для чего мы также используем регулярные выражения. Иначе наше выражение составлено неверно, и нам нужно выкинуть ошибку синтаксиса.
После того, как мы проверим нашу строку, перейдём к её вычислению, обернув их блоками try-except. На данном этапе стоит обратить внимание на то, чтобы имена в обрабатываемом выражении должны быть уникальными, для чего мы с помощью регулярного выражения проходимся по нашей строке, заменяя методом “sub()” идентификаторы на уникальные (например, приписывая им некоторый префикс в начало).
Также нам необходимо учитывать, что на следующем шаге мы будем работать с функцией eval(), для чего нам необходимо передать ей выражение, в котором все операции деления заменены на целочисленные. В этом нам поможет метод replace().
После чего можем непосредственно переходить к вычислению выражения с использованием функции eval(), которая будем принимать наше выражение и некоторый словарь, в который мы будем записывать пары идентификатор: значение (слегка переименованные переменные калькулятора на время eval станут переменными python)
В ходе вычисления блока try мы должны ловить исключение NameError и возвращать соответствующий вывод. И, соответственно, все остальные Exceptions, которые будем считать за Runtime error.
Для надёжности встроим последнюю проверку, которая будет заключаться в том, что мы сверим тип результата с целочисленным типом “int” и, если это не так, выкинем ошибку синтаксиса.
- После вычисления выражения в случае, если в нашей строке имелось присваивание, следующим шагом пополним наш словарь переменных соответствующей парой. Иначе просто вернём значение выражения.
- В основном нашем цикле, который будет последовательно скармливать строки нашей функции обработки просто будем каждый раз выполнять печать результата, в случае, если он не пустой.