{ Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman Does the parsing for the GAS 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 raatt; {$i fpcdefs.inc} interface uses { common } cutils,cclasses, { global } globtype, { aasm } cpubase,cpuinfo,aasmbase,aasmtai,aasmdata,aasmcpu, { assembler reader } rabase, rasm, rautils, { symtable } symconst, { cg } cgbase; type tasmtoken = ( AS_NONE,AS_LABEL,AS_LLABEL,AS_STRING,AS_INTNUM, AS_REALNUM,AS_COMMA,AS_LPAREN, AS_RPAREN,AS_COLON,AS_DOT,AS_PLUS,AS_MINUS,AS_STAR, AS_SEPARATOR,AS_ID,AS_REGISTER,AS_OPCODE,AS_SLASH,AS_DOLLAR, AS_HASH,AS_LSBRACKET,AS_RSBRACKET,AS_LBRACKET,AS_RBRACKET, AS_EQUAL, {------------------ Assembler directives --------------------} AS_DB,AS_DW,AS_DD,AS_DQ,AS_GLOBAL, AS_ALIGN,AS_BALIGN,AS_P2ALIGN,AS_ASCII, AS_ASCIIZ,AS_LCOMM,AS_COMM,AS_SINGLE,AS_DOUBLE,AS_EXTENDED,AS_CEXTENDED, AS_DATA,AS_TEXT,AS_INIT,AS_FINI,AS_RVA,AS_DC_A, AS_SET,AS_WEAK,AS_SECTION,AS_END, {------------------ Assembler Operators --------------------} AS_TYPE,AS_SIZEOF,AS_VMTOFFSET,AS_MOD,AS_SHL,AS_SHR,AS_NOT,AS_AND,AS_OR,AS_XOR,AS_NOR,AS_AT, AS_RELTYPE, // common token for relocation types {------------------ Target-specific directive ---------------} AS_TARGET_DIRECTIVE ); tasmkeyword = string[10]; const { These tokens should be modified accordingly to the modifications } { in the different enumerations. } firstdirective = AS_DB; lastdirective = AS_END; token2str : array[tasmtoken] of tasmkeyword=( '','Label','LLabel','string','integer', 'float',',','(', ')',':','.','+','-','*', ';','identifier','register','opcode','/','$', '#','{','}','[',']', '=', '.byte','.word','.long','.quad','.globl', '.align','.balign','.p2align','.ascii', '.asciz','.lcomm','.comm','.single','.double','.tfloat','.tcfloat', '.data','.text','.init','.fini','.rva','.dc.a', '.set','.weak','.section','END', 'TYPE','SIZEOF','VMTOFFSET','%','<<','>>','!','&','|','^','~','@','reltype', 'directive'); type tattreader = class(tasmreader) actasmtoken : tasmtoken; prevasmtoken : tasmtoken; procedure SetupTables; procedure BuildConstant(constsize: byte); procedure BuildConstantOperand(oper : toperand); procedure BuildRealConstant(typ : tfloattype); procedure BuildStringConstant(asciiz: boolean); procedure BuildRva; procedure BuildRecordOffsetSize(const expr: string;var offset:tcgint;var size:tcgint; var mangledname: string; needvmtofs: boolean); procedure BuildConstSymbolExpression(allowref,betweenbracket,needofs:boolean;var value:tcgint;var asmsym:string;var asmsymtyp:TAsmsymtype); function BuildConstExpression(allowref,betweenbracket:boolean): tcgint; function Assemble: tlinkedlist;override; procedure handleopcode;virtual;abstract; function is_asmopcode(const s: string) : boolean;virtual;abstract; Function is_asmdirective(const s: string):boolean; function is_register(const s:string):boolean;virtual; function is_locallabel(const s: string):boolean; function is_targetdirective(const s: string): boolean;virtual; procedure GetToken; function consume(t : tasmtoken):boolean; procedure RecoverConsume(allowcomma:boolean); procedure handlepercent;virtual; procedure handledollar;virtual; procedure HandleTargetDirective;virtual; end; implementation uses { globals } verbose,systems, { input } scanner, pbase, { symtable } symbase,symtype,symsym,symdef,symtable, {$ifdef x86} rax86, {$endif x86} itcpugas, procinfo; procedure tattreader.SetupTables; var i : tasmop; Begin iasmops:=TFPHashList.create; for i:=firstop to lastop do iasmops.Add(upper(gas_op2str[i]),Pointer(PtrInt(i))); end; function tattreader.is_asmdirective(const s: string):boolean; var i : tasmtoken; hs : string; Begin { GNU as is also not casesensitive with this } hs:=lower(s); for i:=firstdirective to lastdirective do if hs=token2str[i] then begin actasmtoken:=i; is_asmdirective:=true; exit; end; is_asmdirective:=false; end; function tattreader.is_register(const s:string):boolean; begin is_register:=false; actasmregister:=gas_regnum_search(lower(s)); if actasmregister<>NR_NO then begin is_register:=true; actasmtoken:=AS_REGISTER; end; end; function tattreader.is_locallabel(const s: string):boolean; begin is_locallabel:=(length(s)>=2) and (s[1]='.') and (s[2]='L'); end; procedure tattreader.handledollar; begin c:=current_scanner.asmgetchar; actasmtoken:=AS_DOLLAR; end; procedure tattreader.handlepercent; begin c:=current_scanner.asmgetchar; actasmtoken:=AS_MOD; end; function tattreader.is_targetdirective(const s: string): boolean; begin result:=false; end; procedure tattreader.handletargetdirective; begin end; procedure tattreader.GetToken; var len : longint; srsym : tsym; srsymtable : TSymtable; begin c:=scanner.c; { save old token and reset new token } prevasmtoken:=actasmtoken; actasmtoken:=AS_NONE; { reset } 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; { directive or local label } if c = '.' then begin inc(len); actasmpattern[len]:=c; { Let us point to the next character } c:=current_scanner.asmgetchar; while c in ['A'..'Z','a'..'z','0'..'9','_','$','.'] do begin inc(len); actasmpattern[len]:=c; c:=current_scanner.asmgetchar; end; actasmpattern[0]:=chr(len); { this is a local label... } if (c=':') and is_locallabel(actasmpattern) then Begin { local variables are case sensitive } actasmtoken:=AS_LLABEL; c:=current_scanner.asmgetchar; firsttoken:=true; exit; end { must be a directive } else Begin { directives are case sensitive!! } if is_asmdirective(actasmpattern) then exit; if is_targetdirective(actasmpattern) then begin actasmtoken:=AS_TARGET_DIRECTIVE; exit; end; Message1(asmr_e_not_directive_or_local_symbol,actasmpattern); end; end; { only opcodes and global labels are allowed now. } while c in ['A'..'Z','a'..'z','0'..'9','_'] do begin inc(len); actasmpattern[len]:=c; c:=current_scanner.asmgetchar; end; actasmpattern[0]:=chr(len); { Label ? } if c = ':' then begin actasmtoken:=AS_LABEL; { let us point to the next character } c:=current_scanner.asmgetchar; firsttoken:=true; exit; end; {$if defined(POWERPC) or defined(POWERPC64)} { some PowerPC instructions can have the postfix -, + or . this code could be moved to is_asmopcode but I think it's better to ifdef it here (FK) } case c of '.', '-', '+': begin actasmpattern:=actasmpattern+c; c:=current_scanner.asmgetchar; end end; {$endif POWERPC} {$if defined(ARM)} { Thumb-2 instructions can have a .W postfix to indicate 32bit instructions, Also in unified syntax sizes and types are indicated with something like a .