{
    $Id$
    Copyright (c) 1998 by Florian Klaempfl

    Reads inline assembler and writes the lines direct to the output

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

 ****************************************************************************
}
unit radi386;

  interface

    uses
      tree;

     function assemble : ptree;

  implementation

     uses
        i386,hcodegen,globals,scanner,aasm,
        cobjects,symtable,types,verbose,asmutils;

    function assemble : ptree;

      var
         retstr,s,hs : string;
         c : char;
         ende : boolean;
         sym : psym;
         code : paasmoutput;
         l : longint;

       procedure writeasmline;
         var
           i : longint;
         begin
           i:=length(s);
           while (i>0) and (s[i] in [' ',#9]) do
            dec(i);
           s[0]:=chr(i);
           if s<>'' then
            code^.concat(new(pai_direct,init(strpnew(s))));
            { consider it set function set if the offset was loaded }
           if assigned(procinfo.retdef) and
              (pos(retstr,upper(s))>0) then
              procinfo.funcret_is_valid:=true;
           s:='';
         end;

     begin
       ende:=false;
       s:='';
       if assigned(procinfo.retdef) and
          is_fpu(procinfo.retdef) then
         procinfo.funcret_is_valid:=true;
       if assigned(procinfo.retdef) and
          (procinfo.retdef<>pdef(voiddef)) then
         retstr:=upper(tostr(procinfo.retoffset)+'('+att_reg2str[procinfo.framepointer]+')')
       else
         retstr:='';
       c:=asmgetchar;
         code:=new(paasmoutput,init);
         while not(ende) do
           begin
              case c of
                 'A'..'Z','a'..'z','_' : begin
                      hs:='';
                      while ((ord(c)>=ord('A')) and (ord(c)<=ord('Z')))
                         or ((ord(c)>=ord('a')) and (ord(c)<=ord('z')))
                         or ((ord(c)>=ord('0')) and (ord(c)<=ord('9')))
                         or (c='_') do
                        begin
                           inc(byte(hs[0]));
                           hs[length(hs)]:=c;
                           c:=asmgetchar;
                        end;
                      if upper(hs)='END' then
                         ende:=true
                      else
                         begin
                            if c=':' then
                              begin
                                getsym(upper(hs),false);
                                if srsym<>nil then
                                  Message(assem_w_using_defined_as_local);
                              end;
                            if upper(hs)='FWAIT' then
                             FwaitWarning
                            else
                            { access to local variables }
                            if assigned(aktprocsym) then
                              begin
                                 { is the last written character an special }
                                 { char ?                                   }
                                 if (s[length(s)]='%') and
                                    ret_in_acc(procinfo.retdef) and
                                    ((pos('AX',upper(hs))>0) or
                                    (pos('AL',upper(hs))>0)) then
                                   procinfo.funcret_is_valid:=true;
                                 if (s[length(s)]<>'%') and
                                   (s[length(s)]<>'$') and
                                   ((s[length(s)]<>'0') or (hs[1]<>'x')) then
                                   begin
                                      if assigned(aktprocsym^.definition^.localst) then
                                        sym:=aktprocsym^.definition^.localst^.search(upper(hs))
                                      else
                                        sym:=nil;
                                      if assigned(sym) then
                                        begin
                                           if sym^.typ=varsym then
                                             begin
                                             {variables set are after a comma }
                                             {like in movl %eax,I }
                                             if pos(',',s) > 0 then
                                               pvarsym(sym)^.is_valid:=1
                                             else
                                             if (pos('MOV',upper(s)) > 0) and (pvarsym(sym)^.is_valid=0) then
                                              Message1(sym_n_local_var_not_init_yet,hs);
                                             hs:='-'+tostr(pvarsym(sym)^.address)+'('+att_reg2str[procinfo.framepointer]+')';
                                             end
                                           else
                                           { call to local function }
                                           if (sym^.typ=procsym) and (pos('CALL',upper(s))>0) then
                                             begin
                                                hs:=pprocsym(sym)^.definition^.mangledname;
                                             end;
                                        end
                                      else
                                        begin
                                           if assigned(aktprocsym^.definition^.parast) then
                                             sym:=aktprocsym^.definition^.parast^.search(upper(hs))
                                           else
                                             sym:=nil;
                                           if assigned(sym) then
                                             begin
                                                if sym^.typ=varsym then
                                                  begin
                                                     l:=pvarsym(sym)^.address;
                                                     { set offset }
                                                     inc(l,aktprocsym^.definition^.parast^.call_offset);
                                                     hs:=tostr(l)+'('+att_reg2str[procinfo.framepointer]+')';
                                                     if pos(',',s) > 0 then
                                                       pvarsym(sym)^.is_valid:=1;
                                                  end;
                                             end
                                      { I added that but it creates a problem in line.ppi
                                      because there is a local label wbuffer and
                                      a static variable WBUFFER ...
                                      what would you decide, florian ?
                                      else

                                        begin
                                           getsym(upper(hs),false);
                                           sym:=srsym;
                                           if assigned(sym) and (sym^.typ = varsym)
                                              or (sym^.typ = typedconstsym) then
                                             hs:=sym^.mangledname;
                                           if (sym^.typ=procsym) and (pos('CALL',upper(s))>0) then
                                             begin
                                                if assigned(pprocsym(sym)^.definition^.nextoverloaded) then
                                                  begin
                                                     exterror:=strpnew(' calling an overloaded procedure in asm');
                                                     warning(user_defined);
                                                  end;
                                                hs:=pprocsym(sym)^.definition^.mangledname;
                                             end;
                                        end   }
                                           else if upper(hs)='__SELF' then
                                             begin
                                                if assigned(procinfo._class) then
                                                  hs:=tostr(procinfo.ESI_offset)+'('+att_reg2str[procinfo.framepointer]+')'
                                                else
                                                 Message(assem_e_cannot_use_SELF_outside_a_method);
                                             end
                                           else if upper(hs)='__RESULT' then
                                             begin
                                                if assigned(procinfo.retdef) and
                                                  (procinfo.retdef<>pdef(voiddef)) then
                                                  begin
                                                  hs:=retstr;
                                                  end
                                                else
                                                 Message(assem_w_void_function);
                                             end
                                           else if upper(hs)='__OLDEBP' then
                                             begin
                                                            { complicate to check there }
                                                            { we do it: }
                                                if lexlevel>2 then
                                                  hs:=tostr(procinfo.framepointer_offset)
                                                                +'('+att_reg2str[procinfo.framepointer]+')'
                                                else
                                                  Message(assem_e_cannot_use___OLDEBP_outside_nested_procedure);
                                                end;
                                           end;
                                       { end;}
                                   end;
                              end;
                            s:=s+hs;
                         end;
                   end;
 '{',';',#10,#13 : begin
                      if pos(retstr,s) > 0 then
                        procinfo.funcret_is_valid:=true;
                     writeasmline;
                     c:=asmgetchar;
                   end;
             #26 : Message(scan_f_end_of_file);
             else
               begin
                 inc(byte(s[0]));
                 s[length(s)]:=c;
                 c:=asmgetchar;
               end;
           end;
         end;
       writeasmline;
       assemble:=genasmnode(code);
     end;

end.
{
  $Log$
  Revision 1.2  1998-04-08 16:58:06  pierre
    * several bugfixes
      ADD ADC and AND are also sign extended
      nasm output OK (program still crashes at end
      and creates wrong assembler files !!)
      procsym types sym in tdef removed !!

  Revision 1.1.1.1  1998/03/25 11:18:15  root
  * Restored version

  Revision 1.13  1998/03/24 21:48:33  florian
    * just a couple of fixes applied:
         - problem with fixed16 solved
         - internalerror 10005 problem fixed
         - patch for assembler reading
         - small optimizer fix
         - mem is now supported

  Revision 1.12  1998/03/10 16:27:43  pierre
    * better line info in stabs debug
    * symtabletype and lexlevel separated into two fields of tsymtable
    + ifdef MAKELIB for direct library output, not complete
    + ifdef CHAINPROCSYMS for overloaded seach across units, not fully
      working
    + ifdef TESTFUNCRET for setting func result in underfunction, not
      working

  Revision 1.11  1998/03/10 01:17:26  peter
    * all files have the same header
    * messages are fully implemented, EXTDEBUG uses Comment()
    + AG... files for the Assembler generation

  Revision 1.10  1998/03/09 12:58:12  peter
    * FWait warning is only showed for Go32V2 and $E+
    * opcode tables moved to i386.pas/m68k.pas to reduce circular uses (and
      for m68k the same tables are removed)
    + $E for i386

  Revision 1.9  1998/03/06 00:52:51  peter
    * replaced all old messages from errore.msg, only ExtDebug and some
      Comment() calls are left
    * fixed options.pas

  Revision 1.8  1998/03/03 16:45:23  peter
    + message support for assembler parsers

  Revision 1.7  1998/03/02 01:49:14  peter
    * renamed target_DOS to target_GO32V1
    + new verbose system, merged old errors and verbose units into one new
      verbose.pas, so errors.pas is obsolete

  Revision 1.6  1998/02/13 10:35:35  daniel
  * Made Motorola version compilable.
  * Fixed optimizer

  Revision 1.5  1998/02/07 18:01:27  carl
    + fwait warning for emulation

  Revision 1.3  1997/11/30 18:12:17  carl
  * bugfix of line numbering.

  Revision 1.2  1997/11/28 18:14:44  pierre
   working version with several bug fixes

  Revision 1.1.1.1  1997/11/27 08:33:00  michael
  FPC Compiler CVS start


  Pre-CVS log:

  History:
      19th october 1996:
         + created from old asmbl.pas
      13th october 1996:
         + renamed to radi386
}
