home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Programming / fpc / compiler / asmutils.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-09-24  |  58.4 KB  |  1,698 lines

  1. {
  2.     $Id: asmutils.pas,v 1.1.1.1 1998/03/25 11:18:12 root Exp $
  3.     Copyright (c) 1998 Carl Eric Codere
  4.  
  5.     This unit implements some support routines for assembler parsing
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation; either version 2 of the License, or
  10.     (at your option) any later version.
  11.  
  12.     This program is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License
  18.     along with this program; if not, write to the Free Software
  19.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21.  **********************************************************************}
  22.  
  23. Unit AsmUtils;
  24.  
  25. {*************************************************************************}
  26. {  This unit implements some objects as well as utilities which will be   }
  27. {  used by all inline assembler parsers (non-processor specific).         }
  28. {                                                                         }
  29. {  Main routines/objects herein:                                          }
  30. {  o Object TExprParse is a simple expression parser to resolve assembler }
  31. {    expressions. (Based generally on some code by Thai Tran from SWAG).  }
  32. {  o Object TInstruction is a simple object used for instructions         }
  33. {  o Record TOperand is a simple record used to store information on      }
  34. {    each operand.                                                        }
  35. {  o String conversion routines from octal,binary and hex to decimal.     }
  36. {  o A linked list object/record for local labels                         }
  37. {  o Routines for retrieving symbols (local and global)                   }
  38. {  o Object for a linked list of strings (with duplicate strings not      }
  39. {    allowed).                                                            }
  40. {  o Non-processor dependant routines for adding instructions to the      }
  41. {    instruction list.                                                    }
  42. {*************************************************************************}
  43.  
  44.  
  45. {--------------------------------------------------------------------}
  46. { LEFT TO DO:                                                        }
  47. { o Fix the remaining bugs in the expression parser, such as with    }
  48. {     4+-3                                                           }
  49. { o Add support for local typed constants search.                    }
  50. { o Add support for private/protected fields in method assembler     }
  51. {    routines.                                                       }
  52. {--------------------------------------------------------------------}
  53. Interface
  54.  
  55. Uses
  56.   symtable,aasm,hcodegen,verbose,systems,globals,files,strings,
  57.   cobjects,
  58. {$ifdef i386}
  59.   i386;
  60. {$endif}
  61. {$ifdef m68k}
  62.    m68k;
  63. {$endif}
  64.  
  65.  
  66. Const
  67.   RPNMax = 10;             { I think you only need 4, but just to be safe }
  68.   OpMax  = 25;
  69.  
  70.   maxoperands = 3;         { Maximum operands for assembler instructions }
  71.  
  72.  
  73. Type
  74.  
  75.  
  76.   {---------------------------------------------------------------------}
  77.   {                     Label Management types                          }
  78.   {---------------------------------------------------------------------}
  79.  
  80.  
  81.     PAsmLabel = ^TAsmLabel;
  82.     PString = ^String;
  83.  
  84.     { Each local label has this structure associated with it }
  85.     TAsmLabel = record
  86.       name: PString;    { pointer to a pascal string name of label }
  87.       lab: PLabel;      { pointer to a label as defined in FPC     }
  88.       emitted: boolean; { as the label itself been emitted ?       }
  89.       next: PAsmLabel;  { next node                                }
  90.     end;
  91.  
  92.     TAsmLabelList = Object
  93.     public
  94.       First: PAsmLabel;
  95.       Constructor Init;
  96.       Destructor Done;
  97.       Procedure Insert(s:string; lab: PLabel; emitted: boolean);
  98.       Function Search(const s: string): PAsmLabel;
  99.     private
  100.       Last: PAsmLabel;
  101.       Function NewPasStr(s:string): PString;
  102.     end;
  103.  
  104.  
  105.  
  106.   {---------------------------------------------------------------------}
  107.   {                 Instruction management types                        }
  108.   {---------------------------------------------------------------------}
  109.  
  110.   toperandtype = (OPR_NONE,OPR_REFERENCE,OPR_CONSTANT,OPR_REGISTER,OPR_LABINSTR,
  111.                   OPR_REGLIST);
  112.  
  113.     { When the TReference field isintvalue = TRUE }
  114.     { then offset points to an ABSOLUTE address   }
  115.     { otherwise isintvalue should always be false }
  116.  
  117.     { Special cases:                              }
  118.     {   For the M68k Target, size is UNUSED, the  }
  119.     {   opcode determines the size of the         }
  120.     {   instruction.                              }
  121.     {  DIVS/DIVU/MULS/MULU of the form dn,dn:dn   }
  122.     {  is stored as three operands!!              }
  123.  
  124.  
  125.     { Each instruction operand can be of this type }
  126.     TOperand = record
  127.       size: topsize;
  128.       opinfo: longint; { ao_xxxx flags }
  129.       case operandtype:toperandtype of
  130.        { the size of the opr_none field should be at least equal to each }
  131.        { other field as to facilitate initialization.                    }
  132.        OPR_NONE: (l: array[1..sizeof(treference)] of byte);
  133.        OPR_REFERENCE: (ref:treference);
  134.        OPR_CONSTANT:  (val: longint);
  135.        OPR_REGISTER:  (reg:tregister);
  136.        OPR_LABINSTR: (hl: plabel);
  137.        { Register list such as in the movem instruction }
  138.        OPR_REGLIST:  (list: set of tregister);
  139.     end;
  140.  
  141.  
  142.  
  143.     TInstruction = object
  144.     public
  145.       operands: array[1..maxoperands] of TOperand;
  146.       { if numops = zero, a size may still be valid in operands[1] }
  147.       { it still should be checked.                                }
  148.       numops: byte;
  149.       { set to TRUE if the instruction is labeled.                }
  150.       labeled: boolean;
  151.       { This is used for instructions such A_CMPSB... etc, to determine }
  152.       { the size of the instruction.                                    }
  153.       stropsize: topsize;
  154.       procedure init;
  155.       { sets up the prefix field with the instruction pointed to in s }
  156.       procedure addprefix(tok: tasmop);
  157.       { sets up the instruction with the instruction pointed to in s }
  158.       procedure addinstr(tok: tasmop);
  159.       { get the current instruction of this object }
  160.       function getinstruction: tasmop;
  161.       { get the current prefix of this instruction }
  162.       function getprefix: tasmop;
  163.     private
  164.       prefix: tasmop;
  165.       instruction: tasmop;
  166.     end;
  167.  
  168.  
  169.  
  170.  
  171.   {---------------------------------------------------------------------}
  172.   {                   Expression parser types                           }
  173.   {---------------------------------------------------------------------}
  174.  
  175.   { expression parser error codes }
  176.   texpr_error =
  177.   (zero_divide,       { divide by zero.     }
  178.    stack_overflow,    { stack overflow.     }
  179.    stack_underflow,   { stack underflow.    }
  180.    invalid_number,    { invalid conversion  }
  181.    invalid_op);       { invalid operator    }
  182.  
  183.  
  184.    TExprOperator = record
  185.     ch: char;           { operator }
  186.     is_prefix: boolean; { was it a prefix, possible prefixes are +,- and not }
  187.    end;
  188.  
  189.   String15 = String[15];
  190.   {**********************************************************************}
  191.   { The following operators are supported:                              }
  192.   {  '+' : addition                                                     }
  193.   {  '-' : subtraction                                                  }
  194.   {  '*' : multiplication                                               }
  195.   {  '/' : modulo division                                              }
  196.   {  '^' : exclusive or                                                 }
  197.   {  '<' : shift left                                                   }
  198.   {  '>' : shift right                                                  }
  199.   {  '&' : bitwise and                                                  }
  200.   {  '|' : bitwise or                                                   }
  201.   {  '~' : bitwise complement                                           }
  202.   {  '%' : modulo division                                              }
  203.   {  nnn: longint numbers                                               }
  204.   {  ( and ) parenthesis                                                }
  205.   {**********************************************************************}
  206.  
  207.   TExprParse = Object
  208.     public
  209.      Constructor Init;
  210.      Destructor Done;
  211.      Function Evaluate(Expr:  String): longint;
  212.      Procedure Error(anerror: texpr_error); virtual;
  213.      Function Priority(_Operator: Char): Integer; virtual;
  214.     private
  215.      RPNStack   : Array[1..RPNMax] of longint;        { Stack For RPN calculator }
  216.      RPNTop     : Integer;
  217.      OpStack    : Array[1..OpMax] of TExprOperator;    { Operator stack For conversion }
  218.      OpTop      : Integer;
  219.      Procedure RPNPush(Num: Longint);
  220.      Function RPNPop: Longint;
  221.      Procedure RPNCalc(token: String15; prefix: boolean);
  222.      Procedure OpPush(_Operator: char; prefix: boolean);
  223.      { In reality returns TExprOperaotr }
  224.      Procedure OpPop(var _Operator:TExprOperator);
  225.   end;
  226.  
  227.  
  228.   {---------------------------------------------------------------------}
  229.   {                     String routines                                 }
  230.   {---------------------------------------------------------------------}
  231.  
  232.  
  233.   {*********************************************************************}
  234.   { PROCEDURE PadZero;                                                  }
  235.   {  Description: Makes sure that the string specified is of the given  }
  236.   {  length, by padding it with binary zeros, or truncating if necessary}
  237.   {  Remark: The return value is determined BEFORE any eventual padding.}
  238.   {  Return Value: TRUE  = if length of string s was <= then n          }
  239.   {                FALSE = if length of string s was > then n           }
  240.   {*********************************************************************}
  241.   Function PadZero(Var s: String; n: byte): Boolean;
  242.  
  243.   { Converts an Hex digit string to a Decimal string                      }
  244.   { Returns '' if there was an error.                                     }
  245.   Function HexToDec(const S:String): String;
  246.  
  247.   { Converts a binary digit string to a Decimal string                    }
  248.   { Returns '' if there was an error.                                     }
  249.   Function BinaryToDec(const S:String): String;
  250.  
  251.   { Converts an octal digit string to a Decimal string                    }
  252.   { Returns '' if there was an error.                                     }
  253.   Function OctalToDec(const S:String): String;
  254.  
  255.   { Converts a string containing C styled escape sequences to }
  256.   { a pascal style string.                                    }
  257.   Function EscapeToPascal(const s:string): string;
  258.  
  259.   Procedure ConcatPasString(p : paasmoutput;s:string);
  260.   { Writes the string s directly to the assembler output }
  261.   Procedure ConcatDirect(p : paasmoutput;s:string);
  262.  
  263.  
  264.   {---------------------------------------------------------------------}
  265.   {                     Symbol helper routines                          }
  266.   {---------------------------------------------------------------------}
  267.  
  268.   Function GetTypeOffset(const base: string; const field: string;
  269.     Var Offset: longint):boolean;
  270.   Function GetVarOffset(const base: string; const field: string;
  271.     Var Offset: longint):boolean;
  272.   Function SearchIConstant(const s:string; var l:longint): boolean;
  273.   Function SearchLabel(const s: string; var hl: plabel): boolean;
  274.   Function CreateVarInstr(var Instr: TInstruction; const hs:string;
  275.      operandnum:byte):boolean;
  276.   {*********************************************************************}
  277.   { FUNCTION NewPasStr(s:string): PString                               }
  278.   {  Description: This routine allocates a string on the heap and       }
  279.   {  returns a pointer to the allocated string.                         }
  280.   {                                                                     }
  281.   {  Remarks: The string allocated should not be modified, since it's   }
  282.   {  length will be less then 255.                                      }
  283.   {  Remarks: It is assumed that HeapError will be called if an         }
  284.   {  allocation fails.                                                  }
  285.   {*********************************************************************}
  286.   Function newpasstr(s: string): Pointer;
  287.   Procedure SetupResult(Var Instr:TInstruction; operandnum: byte);
  288.   Procedure FWaitWarning;
  289.  
  290.   {---------------------------------------------------------------------}
  291.   {                  Instruction generation routines                    }
  292.   {---------------------------------------------------------------------}
  293.  
  294.   { swaps in the case of a 2/3 operand opcode the destination and the    }
  295.   { source as to put it in AT&T style instruction format.                }
  296.   Procedure SwapOperands(Var instr: TInstruction);
  297.   Procedure ConcatLabel(p : paasmoutput;op : tasmop;var l : plabel);
  298.   Procedure ConcatConstant(p : paasmoutput;value: longint; maxvalue: longint);
  299.   Procedure ConcatRealConstant(p : paasmoutput;value: bestreal; real_typ : tfloattype);
  300.   Procedure ConcatString(p : paasmoutput;s:string);
  301.   Procedure ConcatPublic(p:paasmoutput;const s : string);
  302.   Procedure ConcatLocal(p:paasmoutput;const s : string);
  303.   Procedure ConcatGlobalBss(const s : string;size : longint);
  304.   Procedure ConcatLocalBss(const s : string;size : longint);
  305.   { add to list of external labels }
  306.   Procedure ConcatExternal(const s : string;typ : texternal_typ);
  307.   { add to internal list of labels }
  308.   Procedure ConcatInternal(const s : string;typ : texternal_typ);
  309.  
  310. Implementation
  311.  
  312. {*************************************************************************}
  313. {                         Expression Parser                               }
  314. {*************************************************************************}
  315.  
  316. Constructor TExprParse.Init;
  317. Begin
  318. end;
  319.  
  320. Procedure TExprParse.Error(anerror:texpr_error);
  321. var
  322.   t : tmsgconst;
  323. Begin
  324.   case anerror of
  325.   zero_divide: t:=assem_f_ev_zero_divide;
  326.   stack_overflow: t:=assem_f_ev_stack_overflow;
  327.   stack_underflow: t:=assem_f_ev_stack_underflow;
  328.   invalid_number: t:=assem_f_ev_invalid_number;
  329.   invalid_op: t:=assem_f_ev_invalid_op;
  330.   else
  331.    t:=assem_f_ev_unknown;
  332.   end;
  333.   Message(t);
  334. end;
  335.  
  336. Procedure TExprParse.RPNPush(Num : longint); { Add an operand to the top of the RPN stack }
  337. begin
  338.   if RPNTop < RPNMax then
  339.   begin
  340.     Inc(RPNTop);
  341.     RPNStack[RPNTop] := Num;
  342.   end
  343.   else
  344.     Error(stack_overflow); { Put some error handler here }
  345. end;
  346.  
  347.  
  348.  
  349.  
  350. Function TExprParse.RPNPop : longint;       { Get the operand at the top of the RPN stack }
  351. begin
  352.   if RPNTop > 0 then
  353.   begin
  354.     RPNPop := RPNStack[RPNTop];
  355.     Dec(RPNTop);
  356.   end
  357.   else  { Put some error handler here }
  358.    Error(stack_underflow);
  359. end;
  360.  
  361. Procedure TExprParse.RPNCalc(Token : String15; prefix:boolean);                       { RPN Calculator }
  362. Var
  363.   Temp  : longint;
  364.   LocalError : Integer;
  365. begin
  366. {  Write(Token, ' ');              This just outputs the RPN expression }
  367.  
  368.   if (Length(Token) = 1) and (Token[1] in ['+', '-', '*', '/','&','|','%','^','~','<','>']) then
  369.   Case Token[1] of                                   { Handle operators }
  370.     '+' : Begin
  371.        if prefix then
  372.        else
  373.           RPNPush(RPNPop + RPNPop);
  374.      end;
  375.     '-' : Begin
  376.       if prefix then
  377.          RPNPush(-(RPNPop))
  378.       else
  379.          RPNPush(RPNPop - RPNPop);
  380.      end;
  381.     '*' : RPNPush(RPNPop * RPNPop);
  382.     '&' : RPNPush(RPNPop AND RPNPop);
  383.     '|' : RPNPush(RPNPop OR RPNPop);
  384.     '~' : RPNPush(NOT RPNPop);
  385.     '<' : RPNPush(RPNPop SHL RPNPop);
  386.     '>' : RPNPush(RPNPop SHR RPNPop);
  387.     '%' : begin
  388.       Temp := RPNPop;
  389.       if Temp <> 0 then
  390.        RPNPush(RPNPop mod Temp)
  391.       else Error(zero_divide); { Handle divide by zero error }
  392.      end;
  393.     '^' : RPNPush(RPNPop XOR RPNPop);
  394.     '/' :
  395.     begin
  396.       Temp := RPNPop;
  397.       if Temp <> 0 then
  398.    RPNPush(RPNPop div Temp)
  399.       else  Error(zero_divide);{ Handle divide by 0 error }
  400.     end;
  401.   end
  402.   else
  403.   begin                   { Convert String to number and add to stack }
  404.     if token='-2147483648' then
  405.       begin
  406.          temp:=$80000000;
  407.          localerror:=0;
  408.       end
  409.     else
  410.       Val(Token, Temp, LocalError);
  411.     if LocalError = 0 then
  412.       RPNPush(Temp)
  413.     else  Error(invalid_number);{ Handle error }
  414.   end;
  415. end;
  416.  
  417. Procedure TExprParse.OpPush(_Operator : char;prefix: boolean);  { Add an operator onto top of the stack }
  418. begin
  419.   if OpTop < OpMax then
  420.   begin
  421.     Inc(OpTop);
  422.     OpStack[OpTop].ch := _Operator;
  423.     OpStack[OpTop].is_prefix := prefix;
  424.   end
  425.   else Error(stack_overflow); { Put some error handler here }
  426. end;
  427.  
  428. Procedure TExprParse.OpPop(var _Operator:TExprOperator);               { Get operator at the top of the stack }
  429. begin
  430.   if OpTop > 0 then
  431.   begin
  432.     _Operator := OpStack[OpTop];
  433.     Dec(OpTop);
  434.   end
  435.   else Error(stack_underflow); { Put some error handler here }
  436. end;
  437.  
  438. Function TExprParse.Priority(_Operator : Char) : Integer; { Return priority of operator }
  439. { The greater the priority, the higher the precedence }
  440. begin
  441.   Case _Operator OF
  442.     '('      : Priority := 0;
  443.     '+', '-' : Priority := 1;
  444.     '*', '/','%','<','>' : Priority := 2;
  445.     '|','&','^','~': Priority := 0;
  446.     else  Error(invalid_op);{ More error handling }
  447.   end;
  448. end;
  449.  
  450. Function TExprParse.Evaluate(Expr : String):longint;
  451. Var
  452.   I     : Integer;
  453.   Token : String15;
  454.   opr: TExprOperator;
  455. begin
  456.   OpTop  := 0;                                              { Reset stacks }
  457.   RPNTop := 0;
  458.   Token  := '';
  459.  
  460.   For I := 1 to Length(Expr) DO
  461.  
  462.      if Expr[I] in ['0'..'9'] then
  463.       begin       { Build multi-digit numbers }
  464.    Token := Token + Expr[I];
  465.    if I = Length(Expr) then          { Send last one to calculator }
  466.       RPNCalc(Token,false);
  467.       end
  468.      else
  469.      if Expr[I] in ['+', '-', '*', '/', '(', ')','^','&','|','%','~','<','>'] then
  470.       begin
  471.        if Token <> '' then
  472.    begin        { Send last built number to calc. }
  473.     RPNCalc(Token,false);
  474.     Token := '';
  475.    end;
  476.  
  477.      Case Expr[I] OF
  478.        '(' : OpPush('(',false);
  479.        ')' :
  480.      begin
  481.         While OpStack[OpTop].ch <> '(' DO
  482.         Begin
  483.           OpPop(opr);
  484.           RPNCalc(opr.ch,opr.is_prefix);
  485.         end;
  486.         OpPop(opr);                          { Pop off and ignore the '(' }
  487.      end;
  488.  
  489.    '+','-','~':  Begin
  490.       While (OpTop > 0) AND
  491.           (Priority(Expr[I]) <= Priority(OpStack[OpTop].ch)) DO
  492.         Begin
  493.              OpPop(opr);
  494.              RPNCalc(opr.ch,opr.is_prefix);
  495.         end;
  496.        { if start of expression then surely a prefix }
  497.        { or if previous char was also an operator    }
  498.        { push it and don't evaluate normally         }
  499.        { workaround for -2147483648 }
  500.        if (expr[I]='-') and (expr[i+1] in ['0'..'9']) then
  501.          begin
  502.             token:='-';
  503.             expr[i]:='+';
  504.          end;
  505.        if (I = 1) or (not (Expr[I-1] in ['0'..'9','(',')'])) then
  506.          OpPush(Expr[I],true)
  507.        else
  508.          OpPush(Expr[I],false);
  509.       end;
  510.  
  511.       '*', '/','^','|','&','%','<','>' :
  512.     begin
  513.       While (OpTop > 0) AND
  514.           (Priority(Expr[I]) <= Priority(OpStack[OpTop].ch)) DO
  515.         Begin
  516.              OpPop(opr);
  517.              RPNCalc(opr.ch,opr.is_prefix);
  518.         end;
  519.         OpPush(Expr[I],false);
  520.     end;
  521.      end; { Case }
  522.   end
  523.     else Error(invalid_op);
  524.       { Handle bad input error }
  525.  
  526.   While OpTop > 0 do                     { Pop off the remaining operators }
  527.   Begin
  528.     OpPop(opr);
  529.     RPNCalc(opr.ch,opr.is_prefix);
  530.   end;
  531.  
  532.   { The result is stored on the top of the stack }
  533.   Evaluate := RPNPop;
  534. end;
  535.  
  536.  
  537. Destructor TExprParse.Done;
  538. Begin
  539. end;
  540.  
  541.  
  542. {*************************************************************************}
  543. {                         String conversions/utils                        }
  544. {*************************************************************************}
  545.  
  546.   Function newpasstr(s: string): Pointer;
  547.   Var
  548.    StrPtr: PString;
  549.   Begin
  550.     GetMem(StrPtr, length(s)+1);
  551.     Move(s,StrPtr^,length(s)+1);
  552.     newpasstr:= Strptr;
  553.   end;
  554.  
  555.  
  556.   Function EscapeToPascal(const s:string): string;
  557.   { converts a C styled string - which contains escape }
  558.   { characters to a pascal style string.               }
  559.   var
  560.    i,j: word;
  561.    str: string;
  562.    temp: string;
  563.    value: byte;
  564.    code: integer;
  565.   Begin
  566.    str:='';
  567.    i:=1;
  568.    j:=1;
  569.    repeat
  570.      if s[i] = '\' then
  571.      Begin
  572.       Inc(i);
  573.       if i > 255 then
  574.       Begin
  575.        EscapeToPascal:=str;
  576.        exit;
  577.       end;
  578.       case s[i] of
  579.        '\': insert('\',str,j);
  580.        'b': insert(#08,str,j);
  581.        'f': insert(#12,str,j);
  582.        'n': insert(#10,str,j);
  583.        'r': insert(#13,str,j);
  584.        't': insert(#09,str,j);
  585.        '"': insert('"',str,j);
  586.        { octal number }
  587.        '0'..'7': Begin
  588.                   temp:=s[i];
  589.                   temp:=temp+s[i+1];
  590.                   temp:=temp+s[i+2];
  591.                   inc(i,2);
  592.                   val(octaltodec(temp),value,code);
  593.                   if (code <> 0) then
  594.                    Message(assem_w_invalid_numeric);
  595.                   insert(chr(value),str,j);
  596.                  end;
  597.      { hexadecimal number }
  598.      'x': Begin
  599.             temp:=s[i+1];
  600.             temp:=temp+s[i+2];
  601.             inc(i,2);
  602.             val(hextodec(temp),value,code);
  603.             if (code <> 0) then
  604.              Message(assem_w_invalid_numeric);
  605.             insert(chr(value),str,j);
  606.           end;
  607.      else
  608.       Begin
  609.          Message1(assem_e_escape_seq_ignored,s[i]);
  610.          insert(s[i],str,j);
  611.       end;
  612.     end; {end case }
  613.     Inc(i);
  614.    end
  615.    else
  616.    Begin
  617.     Insert(s[i],str,j);
  618.     Inc(i);
  619.     if i > 255 then
  620.     Begin
  621.      EscapeToPascal:=str;
  622.      exit;
  623.     end;
  624.    end;
  625.    Inc(j);
  626.  until (i > length(s)) or (j > 255);
  627.  EscapeToPascal:=str;
  628. end;
  629.  
  630.  
  631.  
  632.   Function OctalToDec(const S:String): String;
  633.   { Converts an octal string to a Decimal string }
  634.   { Returns '' if there was an error.            }
  635.   var vs: longint;
  636.     c: byte;
  637.     st: string;
  638.   Begin
  639.    vs := 0;
  640.    for c:=1 to length(s) do
  641.    begin
  642.      case s[c] of
  643.      '0': vs:=vs shl 3;
  644.      '1': vs:=vs shl 3+1;
  645.      '2': vs:=vs shl 3+2;
  646.      '3': vs:=vs shl 3+3;
  647.      '4': vs:=vs shl 3+4;
  648.      '5': vs:=vs shl 3+5;
  649.      '6': vs:=vs shl 3+6;
  650.      '7': vs:=vs shl 3+7;
  651.     else
  652.       begin
  653.         OctalToDec := '';
  654.         exit;
  655.       end;
  656.     end;
  657.    end;
  658.      str(vs,st);
  659.      OctalToDec := st;
  660.   end;
  661.  
  662.   Function BinaryToDec(const S:String): String;
  663.   { Converts a binary string to a Decimal string }
  664.   { Returns '' if there was an error.            }
  665.   var vs: longint;
  666.     c: byte;
  667.     st: string;
  668.   Begin
  669.    vs := 0;
  670.    for c:=1 to length(s) do
  671.    begin
  672.      if s[c] = '0' then
  673.        vs:=vs shl 1
  674.      else
  675.      if s[c]='1' then
  676.        vs:=vs shl 1+1
  677.      else
  678.        begin
  679.          BinaryToDec := '';
  680.          exit;
  681.        end;
  682.    end;
  683.      str(vs,st);
  684.      BinaryToDec := st;
  685.   end;
  686.  
  687.  
  688.   Function HexToDec(const S:String): String;
  689.   var vs: longint;
  690.     c: byte;
  691.     st: string;
  692.   Begin
  693.    vs := 0;
  694.    for c:=1 to length(s) do
  695.    begin
  696.      case upcase(s[c]) of
  697.      '0': vs:=vs shl 4;
  698.      '1': vs:=vs shl 4+1;
  699.      '2': vs:=vs shl 4+2;
  700.      '3': vs:=vs shl 4+3;
  701.      '4': vs:=vs shl 4+4;
  702.      '5': vs:=vs shl 4+5;
  703.      '6': vs:=vs shl 4+6;
  704.      '7': vs:=vs shl 4+7;
  705.      '8': vs:=vs shl 4+8;
  706.      '9': vs:=vs shl 4+9;
  707.      'A': vs:=vs shl 4+10;
  708.      'B': vs:=vs shl 4+11;
  709.      'C': vs:=vs shl 4+12;
  710.      'D': vs:=vs shl 4+13;
  711.      'E': vs:=vs shl 4+14;
  712.      'F': vs:=vs shl 4+15;
  713.     else
  714.       begin
  715.         HexToDec := '';
  716.         exit;
  717.       end;
  718.     end;
  719.    end;
  720.      str(vs,st);
  721.      HexToDec := st;
  722.   end;
  723.  
  724.   Function PadZero(Var s: String; n: byte): Boolean;
  725.   Begin
  726.     PadZero := TRUE;
  727.     { Do some error checking first }
  728.     if Length(s) = n then
  729.       exit
  730.     else
  731.     if Length(s) > n then
  732.     Begin
  733.       PadZero := FALSE;
  734.       delete(s,n+1,length(s));
  735.       exit;
  736.     end
  737.     else
  738.       PadZero := TRUE;
  739.     { Fill it up with the specified character }
  740.     fillchar(s[length(s)+1],n-1,#0);
  741.     s[0] := chr(n);
  742.   end;
  743.  
  744. {*************************************************************************}
  745. {                          Instruction utilities                          }
  746. {*************************************************************************}
  747.  
  748.  Procedure TInstruction.init;
  749.  var
  750.   k: integer;
  751.  Begin
  752.   numops := 0;
  753.   labeled := FALSE;
  754.   stropsize := S_NO;
  755.   prefix := A_NONE;
  756.   instruction := A_NONE;
  757.   for k:=1 to maxoperands do
  758.   begin
  759.     operands[k].size := S_NO;
  760.     operands[k].operandtype := OPR_NONE;
  761.     { init to zeros }
  762.     fillchar(operands[k].l, sizeof(operands[k].l),#0);
  763.   end;
  764.  end;
  765.  
  766.  Procedure TInstruction.addprefix(tok: tasmop);
  767.  Begin
  768.    if tok = A_NONE then
  769.     Message(assem_e_syn_prefix_not_found);
  770.    if Prefix = A_NONE then
  771.     Prefix := tok
  772.    else
  773.     Message(assem_e_syn_try_add_more_prefix);
  774.  end;
  775.  
  776.  Procedure TInstruction.addinstr(tok: tasmop);
  777.  Begin
  778.    if tok = A_NONE then
  779.     Message(assem_e_syn_opcode_not_found);
  780.    Instruction := tok;
  781.  end;
  782.  
  783.  function TInstruction.getinstruction: tasmop;
  784.  Begin
  785.    getinstruction := Instruction;
  786.  end;
  787.       { get the current prefix of this instruction }
  788.  function TInstruction.getprefix: tasmop;
  789.  Begin
  790.    getprefix := prefix;
  791.  end;
  792.  
  793. {*************************************************************************}
  794. {                          Local label utilities                          }
  795. {*************************************************************************}
  796.  
  797.   Constructor TAsmLabelList.Init;
  798.   Begin
  799.     First := nil;
  800.     Last := nil;
  801.   end;
  802.  
  803.  
  804.   Procedure TAsmLabelList.Insert(s:string; lab: PLabel; emitted: boolean);
  805.   {*********************************************************************}
  806.   {  Description: Insert a node at the end of the list with lab and     }
  807.   {  and the name in s. The name is allocated on the heap.              }
  808.   {  Duplicates are not allowed.                                        }
  809.   {  Indicate in emitted if this label itself has been emitted, or is it}
  810.   {  a simple labeled instruction?                                      }
  811.   {*********************************************************************}
  812.   Begin
  813.     if search(s) = nil then
  814.     Begin
  815.       if First = nil then
  816.        Begin
  817.           New(First);
  818.           Last := First;
  819.        end
  820.       else
  821.        Begin
  822.           New(Last^.Next);
  823.           Last := Last^.Next;
  824.        end;
  825.       Last^.name := NewPasStr(s);
  826.       Last^.Lab := lab;
  827.       Last^.Next := nil;
  828.       Last^.emitted := emitted;
  829.     end;
  830.   end;
  831.  
  832.  
  833.  
  834.   Function TAsmLabelList.Search(const s: string): PAsmLabel;
  835.   {*********************************************************************}
  836.   {  Description: This routine searches for a label named s in the      }
  837.   {  linked list, returns a pointer to the label if found, otherwise    }
  838.   {  returns nil.                                                       }
  839.   {*********************************************************************}
  840.   Var
  841.     asmlab: PAsmLabel;
  842.   Begin
  843.     asmlab := First;
  844.     if First = nil then
  845.     Begin
  846.       Search := nil;
  847.       exit;
  848.     end;
  849.     While (asmlab^.name^ <> s) and (asmlab^.Next <> nil) do
  850.        asmlab := asmlab^.Next;
  851.     if asmlab^.name^ = s then
  852.        search := asmlab
  853.     else
  854.        search := nil;
  855.   end;
  856.  
  857.  
  858.   Destructor TAsmLabelList.Done;
  859.   {*********************************************************************}
  860.   {  Description: This routine takes care of deallocating all nodes     }
  861.   {  in the linked list, as well as deallocating the string pointers    }
  862.   {  of these nodes.                                                    }
  863.   {                                                                     }
  864.   {  Remark: The PLabel field is NOT freed, the compiler takes care of  }
  865.   {  this.                                                              }
  866.   {*********************************************************************}
  867.   Var
  868.     temp: PAsmLabel;
  869.     temp1: PAsmLabel;
  870.   Begin
  871.     temp := First;
  872.     while temp <> nil do
  873.     Begin
  874.       Freemem(Temp^.name, length(Temp^.name^)+1);
  875.       Temp1 := Temp^.Next;
  876.       Dispose(Temp);
  877.       Temp := Temp1;
  878.       { The plabel could be deleted here, but let us not do }
  879.       { it, FPC will do it instead.                         }
  880.     end;
  881.   end;
  882.  
  883.  
  884.  
  885.   Function TAsmLabelList.newpasstr(s: string): PString;
  886.   {*********************************************************************}
  887.   { FUNCTION NewPasStr(s:string): PString                               }
  888.   {  Description: This routine allocates a string on the heap and       }
  889.   {  returns a pointer to the allocated string.                         }
  890.   {                                                                     }
  891.   {  Remarks: The string allocated should not be modified, since it's   }
  892.   {  length will be less then 255.                                      }
  893.   {  Remarks: It is assumed that HeapError will be called if an         }
  894.   {  allocation fails.                                                  }
  895.   {*********************************************************************}
  896.   Var
  897.    StrPtr: PString;
  898.   Begin
  899.     GetMem(StrPtr, length(s)+1);
  900.     Move(s,StrPtr^,length(s)+1);
  901.     newpasstr:= Strptr;
  902.   end;
  903.  
  904. {*************************************************************************}
  905. {                      Symbol table helper routines                       }
  906. {*************************************************************************}
  907.  
  908.  
  909.   Procedure SwapOperands(Var instr: TInstruction);
  910.   Var
  911.    tempopr: TOperand;
  912.   Begin
  913.     if instr.numops = 2 then
  914.     Begin
  915.       tempopr := instr.operands[1];
  916.       instr.operands[1] := instr.operands[2];
  917.       instr.operands[2] := tempopr;
  918.     end
  919.     else
  920.     if instr.numops = 3 then
  921.     Begin
  922.       tempopr := instr.operands[1];
  923.       instr.operands[1] := instr.operands[3];
  924.       instr.operands[3] := tempopr;
  925.     end;
  926.   end;
  927.  
  928.  
  929.   Function SearchIConstant(const s:string; var l:longint): boolean;
  930.   {**********************************************************************}
  931.   {  Description: Searches for a CONSTANT of name s in either the local  }
  932.   {  symbol list, then in the global symbol list, and returns the value  }
  933.   {  of that constant in l. Returns TRUE if successfull, if not found,   }
  934.   {  or if the constant is not of correct type, then returns FALSE       }
  935.   { Remarks: Also handle TRUE and FALSE returning in those cases 1 and 0 }
  936.   {  respectively.                                                       }
  937.   {**********************************************************************}
  938.   var
  939.     sym: psym;
  940.   Begin
  941.     SearchIConstant := FALSE;
  942.     { check for TRUE or FALSE reserved words first }
  943.     if s = 'TRUE' then
  944.     Begin
  945.        SearchIConstant := TRUE;
  946.        l := 1;
  947.     end
  948.     else
  949.     if s = 'FALSE' then
  950.     Begin
  951.        SearchIConstant := TRUE;
  952.        l := 0;
  953.     end
  954.     else
  955.     if assigned(aktprocsym) then
  956.     Begin
  957.       if assigned(aktprocsym^.definition) then
  958.       Begin
  959.    { Check the local constants }
  960.     if assigned(aktprocsym^.definition^.localst) then
  961.        sym := aktprocsym^.definition^.localst^.search(s)
  962.     else
  963.        sym := nil;
  964.     if assigned(sym) then
  965.     Begin
  966.        if (sym^.typ = constsym) and (pconstsym(sym)^.consttype in
  967.          [constord,constint,constchar,constbool]) then
  968.        Begin
  969.           l:=pconstsym(sym)^.value;
  970.           SearchIConstant := TRUE;
  971.           exit;
  972.        end;
  973.     end;
  974.       end;
  975.     end;
  976.     { Check the global constants }
  977.     getsym(s,false);
  978.     if srsym <> nil then
  979.     Begin
  980.       if (srsym^.typ=constsym) and (pconstsym(srsym)^.consttype in
  981.        [constord,constint,constchar,constbool]) then
  982.       Begin
  983.         l:=pconstsym(srsym)^.value;
  984.         SearchIConstant := TRUE;
  985.         exit;
  986.       end;
  987.     end;
  988.   end;
  989.  
  990.  
  991.   Procedure SetupResult(Var Instr:TInstruction; operandnum: byte);
  992.   {**********************************************************************}
  993.   {  Description: This routine changes the correct fields and correct    }
  994.   {  offset in the reference, so that it points to the __RESULT or       }
  995.   {  @Result variable (depending on the inline asm).                     }
  996.   {  Resturns a reference with all correct offset correctly set up.      }
  997.   {  The Operand should already point to a treference on entry.          }
  998.   {**********************************************************************}
  999.   Begin
  1000.     { replace by correct offset. }
  1001.     if assigned(procinfo.retdef) and
  1002.       (procinfo.retdef<>pdef(voiddef)) then
  1003.     begin
  1004.       instr.operands[operandnum].ref.offset := procinfo.retoffset;
  1005.       instr.operands[operandnum].ref.base :=  procinfo.framepointer;
  1006.       { always assume that the result is valid. }
  1007.       procinfo.funcret_is_valid:=true;
  1008.     end
  1009.     else
  1010.      Message(assem_e_invalid_symbol_ref);
  1011.   end;
  1012.  
  1013.  
  1014.   Procedure FWaitWarning;
  1015.   begin
  1016.     if (target_info.target=target_GO32V2) and (cs_fp_emulation in aktswitches) then
  1017.      Message(assem_w_fwait_emu_prob);
  1018.   end;
  1019.  
  1020.  
  1021.  
  1022.  
  1023.   Function GetVarOffset(const base: string; const field: string;
  1024.     Var Offset: longint):boolean;
  1025.   { search and returns the offset of records/objects of the base }
  1026.   { with field name setup in field.                              }
  1027.   { returns 0 if not found.                                      }
  1028.   { used when base is a variable or a typed constant name.       }
  1029.    var
  1030.     sym:psym;
  1031.     p: psym;
  1032.   Begin
  1033.      GetVarOffset := FALSE;
  1034.      Offset := 0;
  1035.      { local list }
  1036.      if assigned(aktprocsym) then
  1037.      begin
  1038.       if assigned(aktprocsym^.definition^.localst) then
  1039.         sym:=aktprocsym^.definition^.localst^.search(base)
  1040.       else
  1041.         sym:=nil;
  1042.       if assigned(sym) then
  1043.       begin
  1044.         { field of local record variable. }
  1045.         if (sym^.typ=varsym) and (pvarsym(sym)^.definition^.deftype=recorddef) then
  1046.           begin
  1047.              p:=pvarsym(precdef(pvarsym(sym)^.definition)^.symtable^.search(field));
  1048.              if assigned(pvarsym(p)) then
  1049.              Begin
  1050.                 Offset := pvarsym(p)^.address;
  1051.                 GetVarOffset := TRUE;
  1052.                 Exit;
  1053.              end;
  1054.           end;
  1055.       end
  1056.       else
  1057.        begin
  1058.         { field of local record parameter to routine. }
  1059.          if assigned(aktprocsym^.definition^.parast) then
  1060.             sym:=aktprocsym^.definition^.parast^.search(base)
  1061.          else
  1062.            sym:=nil;
  1063.          if assigned(sym) then
  1064.          begin
  1065.            if (sym^.typ=varsym) and (pvarsym(sym)^.definition^.deftype=recorddef)
  1066.            then
  1067.            begin
  1068.              p:=pvarsym(precdef(pvarsym(sym)^.definition)^.symtable^.search(field));
  1069.              if assigned(p) then
  1070.              Begin
  1071.                 Offset := pvarsym(p)^.address;
  1072.                 GetVarOffset := TRUE;
  1073.                 Exit;
  1074.              end;
  1075.            end; { endif }
  1076.          end; {endif }
  1077.        end; { endif }
  1078.      end;
  1079.  
  1080.      { not found.. .now look for global variables. }
  1081.      getsym(base,false);
  1082.      sym:=srsym;
  1083.      if assigned(sym) then
  1084.      Begin
  1085.         { field of global record variable. }
  1086.         if (sym^.typ=varsym) and (pvarsym(sym)^.definition^.deftype=recorddef) then
  1087.           begin
  1088.              p:=pvarsym(precdef(pvarsym(sym)^.definition)^.symtable^.search(field));
  1089.              if assigned(p) then
  1090.              Begin
  1091.                 Offset := pvarsym(p)^.address;
  1092.                 GetVarOffset := TRUE;
  1093.                 Exit;
  1094.              end;
  1095.           end
  1096.         else
  1097.         { field of global record type constant. }
  1098.         if (sym^.typ=typedconstsym) and (ptypedconstsym(sym)^.definition^.deftype=recorddef)
  1099.           then
  1100.           begin
  1101.              p:=pvarsym(precdef(pvarsym(sym)^.definition)^.symtable^.search(field));
  1102.              if assigned(p) then
  1103.              Begin
  1104.                 Offset := pvarsym(p)^.address;
  1105.                 GetVarOffset := TRUE;
  1106.                 Exit;
  1107.              end;
  1108.           end
  1109.      end; { end looking for global variables .. }
  1110.   end;
  1111.  
  1112.  
  1113.  
  1114.   Function GetTypeOffset(const base: string; const field: string;
  1115.     Var Offset: longint):boolean;
  1116.   { search and returns the offset of records/objects of the base }
  1117.   { with field name setup in field.                              }
  1118.   { returns 0 if not found.                                      }
  1119.   { used when base is a variable or a typed constant name.       }
  1120.    var
  1121.     sym:psym;
  1122.     p: psym;
  1123.   Begin
  1124.      Offset := 0;
  1125.      GetTypeOffset := FALSE;
  1126.      { local list }
  1127.      if assigned(aktprocsym) then
  1128.      begin
  1129.       if assigned(aktprocsym^.definition^.localst) then
  1130.         sym:=aktprocsym^.definition^.localst^.search(base)
  1131.       else
  1132.         sym:=nil;
  1133.       if assigned(sym) then
  1134.       begin
  1135.         { field of local record type. }
  1136.         if (sym^.typ=typesym) and (ptypesym(sym)^.definition^.deftype=recorddef) then
  1137.           begin
  1138.              p:=precdef(ptypesym(sym)^.definition)^.symtable^.search(field);
  1139.              if assigned(p) then
  1140.              Begin
  1141.                 Offset := pvarsym(p)^.address;
  1142.                 GetTypeOffset := TRUE;
  1143.                 Exit;
  1144.              end;
  1145.           end;
  1146.       end
  1147.       else
  1148.        begin
  1149.         { field of local record type to routine. }
  1150.          if assigned(aktprocsym^.definition^.parast) then
  1151.             sym:=aktprocsym^.definition^.parast^.search(base)
  1152.          else
  1153.            sym:=nil;
  1154.          if assigned(sym) then
  1155.          begin
  1156.            if (sym^.typ=typesym) and (ptypesym(sym)^.definition^.deftype=recorddef)
  1157.            then
  1158.            begin
  1159.              p:=precdef(ptypesym(sym)^.definition)^.symtable^.search(field);
  1160.              if assigned(p) then
  1161.              Begin
  1162.                 Offset := pvarsym(p)^.address;
  1163.                 GetTypeOffset := TRUE;
  1164.                 Exit;
  1165.              end;
  1166.            end; { endif }
  1167.          end; {endif }
  1168.        end; { endif }
  1169.      end;
  1170.  
  1171.      { not found.. .now look for global types. }
  1172.      getsym(base,false);
  1173.      sym:=srsym;
  1174.      if assigned(sym) then
  1175.      Begin
  1176.         { field of global record types. }
  1177.         if (sym^.typ=typesym) and (ptypesym(sym)^.definition^.deftype=recorddef) then
  1178.           begin
  1179.              p:=precdef(ptypesym(sym)^.definition)^.symtable^.search(field);
  1180.              if assigned(p) then
  1181.              Begin
  1182.                 Offset := pvarsym(p)^.address;
  1183.                 GetTypeOffset := TRUE;
  1184.                 Exit;
  1185.              end
  1186.           end
  1187.         else
  1188.         { public field names of objects }
  1189.         if (sym^.typ=typesym) and (ptypesym(sym)^.definition^.deftype=objectdef)then
  1190.           begin
  1191.              if assigned(pobjectdef(ptypesym(sym)^.definition)^.publicsyms) then
  1192.              Begin
  1193.                p:=pobjectdef(ptypesym(sym)^.definition)^.publicsyms^.search(field);
  1194.                if assigned(p) then
  1195.                Begin
  1196.                   Offset := pvarsym(p)^.address;
  1197.                   GetTypeOffset := TRUE;
  1198.                   Exit;
  1199.                end
  1200.              end;
  1201.           end;
  1202.      end; { end looking for global variables .. }
  1203.   end;
  1204.  
  1205.  
  1206.   Function CreateVarInstr(var Instr: TInstruction; const hs:string;operandnum:byte): Boolean;
  1207.   { search and sets up the correct fields in the Instr record }
  1208.   { for the NON-constant identifier passed to the routine.    }
  1209.   { if not found returns FALSE.                               }
  1210.    var
  1211.     sym:psym;
  1212.     l: longint;
  1213.   Begin
  1214.      CreateVarInstr := FALSE;
  1215.      { are we in a routine ? }
  1216.      if assigned(aktprocsym) then
  1217.      begin
  1218.       if assigned(aktprocsym^.definition^.localst) then
  1219.       { search the local list for the name of this variable. }
  1220.         sym:=aktprocsym^.definition^.localst^.search(hs)
  1221.       else
  1222.         sym:=nil;
  1223.       if assigned(sym) then
  1224.       begin
  1225.         if sym^.typ=varsym then
  1226.           begin
  1227.            { we always assume in asm statements that     }
  1228.            { that the variable is valid.                 }
  1229.            pvarsym(sym)^.is_valid:=1;
  1230.            instr.operands[operandnum].ref.base := procinfo.framepointer;
  1231.            instr.operands[operandnum].ref.offset := - (pvarsym(sym)^.address);
  1232.            { the current size is NOT overriden if it already }
  1233.            { exists, such as in the case of a byte ptr, in   }
  1234.            { front of the identifier.                        }
  1235.            if instr.operands[operandnum].size = S_NO then
  1236.            Begin
  1237.              case pvarsym(sym)^.getsize of
  1238.               1: instr.operands[operandnum].size := S_B;
  1239.               2: instr.operands[operandnum].size := S_W;
  1240.               4: instr.operands[operandnum].size := S_L;
  1241.               8: instr.operands[operandnum].size := S_Q;
  1242.               extended_size: instr.operands[operandnum].size := S_X;
  1243.              else
  1244.                { this is in the case where the instruction is LEA }
  1245.                { or something like that, in that case size is not }
  1246.                { important.                                       }
  1247.                instr.operands[operandnum].size := S_NO;
  1248.              end; { end case }
  1249.            end;
  1250.            { ok, finished for thir variable. }
  1251.            CreateVarInstr := TRUE;
  1252.            Exit;
  1253.           end
  1254.         else
  1255.         { call to local function }
  1256.         if (sym^.typ=procsym) then
  1257.           begin
  1258.             { free the memory before changing the symbol name. }
  1259.             if assigned(instr.operands[operandnum].ref.symbol) then
  1260.               FreeMem(instr.operands[operandnum].ref.symbol,
  1261.             length(instr.operands[operandnum].ref.symbol^)+1);
  1262.             instr.operands[operandnum].ref.symbol:=newpasstr(pprocsym(sym)^.definition^.mangledname);
  1263.             CreateVarInstr := TRUE;
  1264.             Exit;
  1265.           end
  1266. {        else
  1267.         if (sym^.typ = typedconstsym) then
  1268.         Begin}
  1269.            { UGH????? pprocsym??? }
  1270. {           instr.operands[operandnum].ref.symbol:=newpasstr(pprocsym(sym)^.definition^.mangledname);}
  1271.            {* the current size is NOT overriden if it already *}
  1272.            {* exists, such as in the case of a byte ptr, in   *}
  1273.            {* front of the identifier.                        *}
  1274. {           if instr.operands[operandnum].size = S_NO then
  1275.            Begin
  1276.              case ptypedconstsym(sym)^.definition^.size of
  1277.               1: instr.operands[operandnum].size := S_B;
  1278.               2: instr.operands[operandnum].size := S_W;
  1279.               4: instr.operands[operandnum].size := S_L;
  1280.               8: instr.operands[operandnum].size := S_Q;
  1281.               extended_size: instr.operands[operandnum].size := S_X;
  1282.              else}
  1283.                {* this is in the case where the instruction is LEA *}
  1284.                {* or something like that, in that case size is not *}
  1285.                {* important.                                       *}
  1286. {               instr.operands[operandnum].size := S_NO;}
  1287. {             end;} {* end case *}
  1288. {           end;}
  1289.            {* ok, finished for this variable. *}
  1290. {           CreateVarInstr := TRUE;
  1291.            Exit;
  1292.         end }
  1293.       end;
  1294.       { now check for parameters passed to routine }
  1295. {      else}
  1296.        begin
  1297.          if assigned(aktprocsym^.definition^.parast) then
  1298.             sym:=aktprocsym^.definition^.parast^.search(hs)
  1299.          else
  1300.            sym:=nil;
  1301.          if assigned(sym) then
  1302.          begin
  1303.            if sym^.typ=varsym then
  1304.            begin
  1305.              l:=pvarsym(sym)^.address;
  1306.              { set offset }
  1307.              inc(l,aktprocsym^.definition^.parast^.call_offset);
  1308.              pvarsym(sym)^.is_valid:=1;
  1309.              instr.operands[operandnum].ref.base := procinfo.framepointer;
  1310.              instr.operands[operandnum].ref.offset := l;
  1311.              { the current size is NOT overriden if it already }
  1312.              { exists, such as in the case of a byte ptr, in   }
  1313.              { front of the identifier.                        }
  1314.              if instr.operands[operandnum].size = S_NO then
  1315.              Begin
  1316.                case pvarsym(sym)^.getsize of
  1317.                  1: instr.operands[operandnum].size := S_B;
  1318.                  2: instr.operands[operandnum].size := S_W;
  1319.                  4: instr.operands[operandnum].size := S_L;
  1320.                  8: instr.operands[operandnum].size := S_Q;
  1321.                  extended_size: instr.operands[operandnum].size := S_X;
  1322.                else
  1323.                { this is in the case where the instruction is LEA }
  1324.                { or something like that, in that case size is not }
  1325.                { important.                                       }
  1326.                  instr.operands[operandnum].size := S_NO;
  1327.                end; { end case }
  1328.              end; { endif }
  1329.              CreateVarInstr := TRUE;
  1330.              Exit;
  1331.            end; { endif }
  1332.          end; {endif }
  1333.        end; { endif }
  1334.      end;
  1335.  
  1336.      { not found.. .now look for global variables. }
  1337.      getsym(hs,false);
  1338.      sym:=srsym;
  1339.      if assigned(sym) then
  1340.      Begin
  1341.        if (sym^.typ = varsym) or (sym^.typ = typedconstsym) then
  1342.        Begin
  1343.        { free the memory before changing the symbol name. }
  1344.          if assigned(instr.operands[operandnum].ref.symbol) then
  1345.            FreeMem(instr.operands[operandnum].ref.symbol,
  1346.          length(instr.operands[operandnum].ref.symbol^)+1);
  1347.          instr.operands[operandnum].ref.symbol:=newpasstr(sym^.mangledname);
  1348.          { the current size is NOT overriden if it already }
  1349.          { exists, such as in the case of a byte ptr, in   }
  1350.          { front of the identifier.                        }
  1351.          if (instr.operands[operandnum].size = S_NO) and (sym^.typ = varsym) then
  1352.          Begin
  1353.            case pvarsym(sym)^.getsize of
  1354.              1: instr.operands[operandnum].size := S_B;
  1355.              2: instr.operands[operandnum].size := S_W;
  1356.              4: instr.operands[operandnum].size := S_L;
  1357.              8: instr.operands[operandnum].size := S_Q;
  1358.            else
  1359.            { this is in the case where the instruction is LEA }
  1360.            { or something like that, in that case size is not }
  1361.            { important.                                       }
  1362.              instr.operands[operandnum].size := S_NO;
  1363.            end;
  1364.          end
  1365.          else
  1366.          if (instr.operands[operandnum].size = S_NO) and (sym^.typ = typedconstsym) then
  1367.          Begin
  1368.          { only these are valid sizes, otherwise prefixes are }
  1369.          { required.                                          }
  1370.             case ptypedconstsym(sym)^.definition^.size of
  1371.               1: instr.operands[operandnum].size := S_B;
  1372.               2: instr.operands[operandnum].size := S_W;
  1373.               4: instr.operands[operandnum].size := S_L;
  1374.               8: instr.operands[operandnum].size := S_Q;
  1375.             else
  1376.             { this is in the case where the instruction is LEA }
  1377.             { or something like that, in that case size is not }
  1378.             { important.                                       }
  1379.                  instr.operands[operandnum].size := S_NO;
  1380.             end;
  1381.          end; { endif }
  1382.          CreateVarInstr := TRUE;
  1383.          Exit;
  1384.        end;
  1385.        if (sym^.typ=procsym) then
  1386.        begin
  1387.          if assigned(pprocsym(sym)^.definition^.nextoverloaded) then
  1388.           Message(assem_w_calling_overload_func);
  1389.          { free the memory before changing the symbol name. }
  1390.          if assigned(instr.operands[operandnum].ref.symbol) then
  1391.            FreeMem(instr.operands[operandnum].ref.symbol,
  1392.          length(instr.operands[operandnum].ref.symbol^)+1);
  1393.          instr.operands[operandnum].ref.symbol:=
  1394.            newpasstr(pprocsym(sym)^.definition^.mangledname);
  1395.          CreateVarInstr := TRUE;
  1396.          Exit;
  1397.        end;
  1398.      end; { end looking for global variables .. }
  1399.   end;
  1400.  
  1401.  
  1402.  
  1403.   Function SearchLabel(const s: string; var hl: plabel): boolean;
  1404.   {**********************************************************************}
  1405.   {  Description: Searches for a pascal label definition, first in the   }
  1406.   {  local symbol list and then in the global symbol list. If found then }
  1407.   {  return pointer to label and return true, otherwise returns false.   }
  1408.   {**********************************************************************}
  1409.   var
  1410.     sym: psym;
  1411.   Begin
  1412.     SearchLabel := FALSE;
  1413.     if assigned(aktprocsym) then
  1414.     Begin
  1415.       { Check the local constants }
  1416.     if assigned(aktprocsym^.definition) then
  1417.     Begin
  1418.         if assigned(aktprocsym^.definition^.localst) then
  1419.           sym := aktprocsym^.definition^.localst^.search(s)
  1420.       else
  1421.        sym := nil;
  1422.       if assigned(sym) then
  1423.       Begin
  1424.        if (sym^.typ = labelsym) then
  1425.        Begin
  1426.           hl:=plabelsym(sym)^.number;
  1427.           SearchLabel := TRUE;
  1428.           exit;
  1429.        end;
  1430.       end;
  1431.     end;
  1432.   end;
  1433.     { Check the global label symbols... }
  1434.     getsym(s,false);
  1435.     if srsym <> nil then
  1436.     Begin
  1437.       if (srsym^.typ=labelsym) then
  1438.       Begin
  1439.         hl:=plabelsym(srsym)^.number;
  1440.         SearchLabel:= TRUE;
  1441.         exit;
  1442.       end;
  1443.     end;
  1444.   end;
  1445.  
  1446.  
  1447.  {*************************************************************************}
  1448.  {                   Instruction Generation Utilities                      }
  1449.  {*************************************************************************}
  1450.  
  1451.  
  1452.    Procedure ConcatString(p : paasmoutput;s:string);
  1453.   {*********************************************************************}
  1454.   { PROCEDURE ConcatString(s:string);                                   }
  1455.   {  Description: This routine adds the character chain pointed to in   }
  1456.   {  s to the instruction linked list.                                  }
  1457.   {*********************************************************************}
  1458.   Var
  1459.    pc: PChar;
  1460.   Begin
  1461.      getmem(pc,length(s)+1);
  1462.      p^.concat(new(pai_string,init_pchar(strpcopy(pc,s))));
  1463.   end;
  1464.  
  1465.   Procedure ConcatPasString(p : paasmoutput;s:string);
  1466.   {*********************************************************************}
  1467.   { PROCEDURE ConcatPasString(s:string);                                }
  1468.   {  Description: This routine adds the character chain pointed to in   }
  1469.   {  s to the instruction linked list, contrary to ConcatString it      }
  1470.   {  uses a pascal style string, so it conserves null characters.       }
  1471.   {*********************************************************************}
  1472.   Begin
  1473.      p^.concat(new(pai_string,init(s)));
  1474.   end;
  1475.  
  1476.   Procedure ConcatDirect(p : paasmoutput;s:string);
  1477.   {*********************************************************************}
  1478.   { PROCEDURE ConcatDirect(s:string)                                    }
  1479.   {  Description: This routine output the string directly to the asm    }
  1480.   {  output, it is only sed when writing special labels in AT&T mode,   }
  1481.   {  and should not be used without due consideration, since it may     }
  1482.   {  cause problems.                                                    }
  1483.   {*********************************************************************}
  1484.   Var
  1485.    pc: PChar;
  1486.   Begin
  1487.      getmem(pc,length(s)+1);
  1488.      p^.concat(new(pai_direct,init(strpcopy(pc,s))));
  1489.   end;
  1490.  
  1491.  
  1492.  
  1493.  
  1494.    Procedure ConcatConstant(p: paasmoutput; value: longint; maxvalue: longint);
  1495.   {*********************************************************************}
  1496.   { PROCEDURE ConcatConstant(value: longint; maxvalue: longint);        }
  1497.   {  Description: This routine adds the value constant to the current   }
  1498.   {  instruction linked list.                                           }
  1499.   {   maxvalue -> indicates the size of the data to initialize:         }
  1500.   {                  $ff -> create a byte node.                         }
  1501.   {                  $ffff -> create a word node.                       }
  1502.   {                  $ffffffff -> create a dword node.                  }
  1503.   {*********************************************************************}
  1504.   Begin
  1505.       if value > maxvalue then
  1506.       Begin
  1507.          Message(assem_e_constant_out_of_bounds);
  1508.          { assuming a value of maxvalue }
  1509.          value := maxvalue;
  1510.       end;
  1511.       if maxvalue = $ff then
  1512.           p^.concat(new(pai_const,init_8bit(byte(value))))
  1513.       else
  1514.       if maxvalue = $ffff then
  1515.           p^.concat(new(pai_const,init_16bit(word(value))))
  1516.       else
  1517.       if maxvalue = $ffffffff then
  1518.           p^.concat(new(pai_const,init_32bit(longint(value))));
  1519.   end;
  1520.  
  1521.   Procedure ConcatRealConstant(p : paasmoutput;value: bestreal; real_typ : tfloattype);
  1522.   {***********************************************************************}
  1523.   { PROCEDURE ConcatRealConstant(value: bestreal; real_typ : tfloattype); }
  1524.   {  Description: This routine adds the value constant to the current     }
  1525.   {  instruction linked list.                                             }
  1526.   {   real_typ -> indicates the type of the real data to initialize:      }
  1527.   {                  s32real -> create a single node.                     }
  1528.   {                  s64real -> create a double node.                     }
  1529.   {                  s80real -> create an extended node.                  }
  1530.   {                  s64bit ->  create a  comp node.                      }
  1531.   {                  f32bit ->  create a  fixed node. (not used normally) }
  1532.   {***********************************************************************}
  1533.     Begin
  1534.        case real_typ of
  1535.           s32real : p^.concat(new(pai_single,init(value)));
  1536.           s64real : p^.concat(new(pai_double,init(value)));
  1537.           s80real : p^.concat(new(pai_extended,init(value)));
  1538.           s64bit  : p^.concat(new(pai_comp,init(value)));
  1539.           f32bit  : p^.concat(new(pai_const,init_32bit(trunc(value*$10000))));
  1540.        end;
  1541.     end;
  1542.  
  1543.    Procedure ConcatLabel(p: paasmoutput;op : tasmop;var l : plabel);
  1544.   {*********************************************************************}
  1545.   { PROCEDURE ConcatLabel                                               }
  1546.   {  Description: This routine either emits a label or a labeled        }
  1547.   {  instruction to the linked list of instructions.                    }
  1548.   {*********************************************************************}
  1549.    begin
  1550.          if op=A_LABEL then
  1551.            p^.concat(new(pai_label,init(l)))
  1552.          else
  1553.            p^.concat(new(pai_labeled,init(op,l)))
  1554.    end;
  1555.  
  1556.    procedure ConcatPublic(p:paasmoutput;const s : string);
  1557.   {*********************************************************************}
  1558.   { PROCEDURE ConcatPublic                                              }
  1559.   {  Description: This routine emits an global   definition to the      }
  1560.   {  linked list of instructions.(used by AT&T styled asm)              }
  1561.   {*********************************************************************}
  1562.    begin
  1563.        p^.concat(new(pai_symbol,init_global(s)));
  1564.        { concat_internal(s,EXT_NEAR); done in aasm }
  1565.    end;
  1566.  
  1567.    procedure ConcatLocal(p:paasmoutput;const s : string);
  1568.   {*********************************************************************}
  1569.   { PROCEDURE ConcatLocal                                               }
  1570.   {  Description: This routine emits an local    definition to the      }
  1571.   {  linked list of instructions.                                       }
  1572.   {*********************************************************************}
  1573.    begin
  1574.        p^.concat(new(pai_symbol,init(s)));
  1575.        { concat_internal(s,EXT_NEAR); done in aasm }
  1576.    end;
  1577.  
  1578.   Procedure ConcatGlobalBss(const s : string;size : longint);
  1579.   {*********************************************************************}
  1580.   { PROCEDURE ConcatGlobalBss                                           }
  1581.   {  Description: This routine emits an global  datablock   to the      }
  1582.   {  linked list of instructions.                                       }
  1583.   {*********************************************************************}
  1584.    begin
  1585.        bsssegment^.concat(new(pai_datablock,init_global(s,size)));
  1586.        { concat_internal(s,EXT_NEAR); done in aasm }
  1587.    end;
  1588.  
  1589.   Procedure ConcatLocalBss(const s : string;size : longint);
  1590.   {*********************************************************************}
  1591.   { PROCEDURE ConcatLocalBss                                            }
  1592.   {  Description: This routine emits a local datablcok      to the      }
  1593.   {  linked list of instructions.                                       }
  1594.   {*********************************************************************}
  1595.    begin
  1596.        bsssegment^.concat(new(pai_datablock,init(s,size)));
  1597.        { concat_internal(s,EXT_NEAR); done in aasm }
  1598.    end;
  1599.  
  1600.   { add to list of external labels }
  1601.   Procedure ConcatExternal(const s : string;typ : texternal_typ);
  1602.   {*********************************************************************}
  1603.   { PROCEDURE ConcatExternal                                            }
  1604.   {  Description: This routine emits an external definition to the      }
  1605.   {  linked list of instructions.(used by AT&T styled asm)              }
  1606.   {*********************************************************************}
  1607.   { check if in internal list and remove it there                       }
  1608.   var p : pai_external;
  1609.    begin
  1610.        p:=search_assembler_symbol(internals,s,typ);
  1611.        if p<>nil then internals^.remove(p);
  1612.        concat_external(s,typ);
  1613.    end;
  1614.  
  1615.   { add to internal list of labels }
  1616.   Procedure ConcatInternal(const s : string;typ : texternal_typ);
  1617.   {*********************************************************************}
  1618.   { PROCEDURE ConcatInternal                                            }
  1619.   {  Description: This routine emits an internal definition of a symbol }
  1620.   {  (used by AT&T styled asm for undefined labels)                     }
  1621.   {*********************************************************************}
  1622.    begin
  1623.        concat_internal(s,typ);
  1624.    end;
  1625.  
  1626. end.
  1627. {
  1628.   $Log: asmutils.pas,v $
  1629.   Revision 1.1.1.1  1998/03/25 11:18:12  root
  1630.   * Restored version
  1631.  
  1632.   Revision 1.15  1998/03/10 01:17:14  peter
  1633.     * all files have the same header
  1634.     * messages are fully implemented, EXTDEBUG uses Comment()
  1635.     + AG... files for the Assembler generation
  1636.  
  1637.   Revision 1.14  1998/03/09 12:58:10  peter
  1638.     * FWait warning is only showed for Go32V2 and $E+
  1639.     * opcode tables moved to i386.pas/m68k.pas to reduce circular uses (and
  1640.       for m68k the same tables are removed)
  1641.     + $E for i386
  1642.  
  1643.   Revision 1.13  1998/03/03 16:45:16  peter
  1644.     + message support for assembler parsers
  1645.  
  1646.   Revision 1.12  1998/03/02 01:48:02  peter
  1647.     * renamed target_DOS to target_GO32V1
  1648.     + new verbose system, merged old errors and verbose units into one new
  1649.       verbose.pas, so errors.pas is obsolete
  1650.  
  1651.   Revision 1.11  1998/02/13 10:34:34  daniel
  1652.   * Made Motorola version compilable.
  1653.   * Fixed optimizer
  1654.  
  1655.   Revision 1.10  1998/01/09 19:21:19  carl
  1656.   + added support for m68k
  1657.  
  1658.   Revision 1.7  1997/12/14 22:43:17  florian
  1659.     + command line switch -Xs for DOS (passes -s to the linker to strip symbols from
  1660.       executable)
  1661.     * some changes of Carl-Eric implemented
  1662.  
  1663.   Revision 1.5  1997/12/09 13:23:54  carl
  1664.   + less processor specific
  1665.   - moved searching for externals/internal symbols from CreateVarInstr to
  1666.     ratti386.pas (this would cause invalid stuff in rai386.pas!)
  1667.  
  1668.   Revision 1.4  1997/12/04 12:20:39  pierre
  1669.     +* MMX instructions added to att output with a warning that
  1670.        GNU as version >= 2.81 is needed
  1671.        bug in reading of reals under att syntax corrected
  1672.  
  1673.   Revision 1.3  1997/12/01 17:42:49  pierre
  1674.      + added some more functionnality to the assembler parser
  1675.  
  1676.   Revision 1.2  1997/11/27 17:55:11  carl
  1677.   * made it compile under bp (one comment was nested)
  1678.  
  1679.   Revision 1.1.1.1  1997/11/27 08:32:50  michael
  1680.   FPC Compiler CVS start
  1681.  
  1682.  
  1683.   Pre-CVS log:
  1684.  
  1685.   CEC   Carl-Eric Codere
  1686.   FK    Florian Klaempfl
  1687.   PM    Pierre Muller
  1688.   +     feature added
  1689.   -     removed
  1690.   *     bug fixed or changed
  1691.  
  1692.  11th november 1997:
  1693.    * fixed problems when using reserved words TRUE and FALSE (CEC).
  1694.  22th november 1997:
  1695.    * changed operator (reserved word) into _operator (PM).
  1696.  
  1697. }
  1698.