3 Copyright (c) 1998-2000 by Carl Eric Codere and Peter Vreman
5 This unit implements some support routines for assembler parsing
6 independent of the processor
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 **********************************************************************}
29 globtype
,types
,systems
,verbose
,globals
,files
,
30 symconst
,symtable
,aasm
,cpubase
,cpuasm
39 RPNMax
= 10; { I think you only need 4, but just to be safe }
42 maxoperands
= 3; { Maximum operands for assembler instructions }
45 {---------------------------------------------------------------------
46 Local Label Management
47 ---------------------------------------------------------------------}
50 { Each local label has this structure associated with it }
51 PLocalLabel
= ^TLocalLabel
;
52 TLocalLabel
= object(TNamedIndexObject
)
54 constructor Init(const n
:string);
55 function Getpasmlabel
:pasmlabel
;
60 PLocalLabelList
= ^TLocalLabelList
;
61 TLocalLabelList
= Object(TDictionary
)
62 procedure CheckEmitted
;
66 LocalLabelList
: PLocalLabelList
;
68 function CreateLocalLabel(const s
: string; var hl
: pasmlabel
; emit
:boolean):boolean;
69 Function SearchLabel(const s
: string; var hl
: pasmlabel
;emit
:boolean): boolean;
72 {---------------------------------------------------------------------
73 Instruction management
74 ---------------------------------------------------------------------}
77 TOprType
=(OPR_NONE
,OPR_CONSTANT
,OPR_SYMBOL
,OPR_REFERENCE
,OPR_REGISTER
);
82 OPR_CONSTANT
: (val
:longint);
83 OPR_SYMBOL
: (symbol
:PAsmSymbol
;symofs
:longint);
84 OPR_REFERENCE
: (ref
:treference
);
85 OPR_REGISTER
: (reg
:tregister
);
91 hastype
, { if the operand has typecasted variable }
92 hasvar
: boolean; { if the operand is loaded with a variable }
95 destructor done
;virtual;
96 Procedure BuildOperand
;virtual;
97 Procedure SetSize(_size
:longint;force
:boolean);
98 Procedure SetCorrectSize(opcode
:tasmop
);virtual;
99 Function SetupResult
:boolean;virtual;
100 Function SetupSelf
:boolean;
101 Function SetupOldEBP
:boolean;
102 Function SetupVar(const hs
:string;GetOffset
: boolean): Boolean;
103 Function SetupDirectVar(const hs
:string): Boolean;
107 PInstruction
= ^TInstruction
;
108 TInstruction
= object
111 condition
: tasmcond
;
113 operands
: array[1..maxoperands
] of POperand
;
115 destructor done
;virtual;
116 Procedure InitOperands
;virtual;
117 Procedure BuildOpcode
;virtual;
118 procedure ConcatInstruction(p
:PAasmoutput
);virtual;
119 Procedure SwapOperands
;
123 {---------------------------------------------------------------------}
124 { Expression parser types }
125 {---------------------------------------------------------------------}
127 TExprOperator
= record
128 ch
: char; { operator }
129 is_prefix
: boolean; { was it a prefix, possible prefixes are +,- and not }
132 String15
= String[15];
133 {**********************************************************************}
134 { The following operators are supported: }
136 { '-' : subtraction }
137 { '*' : multiplication }
138 { '/' : modulo division }
139 { '^' : exclusive or }
141 { '>' : shift right }
142 { '&' : bitwise and }
144 { '~' : bitwise complement }
145 { '%' : modulo division }
146 { nnn: longint numbers }
147 { ( and ) parenthesis }
148 {**********************************************************************}
154 Function Evaluate(Expr
: String): longint;
155 Function Priority(_Operator
: Char): Integer; virtual;
157 RPNStack
: Array[1..RPNMax
] of longint; { Stack For RPN calculator }
159 OpStack
: Array[1..OpMax
] of TExprOperator
; { Operator stack For conversion }
161 Procedure RPNPush(Num
: Longint);
162 Function RPNPop
: Longint;
163 Procedure RPNCalc(token
: String15
; prefix
: boolean);
164 Procedure OpPush(_Operator
: char; prefix
: boolean);
165 { In reality returns TExprOperaotr }
166 Procedure OpPop(var _Operator
:TExprOperator
);
169 { Evaluate an expression string to a longint }
170 Function CalculateExpression(const expression
: string): longint;
172 {---------------------------------------------------------------------}
174 {---------------------------------------------------------------------}
176 Function ValDecimal(const S
:String):longint;
177 Function ValOctal(const S
:String):longint;
178 Function ValBinary(const S
:String):longint;
179 Function ValHexaDecimal(const S
:String):longint;
180 Function PadZero(Var s
: String; n
: byte): Boolean;
181 Function EscapeToPascal(const s
:string): string;
183 {---------------------------------------------------------------------
184 Symbol helper routines
185 ---------------------------------------------------------------------}
187 Function GetRecordOffsetSize(s
:string;Var Offset
: longint;var Size
:longint):boolean;
188 Function SearchType(const hs
:string): Boolean;
189 Function SearchRecordType(const s
:string): boolean;
190 Function SearchIConstant(const s
:string; var l
:longint): boolean;
193 {---------------------------------------------------------------------
194 Instruction generation routines
195 ---------------------------------------------------------------------}
197 Procedure ConcatPasString(p
: paasmoutput
;s
:string);
198 Procedure ConcatDirect(p
: paasmoutput
;s
:string);
199 Procedure ConcatLabel(p
: paasmoutput
;var l
: pasmlabel
);
200 Procedure ConcatConstant(p
: paasmoutput
;value
: longint; maxvalue
: longint);
201 Procedure ConcatConstSymbol(p
: paasmoutput
;const sym
:string;l
:longint);
202 Procedure ConcatRealConstant(p
: paasmoutput
;value
: bestreal
; real_typ
: tfloattype
);
203 Procedure ConcatString(p
: paasmoutput
;s
:string);
204 procedure ConcatAlign(p
:paasmoutput
;l
:longint);
205 Procedure ConcatPublic(p
:paasmoutput
;const s
: string);
206 Procedure ConcatLocal(p
:paasmoutput
;const s
: string);
207 Procedure ConcatGlobalBss(const s
: string;size
: longint);
208 Procedure ConcatLocalBss(const s
: string;size
: longint);
214 {*************************************************************************
216 *************************************************************************}
218 Constructor TExprParse
.Init
;
223 Procedure TExprParse
.RPNPush(Num
: longint);
224 { Add an operand to the top of the RPN stack }
226 if RPNTop
< RPNMax
then
229 RPNStack
[RPNTop
]:=Num
;
232 Message(asmr_e_expr_illegal
);
236 Function TExprParse
.RPNPop
: longint;
237 { Get the operand at the top of the RPN stack }
241 RPNPop
:=RPNStack
[RPNTop
];
245 Message(asmr_e_expr_illegal
);
249 Procedure TExprParse
.RPNCalc(Token
: String15
; prefix
:boolean); { RPN Calculator }
253 LocalError
: Integer;
256 if (Length(Token
) = 1) and (Token
[1] in ['+', '-', '*', '/','&','|','%','^','~','<','>']) then
261 RPNPush(RPNPop
+ RPNPop
);
274 '*' : RPNPush(RPNPop
* RPNPop
);
287 '~' : RPNPush(NOT RPNPop
);
304 RPNPush(RPNPop
mod Temp
)
307 Message(asmr_e_expr_zero_divide
);
308 { push 1 for error recovery }
312 '^' : RPNPush(RPNPop
XOR RPNPop
);
317 RPNPush(RPNPop
div Temp
)
320 Message(asmr_e_expr_zero_divide
);
321 { push 1 for error recovery }
328 { Convert String to number and add to stack }
329 if token
='-2147483648' then
335 Val(Token
, Temp
, LocalError
);
336 if LocalError
= 0 then
340 Message(asmr_e_expr_illegal
);
341 { push 1 for error recovery }
348 Procedure TExprParse
.OpPush(_Operator
: char;prefix
: boolean);
349 { Add an operator onto top of the stack }
351 if OpTop
< OpMax
then
354 OpStack
[OpTop
].ch
:=_Operator
;
355 OpStack
[OpTop
].is_prefix
:=prefix
;
358 Message(asmr_e_expr_illegal
);
362 Procedure TExprParse
.OpPop(var _Operator
:TExprOperator
);
363 { Get operator at the top of the stack }
367 _Operator
:=OpStack
[OpTop
];
371 Message(asmr_e_expr_illegal
);
375 Function TExprParse
.Priority(_Operator
: Char) : Integer;
376 { Return priority of operator }
377 { The greater the priority, the higher the precedence }
384 '*', '/','%','<','>' :
389 Message(asmr_e_expr_illegal
);
394 Function TExprParse
.Evaluate(Expr
: String):longint;
408 For I
:=1 to Length(Expr
) DO
410 if Expr
[I
] in ['0'..'9'] then
411 begin { Build multi-digit numbers }
412 Token
:=Token
+ Expr
[I
];
413 if I
= Length(Expr
) then { Send last one to calculator }
414 RPNCalc(Token
,false);
417 if Expr
[I
] in ['+', '-', '*', '/', '(', ')','^','&','|','%','~','<','>'] then
420 begin { Send last built number to calc. }
421 RPNCalc(Token
,false);
426 '(' : OpPush('(',false);
428 While OpStack
[OpTop
].ch
<> '(' DO
431 RPNCalc(opr
.ch
,opr
.is_prefix
);
433 OpPop(opr
); { Pop off and ignore the '(' }
436 { workaround for -2147483648 }
437 if (expr
[I
]='-') and (expr
[i
+1] in ['0'..'9']) then
442 { if start of expression then surely a prefix }
443 { or if previous char was also an operator }
444 if (I
= 1) or (not (Expr
[I
-1] in ['0'..'9','(',')'])) then
448 { Evaluate all higher priority operators }
449 While (OpTop
> 0) AND (Priority(Expr
[I
]) <= Priority(OpStack
[OpTop
].ch
)) DO
452 RPNCalc(opr
.ch
,opr
.is_prefix
);
454 OpPush(Expr
[I
],false);
460 While (OpTop
> 0) and (Priority(Expr
[I
]) <= Priority(OpStack
[OpTop
].ch
)) DO
463 RPNCalc(opr
.ch
,opr
.is_prefix
);
465 OpPush(Expr
[I
],false);
470 Message(asmr_e_expr_illegal
); { Handle bad input error }
473 { Pop off the remaining operators }
477 RPNCalc(opr
.ch
,opr
.is_prefix
);
480 { The result is stored on the top of the stack }
485 Destructor TExprParse
.Done
;
490 Function CalculateExpression(const expression
: string): longint;
495 CalculateExpression
:=expr
.Evaluate(expression
);
500 {*************************************************************************}
501 { String conversions/utils }
502 {*************************************************************************}
504 Function EscapeToPascal(const s
:string): string;
505 { converts a C styled string - which contains escape }
506 { characters to a pascal style string. }
516 while (i
<length(s
)) and (len
<255) do
519 if (s
[i
]='\') and (i
<length(s
)) then
543 c
:=chr(ValOctal(temp
));
550 c
:=chr(ValHexaDecimal(temp
));
554 Message1(asmr_e_escape_seq_ignored
,s
[i
]);
569 Function ValDecimal(const S
:String):longint;
570 { Converts a decimal string to longint }
575 for c
:=1 to length(s
) do
578 if s
[c
] in ['0'..'9'] then
579 inc(vs
,ord(s
[c
])-ord('0'))
582 Message1(asmr_e_error_converting_decimal
,s
);
591 Function ValOctal(const S
:String):longint;
592 { Converts an octal string to longint }
597 for c
:=1 to length(s
) do
600 if s
[c
] in ['0'..'7'] then
601 inc(vs
,ord(s
[c
])-ord('0'))
604 Message1(asmr_e_error_converting_octal
,s
);
613 Function ValBinary(const S
:String):longint;
614 { Converts a binary string to longint }
619 for c
:=1 to length(s
) do
622 if s
[c
] in ['0'..'1'] then
623 inc(vs
,ord(s
[c
])-ord('0'))
626 Message1(asmr_e_error_converting_binary
,s
);
635 Function ValHexadecimal(const S
:String):longint;
636 { Converts a binary string to longint }
641 for c
:=1 to length(s
) do
646 inc(vs
,ord(s
[c
])-ord('0'));
648 inc(vs
,ord(s
[c
])-ord('A')+10);
650 inc(vs
,ord(s
[c
])-ord('a')+10);
653 Message1(asmr_e_error_converting_hexadecimal
,s
);
663 Function PadZero(Var s
: String; n
: byte): Boolean;
666 { Do some error checking first }
667 if Length(s
) = n
then
670 if Length(s
) > n
then
673 delete(s
,n
+1,length(s
));
678 { Fill it up with the specified character }
679 fillchar(s
[length(s
)+1],n
-1,#0);
684 {****************************************************************************
686 ****************************************************************************}
688 constructor TOperand
.init
;
693 FillChar(Opr
,sizeof(Opr
),0);
697 destructor TOperand
.done
;
702 Procedure TOperand
.SetCorrectSize(opcode
:tasmop
);
706 Procedure TOperand
.SetSize(_size
:longint;force
:boolean);
709 ((size
= S_NO
) and (_size
<=extended_size
)) then
713 2 : size
:=S_W
{ could be S_IS};
714 4 : size
:=S_L
{ could be S_IL or S_FS};
715 8 : size
:=S_IQ
{ could be S_D or S_FL};
716 extended_size
: size
:=S_FX
;
722 Function TOperand
.SetupResult
:boolean;
725 { replace by correct offset. }
726 if assigned(procinfo
^.returntype
.def
) and
727 (procinfo
^.returntype
.def
<>pdef(voiddef
)) then
729 if (procinfo
^.return_offset
=0) and ((m_tp
in aktmodeswitches
) or
730 (m_delphi
in aktmodeswitches
)) then
732 Message(asmr_e_cannot_use_RESULT_here
);
735 opr
.ref
.offset
:=procinfo
^.return_offset
;
736 opr
.ref
.base
:= procinfo
^.framepointer
;
737 { always assume that the result is valid. }
738 procinfo
^.funcret_state
:=vs_assigned
;
739 if (opr
.ref
.offset
=0) and
740 ((m_tp
in aktmodeswitches
) or (m_delphi
in aktmodeswitches
)) then
741 Message(asmr_e_cannot_use_RESULT_here
)
746 Message
(asmr_e_void_function
);
750 Function TOperand
.SetupSelf
:boolean;
753 if assigned(procinfo
^._class
) then
755 opr
.typ
:=OPR_REFERENCE
;
756 opr
.ref
.offset
:=procinfo
^.selfpointer_offset
;
757 opr
.ref
.base
:=procinfo
^.framepointer
;
758 opr
.ref
.options
:=ref_selffixup
;
762 Message(asmr_e_cannot_use_SELF_outside_a_method
);
766 Function TOperand
.SetupOldEBP
:boolean;
769 if lexlevel
>normal_function_level
then
771 opr
.typ
:=OPR_REFERENCE
;
772 opr
.ref
.offset
:=procinfo
^.framepointer_offset
;
773 opr
.ref
.base
:=procinfo
^.framepointer
;
777 Message(asmr_e_cannot_use_OLDEBP_outside_nested_procedure
);
781 Function TOperand
.SetupVar(const hs
:string;GetOffset
: boolean): Boolean;
782 { search and sets up the correct fields in the Instr record }
783 { for the NON-constant identifier passed to the routine. }
784 { if not found returns FALSE. }
790 { are we in a routine ? }
798 { we always assume in asm statements that }
799 { that the variable is valid. }
800 pvarsym(sym)^.varstate:=vs_used;
801 inc(pvarsym(sym)^.refs);
802 case pvarsym(sym)^.owner^.symtabletype of
805 { this is not allowed, because we don't know if the self
806 register is still free, and loading it first is also
807 not possible, because this could break code }
808 { Be TP/Delphi compatible in Delphi or TP modes }
809 if (m_tp in aktmodeswitches) then
811 opr.typ:=OPR_CONSTANT;
812 opr.val:=pvarsym(sym)^.address;
814 { I do not agree here people using method vars should ensure
815 that %esi is valid there }
818 opr.ref.base:=self_pointer;
819 opr.ref.offset:=pvarsym(sym)^.address;
828 opr.ref.symbol:=newasmsymbol(pvarsym(sym)^.mangledname);
831 { if we only want the offset we don't have to care
832 the base will be zeroed after ! }
833 if (lexlevel=pvarsym(sym)^.owner^.symtablelevel) or
834 { this below is wrong because there are two parast
835 for global functions one of interface the second of
837 if (pvarsym(sym)^.owner=procinfo^.def^.parast) or }
840 opr.ref.base:=procinfo^.framepointer;
844 if (procinfo^.framepointer=R_ESP) and
845 assigned(procinfo^.parent) and
846 (lexlevel=pvarsym(sym)^.owner^.symtablelevel+1) and
847 { same problem as above !!
848 (procinfo^.parent^.sym^.definition^.parast=pvarsym(sym)^.owner) and }
849 (lexlevel>normal_function_level) then
850 opr.ref.base:=procinfo^.parent^.framepointer
852 message1(asmr_e_local_para_unreachable,hs);
854 opr.ref.offset:=pvarsym(sym)^.address;
855 if (lexlevel=pvarsym(sym)^.owner^.symtablelevel) then
857 opr.ref.offsetfixup:=aktprocsym^.definition^.parast^.address_fixup;
858 opr.ref.options:=ref_parafixup;
862 opr.ref.offsetfixup:=0;
863 opr.ref.options:=ref_none;
865 if (pvarsym(sym)^.varspez=vs_var) or
866 ((pvarsym(sym)^.varspez=vs_const) and
867 push_addr_param(pvarsym(sym)^.vartype.def)) then
868 SetSize(target_os.size_of_pointer,false);
872 if (vo_is_external in pvarsym(sym)^.varoptions) then
873 opr.ref.symbol:=newasmsymbol(pvarsym(sym)^.mangledname)
876 { if we only want the offset we don't have to care
877 the base will be zeroed after ! }
878 if (lexlevel=pvarsym(sym)^.owner^.symtablelevel) or
879 {if (pvarsym(sym)^.owner=procinfo^.def^.localst) or}
881 opr.ref.base:=procinfo^.framepointer
884 if (procinfo^.framepointer=R_ESP) and
885 assigned(procinfo^.parent) and
886 (lexlevel=pvarsym(sym)^.owner^.symtablelevel+1) and
887 {(procinfo^.parent^.sym^.definition^.localst=pvarsym(sym)^.owner) and}
888 (lexlevel>normal_function_level) then
889 opr.ref.base:=procinfo^.parent^.framepointer
891 message1(asmr_e_local_para_unreachable,hs);
893 opr.ref.offset:=-(pvarsym(sym)^.address);
894 if (lexlevel=pvarsym(sym)^.owner^.symtablelevel) then
896 opr.ref.offsetfixup:=aktprocsym^.definition^.localst^.address_fixup;
897 opr.ref.options:=ref_localfixup;
901 opr.ref.offsetfixup:=0;
902 opr.ref.options:=ref_none;
907 case pvarsym(sym)^.vartype.def^.deftype of
912 SetSize(pvarsym(sym)^.getsize,false);
915 { for arrays try to get the element size, take care of
917 harrdef:=Parraydef(PVarsym(sym)^.vartype.def);
918 while assigned(harrdef^.elementtype.def) and
919 (harrdef^.elementtype.def^.deftype=arraydef) do
920 harrdef:=parraydef(harrdef^.elementtype.def);
921 SetSize(harrdef^.elesize,false);
930 opr.ref.symbol:=newasmsymbol(ptypedconstsym(sym)^.mangledname);
931 case ptypedconstsym(sym)^.typedconsttype.def^.deftype of
936 SetSize(ptypedconstsym(sym)^.getsize,false);
939 { for arrays try to get the element size, take care of
941 harrdef:=Parraydef(PTypedConstSym(sym)^.typedconsttype.def);
942 while assigned(harrdef^.elementtype.def) and
943 (harrdef^.elementtype.def^.deftype=arraydef) do
944 harrdef:=parraydef(harrdef^.elementtype.def);
945 SetSize(harrdef^.elesize,false);
954 if pconstsym(sym)^.consttyp in [constint,constchar,constbool] then
956 opr.typ:=OPR_CONSTANT;
957 opr.val:=pconstsym(sym)^.value;
964 if ptypesym(sym)^.restype.def^.deftype in [recorddef,objectdef] then
966 opr.typ:=OPR_CONSTANT;
974 if assigned(pprocsym(sym)^.definition^.nextoverloaded) then
975 Message(asmr_w_calling_overload_func);
977 opr.symbol:=newasmsymbol(pprocsym(sym)^.definition^.mangledname);
984 Message(asmr_e_unsupported_symbol_type);
991 { looks for internal names of variables and routines }
992 Function TOperand.SetupDirectVar(const hs:string): Boolean;
993 {$ifndef OLDDIRECTVAR}
997 SetupDirectVar:=false;
1003 SetupDirectVar:=true;
1010 SearchDirectVar:=false;
1011 { search in the list of internals }
1012 p:=search_assembler_symbol(internals,hs,EXT_ANY);
1014 p:=search_assembler_symbol(externals,hs,EXT_ANY);
1017 instr.operands[operandnum].opr.ref.symbol:=p^.sym;
1019 EXT_BYTE : instr.operands[operandnum].size:=S_B;
1020 EXT_WORD : instr.operands[operandnum].size:=S_W;
1021 EXT_NEAR,EXT_FAR,EXT_PROC,EXT_DWORD,EXT_CODEPTR,EXT_DATAPTR:
1022 instr.operands[operandnum].size:=S_L;
1023 EXT_QWORD : instr.operands[operandnum].size:=S_FL;
1024 EXT_TBYTE : instr.operands[operandnum].size:=S_FX;
1026 { this is in the case where the instruction is LEA }
1027 { or something like that, in that case size is not }
1029 instr.operands[operandnum].size:=S_NO;
1031 instr.operands[operandnum].hasvar:=true;
1032 SearchDirectVar:=TRUE;
1038 procedure TOperand.InitRef;
1039 {*********************************************************************}
1040 { Description: This routine first check if the opcode is of }
1041 { type OPR_NONE, or OPR_REFERENCE , if not it gives out an error. }
1042 { If the operandtype = OPR_NONE or <> OPR_REFERENCE then it sets up }
1043 { the operand type to OPR_REFERENCE, as well as setting up the ref }
1044 { to point to the default segment. }
1045 {*********************************************************************}
1052 Message(asmr_e_invalid_operand_type);
1054 opr.typ := OPR_REFERENCE;
1055 reset_reference(opr.ref);
1059 procedure TOperand.BuildOperand;
1065 {****************************************************************************
1067 ****************************************************************************}
1069 constructor TInstruction.init;
1079 destructor TInstruction.done;
1084 Dispose(Operands[i],Done);
1088 procedure TInstruction.InitOperands;
1093 New(Operands[i],init);
1097 Procedure TInstruction.SwapOperands;
1105 Operands[1]:=Operands[2];
1111 Operands[1]:=Operands[3];
1118 procedure TInstruction.ConcatInstruction(p:PAasmOutput);
1124 procedure TInstruction.BuildOpcode;
1130 {***************************************************************************
1132 ***************************************************************************}
1134 constructor TLocalLabel.Init(const n:string);
1136 inherited InitName(n);
1142 function TLocalLabel.Getpasmlabel:pasmlabel;
1144 if not assigned(lab) then
1147 { this label is forced to be used so it's always written }
1154 {***************************************************************************
1156 ***************************************************************************}
1158 procedure LocalLabelEmitted(p:PNamedIndexObject);{$ifndef FPC}far;{$endif}
1160 if not PLocalLabel(p)^.emitted then
1161 Message1(asmr_e_unknown_label_identifier,p^.name);
1164 procedure TLocalLabelList.CheckEmitted;
1166 ForEach({$ifndef TP}@{$endif}LocalLabelEmitted)
1170 function CreateLocalLabel(const s: string; var hl: pasmlabel; emit:boolean):boolean;
1174 CreateLocalLabel:=true;
1175 { Check if it already is defined }
1176 lab:=PLocalLabel(LocalLabelList^.Search(s));
1177 if not assigned(lab) then
1180 LocalLabelList^.Insert(lab);
1182 { set emitted flag and check for dup syms }
1185 if lab^.Emitted then
1187 Message1(asmr_e_dup_local_sym,lab^.Name);
1188 CreateLocalLabel:=false;
1192 hl:=lab^.Getpasmlabel;
1196 {****************************************************************************
1197 Symbol table helper routines
1198 ****************************************************************************}
1200 Function SearchType(const hs:string): Boolean;
1203 SearchType:=assigned(srsym) and
1204 (srsym^.typ=typesym);
1209 Function SearchRecordType(const s:string): boolean;
1211 SearchRecordType:=false;
1212 { Check the constants in symtable }
1214 if srsym <> nil then
1219 if ptypesym(srsym)^.restype.def^.deftype in [recorddef,objectdef] then
1221 SearchRecordType:=true;
1230 Function SearchIConstant(const s:string; var l:longint): boolean;
1231 {**********************************************************************}
1232 { Description: Searches for a CONSTANT of name s in either the local }
1233 { symbol list, then in the global symbol list, and returns the value }
1234 { of that constant in l. Returns TRUE if successfull, if not found, }
1235 { or if the constant is not of correct type, then returns FALSE }
1236 { Remarks: Also handle TRUE and FALSE returning in those cases 1 and 0 }
1238 {**********************************************************************}
1240 SearchIConstant:=false;
1241 { check for TRUE or FALSE reserved words first }
1244 SearchIConstant:=TRUE;
1250 SearchIConstant:=TRUE;
1254 { Check the constants in symtable }
1256 if srsym <> nil then
1261 if (pconstsym(srsym)^.consttyp in [constord,constint,constchar,constbool]) then
1263 l:=pconstsym(srsym)^.value;
1264 SearchIConstant:=TRUE;
1270 l:=penumsym(srsym)^.value;
1271 SearchIConstant:=TRUE;
1279 Function GetRecordOffsetSize(s:string;Var Offset: longint;var Size:longint):boolean;
1280 { search and returns the offset and size of records/objects of the base }
1281 { with field name setup in field. }
1282 { returns FALSE if not found. }
1283 { used when base is a variable or a typed constant name. }
1286 harrdef : parraydef;
1291 GetRecordOffsetSize:=FALSE;
1297 base:=Copy(s,1,i-1);
1300 st:=procinfo^._class^.symtable
1306 { we can start with a var,type,typedconst }
1310 case pvarsym(sym)^.vartype.def^.deftype of
1312 st:=precorddef(pvarsym(sym)^.vartype.def)^.symtable;
1314 st:=pobjectdef(pvarsym(sym)^.vartype.def)^.symtable;
1319 case ptypesym(sym)^.restype.def^.deftype of
1321 st:=precorddef(ptypesym(sym)^.restype.def)^.symtable;
1323 st:=pobjectdef(ptypesym(sym)^.restype.def)^.symtable;
1328 case ptypedconstsym(sym)^.typedconsttype.def^.deftype of
1330 st:=precorddef(ptypedconstsym(sym)^.typedconsttype.def)^.symtable;
1332 st:=pobjectdef(ptypedconstsym(sym)^.typedconsttype.def)^.symtable;
1337 { now walk all recordsymtables }
1338 while assigned(st) and (s<>'') do
1340 { load next field in base }
1344 base:=Copy(s,1,i-1);
1346 if st^.symtabletype=objectsymtable then
1347 sym:=search_class_member(pobjectdef(st^.defowner),base)
1349 sym:=st^.search(base);
1350 if not assigned(sym) then
1352 GetRecordOffsetSize:=false;
1359 inc(Offset,pvarsym(sym)^.address);
1360 Size:=PVarsym(sym)^.getsize;
1361 case pvarsym(sym)^.vartype.def^.deftype of
1364 { for arrays try to get the element size, take care of
1366 harrdef:=Parraydef(PVarsym(sym)^.vartype.def);
1367 while assigned(harrdef^.elementtype.def) and
1368 (harrdef^.elementtype.def^.deftype=arraydef) do
1369 harrdef:=parraydef(harrdef^.elementtype.def);
1370 size:=harrdef^.elesize;
1373 st:=precorddef(pvarsym(sym)^.vartype.def)^.symtable;
1375 st:=pobjectdef(pvarsym(sym)^.vartype.def)^.symtable;
1380 GetRecordOffsetSize:=(s='');
1384 Function SearchLabel(const s: string; var hl: pasmlabel;emit:boolean): boolean;
1391 { Check for pascal labels, which are case insensetive }
1400 hl:=plabelsym(sym)^.lab;
1402 plabelsym(sym)^.defined:=true
1404 plabelsym(sym)^.used:=true;
1412 {*************************************************************************}
1413 { Instruction Generation Utilities }
1414 {*************************************************************************}
1417 Procedure ConcatString(p : paasmoutput;s:string);
1418 {*********************************************************************}
1419 { PROCEDURE ConcatString(s:string); }
1420 { Description: This routine adds the character chain pointed to in }
1421 { s to the instruction linked list. }
1422 {*********************************************************************}
1426 getmem(pc,length(s)+1);
1427 p^.concat(new(pai_string,init_length_pchar(strpcopy(pc,s),length(s))));
1430 Procedure ConcatPasString(p : paasmoutput;s:string);
1431 {*********************************************************************}
1432 { PROCEDURE ConcatPasString(s:string); }
1433 { Description: This routine adds the character chain pointed to in }
1434 { s to the instruction linked list, contrary to ConcatString it }
1435 { uses a pascal style string, so it conserves null characters. }
1436 {*********************************************************************}
1438 p^.concat(new(pai_string,init(s)));
1441 Procedure ConcatDirect(p : paasmoutput;s:string);
1442 {*********************************************************************}
1443 { PROCEDURE ConcatDirect(s:string) }
1444 { Description: This routine output the string directly to the asm }
1445 { output, it is only sed when writing special labels in AT&T mode, }
1446 { and should not be used without due consideration, since it may }
1448 {*********************************************************************}
1452 getmem(pc,length(s)+1);
1453 p^.concat(new(pai_direct,init(strpcopy(pc,s))));
1459 Procedure ConcatConstant(p: paasmoutput; value: longint; maxvalue: longint);
1460 {*********************************************************************}
1461 { PROCEDURE ConcatConstant(value: longint; maxvalue: longint); }
1462 { Description: This routine adds the value constant to the current }
1463 { instruction linked list. }
1464 { maxvalue -> indicates the size of the data to initialize: }
1465 { $ff -> create a byte node. }
1466 { $ffff -> create a word node. }
1467 { $ffffffff -> create a dword node. }
1468 {*********************************************************************}
1470 if (maxvalue <> longint($ffffffff)) and (value > maxvalue) then
1472 Message(asmr_e_constant_out_of_bounds);
1473 { assuming a value of maxvalue }
1476 if maxvalue = $ff then
1477 p^.concat(new(pai_const,init_8bit(byte(value))))
1479 if maxvalue = $ffff then
1480 p^.concat(new(pai_const,init_16bit(word(value))))
1482 if maxvalue = longint($ffffffff) then
1483 p^.concat(new(pai_const,init_32bit(longint(value))));
1487 Procedure ConcatConstSymbol(p : paasmoutput;const sym:string;l:longint);
1489 p^.concat(new(pai_const_symbol,initname_offset(sym,l)));
1493 Procedure ConcatRealConstant(p : paasmoutput;value: bestreal; real_typ : tfloattype);
1494 {***********************************************************************}
1495 { PROCEDURE ConcatRealConstant(value: bestreal; real_typ : tfloattype); }
1496 { Description: This routine adds the value constant to the current }
1497 { instruction linked list. }
1498 { real_typ -> indicates the type of the real data to initialize: }
1499 { s32real -> create a single node. }
1500 { s64real -> create a double node. }
1501 { s80real -> create an extended node. }
1502 { s64bit -> create a comp node. }
1503 { f32bit -> create a fixed node. (not used normally) }
1504 {***********************************************************************}
1507 s32real : p^.concat(new(pai_real_32bit,init(value)));
1508 s64real : p^.concat(new(pai_real_64bit,init(value)));
1509 s80real : p^.concat(new(pai_real_80bit,init(value)));
1510 s64comp : p^.concat(new(pai_comp_64bit,init(value)));
1511 f32bit : p^.concat(new(pai_const,init_32bit(trunc(value*$10000))));
1515 Procedure ConcatLabel(p: paasmoutput;var l : pasmlabel);
1516 {*********************************************************************}
1517 { PROCEDURE ConcatLabel }
1518 { Description: This routine either emits a label or a labeled }
1519 { instruction to the linked list of instructions. }
1520 {*********************************************************************}
1522 p^.concat(new(pai_label,init(l)));
1525 procedure ConcatAlign(p:paasmoutput;l:longint);
1526 {*********************************************************************}
1527 { PROCEDURE ConcatPublic }
1528 { Description: This routine emits an global definition to the }
1529 { linked list of instructions.(used by AT&T styled asm) }
1530 {*********************************************************************}
1532 p^.concat(new(pai_align,init(l)));
1535 procedure ConcatPublic(p:paasmoutput;const s : string);
1536 {*********************************************************************}
1537 { PROCEDURE ConcatPublic }
1538 { Description: This routine emits an global definition to the }
1539 { linked list of instructions.(used by AT&T styled asm) }
1540 {*********************************************************************}
1542 p^.concat(new(pai_symbol,initname_global(s,0)));
1545 procedure ConcatLocal(p:paasmoutput;const s : string);
1546 {*********************************************************************}
1547 { PROCEDURE ConcatLocal }
1548 { Description: This routine emits an local definition to the }
1549 { linked list of instructions. }
1550 {*********************************************************************}
1552 p^.concat(new(pai_symbol,initname(s,0)));
1555 Procedure ConcatGlobalBss(const s : string;size : longint);
1556 {*********************************************************************}
1557 { PROCEDURE ConcatGlobalBss }
1558 { Description: This routine emits an global datablock to the }
1559 { linked list of instructions. }
1560 {*********************************************************************}
1562 bsssegment^.concat(new(pai_datablock,init_global(s,size)));
1565 Procedure ConcatLocalBss(const s : string;size : longint);
1566 {*********************************************************************}
1567 { PROCEDURE ConcatLocalBss }
1568 { Description: This routine emits a local datablcok to the }
1569 { linked list of instructions. }
1570 {*********************************************************************}
1572 bsssegment^.concat(new(pai_datablock,init(s,size)));
1578 Revision 1.1 2002/02/19 08:23:45 sasu
1581 Revision 1.1.2.4 2000/11/06 16:57:38 pierre
1582 * issue error in TP and Delphi modes if result is a register
1584 Revision 1.1.2.3 2000/10/31 07:30:12 pierre
1585 * fix for bug 1157 second part
1587 Revision 1.1.2.2 2000/10/07 23:41:06 pierre
1590 Revision 1.1.2.1 2000/08/06 10:29:03 peter
1591 * fixed expression evaluator (bug 1090)
1593 Revision 1.1 2000/07/13 06:29:56 michael
1596 Revision 1.46 2000/05/26 18:23:11 peter
1597 * fixed % parsing and added modulo support
1598 * changed some evaulator errors to more generic illegal expresion
1600 Revision 1.45 2000/05/23 20:36:28 peter
1601 + typecasting support for variables, but be carefull as word,byte can't
1602 be used because they are reserved assembler keywords
1604 Revision 1.44 2000/05/22 12:47:52 pierre
1605 fix wrong handling of var para for size bug 961
1607 Revision 1.43 2000/05/18 17:05:16 peter
1608 * fixed size of const parameters in asm readers
1610 Revision 1.42 2000/05/11 09:56:22 pierre
1611 * fixed several compare problems between longints and
1612 const > $80000000 that are treated as int64 constanst
1613 by Delphi reported by Kovacs Attila Zoltan
1615 Revision 1.41 2000/05/08 13:23:05 peter
1616 * fixed reference parsing
1618 Revision 1.40 2000/04/06 07:56:04 pierre
1619 * bug in TOperand.SetSize corrected
1621 Revision 1.39 2000/04/04 13:48:45 pierre
1622 + TOperand.SetCorrectSize virtual method added
1623 to be able to change the suffix according to the instruction
1624 (FIADD word ptr w need a s as ATT suffix
1625 wheras FILD word ptr w need a w suffix :( )
1627 Revision 1.38 2000/03/28 22:10:12 pierre
1628 * Object fields are simple offsets in TP/Delphi mode
1630 Revision 1.37 2000/03/16 15:10:25 pierre
1631 * correct the fixups for inlined assembler code
1633 Revision 1.36 2000/03/15 23:10:01 pierre
1634 * fix for bug 848 (that still genrated wrong code)
1635 + better testing for variables used in assembler
1636 (gives an error if variable is not directly reachable !)
1638 Revision 1.35 2000/02/09 13:23:03 peter
1641 Revision 1.34 2000/01/07 01:14:37 peter
1642 * updated copyright to 2000
1644 Revision 1.33 1999/12/22 00:57:30 peter
1645 * label are set to used so an error is given if used but not defined
1647 Revision 1.32 1999/12/17 10:43:34 florian
1650 Revision 1.31 1999/11/30 10:40:54 peter
1653 Revision 1.30 1999/11/17 17:05:04 pierre
1654 * Notes/hints changes
1656 Revision 1.29 1999/11/09 23:06:46 peter
1657 * esi_offset -> selfpointer_offset to be newcg compatible
1658 * hcogegen -> cgbase fixes for newcg
1660 Revision 1.28 1999/11/06 14:34:26 peter
1661 * truncated log to 20 revs
1663 Revision 1.27 1999/09/27 23:44:58 peter
1664 * procinfo is now a pointer
1665 * support for result setting in sub procedure
1667 Revision 1.26 1999/09/08 16:04:04 peter
1668 * better support for object fields and more error checks for
1669 field accesses which create buggy code
1671 Revision 1.25 1999/09/04 20:29:11 florian
1674 Revision 1.24 1999/08/27 14:37:50 peter
1675 * fixed crash with typedconst array
1677 Revision 1.23 1999/08/13 21:28:38 peter
1678 * more reference types support
1679 * arraydef size returns elementsize, also for multiple indexing array
1681 Revision 1.22 1999/08/04 00:23:28 florian
1682 * renamed i386asm and i386base to cpuasm and cpubase
1684 Revision 1.21 1999/08/03 22:03:12 peter
1685 * moved bitmask constants to sets
1686 * some other type/const renamings
1688 Revision 1.20 1999/07/29 20:54:06 peter