{
****************************************************************************
*                                                                          *
*       Unit Gen_Code.pas : contains procedures for generating asm codes.  *
*                                                                          *
****************************************************************************
}
unit Gen_Code;
interface
uses Globals,Errors;

procedure Emit(s : string);
procedure EmitLn(s : string);
procedure EmitInc(s : string);
function  NewLabel : LabelStr;
Function  GenCode(c : ObjCode; n : integer; s : string) : integer;
{ Procedure DumpStrings; }
Var
  LabelCount : Word;

implementation

{Procedure DumpStrings;
Var
  i : integer;
  s : string;
Begin
  WriteLn(Dest,'; String constants');
  for i := 0 to StringCount-1 do
  begin
    s := StringConst[i];
    WriteLn(Dest,'_STR'+Numb(i),TAB,
                 'DD',TAB,
                 Numb(Length(S)));
    WriteLn(Dest,TAB,'DB',TAB,'''',S,'''');
  end;
End;}

procedure Emit(s : string);
begin
  Write(Dest,'      ', s);
end;

procedure EmitLn(s : string);
begin
  Emit(s);
  WriteLn(Dest);
end;

procedure EmitInc(s : string);
begin
  WriteLn(Inc_Proc,TAB+s);
end;

function  NewLabel:LabelStr;
var
  tmp : string;
begin
  Str(LabelCount,tmp); Inc(LabelCount);
  tmp := 'L'+tmp;
  NewLabel := tmp;
end;

Function GenCode(c : ObjCode; n : integer; s : string) : integer;
Var
 Tmp : String;
 x,y : integer;
Begin
if (ProcB <> true) or (n = -100) then begin
  Case c of
    _Clear      : EmitLn('xor   eax,eax');
    _LoadConst  : EmitLn('mov   eax,'+Numb(N));
    _LoadVar    : begin
                    x := CheckSymbol(s);
                    y := TypeTable[x].Size;
                    Case Y of
                      1 : begin
                               EmitLn('xor   eax,eax');
                               EmitLn('mov   al,BYTE ptr['+S+']')
                          end;
                      2 : begin
                            EmitLn('xor   eax,eax');
                            EmitLn('mov   ax,WORD ptr['+S+']')
                          end;
                      4 : begin
                            EmitLn('xor   eax,eax');
                            EmitLn('mov   eax,DWORD ptr['+S+']');
                          end;
                    else
                        Abort('Illegal variable size');
                    end;
                  end;

    _Push       : EmitLn('push  eax');
    _PopAdd     : begin
                    EmitLn('pop   ebx');
                    EmitLn('add   eax,ebx');
                  end;
    _PopSub     : begin
                    EmitLn('pop   ebx');
                    EmitLn('sub   ebx,eax');
                    EmitLn('mov   eax,ebx');
                  end;
    _PopMul     : begin
                    EmitLn('pop   ebx');
                    EmitLn('pop   ebx');
                  end;
    _PopDiv     : begin
                    EmitLn('mov   ebx,eax');
                    EmitLn('xor   edx,edx');
                    EmitLn('pop   eax');
                    EmitLn('div   ebx');
                  end;
    _Store      : begin
                    x := CheckSymbol(s);
                    y := TypeTable[x].Size;
                    Case Y of
                      1 : EmitLn('mov   BYTE  ptr['+S+'],al');
                      2 : EmitLn('mov   WORD  ptr['+S+'],ax');
                      4 : EmitLn('mov   DWORD ptr['+S+'],eax');
                    else
                      Abort('Illegal variable size');
                    end;
                  end;
    _Inc_Const  : begin
                    (* if N = 1 then
                      EmitLn('inc   ['+S+']')
                    else *)
                      EmitLn('add   ['+S+'],'+numb(N) );
                  end;
    _PutLabel   : WriteLn(Dest,S+':');
    _JumpTo     : EmitLn('jmp   '+S);
    _IfJumpTo   : Begin
                    Tmp := NewLabel;
                    EmitLn('or    eax,eax');
                    EmitLn('jnz   '+S);
                  End;

    _IfNotJumpTo: Begin
                    Tmp := NewLabel;
                    EmitLn('or    eax,eax');   { Avoid 128 byte jump bounds }
                    EmitLn('jz    '+S);
                  End;

    _ProgramInit: Begin
                    Writeln(Dest,'; Program name: '+ ProgramName);
                    if Console_App = True then
                       Writeln(Dest,'.MODEL WIN32 CONSOLE')
                    else Writeln(Dest,'.MODEL WIN32');

                    Writeln(Dest,'.MEM 32');
                    Writeln(Dest,'.STACK 32');

                    if Console_App = True then
                       Writeln(Dest,'.INCLUDE CONSOLE.INC');

                    Writeln(Dest,'.INCLUDE WINSYS.INC');
                    WriteLn(Dest);
                    WriteLn(Dest,'Start:                             ');
                  End;

    _ProgramExit: Begin
                    EmitLn('.invoke .win32 ''Kernel32.ExitProcess''');
                  End;

    _Logical    : Begin
                    EmitLn('neg   eax');         { AX <> 0 ---> Carry  }
                    EmitLn('mov   eax,0');       {       0 ---> AX     }
                    EmitLn('sbb   eax,eax');     { Carry  ----> ALL AX }
                  End;

    _Logical_Not: Begin
                    EmitLn('neg   eax');         { AX <> 0 ---> Carry  }
                    EmitLn('mov   eax,-1');      {      -1 ---> AX     }
                    EmitLn('adc   eax,0');       { Not Carry -> ALL AX }
                  End;

    Greater     : Begin
                    EmitLn('pop   ebx');
                    EmitLn('sub   eax,ebx');
                    EmitLn('mov   eax,0' );
                    EmitLn('sbb   eax,0' );
                  end;

    Less        : Begin
                    EmitLn('pop   ebx');
                    EmitLn('sub   ebx,eax');
                    EmitLn('mov   eax,0' );
                    EmitLn('sbb   eax,0' );
                  end;

    _PutRead    : EmitLn('ReadLn');

    _PutBox     : begin
                    EmitLn('mov ecx,0');
                    EmitLn('push ecx');
                    EmitLn('push ecx');
                    Writeln(Dest,'      push offset N', StringCount-1);
                    WriteLn(Dest,'      push offset N',StringCount);
                    EmitLn('push 0');
                    EmitLn('call MessageBox');
                  end;
    _IncludeProc: EmitLn('.INCLUDE '+ s +'.inc');
    _CallMacro  : EmitLn(s);
    else
      Abort('Unknown ObjCode');
  end;
end
else if ProcB = true then begin
  Case c of
    _Clear      : EmitInc('xor   eax,eax');
    _LoadConst  : EmitInc('mov   eax,'+Numb(N));
    _LoadVar    : begin
                    x := CheckSymbol(s);
                    y := TypeTable[x].Size;
                    Case Y of
                      1 : begin
                               EmitInc('xor   eax,eax');
                               EmitInc('mov   al,BYTE ptr['+S+']')
                          end;
                      2 : begin
                            EmitInc('xor   eax,eax');
                            EmitInc('mov   ax,WORD ptr['+S+']')
                          end;
                      4 : EmitInc('mov   eax,DWORD ptr['+S+']');
                    else
                        Abort('Illegal variable size');
                    end;
                  end;

    _Push       : EmitInc('push  eax');
    _PopAdd     : begin
                    EmitInc('pop   ebx');
                    EmitInc('add   eax,ebx');
                  end;
    _PopSub     : begin
                    EmitInc('pop   ebx');
                    EmitInc('sub   ebx,eax');
                    EmitInc('mov   eax,ebx');
                  end;
    _PopMul     : begin
                    EmitInc('pop   ebx');
                    EmitInc('pop   ebx');
                  end;
    _PopDiv     : begin
                    EmitInc('mov   ebx,eax');
                    EmitInc('xor   edx,edx');
                    EmitInc('pop   eax');
                    EmitInc('div   ebx');
                  end;
    _Store      : begin
                    x := CheckSymbol(s);
                    y := TypeTable[x].Size;
                    Case Y of
                      1 : EmitInc('mov   BYTE  ptr['+S+'],al');
                      2 : EmitInc('mov   WORD  ptr['+S+'],ax');
                      4 : EmitInc('mov   DWORD ptr['+S+'],eax');
                    else
                      Abort('Illegal variable size');
                    end;
                  end;
    _Inc_Const  : begin
                    (* if N = 1 then
                      EmitInc('inc   ['+S+']')
                    else *)
                      EmitInc('add   ['+S+'],'+numb(N) );
                  end;
    _PutLabel   : WriteLn(Inc_Proc,S+':');
    _JumpTo     : EmitInc('jmp   '+S);
    _IfJumpTo   : Begin
                    Tmp := NewLabel;
                    EmitInc('or    eax,eax');
                    EmitInc('jnz   '+S);
                  End;

    _IfNotJumpTo: Begin
                    Tmp := NewLabel;
                    EmitInc('or    eax,eax');   { Avoid 128 byte jump bounds }
                    EmitInc('jz    '+S);
                  End;

    _Logical    : Begin
                    EmitInc('neg   eax');         { AX <> 0 ---> Carry  }
                    EmitInc('mov   eax,0');       {       0 ---> AX     }
                    EmitInc('sbb   eax,eax');     { Carry  ----> ALL AX }
                  End;

    _Logical_Not: Begin
                    EmitInc('neg   eax');         { AX <> 0 ---> Carry  }
                    EmitInc('mov   eax,-1');      {      -1 ---> AX     }
                    EmitInc('adc   eax,0');       { Not Carry -> ALL AX }
                  End;

    Greater     : Begin
                    EmitInc('pop   ebx');
                    EmitInc('sub   eax,ebx');
                    EmitInc('mov   eax,0' );
                    EmitInc('sbb   eax,0' );
                  end;

    Less        : Begin
                    EmitInc('pop   ebx');
                    EmitInc('sub   ebx,eax');
                    EmitInc('mov   eax,0' );
                    EmitInc('sbb   eax,0' );
                  end;

    _PutRead    : EmitInc('ReadLn');

    _PutBox     : begin
                    EmitInc('mov ecx,0');
                    EmitInc('push ecx');
                    EmitInc('push ecx');
                    Writeln(Inc_Proc,'      push offset N', StringCount-1);
                    WriteLn(Inc_Proc,'      push offset N',StringCount);
                    EmitInc('push 0');
                    EmitInc('call MessageBox');
                  end;

  else
    Abort('Unknown ObjCode');
   end;
  end;
 end;
end.