diff options
Diffstat (limited to 'closures/compiler/x86/rax86int.pas')
-rw-r--r-- | closures/compiler/x86/rax86int.pas | 2238 |
1 files changed, 2238 insertions, 0 deletions
diff --git a/closures/compiler/x86/rax86int.pas b/closures/compiler/x86/rax86int.pas new file mode 100644 index 0000000000..e5536a1083 --- /dev/null +++ b/closures/compiler/x86/rax86int.pas @@ -0,0 +1,2238 @@ +{ + Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman + + Does the parsing process for the intel styled inline assembler. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + **************************************************************************** +} +Unit Rax86int; + +{$i fpcdefs.inc} + + interface + + uses + cclasses, + cpubase, + globtype, + aasmbase, + rasm, + rax86; + + type + tasmtoken = ( + AS_NONE,AS_LABEL,AS_LLABEL,AS_STRING,AS_INTNUM, + AS_COMMA,AS_LBRACKET,AS_RBRACKET,AS_LPAREN, + AS_RPAREN,AS_COLON,AS_DOT,AS_PLUS,AS_MINUS,AS_STAR, + AS_SEPARATOR,AS_ID,AS_REGISTER,AS_OPCODE,AS_SLASH, + {------------------ Assembler directives --------------------} + AS_ALIGN,AS_DB,AS_DW,AS_DD,AS_DQ,AS_END, + {------------------ Assembler Operators --------------------} + AS_BYTE,AS_WORD,AS_DWORD,AS_QWORD,AS_TBYTE,AS_DQWORD,AS_NEAR,AS_FAR, + AS_HIGH,AS_LOW,AS_OFFSET,AS_SIZEOF,AS_VMTOFFSET,AS_SEG,AS_TYPE,AS_PTR,AS_MOD,AS_SHL,AS_SHR,AS_NOT, + AS_AND,AS_OR,AS_XOR); + + type + tx86intreader = class(tasmreader) + actasmtoken : tasmtoken; + prevasmtoken : tasmtoken; + ActOpsize : topsize; + constructor create;override; + function is_asmopcode(const s: string):boolean; + function is_asmoperator(const s: string):boolean; + function is_asmdirective(const s: string):boolean; + function is_register(const s:string):boolean; + function is_locallabel(const s:string):boolean; + function Assemble: tlinkedlist;override; + procedure GetToken; + function consume(t : tasmtoken):boolean; + procedure RecoverConsume(allowcomma:boolean); + procedure BuildRecordOffsetSize(const expr: string;var offset:aint;var size:aint; var mangledname: string; needvmtofs: boolean); + procedure BuildConstSymbolExpression(needofs,isref,startingminus:boolean;var value:aint;var asmsym:string;var asmsymtyp:TAsmsymtype); + function BuildConstExpression:aint; + function BuildRefConstExpression:aint; + procedure BuildReference(oper : tx86operand); + procedure BuildOperand(oper: tx86operand;istypecast:boolean); + procedure BuildConstantOperand(oper: tx86operand); + procedure BuildOpCode(instr : tx86instruction); + procedure BuildConstant(constsize: byte); + end; + + + implementation + + uses + { common } + cutils, + { global } + globals,verbose, + systems, + { aasm } + aasmtai,aasmdata,aasmcpu, + { symtable } + symconst,symbase,symtype,symsym,symdef,symtable, + { parser } + scanner, + { register allocator } + rabase,rautils,itx86int, + { codegen } + cgbase,cgobj,procinfo + ; + + type + tasmkeyword = string[9]; + + + const + { These tokens should be modified accordingly to the modifications } + { in the different enumerations. } + firstdirective = AS_ALIGN; + lastdirective = AS_END; + firstoperator = AS_BYTE; + lastoperator = AS_XOR; + + _count_asmdirectives = longint(lastdirective)-longint(firstdirective); + _count_asmoperators = longint(lastoperator)-longint(firstoperator); + + _asmdirectives : array[0.._count_asmdirectives] of tasmkeyword = + ('ALIGN','DB','DW','DD','DQ','END'); + + { problems with shl,shr,not,and,or and xor, they are } + { context sensitive. } + _asmoperators : array[0.._count_asmoperators] of tasmkeyword = ( + 'BYTE','WORD','DWORD','QWORD','TBYTE','DQWORD','NEAR','FAR','HIGH', + 'LOW','OFFSET','SIZEOF','VMTOFFSET','SEG','TYPE','PTR','MOD','SHL','SHR','NOT','AND', + 'OR','XOR'); + + token2str : array[tasmtoken] of string[10] = ( + '','Label','LLabel','String','Integer', + ',','[',']','(', + ')',':','.','+','-','*', + ';','identifier','register','opcode','/', + '','','','','','END', + '','','','','','','','','', + '','','sizeof','vmtoffset','','type','ptr','mod','shl','shr','not', + 'and','or','xor' + ); + + var + inexpression : boolean; + + constructor tx86intreader.create; + var + i : tasmop; + Begin + inherited create; + iasmops:=TFPHashList.create; + for i:=firstop to lastop do + iasmops.Add(upper(std_op2str[i]),Pointer(PtrInt(i))); + end; + + +{---------------------------------------------------------------------} +{ Routines for the tokenizing } +{---------------------------------------------------------------------} + + + function tx86intreader.is_asmopcode(const s: string):boolean; + var + cond : string[4]; + cnd : tasmcond; + j: longint; + Begin + is_asmopcode:=FALSE; + + actopcode:=A_None; + actcondition:=C_None; + actopsize:=S_NO; + + { Search opcodes } + actopcode:=tasmop(PtrUInt(iasmops.Find(s))); + if actopcode<>A_NONE then + begin + actasmtoken:=AS_OPCODE; + result:=TRUE; + exit; + end; + + { not found yet, check condition opcodes } + j:=0; + while (j<CondAsmOps) do + begin + if Copy(s,1,Length(CondAsmOpStr[j]))=CondAsmOpStr[j] then + begin + cond:=Copy(s,Length(CondAsmOpStr[j])+1,255); + if cond<>'' then + begin + for cnd:=low(TasmCond) to high(TasmCond) do + if Cond=Upper(cond2str[cnd]) then + begin + actopcode:=CondASmOp[j]; + actcondition:=cnd; + is_asmopcode:=TRUE; + actasmtoken:=AS_OPCODE; + exit + end; + end; + end; + inc(j); + end; + end; + + + function tx86intreader.is_asmoperator(const s: string):boolean; + var + i : longint; + Begin + for i:=0 to _count_asmoperators do + if s=_asmoperators[i] then + begin + actasmtoken:=tasmtoken(longint(firstoperator)+i); + is_asmoperator:=true; + exit; + end; + is_asmoperator:=false; + end; + + + Function tx86intreader.is_asmdirective(const s: string):boolean; + var + i : longint; + Begin + for i:=0 to _count_asmdirectives do + if s=_asmdirectives[i] then + begin + actasmtoken:=tasmtoken(longint(firstdirective)+i); + is_asmdirective:=true; + exit; + end; + is_asmdirective:=false; + end; + + + function tx86intreader.is_register(const s:string):boolean; + var + entry: TSymEntry; + begin + is_register:=false; + actasmregister:=masm_regnum_search(lower(s)); + if (actasmregister=NR_NO) and + (current_procinfo.procdef.proccalloption=pocall_register) and + (po_assembler in current_procinfo.procdef.procoptions) then + begin + entry:=current_procinfo.procdef.parast.Find(s); + if assigned(entry) and + (entry.typ=paravarsym) and + assigned(tparavarsym(entry).paraloc[calleeside].Location) and + (tparavarsym(entry).paraloc[calleeside].Location^.Loc=LOC_REGISTER) then + actasmregister:=tparavarsym(entry).paraloc[calleeside].Location^.register; + end; + if actasmregister<>NR_NO then + begin + is_register:=true; + actasmtoken:=AS_REGISTER; + end; + end; + + + function tx86intreader.is_locallabel(const s:string):boolean; + begin + is_locallabel:=(length(s)>1) and (s[1]='@'); + end; + + + Procedure tx86intreader.GetToken; + var + len : longint; + forcelabel : boolean; + srsym : tsym; + srsymtable : TSymtable; + begin + { save old token and reset new token } + prevasmtoken:=actasmtoken; + actasmtoken:=AS_NONE; + { reset } + forcelabel:=FALSE; + actasmpattern:=''; + { while space and tab , continue scan... } + while (c in [' ',#9]) do + c:=current_scanner.asmgetchar; + { get token pos } + if not (c in [#10,#13,'{',';']) then + current_scanner.gettokenpos; + { Local Label, Label, Directive, Prefix or Opcode } + if firsttoken and not (c in [#10,#13,'{',';']) then + begin + firsttoken:=FALSE; + len:=0; + while c in ['A'..'Z','a'..'z','0'..'9','_','@'] do + begin + { if there is an at_sign, then this must absolutely be a label } + if c = '@' then + forcelabel:=TRUE; + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + end; + actasmpattern[0]:=chr(len); + uppervar(actasmpattern); + { allow spaces } + while (c in [' ',#9]) do + c:=current_scanner.asmgetchar; + { label ? } + if c = ':' then + begin + if actasmpattern[1]='@' then + actasmtoken:=AS_LLABEL + else + actasmtoken:=AS_LABEL; + { let us point to the next character } + c:=current_scanner.asmgetchar; + firsttoken:=true; + exit; + end; + { Are we trying to create an identifier with } + { an at-sign...? } + if forcelabel then + Message(asmr_e_none_label_contain_at); + { opcode ? } + If is_asmopcode(actasmpattern) then + Begin + { check if we are in an expression } + { then continue with asm directives } + if not inexpression then + exit; + end; + if is_asmdirective(actasmpattern) then + exit; + message1(asmr_e_unknown_opcode,actasmpattern); + actasmtoken:=AS_NONE; + exit; + end + else { else firsttoken } + begin + case c of + '@' : { possiblities : - local label reference , such as in jmp @local1 } + { - @Result, @Code or @Data special variables. } + begin + actasmpattern:=c; + c:=current_scanner.asmgetchar; + while c in ['A'..'Z','a'..'z','0'..'9','_','@'] do + begin + actasmpattern:=actasmpattern + c; + c:=current_scanner.asmgetchar; + end; + uppervar(actasmpattern); + actasmtoken:=AS_ID; + exit; + end; + + 'A'..'Z','a'..'z','_': { identifier, register, opcode, prefix or directive } + begin + actasmpattern:=c; + c:=current_scanner.asmgetchar; + while c in ['A'..'Z','a'..'z','0'..'9','_'] do + begin + actasmpattern:=actasmpattern + c; + c:=current_scanner.asmgetchar; + end; + uppervar(actasmpattern); + { after prefix we allow also a new opcode } + If is_prefix(actopcode) and is_asmopcode(actasmpattern) then + Begin + { if we are not in a constant } + { expression than this is an } + { opcode. } + if not inexpression then + exit; + end; + { support st(X) for fpu registers } + if (actasmpattern = 'ST') and (c='(') then + Begin + actasmpattern:=actasmpattern+c; + c:=current_scanner.asmgetchar; + { allow spaces } + while (c in [' ',#9]) do + c:=current_scanner.asmgetchar; + if c in ['0'..'7'] then + actasmpattern:=actasmpattern + c + else + Message(asmr_e_invalid_fpu_register); + c:=current_scanner.asmgetchar; + { allow spaces } + while (c in [' ',#9]) do + c:=current_scanner.asmgetchar; + if c <> ')' then + Message(asmr_e_invalid_fpu_register) + else + Begin + actasmpattern:=actasmpattern + c; + c:=current_scanner.asmgetchar; + end; + end; + if is_asmdirective(actasmpattern) then + exit; + if is_asmoperator(actasmpattern) then + exit; + if is_register(actasmpattern) then + exit; + { allow spaces } + while (c in [' ',#9]) do + c:=current_scanner.asmgetchar; + { if next is a '.' and this is a unitsym then we also need to + parse the identifier } + if (c='.') then + begin + asmsearchsym(actasmpattern,srsym,srsymtable); + if assigned(srsym) and + (srsym.typ=unitsym) and + (srsym.owner.symtabletype in [staticsymtable,globalsymtable]) and + srsym.owner.iscurrentunit then + begin + { Add . to create System.Identifier } + actasmpattern:=actasmpattern+c; + c:=current_scanner.asmgetchar; + { Delphi allows System.@Halt, just ignore the @ } + if c='@' then + c:=current_scanner.asmgetchar; + while c in ['A'..'Z','a'..'z','0'..'9','_','$'] do + begin + actasmpattern:=actasmpattern + upcase(c); + c:=current_scanner.asmgetchar; + end; + end; + end; + actasmtoken:=AS_ID; + exit; + end; + + '''' : { string or character } + begin + actasmpattern:=''; + current_scanner.in_asm_string:=true; + repeat + if c = '''' then + begin + c:=current_scanner.asmgetchar; + if c in [#10,#13] then + begin + Message(scan_f_string_exceeds_line); + break; + end; + repeat + if c='''' then + begin + c:=current_scanner.asmgetchar; + if c='''' then + begin + actasmpattern:=actasmpattern+''''; + c:=current_scanner.asmgetchar; + if c in [#10,#13] then + begin + Message(scan_f_string_exceeds_line); + break; + end; + end + else + break; + end + else + begin + actasmpattern:=actasmpattern+c; + c:=current_scanner.asmgetchar; + if c in [#10,#13] then + begin + Message(scan_f_string_exceeds_line); + break + end; + end; + until false; { end repeat } + end + else + break; { end if } + until false; + current_scanner.in_asm_string:=false; + actasmtoken:=AS_STRING; + exit; + end; + + '"' : { string or character } + begin + current_scanner.in_asm_string:=true; + actasmpattern:=''; + repeat + if c = '"' then + begin + c:=current_scanner.asmgetchar; + if c in [#10,#13] then + begin + Message(scan_f_string_exceeds_line); + break; + end; + repeat + if c='"' then + begin + c:=current_scanner.asmgetchar; + if c='"' then + begin + actasmpattern:=actasmpattern+'"'; + c:=current_scanner.asmgetchar; + if c in [#10,#13] then + begin + Message(scan_f_string_exceeds_line); + break; + end; + end + else + break; + end + else + begin + actasmpattern:=actasmpattern+c; + c:=current_scanner.asmgetchar; + if c in [#10,#13] then + begin + Message(scan_f_string_exceeds_line); + break + end; + end; + until false; { end repeat } + end + else + break; { end if } + until false; + current_scanner.in_asm_string:=false; + actasmtoken:=AS_STRING; + exit; + end; + + '$' : + begin + c:=current_scanner.asmgetchar; + while c in ['0'..'9','A'..'F','a'..'f'] do + begin + actasmpattern:=actasmpattern + c; + c:=current_scanner.asmgetchar; + end; + actasmpattern:=tostr(ParseVal(actasmpattern,16)); + actasmtoken:=AS_INTNUM; + exit; + end; + + '&' : { identifier } + begin + actasmpattern:=''; + c:=current_scanner.asmgetchar; + while c in ['A'..'Z','a'..'z','0'..'9','_'] do + begin + actasmpattern:=actasmpattern + c; + c:=current_scanner.asmgetchar; + end; + uppervar(actasmpattern); + actasmtoken:=AS_ID; + exit; + end; + + ',' : + begin + actasmtoken:=AS_COMMA; + c:=current_scanner.asmgetchar; + exit; + end; + + '[' : + begin + actasmtoken:=AS_LBRACKET; + c:=current_scanner.asmgetchar; + exit; + end; + + ']' : + begin + actasmtoken:=AS_RBRACKET; + c:=current_scanner.asmgetchar; + exit; + end; + + '(' : + begin + actasmtoken:=AS_LPAREN; + c:=current_scanner.asmgetchar; + exit; + end; + + ')' : + begin + actasmtoken:=AS_RPAREN; + c:=current_scanner.asmgetchar; + exit; + end; + + ':' : + begin + actasmtoken:=AS_COLON; + c:=current_scanner.asmgetchar; + exit; + end; + + '.' : + begin + actasmtoken:=AS_DOT; + c:=current_scanner.asmgetchar; + exit; + end; + + '+' : + begin + actasmtoken:=AS_PLUS; + c:=current_scanner.asmgetchar; + exit; + end; + + '-' : + begin + actasmtoken:=AS_MINUS; + c:=current_scanner.asmgetchar; + exit; + end; + + '*' : + begin + actasmtoken:=AS_STAR; + c:=current_scanner.asmgetchar; + exit; + end; + + '/' : + begin + actasmtoken:=AS_SLASH; + c:=current_scanner.asmgetchar; + exit; + end; + + '0'..'9': + begin + actasmpattern:=c; + c:=current_scanner.asmgetchar; + { Get the possible characters } + while c in ['0'..'9','A'..'F','a'..'f'] do + begin + actasmpattern:=actasmpattern + c; + c:=current_scanner.asmgetchar; + end; + { Get ending character } + uppervar(actasmpattern); + c:=upcase(c); + { possibly a binary number. } + if (actasmpattern[length(actasmpattern)] = 'B') and (c <> 'H') then + Begin + { Delete the last binary specifier } + delete(actasmpattern,length(actasmpattern),1); + actasmpattern:=tostr(ParseVal(actasmpattern,2)); + actasmtoken:=AS_INTNUM; + exit; + end + else + Begin + case c of + 'O' : + Begin + actasmpattern:=tostr(ParseVal(actasmpattern,8)); + actasmtoken:=AS_INTNUM; + c:=current_scanner.asmgetchar; + exit; + end; + 'H' : + Begin + actasmpattern:=tostr(ParseVal(actasmpattern,16)); + actasmtoken:=AS_INTNUM; + c:=current_scanner.asmgetchar; + exit; + end; + else { must be an integer number } + begin + actasmpattern:=tostr(ParseVal(actasmpattern,10)); + actasmtoken:=AS_INTNUM; + exit; + end; + end; + end; + end; + ';','{',#13,#10 : + begin + c:=current_scanner.asmgetchar; + firsttoken:=TRUE; + actasmtoken:=AS_SEPARATOR; + exit; + end; + + else + current_scanner.illegal_char(c); + end; + end; + end; + + + function tx86intreader.consume(t : tasmtoken):boolean; + begin + Consume:=true; + if t<>actasmtoken then + begin + Message2(scan_f_syn_expected,token2str[t],token2str[actasmtoken]); + Consume:=false; + end; + repeat + gettoken; + until actasmtoken<>AS_NONE; + end; + + + procedure tx86intreader.RecoverConsume(allowcomma:boolean); + begin + While not (actasmtoken in [AS_SEPARATOR,AS_END]) do + begin + if allowcomma and (actasmtoken=AS_COMMA) then + break; + Consume(actasmtoken); + end; + end; + + +{***************************************************************************** + Parsing Helpers +*****************************************************************************} + + { This routine builds up a record offset after a AS_DOT + token is encountered. + On entry actasmtoken should be equal to AS_DOT } + Procedure tx86intreader.BuildRecordOffsetSize(const expr: string;var offset:aint;var size:aint; var mangledname: string; needvmtofs: boolean); + var + s: string; + Begin + offset:=0; + size:=0; + s:=expr; + while (actasmtoken=AS_DOT) do + begin + Consume(AS_DOT); + if actasmtoken in [AS_BYTE,AS_ID,AS_WORD,AS_DWORD,AS_QWORD,AS_REGISTER] then + begin + s:=s+'.'+actasmpattern; + consume(actasmtoken); + end + else + begin + Consume(AS_ID); + RecoverConsume(true); + break; + end; + end; + if not GetRecordOffsetSize(s,offset,size,mangledname,needvmtofs) then + Message(asmr_e_building_record_offset); + end; + + + Procedure tx86intreader.BuildConstSymbolExpression(needofs,isref,startingminus:boolean;var value:aint;var asmsym:string;var asmsymtyp:TAsmsymtype); + var + tempstr,expr,hs,mangledname : string; + parenlevel : longint; + l,k : aint; + hasparen, + errorflag, + needvmtofs : boolean; + prevtok : tasmtoken; + hl : tasmlabel; + hssymtyp : Tasmsymtype; + def : tdef; + sym : tsym; + srsymtable : TSymtable; + Begin + { reset } + value:=0; + asmsym:=''; + asmsymtyp:=AT_DATA; + errorflag:=FALSE; + tempstr:=''; + expr:=''; + if startingminus then + expr:='-'; + inexpression:=TRUE; + parenlevel:=0; + sym:=nil; + needvmtofs:=FALSE; + Repeat + { Support ugly delphi constructs like: [ECX].1+2[EDX] } + if isref and (actasmtoken=AS_LBRACKET) then + break; + Case actasmtoken of + AS_LPAREN: + Begin + Consume(AS_LPAREN); + expr:=expr + '('; + inc(parenlevel); + end; + AS_RPAREN: + Begin + { Keep the AS_PAREN in actasmtoken, it is maybe a typecast } + if parenlevel=0 then + break; + Consume(AS_RPAREN); + expr:=expr + ')'; + dec(parenlevel); + end; + AS_SHL: + Begin + Consume(AS_SHL); + expr:=expr + '<'; + end; + AS_SHR: + Begin + Consume(AS_SHR); + expr:=expr + '>'; + end; + AS_SLASH: + Begin + Consume(AS_SLASH); + expr:=expr + '/'; + end; + AS_MOD: + Begin + Consume(AS_MOD); + expr:=expr + '%'; + end; + AS_STAR: + Begin + Consume(AS_STAR); + if isref and (actasmtoken=AS_REGISTER) then + break; + expr:=expr + '*'; + end; + AS_PLUS: + Begin + Consume(AS_PLUS); + if isref and (actasmtoken=AS_REGISTER) then + break; + expr:=expr + '+'; + end; + AS_MINUS: + Begin + Consume(AS_MINUS); + expr:=expr + '-'; + end; + AS_AND: + Begin + Consume(AS_AND); + expr:=expr + '&'; + end; + AS_NOT: + Begin + Consume(AS_NOT); + expr:=expr + '~'; + end; + AS_XOR: + Begin + Consume(AS_XOR); + expr:=expr + '^'; + end; + AS_OR: + Begin + Consume(AS_OR); + expr:=expr + '|'; + end; + AS_INTNUM: + Begin + expr:=expr + actasmpattern; + Consume(AS_INTNUM); + end; + AS_VMTOFFSET, + AS_OFFSET: + begin + if (actasmtoken = AS_OFFSET) then + needofs:=true + else + needvmtofs:=true; + Consume(actasmtoken); + if actasmtoken<>AS_ID then + Message(asmr_e_offset_without_identifier); + end; + AS_SIZEOF, + AS_TYPE: + begin + l:=0; + hasparen:=false; + Consume(actasmtoken); + if actasmtoken=AS_LPAREN then + begin + hasparen:=true; + Consume(AS_LPAREN); + end; + if actasmtoken<>AS_ID then + Message(asmr_e_type_without_identifier) + else + begin + tempstr:=actasmpattern; + Consume(AS_ID); + if actasmtoken=AS_DOT then + begin + BuildRecordOffsetSize(tempstr,k,l,mangledname,false); + if mangledname<>'' then + { procsym } + Message(asmr_e_wrong_sym_type); + end + else + begin + asmsearchsym(tempstr,sym,srsymtable); + if assigned(sym) then + begin + case sym.typ of + staticvarsym, + localvarsym, + paravarsym : + l:=tabstractvarsym(sym).getsize; + typesym : + l:=ttypesym(sym).typedef.size; + else + Message(asmr_e_wrong_sym_type); + end; + end + else + Message1(sym_e_unknown_id,tempstr); + end; + end; + str(l, tempstr); + expr:=expr + tempstr; + if hasparen then + Consume(AS_RPAREN); + end; + AS_PTR : + begin + { Support ugly delphi constructs like <constant> PTR [ref] } + break; + end; + AS_STRING: + begin + l:=0; + case Length(actasmpattern) of + 1 : + l:=ord(actasmpattern[1]); + 2 : + l:=ord(actasmpattern[2]) + ord(actasmpattern[1]) shl 8; + 3 : + l:=ord(actasmpattern[3]) + + Ord(actasmpattern[2]) shl 8 + ord(actasmpattern[1]) shl 16; + 4 : + l:=ord(actasmpattern[4]) + ord(actasmpattern[3]) shl 8 + + Ord(actasmpattern[2]) shl 16 + ord(actasmpattern[1]) shl 24; + else + Message1(asmr_e_invalid_string_as_opcode_operand,actasmpattern); + end; + str(l, tempstr); + expr:=expr + tempstr; + Consume(AS_STRING); + end; + AS_ID: + begin + hs:=''; + hssymtyp:=AT_DATA; + def:=nil; + tempstr:=actasmpattern; + prevtok:=prevasmtoken; + { stop parsing a constant expression if we find an opcode after a + non-operator like "db $66 mov eax,ebx" } + if (prevtok in [AS_ID,AS_INTNUM,AS_RPAREN]) and + is_asmopcode(actasmpattern) then + break; + consume(AS_ID); + if SearchIConstant(tempstr,l) then + begin + str(l, tempstr); + expr:=expr + tempstr; + end + else + begin + if is_locallabel(tempstr) then + begin + CreateLocalLabel(tempstr,hl,false); + hs:=hl.name; + hssymtyp:=AT_FUNCTION; + end + else + if SearchLabel(tempstr,hl,false) then + begin + hs:=hl.name; + hssymtyp:=AT_FUNCTION; + end + else + begin + asmsearchsym(tempstr,sym,srsymtable); + if assigned(sym) then + begin + case sym.typ of + staticvarsym : + begin + hs:=tstaticvarsym(sym).mangledname; + def:=tstaticvarsym(sym).vardef; + end; + localvarsym, + paravarsym : + begin + Message(asmr_e_no_local_or_para_allowed); + end; + procsym : + begin + if Tprocsym(sym).ProcdefList.Count>1 then + Message(asmr_w_calling_overload_func); + hs:=tprocdef(tprocsym(sym).ProcdefList[0]).mangledname; + hssymtyp:=AT_FUNCTION; + end; + typesym : + begin + if not(ttypesym(sym).typedef.typ in [recorddef,objectdef]) then + Message(asmr_e_wrong_sym_type); + end; + fieldvarsym : + begin + tempstr:=upper(tdef(sym.owner.defowner).GetTypeName)+'.'+tempstr; + end; + else + Message(asmr_e_wrong_sym_type); + end; + end + else + Message1(sym_e_unknown_id,tempstr); + end; + { symbol found? } + if hs<>'' then + begin + if asmsym='' then + begin + asmsym:=hs; + asmsymtyp:=hssymtyp; + end + else + Message(asmr_e_cant_have_multiple_relocatable_symbols); + if (expr='') or (expr[length(expr)]='+') then + begin + { don't remove the + if there could be a record field } + if actasmtoken<>AS_DOT then + delete(expr,length(expr),1); + end + else + if needofs then + begin + if (prevtok<>AS_OFFSET) then + Message(asmr_e_need_offset); + end + else + Message(asmr_e_only_add_relocatable_symbol); + end; + if (actasmtoken=AS_DOT) or + (assigned(sym) and + (sym.typ = fieldvarsym)) then + begin + BuildRecordOffsetSize(tempstr,l,k,hs,needvmtofs); + if hs <> '' then + hssymtyp:=AT_FUNCTION + else + begin + str(l, tempstr); + expr:=expr + tempstr; + end + end + else + begin + if (expr='') or (expr[length(expr)] in ['+','-','/','*']) then + delete(expr,length(expr),1); + end; + if (actasmtoken=AS_LBRACKET) and + assigned(def) and + (def.typ=arraydef) then + begin + consume(AS_LBRACKET); + l:=BuildConstExpression; + if l<tarraydef(def).lowrange then + begin + Message(asmr_e_constant_out_of_bounds); + l:=0; + end + else + l:=(l-tarraydef(def).lowrange)*tarraydef(def).elesize; + str(l, tempstr); + expr:=expr + '+' + tempstr; + consume(AS_RBRACKET); + end; + end; + { check if there are wrong operator used like / or mod etc. } + if (hs<>'') and not(actasmtoken in [AS_MINUS,AS_PLUS,AS_COMMA,AS_SEPARATOR,AS_END,AS_RBRACKET]) then + Message(asmr_e_only_add_relocatable_symbol); + end; + AS_ALIGN, + AS_DB, + AS_DW, + AS_DD, + AS_DQ, + AS_END, + AS_RBRACKET, + AS_SEPARATOR, + AS_COMMA, + AS_COLON: + break; + else + begin + { write error only once. } + if not errorflag then + Message(asmr_e_invalid_constant_expression); + { consume tokens until we find COMMA or SEPARATOR } + Consume(actasmtoken); + errorflag:=TRUE; + end; + end; + Until false; + { calculate expression } + if not ErrorFlag then + value:=CalculateExpression(expr) + else + value:=0; + { no longer in an expression } + inexpression:=FALSE; + end; + + + Function tx86intreader.BuildConstExpression:aint; + var + l : aint; + hs : string; + hssymtyp : TAsmsymtype; + begin + BuildConstSymbolExpression(false,false,false,l,hs,hssymtyp); + if hs<>'' then + Message(asmr_e_relocatable_symbol_not_allowed); + BuildConstExpression:=l; + end; + + + Function tx86intreader.BuildRefConstExpression:aint; + var + l : aint; + hs : string; + hssymtyp : TAsmsymtype; + begin + BuildConstSymbolExpression(false,true,false,l,hs,hssymtyp); + if hs<>'' then + Message(asmr_e_relocatable_symbol_not_allowed); + BuildRefConstExpression:=l; + end; + + + procedure tx86intreader.BuildReference(oper : tx86operand); + var + scale : byte; + k,l : aint; + tempstr,hs : string; + tempsymtyp : tasmsymtype; + code : integer; + hreg : tregister; + GotStar,GotOffset,HadVar, + GotPlus,Negative : boolean; + hl : tasmlabel; + Begin + Consume(AS_LBRACKET); + if not(oper.opr.typ in [OPR_LOCAL,OPR_REFERENCE]) then + oper.InitRef; + GotStar:=false; + GotPlus:=true; + GotOffset:=false; + Negative:=false; + Scale:=0; + repeat + if GotOffset and (actasmtoken<>AS_ID) then + Message(asmr_e_invalid_reference_syntax); + + Case actasmtoken of + AS_ID, { Constant reference expression OR variable reference expression } + AS_VMTOFFSET: + Begin + if not GotPlus then + Message(asmr_e_invalid_reference_syntax); + GotStar:=false; + GotPlus:=false; + if (actasmtoken = AS_VMTOFFSET) or + (SearchIConstant(actasmpattern,l) or + SearchRecordType(actasmpattern)) then + begin + l:=BuildRefConstExpression; + GotPlus:=(prevasmtoken=AS_PLUS); + GotStar:=(prevasmtoken=AS_STAR); + case oper.opr.typ of + OPR_LOCAL : + begin + if GotStar then + Message(asmr_e_invalid_reference_syntax); + if negative then + Dec(oper.opr.localsymofs,l) + else + Inc(oper.opr.localsymofs,l); + end; + OPR_REFERENCE : + begin + if GotStar then + oper.opr.ref.scalefactor:=l + else + begin + if negative then + Dec(oper.opr.ref.offset,l) + else + Inc(oper.opr.ref.offset,l); + end; + end; + end; + end + else + Begin + if negative and not oper.hasvar then + Message(asmr_e_only_add_relocatable_symbol) + else if oper.hasvar and not GotOffset and + (not negative or assigned(oper.opr.ref.relsymbol)) then + Message(asmr_e_cant_have_multiple_relocatable_symbols); + HadVar:=oper.hasvar and GotOffset; + tempstr:=actasmpattern; + Consume(AS_ID); + { typecasting? } + if (actasmtoken=AS_LPAREN) and + SearchType(tempstr,l) then + begin + oper.hastype:=true; + oper.typesize:=l; + Consume(AS_LPAREN); + BuildOperand(oper,true); + Consume(AS_RPAREN); + end + else + if is_locallabel(tempstr) then + begin + CreateLocalLabel(tempstr,hl,false); + oper.InitRef; + if not negative then + begin + oper.opr.ref.symbol:=hl; + oper.hasvar:=true; + end + else + oper.opr.ref.relsymbol:=hl; + end + else + if oper.SetupVar(tempstr,GotOffset) then + begin + { force OPR_LOCAL to be a reference } + if oper.opr.typ=OPR_LOCAL then + oper.opr.localforceref:=true; + end + else + Message1(sym_e_unknown_id,tempstr); + { record.field ? } + if actasmtoken=AS_DOT then + begin + BuildRecordOffsetSize(tempstr,l,k,hs,false); + if (hs<>'') then + Message(asmr_e_invalid_symbol_ref); + case oper.opr.typ of + OPR_LOCAL : + inc(oper.opr.localsymofs,l); + OPR_REFERENCE : + inc(oper.opr.ref.offset,l); + end; + end; + if GotOffset then + begin + if oper.hasvar and (oper.opr.ref.base=current_procinfo.framepointer) then + begin + if (oper.opr.typ=OPR_REFERENCE) then + oper.opr.ref.base:=NR_NO; + oper.hasvar:=hadvar; + end + else + begin + if oper.hasvar and hadvar then + Message(asmr_e_cant_have_multiple_relocatable_symbols); + { should we allow ?? } + end; + end; + end; + GotOffset:=false; + end; + + AS_PLUS : + Begin + Consume(AS_PLUS); + Negative:=false; + GotPlus:=true; + GotStar:=false; + Scale:=0; + end; + + AS_DOT : + Begin + { Handle like a + } + Consume(AS_DOT); + Negative:=false; + GotPlus:=true; + GotStar:=false; + Scale:=0; + end; + + AS_MINUS : + begin + Consume(AS_MINUS); + Negative:=true; + GotPlus:=true; + GotStar:=false; + Scale:=0; + end; + + AS_STAR : { Scaling, with eax*4 order } + begin + Consume(AS_STAR); + hs:=''; + l:=0; + case actasmtoken of + AS_LPAREN : + l:=BuildConstExpression; + AS_INTNUM: + Begin + hs:=actasmpattern; + Consume(AS_INTNUM); + end; + AS_REGISTER : + begin + case oper.opr.typ of + OPR_REFERENCE : + begin + if oper.opr.ref.scalefactor=0 then + begin + if scale<>0 then + begin + oper.opr.ref.scalefactor:=scale; + scale:=0; + end + else + Message(asmr_e_wrong_scale_factor); + end + else + Message(asmr_e_invalid_reference_syntax); + end; + OPR_LOCAL : + begin + if oper.opr.localscale=0 then + begin + if scale<>0 then + begin + oper.opr.localscale:=scale; + scale:=0; + end + else + Message(asmr_e_wrong_scale_factor); + end + else + Message(asmr_e_invalid_reference_syntax); + end; + end; + end; + else + Message(asmr_e_invalid_reference_syntax); + end; + if actasmtoken<>AS_REGISTER then + begin + if hs<>'' then + val(hs,l,code); + case oper.opr.typ of + OPR_REFERENCE : + oper.opr.ref.scalefactor:=l; + OPR_LOCAL : + oper.opr.localscale:=l; + end; + if l>9 then + Message(asmr_e_wrong_scale_factor); + end; + GotPlus:=false; + GotStar:=false; + end; + + AS_REGISTER : + begin + if not((GotPlus and (not Negative)) or + GotStar) then + Message(asmr_e_invalid_reference_syntax); + hreg:=actasmregister; + Consume(AS_REGISTER); + { this register will be the index: + 1. just read a * + 2. next token is a * + 3. base register is already used } + case oper.opr.typ of + OPR_LOCAL : + begin + if (oper.opr.localindexreg<>NR_NO) then + Message(asmr_e_multiple_index); + oper.opr.localindexreg:=hreg; + if scale<>0 then + begin + oper.opr.localscale:=scale; + scale:=0; + end; + end; + OPR_REFERENCE : + begin + if (GotStar) or + (actasmtoken=AS_STAR) or + (oper.opr.ref.base<>NR_NO) then + begin + if (oper.opr.ref.index<>NR_NO) then + Message(asmr_e_multiple_index); + oper.opr.ref.index:=hreg; + if scale<>0 then + begin + oper.opr.ref.scalefactor:=scale; + scale:=0; + end; + end + else + oper.opr.ref.base:=hreg; + end; + end; + GotPlus:=false; + GotStar:=false; + end; + + AS_OFFSET : + begin + Consume(AS_OFFSET); + GotOffset:=true; + end; + + AS_TYPE, + AS_NOT, + AS_STRING, + AS_INTNUM, + AS_LPAREN : { Constant reference expression } + begin + if not GotPlus and not GotStar then + Message(asmr_e_invalid_reference_syntax); + BuildConstSymbolExpression(true,true,GotPlus and negative,l,tempstr,tempsymtyp); + { already handled by BuildConstSymbolExpression(); must be + handled there to avoid [reg-1+1] being interpreted as + [reg-(1+1)] } + negative:=false; + + if tempstr<>'' then + begin + if GotStar then + Message(asmr_e_only_add_relocatable_symbol); + if not assigned(oper.opr.ref.symbol) then + oper.opr.ref.symbol:=current_asmdata.RefAsmSymbol(tempstr) + else + Message(asmr_e_cant_have_multiple_relocatable_symbols); + end; + case oper.opr.typ of + OPR_REFERENCE : + begin + if GotStar then + oper.opr.ref.scalefactor:=l + else if (prevasmtoken = AS_STAR) then + begin + if scale<>0 then + scale:=l*scale + else + scale:=l; + end + else + Inc(oper.opr.ref.offset,l); + end; + OPR_LOCAL : + begin + if GotStar then + oper.opr.localscale:=l + else if (prevasmtoken = AS_STAR) then + begin + if scale<>0 then + scale:=l*scale + else + scale:=l; + end + else + Inc(oper.opr.localsymofs,l); + end; + end; + GotPlus:=(prevasmtoken=AS_PLUS) or + (prevasmtoken=AS_MINUS); + if GotPlus then + negative := prevasmtoken = AS_MINUS; + GotStar:=(prevasmtoken=AS_STAR); + end; + + AS_RBRACKET : + begin + if GotPlus or GotStar then + Message(asmr_e_invalid_reference_syntax); + Consume(AS_RBRACKET); + break; + end; + + else + Begin + Message(asmr_e_invalid_reference_syntax); + RecoverConsume(true); + break; + end; + end; + until false; + end; + + + Procedure tx86intreader.BuildConstantOperand(oper: tx86operand); + var + l : aint; + tempstr : string; + tempsymtyp : tasmsymtype; + begin + if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then + Message(asmr_e_invalid_operand_type); + BuildConstSymbolExpression(true,false,false,l,tempstr,tempsymtyp); + if tempstr<>'' then + begin + oper.opr.typ:=OPR_SYMBOL; + oper.opr.symofs:=l; + oper.opr.symbol:=current_asmdata.RefAsmSymbol(tempstr); + end + else + if oper.opr.typ=OPR_NONE then + begin + oper.opr.typ:=OPR_CONSTANT; + oper.opr.val:=l; + end + else + inc(oper.opr.val,l); + end; + + + Procedure tx86intreader.BuildOperand(oper: tx86operand;istypecast:boolean); + + procedure AddLabelOperand(hl:tasmlabel); + begin + if (oper.opr.typ=OPR_NONE) and + is_calljmp(actopcode) then + begin + oper.opr.typ:=OPR_SYMBOL; + oper.opr.symbol:=hl; + end + else + begin + oper.InitRef; + oper.opr.ref.symbol:=hl; + end; + end; + + var + expr, + hs : string; + tempreg : tregister; + l : aint; + hl : tasmlabel; + toffset, + tsize : aint; + begin + expr:=''; + repeat + if actasmtoken=AS_DOT then + begin + if expr<>'' then + begin + BuildRecordOffsetSize(expr,toffset,tsize,hs,false); + if (oper.opr.typ<>OPR_NONE) and + (hs<>'') then + Message(asmr_e_wrong_sym_type); + oper.SetSize(tsize,true); + { we have used the size of a field. Reset the typesize of the record } + oper.typesize:=0; + case oper.opr.typ of + OPR_LOCAL : + begin + { don't allow direct access to fields of parameters, because that + will generate buggy code. Allow it only for explicit typecasting + and when the parameter is in a register (delphi compatible) } + if (not oper.hastype) and + (oper.opr.localsym.owner.symtabletype=parasymtable) and + (current_procinfo.procdef.proccalloption<>pocall_register) then + Message(asmr_e_cannot_access_field_directly_for_parameters); + inc(oper.opr.localsymofs,toffset) + end; + OPR_CONSTANT : + inc(oper.opr.val,toffset); + OPR_REFERENCE : + inc(oper.opr.ref.offset,toffset); + OPR_NONE : + begin + if (hs <> '') then + begin + oper.opr.typ:=OPR_SYMBOL; + oper.opr.symbol:=current_asmdata.RefAsmSymbol(hs); + end + else + begin + oper.opr.typ:=OPR_CONSTANT; + oper.opr.val:=toffset; + end; + end; + OPR_REGISTER : + Message(asmr_e_invalid_reference_syntax); + OPR_SYMBOL: + Message(asmr_e_invalid_symbol_ref); + else + internalerror(200309222); + end; + expr:=''; + end + else + begin + { See it as a separator } + Consume(AS_DOT); + end; + end; + + case actasmtoken of + AS_OFFSET, + AS_SIZEOF, + AS_VMTOFFSET, + AS_TYPE, + AS_NOT, + AS_STRING, + AS_PLUS, + AS_MINUS, + AS_LPAREN, + AS_INTNUM : + begin + case oper.opr.typ of + OPR_REFERENCE : + if (actasmtoken=AS_OFFSET) and + (cs_create_pic in current_settings.moduleswitches) then + begin + Consume(AS_OFFSET); + oper.opr.ref.refaddr:=addr_pic; + BuildOperand(oper,false); + end + else + inc(oper.opr.ref.offset,BuildRefConstExpression); + OPR_LOCAL : + inc(oper.opr.localsymofs,BuildConstExpression); + OPR_NONE, + OPR_CONSTANT : + BuildConstantOperand(oper); + else + Message(asmr_e_invalid_operand_type); + end; + end; + + AS_PTR : + begin + if not oper.hastype then + begin + if (oper.opr.typ=OPR_CONSTANT) then + begin + oper.typesize:=oper.opr.val; + { reset constant value of operand } + oper.opr.typ:=OPR_NONE; + oper.opr.val:=0; + end + else + Message(asmr_e_syn_operand); + end; + Consume(AS_PTR); + oper.InitRef; + { if the operand subscripts a record, the typesize will be + rest -> save it here and restore it afterwards } + l:=oper.typesize; + BuildOperand(oper,false); + oper.setsize(l,true); + end; + + AS_ID : { A constant expression, or a Variable ref. } + Begin + { Label or Special symbol reference? } + if actasmpattern[1] = '@' then + Begin + if actasmpattern = '@RESULT' then + Begin + oper.SetupResult; + Consume(AS_ID); + end + else + if (actasmpattern = '@CODE') or (actasmpattern = '@DATA') then + begin + Message(asmr_w_CODE_and_DATA_not_supported); + Consume(AS_ID); + end + else + { Local Label } + begin + CreateLocalLabel(actasmpattern,hl,false); + Consume(AS_ID); + AddLabelOperand(hl); + end; + end + else + { support result for delphi modes } + if (m_objpas in current_settings.modeswitches) and (actasmpattern='RESULT') then + begin + oper.SetUpResult; + Consume(AS_ID); + end + { probably a variable or normal expression } + { or a procedure (such as in CALL ID) } + else + Begin + { is it a constant ? } + if SearchIConstant(actasmpattern,l) then + Begin + case oper.opr.typ of + OPR_REFERENCE : + inc(oper.opr.ref.offset,BuildRefConstExpression); + OPR_LOCAL : + inc(oper.opr.localsymofs,BuildRefConstExpression); + OPR_NONE, + OPR_CONSTANT : + BuildConstantOperand(oper); + else + Message(asmr_e_invalid_operand_type); + end; + end + else + { Check for pascal label } + if SearchLabel(actasmpattern,hl,false) then + begin + Consume(AS_ID); + AddLabelOperand(hl); + end + else + { is it a normal variable ? } + Begin + expr:=actasmpattern; + Consume(AS_ID); + { typecasting? } + if SearchType(expr,l) then + begin + oper.hastype:=true; + oper.typesize:=l; + case actasmtoken of + AS_LPAREN : + begin + { Support Type([Reference]) } + Consume(AS_LPAREN); + BuildOperand(oper,true); + { Delphi also supports Type(Register) and + interprets it the same as Type([Register]). } + if (oper.opr.typ = OPR_REGISTER) then + { This also sets base to the register. } + oper.InitRef; + Consume(AS_RPAREN); + end; + AS_LBRACKET : + begin + { Support Var.Type[Index] } + { Convert @label.Byte[1] to reference } + if oper.opr.typ=OPR_SYMBOL then + oper.initref; + end; + end; + end + else + begin + if not oper.SetupVar(expr,false) then + Begin + { not a variable, check special variables.. } + if expr = 'SELF' then + oper.SetupSelf + else + Message1(sym_e_unknown_id,expr); + expr:=''; + end; + { indexed access to variable? } + if actasmtoken=AS_LBRACKET then + begin + { ... then the operand size is not known anymore } + oper.size:=OS_NO; + BuildReference(oper); + end; + end; + end; + end; + end; + + AS_REGISTER : { Register, a variable reference or a constant reference } + begin + { save the type of register used. } + tempreg:=actasmregister; + Consume(AS_REGISTER); + if actasmtoken = AS_COLON then + Begin + Consume(AS_COLON); + oper.InitRef; + oper.opr.ref.segment:=tempreg; + BuildReference(oper); + end + else + { Simple register } + begin + if (oper.opr.typ <> OPR_NONE) then + Message(asmr_e_syn_operand); + oper.opr.typ:=OPR_REGISTER; + oper.opr.reg:=tempreg; + oper.SetSize(tcgsize2size[reg_cgsize(oper.opr.reg)],true); + end; + end; + + AS_LBRACKET: { a variable reference, register ref. or a constant reference } + Begin + BuildReference(oper); + end; + + AS_SEG : + Begin + Message(asmr_e_seg_not_supported); + Consume(actasmtoken); + end; + + AS_DWORD, + AS_BYTE, + AS_WORD, + AS_TBYTE, + AS_DQWORD, + AS_QWORD : + begin + { Type specifier } + oper.hastype:=true; + oper.typesize:=0; + case actasmtoken of + AS_DWORD : oper.typesize:=4; + AS_WORD : oper.typesize:=2; + AS_BYTE : oper.typesize:=1; + AS_QWORD : oper.typesize:=8; + AS_DQWORD : oper.typesize:=16; + AS_TBYTE : oper.typesize:=10; + else + internalerror(2010061101); + end; + Consume(actasmtoken); + if (actasmtoken=AS_LPAREN) then + begin + { Support "xxx ptr [Reference]" } + { in case the expression subscripts a record, the typesize + is reset, so save the explicit size we set above } + l:=oper.typesize; + Consume(AS_LPAREN); + BuildOperand(oper,true); + Consume(AS_RPAREN); + oper.setsize(l,true); + end; + end; + + AS_SEPARATOR, + AS_END, + AS_COMMA, + AS_COLON: + begin + break; + end; + + AS_RPAREN: + begin + if not istypecast then + begin + Message(asmr_e_syn_operand); + Consume(AS_RPAREN); + end + else + break; + end; + + else + begin + Message(asmr_e_syn_operand); + RecoverConsume(true); + break; + end; + end; + until false; + { End of operand, update size if a typecast is forced } + if (oper.typesize<>0) and + (oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL]) then + oper.SetSize(oper.typesize,true); + end; + + + Procedure tx86intreader.BuildOpCode(instr : tx86instruction); + var + PrefixOp,OverrideOp: tasmop; + operandnum : longint; + is_far_const:boolean; + i:byte; + begin + PrefixOp:=A_None; + OverrideOp:=A_None; + is_far_const:=false; + { prefix seg opcode / prefix opcode } + repeat + if is_prefix(actopcode) then + with instr do + begin + OpOrder:=op_intel; + PrefixOp:=ActOpcode; + opcode:=ActOpcode; + condition:=ActCondition; + opsize:=ActOpsize; + ConcatInstruction(curlist); + consume(AS_OPCODE); + end + else + if is_override(actopcode) then + with instr do + begin + OpOrder:=op_intel; + OverrideOp:=ActOpcode; + opcode:=ActOpcode; + condition:=ActCondition; + opsize:=ActOpsize; + ConcatInstruction(curlist); + consume(AS_OPCODE); + end + else + break; + { allow for newline after prefix or override } + while actasmtoken=AS_SEPARATOR do + consume(AS_SEPARATOR); + until (actasmtoken<>AS_OPCODE); + { opcode } + if (actasmtoken <> AS_OPCODE) then + begin + Message(asmr_e_invalid_or_missing_opcode); + RecoverConsume(false); + exit; + end; + { Fill the instr object with the current state } + with instr do + begin + OpOrder:=op_intel; + Opcode:=ActOpcode; + condition:=ActCondition; + opsize:=ActOpsize; + + { Valid combination of prefix/override and instruction ? } + if (prefixop<>A_NONE) and (NOT CheckPrefix(PrefixOp,actopcode)) then + Message1(asmr_e_invalid_prefix_and_opcode,actasmpattern); + if (overrideop<>A_NONE) and (NOT CheckOverride(OverrideOp,ActOpcode)) then + Message1(asmr_e_invalid_override_and_opcode,actasmpattern); + end; + { pushf/popf/pusha/popa have to default to 16 bit in Intel mode + (Intel manual and Delphi-compatbile) -- setting the opsize for + these instructions doesn't change anything in the internal assember, + so change the opcode } + if (instr.opcode=A_POPF) then + instr.opcode:=A_POPFW + else if (instr.opcode=A_PUSHF) then + instr.opcode:=A_PUSHFW + else if (instr.opcode=A_PUSHA) then + instr.opcode:=A_PUSHAW + else if (instr.opcode=A_POPA) then + instr.opcode:=A_POPAW; + { We are reading operands, so opcode will be an AS_ID } + operandnum:=1; + is_far_const:=false; + Consume(AS_OPCODE); + { Zero operand opcode ? } + if actasmtoken in [AS_SEPARATOR,AS_END] then + begin + operandnum:=0; + exit; + end; + { Read Operands } + repeat + case actasmtoken of + { End of asm operands for this opcode } + AS_END, + AS_SEPARATOR : + break; + + { Operand delimiter } + AS_COMMA : + begin + if operandnum > Max_Operands then + Message(asmr_e_too_many_operands) + else + Inc(operandnum); + Consume(AS_COMMA); + end; + + {Far constant, i.e. jmp $0000:$11111111.} + AS_COLON: + begin + is_far_const:=true; + if operandnum>1 then + message(asmr_e_too_many_operands) + else + inc(operandnum); + consume(AS_COLON); + end; + + { Type specifier } + AS_NEAR, + AS_FAR : + begin + if actasmtoken = AS_NEAR then + begin + Message(asmr_w_near_ignored); + instr.opsize:=S_NEAR; + end + else + begin + Message(asmr_w_far_ignored); + instr.opsize:=S_FAR; + end; + Consume(actasmtoken); + if actasmtoken=AS_PTR then + begin + Consume(AS_PTR); + instr.Operands[operandnum].InitRef; + end; + BuildOperand(instr.Operands[operandnum] as tx86operand,false); + end; + else + BuildOperand(instr.Operands[operandnum] as tx86operand,false); + end; { end case } + until false; + instr.ops:=operandnum; + { Check operands } + for i:=1 to operandnum do + begin + if is_far_const and + (instr.operands[i].opr.typ<>OPR_CONSTANT) then + message(asmr_e_expr_illegal) + else + if instr.operands[i].opr.typ=OPR_NONE then + Message(asmr_e_syntax_error); + end; + { e.g. for "push dword 1", "push word 6" } + if (instr.ops=1) and + (instr.operands[1].typesize<>0) then + instr.operands[1].setsize(instr.operands[1].typesize,false); + end; + + + Procedure tx86intreader.BuildConstant(constsize: byte); + var + asmsymtyp : tasmsymtype; + asmsym, + expr: string; + value : aint; + Begin + Repeat + Case actasmtoken of + AS_STRING: + Begin + { DD and DW cases } + if constsize <> 1 then + Begin + if Not PadZero(actasmpattern,constsize) then + Message(scan_f_string_exceeds_line); + end; + expr:=actasmpattern; + Consume(AS_STRING); + Case actasmtoken of + AS_COMMA: + Consume(AS_COMMA); + AS_END, + AS_SEPARATOR: ; + else + Message(asmr_e_invalid_string_expression); + end; + ConcatString(curlist,expr); + end; + AS_PLUS, + AS_MINUS, + AS_LPAREN, + AS_NOT, + AS_INTNUM, + AS_ID : + Begin + BuildConstSymbolExpression(false,false,false,value,asmsym,asmsymtyp); + if asmsym<>'' then + begin + if constsize<>sizeof(pint) then + Message1(asmr_w_const32bit_for_address,asmsym); + ConcatConstSymbol(curlist,asmsym,asmsymtyp,value) + end + else + ConcatConstant(curlist,value,constsize); + end; + AS_COMMA: + begin + Consume(AS_COMMA); + end; + AS_ALIGN, + AS_DB, + AS_DW, + AS_DD, + AS_DQ, + AS_OPCODE, + AS_END, + AS_SEPARATOR: + break; + else + begin + Message(asmr_e_syn_constant); + RecoverConsume(false); + end + end; + Until false; + end; + + + function tx86intreader.Assemble: tlinkedlist; + Var + hl : tasmlabel; + instr : Tx86Instruction; + Begin + Message1(asmr_d_start_reading,'intel'); + inexpression:=FALSE; + firsttoken:=TRUE; + { sets up all opcode and register tables in uppercase + done in the construtor now + if not _asmsorted then + Begin + SetupTables; + _asmsorted:=TRUE; + end; + } + curlist:=TAsmList.Create; + { setup label linked list } + LocalLabelList:=TLocalLabelList.Create; + { we might need to know which parameters are passed in registers } + current_procinfo.generate_parameter_info; + { start tokenizer } + c:=current_scanner.asmgetcharstart; + gettoken; + { main loop } + repeat + case actasmtoken of + AS_LLABEL: + Begin + if CreateLocalLabel(actasmpattern,hl,true) then + ConcatLabel(curlist,hl); + Consume(AS_LLABEL); + end; + + AS_LABEL: + Begin + if SearchLabel(upper(actasmpattern),hl,true) then + ConcatLabel(curlist,hl) + else + Message1(asmr_e_unknown_label_identifier,actasmpattern); + Consume(AS_LABEL); + end; + + AS_DW : + Begin + inexpression:=true; + Consume(AS_DW); + BuildConstant(2); + inexpression:=false; + end; + + AS_DB : + Begin + inexpression:=true; + Consume(AS_DB); + BuildConstant(1); + inexpression:=false; + end; + + AS_DD : + Begin + inexpression:=true; + Consume(AS_DD); + BuildConstant(4); + inexpression:=false; + end; + +{$ifdef cpu64bitaddr} + AS_DQ: + Begin + inexpression:=true; + Consume(AS_DQ); + BuildConstant(8); + inexpression:=false; + end; +{$endif cpu64bitaddr} + + AS_ALIGN: + Begin + Consume(AS_ALIGN); + ConcatAlign(curlist,BuildConstExpression); + if actasmtoken<>AS_SEPARATOR then + Consume(AS_SEPARATOR); + end; + + AS_OPCODE : + Begin + instr:=Tx86Instruction.Create(Tx86Operand); + BuildOpcode(instr); + with instr do + begin + { We need AT&T style operands } + Swapoperands; + { Must be done with args in ATT order } + CheckNonCommutativeOpcodes; + AddReferenceSizes; + SetInstructionOpsize; + CheckOperandSizes; + ConcatInstruction(curlist); + end; + instr.Free; + end; + + AS_SEPARATOR : + Begin + Consume(AS_SEPARATOR); + end; + + AS_END : + break; { end assembly block } + + else + Begin + Message(asmr_e_syntax_error); + RecoverConsume(false); + end; + end; { end case } + until false; + { Check LocalLabelList } + LocalLabelList.CheckEmitted; + LocalLabelList.Free; + { Return the list in an asmnode } + assemble:=curlist; + Message1(asmr_d_finish_reading,'intel'); + end; + + +end. |