Лекции по построению компилятора на Pascal
## PopAdd := T2;
end;
{---------------------------------------------------------------}
{ Generate Code to Subtract Primary from the Stack }
function PopSub(T1, T2: char): char;
begin
## Pop(T1);
## T2 := SameType(T1, T2);
## GenSub(T2);
## PopSub := T2;
end;
{---------------------------------------------------------------}
После всех этих приготовлений, в конечном результате нет почти ничего кульминационного.
Снова, вы можете видеть что логика совершенно проста. Все что делают эти две
подпрограммы - выталкивают вершину стека в D7, приводят два операнда к одному размеру
и затем генерируют код.
Обратите внимание на две новые подпрограммы генерации кода GenAdd и GenSub. Они
являются остаточной формой оригинальных PopAdd и PopSub. Т.е. они являются чистыми
генераторами кода, производящими сложение и вычитание регистров:
{---------------------------------------------------------------}
{ Add Top of Stack to Primary }
procedure GenAdd(Size: char);
begin
## EmitLn('ADD.' + Size + ' D7,D0');
end;
{---------------------------------------------------------------}
{ Subtract Primary from Top of Stack }
procedure GenSub(Size: char);
begin
## EmitLn('SUB.' + Size + ' D7,D0');
## EmitLn('NEG.' + Size + ' D0');
end;
{---------------------------------------------------------------}
ОК, я соглашусь с вами: я выдал вам множество подпрограмм с тех пор, как мы в последний
раз протестировали код. Но вы должны признать, что каждая новая подпрограмма довольно
проста и ясна. Если вам (как и мне) не нравится тестировать так много новых подпрограмм
одновременно все в порядке. Вы можете заглушить подпрограммы типа Convert, Promote и
SameType так как они не считывают входной поток. Вы не получите корректный код,
конечно, но программа должна работать. Затем постепенно расширяйте их.
При тестировании программы не забудьте, что] вы сначала должны объявить некоторые
переменные а затем начать "тело" программы с "B" в верхнем регистре (для BEGIN). Вы
должны обнаружить, что синтаксический анализатор обрабатывает любые аддитивные
выражения. Как только все подпрограммы преобразования будет введены, вы должны
увидеть, что генерируется правильный код и код для преобразования типов вставляется в
нужных местах. Попробуйте смешивать переменные различных размеров а также литералы.
Удостоверьтесь, что все работает правильно. Как обычно, хорошо было бы попробовать
некоторые ошибочные выражения и посмотреть, как компилятор обрабатывает их.
ПОЧЕМУ ТАК МНОГО ПРОЦЕДУР?
К этому моменту вы можете подумать, что я зашел слишком далеко в смысле глубоко
вложенных процедур. В этом несомненно есть большие накладные расходы. Но в моем
безумии есть смысл. Как в случае с UnOp, я заглядываю вперед на время, когда мы захотим
генерировать лучший код. С таким способом организации кода мы можем достичь этого без
значительных изменений в программе Например, в случаях, где значение, помещенное в стек
не должно преобразовываться, все же лучше использовать инструкцию "вытолкнуть и
сложить". Если мы решим проверять такие случаи, мы можем включить дополнительные
тесты в PopAdd] и] PopSub не изменяя что-либо еще.