processSuspendedSymbol(c)
pop
when SYM_OPER
processSuspendedSymbol(c)
push(c)
when SYM_OTHER
nextOther(c)
end
end
def processSuspendedSymbol(c)
while precedes(top, c)
nextOper(pop)
end
end
Работа начинается с вызова метода compile, в котором все символы строки str последовательно передаются методу processSymbol.
def priority(c)
(c == ’+’ or c == ’-’) ? 1 : 2 end
def precedes(a, b)
return false if symType(a) == SYM_LEFT
return true
if symType(b) == SYM_RIGHT
priority(a) >= priority(b) end
protected
SYM_LEFT = 0; SYM_RIGHT = 1; SYM_OPER = 2; SYM_OTHER = 3
def symOther(c)
# Сравнение символа с образцом (регулярным выражением).
raise "Недопустимый символ #{c}" if c !~ /[a-z]/
SYM_OTHER
end
def nextOper(c)
print "#{c} "
end
def nextOther(c)
nextOper(c)
end
end
Квалификатор доступа protected и метод nextOther нужны для создания на базе класса Compf нового класса Calc, реализующего калькулятор формул[13].
Класс Calc (калькулятор числовых формул) выведен из класса Compf, переопределяет некоторые методы последнего, и имеет дополнительный стек для размещения в нём чисел. Калькулятор работает только с цифрами (числами от 0 до 9).
Несколько комментариев к методу nextOper(c) класса Calc. Множественное присваивание в первой строке метода корректно, т.к. в языке Ruby при выполнении множественного (параллельного) присваивания сначала последовательно вычисляются все выражения в правой части оператора присваивания.
require ’Compf’
class Calc < Compf def initialize
# Вызов метода initialize базового класса Compf. super
# Создание стека результатов операций.
@s = Stack.new
end
def compile(str) super
return @s.top end
protected
def symOther(c)
raise "Недопустимый символ #{c}" if c !~ /[0-9]/ SYM_OTHER end
def nextOper(c)
second, first = @s.pop, @s.pop @s.push(first.method(c).call(second)) end
def nextOther(c)
@s.push(c.to_i)
end
end
Конструкция first.method(c).call(second) во второй строке метода может быть объяснена таким примером: выражение 3.metod(’-’).call(2), эквивалентно выражению 3. – (2) или просто 3-2.
Задача 1. Добавьте операции sin, cos и унарный минус.
Задача 2. Добавьте правоассоциативную операцию ~ возведения в степень.
Задача 3. Добавьте квадратные и фигурные скобки.
Задача 4. Измените программу так, чтобы допускались в качестве имен переменных произвольные идентификаторы языка Ruby.
Задача 5. Добавьте левоассоциативную операцию % с приоритетом, равным приоритету операции /.
Задача 6. Добавьте возможность записи формулы с пробелами и комментариями двух типов (/* */ и //).
Задача 7. Измените программу так, чтобы ввод, содержащий в качестве аргументов только восьмеричные числа (начинающиеся с нуля, например 056), компилировался в программу, содержащую десятичные числа.
Задача 8. Измените программу так, чтобы ввод, содержащий в качестве аргументов только шестнадцатеричные числа (начинающиеся с 0x, например 0x56), компилировался в программу, содержащую восьмеричные числа.
Задача 9. Измените программу так, чтобы ввод, содержащий в качестве аргументов только римские числа, не превосходящие 5000, компилировался в программу, содержащую десятичные числа.
Задача 10. Измените программу так, чтобы для коммутативной операции аргументы выдавались в алфавитном порядке.
Задача 11. Добавьте фигурные скобки, означающие возведение в квадрат. Используйте операцию DUP стекового калькулятора.
Задача 12. Считая, что a = 0, оптимизируйте формулу (уберите лишние сложения).
Задача 13. Считая, что b = 1, оптимизируйте формулу (уберите лишние умножения).
Задача 14. Добавьте возможность ввода формулы на нескольких строках.
Три шага к свободному ПО
Не все знают, что стоимость проприетарного (коммерческого) программного обеспечения, способного превратить «компьютерное железо» в современный компьютер, значительно больше стоимости самого «железа». Не знают зачастую потому, что используют контрафактное (то есть приобретённое без лицензии) ПО, что является нарушением действующего законодательства.