diff options
author | peter <peter@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2005-10-20 19:20:38 +0000 |
---|---|---|
committer | peter <peter@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2005-10-20 19:20:38 +0000 |
commit | 5ed980d600661e3e77f429a510f093f4a001dee9 (patch) | |
tree | 40d655e7921c1019d039da654a9df550de3cd249 /compiler/raatt.pas | |
parent | 907c764cb881dab769452696fc5e6bee076c2656 (diff) | |
download | fpc-unitrw.tar.gz |
* retag for unitrwunitrw
git-svn-id: http://svn.freepascal.org/svn/fpc/branches/unitrw@1551 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'compiler/raatt.pas')
-rw-r--r-- | compiler/raatt.pas | 1534 |
1 files changed, 1534 insertions, 0 deletions
diff --git a/compiler/raatt.pas b/compiler/raatt.pas new file mode 100644 index 0000000000..2e70b9c04a --- /dev/null +++ b/compiler/raatt.pas @@ -0,0 +1,1534 @@ +{ + 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,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, + {------------------ 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_DATA,AS_TEXT,AS_END, + {------------------ Assembler Operators --------------------} + AS_TYPE,AS_SIZEOF,AS_MOD,AS_SHL,AS_SHR,AS_NOT,AS_AND,AS_OR,AS_XOR,AS_NOR,AS_AT, + AS_LO,AS_HI); + + 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', + '.data','.text','END', + 'TYPE','SIZEOF','%','<<','>>','!','&','|','^','~','@','lo','hi'); + + 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 BuildRecordOffsetSize(const expr: string;var offset:aint;var size:aint); + procedure BuildConstSymbolExpression(allowref,betweenbracket,needofs:boolean;var value:aint;var asmsym:string;var asmsymtyp:TAsmsymtype); + function BuildConstExpression(allowref,betweenbracket:boolean): aint; + 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; + procedure GetToken; + function consume(t : tasmtoken):boolean; + procedure RecoverConsume(allowcomma:boolean); + procedure handlepercent;virtual; + end; + tcattreader = class of tattreader; + + var + cattreader : tcattreader; + + implementation + + uses + { globals } + verbose,systems, + { input } + scanner, + { symtable } + symbase,symtype,symsym,symtable, +{$ifdef x86} + rax86, +{$endif x86} + itcpugas, + procinfo; + + + procedure tattreader.SetupTables; + { creates uppercased symbol tables for speed access } + var + i : tasmop; + str2opentry: tstr2opentry; + Begin + { opcodes } + iasmops:=TDictionary.Create; + iasmops.delete_doubles:=true; + for i:=firstop to lastop do + begin + str2opentry:=tstr2opentry.createname(upper(gas_op2str[i])); + str2opentry.op:=i; + iasmops.insert(str2opentry); + end; + 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.handlepercent; + begin + c:=current_scanner.asmgetchar; + actasmtoken:=AS_MOD; + end; + + + procedure tattreader.GetToken; + var + len : longint; + srsym : tsym; + srsymtable : tsymtable; + begin + { 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 } +{$ifdef arm} + if not (c in [#10,#13,';']) then + current_scanner.gettokenpos; +{$else arm} + if not (c in [#10,#13,'{',';']) then + current_scanner.gettokenpos; +{$endif arm} + + { Local Label, Label, Directive, Prefix or Opcode } +{$ifdef arm} + if firsttoken and not(c in [#10,#13,';']) then +{$else arm} + if firsttoken and not(c in [#10,#13,'{',';']) then +{$endif arm} + 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; + 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; +{$ifdef POWERPC} + { 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} +{$ifdef 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 POWERPC64} + { Opcode ? } + If is_asmopcode(upper(actasmpattern)) then + Begin + uppervar(actasmpattern); + exit; + end; + { End of assemblerblock ? } + if upper(actasmpattern) = 'END' then + begin + actasmtoken:=AS_END; + exit; + end; + message1(asmr_e_unknown_opcode,actasmpattern); + actasmtoken:=AS_NONE; + end + else { else firsttoken } + { Here we must handle all possible cases } + begin + case c of + '.' : { possiblities : - local label reference , such as in jmp @local1 } + { - field of object/record } + { - directive. } + begin + if (prevasmtoken in [AS_ID,AS_RPAREN]) then + begin + c:=current_scanner.asmgetchar; + actasmtoken:=AS_DOT; + exit; + end; + 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; + if is_asmdirective(actasmpattern) then + exit; + { local label references and directives } + { are case sensitive } + actasmtoken:=AS_ID; + exit; + end; + + { identifier, register, prefix or directive } + '_','A'..'Z','a'..'z': + begin + len:=0; + 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); + uppervar(actasmpattern); +{$ifdef x86} + { only x86 architectures have instruction prefixes } + + { Opcode, can only be when the previous was a prefix } + If is_prefix(actopcode) and is_asmopcode(actasmpattern) then + Begin + uppervar(actasmpattern); + exit; + end; +{$endif x86} + { check for end which is a reserved word unlike the opcodes } + if actasmpattern = 'END' then + Begin + actasmtoken:=AS_END; + exit; + end; + if actasmpattern = 'TYPE' then + Begin + actasmtoken:=AS_TYPE; + exit; + end; + if actasmpattern = 'SIZEOF' then + Begin + actasmtoken:=AS_SIZEOF; + exit; + end; + if is_register(actasmpattern) then + begin + actasmtoken:=AS_REGISTER; + exit; + end; + { if next is a '.' and this is a unitsym then we also need to + parse the identifier } + if (c='.') then + begin + searchsym(actasmpattern,srsym,srsymtable); + if assigned(srsym) and + (srsym.typ=unitsym) and + (srsym.owner.symtabletype in [staticsymtable,globalsymtable]) and + srsym.owner.iscurrentunit then + begin + actasmpattern:=actasmpattern+c; + 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; + + '%' : { register or modulo } + handlepercent; + + '1'..'9': { integer number } + begin + len:=0; + while c in ['0'..'9'] do + Begin + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + end; + actasmpattern[0]:=chr(len); + actasmpattern:=tostr(ParseVal(actasmpattern,10)); + actasmtoken:=AS_INTNUM; + exit; + end; + '0' : { octal,hexa,real or binary number. } + begin + actasmpattern:=c; + c:=current_scanner.asmgetchar; + case upcase(c) of + 'B': { binary } + Begin + c:=current_scanner.asmgetchar; + while c in ['0','1'] do + Begin + actasmpattern:=actasmpattern + c; + c:=current_scanner.asmgetchar; + end; + actasmpattern:=tostr(ParseVal(actasmpattern,2)); + actasmtoken:=AS_INTNUM; + exit; + end; + 'D': { real } + Begin + c:=current_scanner.asmgetchar; + { get ridd of the 0d } + if (c in ['+','-']) then + begin + actasmpattern:=c; + c:=current_scanner.asmgetchar; + end + else + actasmpattern:=''; + while c in ['0'..'9'] do + Begin + actasmpattern:=actasmpattern + c; + c:=current_scanner.asmgetchar; + end; + if c='.' then + begin + actasmpattern:=actasmpattern + c; + c:=current_scanner.asmgetchar; + while c in ['0'..'9'] do + Begin + actasmpattern:=actasmpattern + c; + c:=current_scanner.asmgetchar; + end; + if upcase(c) = 'E' then + begin + actasmpattern:=actasmpattern + c; + c:=current_scanner.asmgetchar; + if (c in ['+','-']) then + begin + actasmpattern:=actasmpattern + c; + c:=current_scanner.asmgetchar; + end; + while c in ['0'..'9'] do + Begin + actasmpattern:=actasmpattern + c; + c:=current_scanner.asmgetchar; + end; + end; + actasmtoken:=AS_REALNUM; + exit; + end + else + begin + Message1(asmr_e_invalid_float_const,actasmpattern+c); + actasmtoken:=AS_NONE; + end; + end; + 'X': { hexadecimal } + 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; + '1'..'7': { octal } + begin + actasmpattern:=actasmpattern + c; + while c in ['0'..'7'] do + Begin + actasmpattern:=actasmpattern + c; + c:=current_scanner.asmgetchar; + end; + actasmpattern:=tostr(ParseVal(actasmpattern,8)); + actasmtoken:=AS_INTNUM; + exit; + end; + else { octal number zero value...} + Begin + actasmpattern:=tostr(ParseVal(actasmpattern,8)); + actasmtoken:=AS_INTNUM; + exit; + end; + end; { end case } + end; + + '&' : + begin + c:=current_scanner.asmgetchar; + actasmtoken:=AS_AND; + end; + + '''' : { char } + begin + current_scanner.in_asm_string:=true; + actasmpattern:=''; + repeat + c:=current_scanner.asmgetchar; + case c of + '\' : + begin + { copy also the next char so \" is parsed correctly } + actasmpattern:=actasmpattern+c; + c:=current_scanner.asmgetchar; + actasmpattern:=actasmpattern+c; + end; + '''' : + begin + c:=current_scanner.asmgetchar; + break; + end; + #10,#13: + Message(scan_f_string_exceeds_line); + else + actasmpattern:=actasmpattern+c; + end; + until false; + actasmpattern:=EscapeToPascal(actasmpattern); + actasmtoken:=AS_STRING; + current_scanner.in_asm_string:=false; + exit; + end; + + '"' : { string } + begin + current_scanner.in_asm_string:=true; + actasmpattern:=''; + repeat + c:=current_scanner.asmgetchar; + case c of + '\' : + begin + { copy also the next char so \" is parsed correctly } + actasmpattern:=actasmpattern+c; + c:=current_scanner.asmgetchar; + actasmpattern:=actasmpattern+c; + end; + '"' : + begin + c:=current_scanner.asmgetchar; + break; + end; + #10,#13: + Message(scan_f_string_exceeds_line); + else + actasmpattern:=actasmpattern+c; + end; + until false; + actasmpattern:=EscapeToPascal(actasmpattern); + actasmtoken:=AS_STRING; + current_scanner.in_asm_string:=false; + exit; + end; + + '$' : + begin + actasmtoken:=AS_DOLLAR; + c:=current_scanner.asmgetchar; + exit; + end; + + '#' : + begin + actasmtoken:=AS_HASH; + 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; +{$ifdef arm} + // the arm assembler uses { ... } for register sets + '{' : + begin + actasmtoken:=AS_LSBRACKET; + c:=current_scanner.asmgetchar; + exit; + end; + + '}' : + begin + actasmtoken:=AS_RSBRACKET; + c:=current_scanner.asmgetchar; + exit; + end; +{$endif arm} + + ',' : + begin + actasmtoken:=AS_COMMA; + c:=current_scanner.asmgetchar; + exit; + end; + + '<' : + begin + actasmtoken:=AS_SHL; + c:=current_scanner.asmgetchar; + if c = '<' then + c:=current_scanner.asmgetchar; + exit; + end; + + '>' : + begin + actasmtoken:=AS_SHL; + c:=current_scanner.asmgetchar; + if c = '>' then + c:=current_scanner.asmgetchar; + exit; + end; + + '|' : + begin + actasmtoken:=AS_OR; + c:=current_scanner.asmgetchar; + exit; + end; + + '^' : + begin + actasmtoken:=AS_XOR; + 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_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; + + '!' : + begin + actasmtoken:=AS_NOT; + c:=current_scanner.asmgetchar; + exit; + end; + + '@' : + begin + actasmtoken:=AS_AT; + c:=current_scanner.asmgetchar; + exit; + end; + +{$ifndef arm} + '{', +{$endif arm} + #13,#10,';' : + begin + { the comment is read by asmgetchar } + c:=current_scanner.asmgetchar; + firsttoken:=TRUE; + actasmtoken:=AS_SEPARATOR; + exit; + end; + + else + current_scanner.illegal_char(c); + end; + end; + end; + + + function tattreader.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 tattreader.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; + + + Procedure tattreader.BuildConstant(constsize: byte); + var + asmsymtyp : TAsmSymType; + asmsym, + expr: string; + value : aint; + Begin + Repeat + Case actasmtoken of + AS_STRING: + Begin + expr:=actasmpattern; + if length(expr) > 1 then + Message(asmr_e_string_not_allowed_as_const); + Consume(AS_STRING); + Case actasmtoken of + AS_COMMA: Consume(AS_COMMA); + AS_END, + AS_SEPARATOR: ; + else + Message(asmr_e_invalid_string_expression); + end; { end case } + ConcatString(curlist,expr); + end; + AS_INTNUM, + AS_PLUS, + AS_MINUS, + AS_LPAREN, + AS_TYPE, + AS_SIZEOF, + AS_NOT, + AS_ID : + Begin + BuildConstSymbolExpression(false,false,false,value,asmsym,asmsymtyp); + if asmsym<>'' then + begin + if constsize<>sizeof(aint) then + Message(asmr_w_32bit_const_for_address); + ConcatConstSymbol(curlist,asmsym,asmsymtyp,value) + end + else + ConcatConstant(curlist,value,constsize); + end; + AS_COMMA: + Consume(AS_COMMA); + AS_END, + AS_SEPARATOR: + break; + else + begin + Message(asmr_e_syn_constant); + RecoverConsume(false); + end + end; { end case } + Until false; + end; + + + Procedure tattreader.BuildRealConstant(typ : tfloattype); + var + expr : string; + r : bestreal; + code : integer; + negativ : boolean; + errorflag: boolean; + Begin + errorflag:=FALSE; + Repeat + negativ:=false; + expr:=''; + if actasmtoken=AS_PLUS then + Consume(AS_PLUS) + else + if actasmtoken=AS_MINUS then + begin + negativ:=true; + consume(AS_MINUS); + end; + Case actasmtoken of + AS_INTNUM: + Begin + expr:=actasmpattern; + Consume(AS_INTNUM); + if negativ then + expr:='-'+expr; + val(expr,r,code); + if code<>0 then + Begin + r:=0; + Message(asmr_e_invalid_float_expr); + End; + ConcatRealConstant(curlist,r,typ); + end; + AS_REALNUM: + Begin + expr:=actasmpattern; + Consume(AS_REALNUM); + { in ATT syntax you have 0d in front of the real } + { should this be forced ? yes i think so, as to } + { conform to gas as much as possible. } + if (expr[1]='0') and (upper(expr[2])='D') then + Delete(expr,1,2); + if negativ then + expr:='-'+expr; + val(expr,r,code); + if code<>0 then + Begin + r:=0; + Message(asmr_e_invalid_float_expr); + End; + ConcatRealConstant(curlist,r,typ); + end; + AS_COMMA: + begin + Consume(AS_COMMA); + end; + AS_END, + AS_SEPARATOR: + begin + break; + end; + else + Begin + Consume(actasmtoken); + if not errorflag then + Message(asmr_e_invalid_float_expr); + errorflag:=TRUE; + end; + end; + Until false; + end; + + + Procedure tattreader.BuildStringConstant(asciiz: boolean); + var + expr: string; + errorflag : boolean; + Begin + errorflag:=FALSE; + Repeat + Case actasmtoken of + AS_STRING: + Begin + expr:=actasmpattern; + if asciiz then + expr:=expr+#0; + ConcatPasString(curlist,expr); + Consume(AS_STRING); + end; + AS_COMMA: + begin + Consume(AS_COMMA); + end; + AS_END, + AS_SEPARATOR: + begin + break; + end; + else + Begin + Consume(actasmtoken); + if not errorflag then + Message(asmr_e_invalid_string_expression); + errorflag:=TRUE; + end; + end; + Until false; + end; + + + Function tattreader.Assemble: tlinkedlist; + Var + hl : tasmlabel; + commname : string; + lasTSec : TAsmSectionType; + l1,l2 : longint; + Begin + Message1(asmr_d_start_reading,'GNU AS'); + firsttoken:=TRUE; + { sets up all opcode and register tables in uppercase } + if not _asmsorted then + Begin + SetupTables; + _asmsorted:=TRUE; + end; + curlist:=TAAsmoutput.Create; + lasTSec:=sec_code; + { setup label linked list } + LocalLabelList:=TLocalLabelList.Create; + { 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 + Consume(AS_DW); + BuildConstant(2); + end; + + AS_DATA: + Begin + new_section(curList,sec_data,lower(current_procinfo.procdef.mangledname),0); + lasTSec:=sec_data; + Consume(AS_DATA); + end; + + AS_TEXT: + Begin + new_section(curList,sec_code,lower(current_procinfo.procdef.mangledname),0); + lasTSec:=sec_code; + Consume(AS_TEXT); + end; + + AS_DB: + Begin + Consume(AS_DB); + BuildConstant(1); + end; + + AS_DD: + Begin + Consume(AS_DD); + BuildConstant(4); + end; + + AS_DQ: + Begin + Consume(AS_DQ); +{$ifdef cpu64bit} + BuildConstant(8); +{$else cpu64bit} + BuildRealConstant(s64comp); +{$endif cpu64bit} + end; + + AS_SINGLE: + Begin + Consume(AS_SINGLE); + BuildRealConstant(s32real); + end; + + AS_DOUBLE: + Begin + Consume(AS_DOUBLE); + BuildRealConstant(s64real); + end; + + AS_EXTENDED: + Begin + Consume(AS_EXTENDED); + BuildRealConstant(s80real); + end; + + AS_GLOBAL: + Begin + Consume(AS_GLOBAL); + if actasmtoken=AS_ID then + ConcatPublic(curlist,actasmpattern); + Consume(AS_ID); + if actasmtoken<>AS_SEPARATOR then + Consume(AS_SEPARATOR); + end; + + AS_ALIGN: + Begin + Consume(AS_ALIGN); + l1:=BuildConstExpression(false,false); + if (target_info.system in [system_i386_GO32V2]) then + begin + l2:=1; + if (l1>=0) and (l1<=16) then + while (l1>0) do + begin + l2:=2*l2; + dec(l1); + end; + l1:=l2; + end; + ConcatAlign(curlist,l1); + Message(asmr_n_align_is_target_specific); + if actasmtoken<>AS_SEPARATOR then + Consume(AS_SEPARATOR); + end; + + AS_BALIGN: + Begin + Consume(AS_BALIGN); + ConcatAlign(curlist,BuildConstExpression(false,false)); + if actasmtoken<>AS_SEPARATOR then + Consume(AS_SEPARATOR); + end; + + AS_P2ALIGN: + Begin + Consume(AS_P2ALIGN); + l1:=BuildConstExpression(false,false); + l2:=1; + if (l1>=0) and (l1<=16) then + while (l1>0) do + begin + l2:=2*l2; + dec(l1); + end; + l1:=l2; + ConcatAlign(curlist,l1); + if actasmtoken<>AS_SEPARATOR then + Consume(AS_SEPARATOR); + end; + + AS_ASCIIZ: + Begin + Consume(AS_ASCIIZ); + BuildStringConstant(TRUE); + end; + + AS_ASCII: + Begin + Consume(AS_ASCII); + BuildStringConstant(FALSE); + end; + + AS_LCOMM: + Begin + Consume(AS_LCOMM); + commname:=actasmpattern; + Consume(AS_ID); + Consume(AS_COMMA); + curList.concat(Tai_datablock.Create(commname,BuildConstExpression(false,false))); + if actasmtoken<>AS_SEPARATOR then + Consume(AS_SEPARATOR); + end; + + AS_COMM: + Begin + Consume(AS_COMM); + commname:=actasmpattern; + Consume(AS_ID); + Consume(AS_COMMA); + curList.concat(Tai_datablock.Create_global(commname,BuildConstExpression(false,false))); + if actasmtoken<>AS_SEPARATOR then + Consume(AS_SEPARATOR); + end; + + AS_OPCODE: + Begin + HandleOpCode; + end; + + AS_SEPARATOR: + Begin + Consume(AS_SEPARATOR); + end; + + AS_END: + begin + break; { end assembly block } + end; + + else + Begin + Message(asmr_e_syntax_error); + RecoverConsume(false); + end; + end; + until false; + { Check LocalLabelList } + LocalLabelList.CheckEmitted; + LocalLabelList.Free; + { are we back in the code section? } + if lasTSec<>sec_code then + begin + Message(asmr_w_assembler_code_not_returned_to_text); + new_section(curList,sec_code,lower(current_procinfo.procdef.mangledname),0); + end; + { Return the list in an asmnode } + assemble:=curlist; + Message1(asmr_d_finish_reading,'GNU AS'); + end; + + +{***************************************************************************** + Parsing Helpers +*****************************************************************************} + + Procedure tattreader.BuildRecordOffsetSize(const expr: string;var offset:aint;var size:aint); + { Description: This routine builds up a record offset after a AS_DOT } + { token is encountered. } + { On entry actasmtoken should be equal to AS_DOT } + var + s : string; + Begin + offset:=0; + size:=0; + s:=expr; + while (actasmtoken=AS_DOT) do + begin + Consume(AS_DOT); + if actasmtoken=AS_ID then + s:=s+'.'+actasmpattern; + if not Consume(AS_ID) then + begin + RecoverConsume(true); + break; + end; + end; + if not GetRecordOffsetSize(s,offset,size) then + Message(asmr_e_building_record_offset); + end; + + + procedure tattreader.BuildConstSymbolExpression(allowref,betweenbracket,needofs:boolean;var value:aint;var asmsym:string;var asmsymtyp:TAsmsymtype); + var + hssymtyp : TAsmSymType; + hs,tempstr,expr : string; + parenlevel : longint; + l,k : aint; + errorflag : boolean; + prevtok : tasmtoken; + sym : tsym; + srsymtable : tsymtable; + hl : tasmlabel; + Begin + asmsym:=''; + asmsymtyp:=AT_DATA; + value:=0; + errorflag:=FALSE; + tempstr:=''; + expr:=''; + parenlevel:=0; + Repeat + Case actasmtoken of + AS_LPAREN: + Begin + { Exit if ref? } + if allowref and (prevasmtoken in [AS_INTNUM,AS_ID]) then + break; + Consume(AS_LPAREN); + expr:=expr + '('; + inc(parenlevel); + end; + AS_RBRACKET: + begin + if betweenbracket then + break; + { 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; + AS_RPAREN: + Begin + { end of ref ? } + if (parenlevel=0) and betweenbracket 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); + expr:=expr + '*'; + end; + AS_PLUS: + Begin + Consume(AS_PLUS); + 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_DOLLAR: + begin + Consume(AS_DOLLAR); + if actasmtoken<>AS_ID then + Message(asmr_e_dollar_without_identifier); + 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_SIZEOF, + AS_TYPE: + begin + l:=0; + Consume(actasmtoken); + if actasmtoken<>AS_ID then + Message(asmr_e_type_without_identifier) + else + begin + tempstr:=actasmpattern; + Consume(AS_ID); + if actasmtoken=AS_DOT then + BuildRecordOffsetSize(tempstr,k,l) + else + begin + searchsym(tempstr,sym,srsymtable); + if assigned(sym) then + begin + case sym.typ of + globalvarsym, + localvarsym, + paravarsym : + l:=tabstractvarsym(sym).getsize; + typedconstsym : + l:=ttypedconstsym(sym).getsize; + typesym : + l:=ttypesym(sym).restype.def.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; + end; + AS_ID: + Begin + hs:=''; + hssymtyp:=AT_DATA; + tempstr:=actasmpattern; + prevtok:=prevasmtoken; + 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_LABEL; + end + else + if SearchLabel(tempstr,hl,false) then + begin + hs:=hl.name; + hssymtyp:=AT_FUNCTION; + end + else + begin + searchsym(tempstr,sym,srsymtable); + if assigned(sym) then + begin + case sym.typ of + globalvarsym : + hs:=tglobalvarsym(sym).mangledname; + localvarsym, + paravarsym : + Message(asmr_e_no_local_or_para_allowed); + typedconstsym : + hs:=ttypedconstsym(sym).mangledname; + procsym : + with Tprocsym(sym) do + begin + if procdef_count>1 then + message(asmr_w_calling_overload_func); + hs:=first_procdef.mangledname; + hssymtyp:=AT_FUNCTION; + end; + typesym : + begin + if not(ttypesym(sym).restype.def.deftype in [recorddef,objectdef]) then + Message(asmr_e_wrong_sym_type); + 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 needofs and (prevtok<>AS_DOLLAR) then + Message(asmr_e_need_dollar); + 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 + Message(asmr_e_only_add_relocatable_symbol); + end; + if actasmtoken=AS_DOT then + begin + BuildRecordOffsetSize(tempstr,l,k); + str(l, tempstr); + expr:=expr + tempstr; + end + else + begin + if (expr='') or (expr[length(expr)] in ['+','-','/','*']) then + delete(expr,length(expr),1); + 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_LPAREN,AS_RPAREN,AS_RBRACKET,AS_END]) then + Message(asmr_e_only_add_relocatable_symbol); + end; + AS_END, + AS_SEPARATOR, + AS_COMMA: + 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; + end; + + + function tattreader.BuildConstExpression(allowref,betweenbracket:boolean): aint; + var + l : aint; + hs : string; + hssymtyp : TAsmSymType; + begin + BuildConstSymbolExpression(allowref,betweenbracket,false,l,hs,hssymtyp); + if hs<>'' then + Message(asmr_e_relocatable_symbol_not_allowed); + BuildConstExpression:=l; + end; + + + Procedure tattreader.BuildConstantOperand(oper : toperand); + var + l : aint; + tempstr : string; + tempsymtyp : TAsmSymType; + begin + BuildConstSymbolExpression(false,false,true,l,tempstr,tempsymtyp); + if tempstr<>'' then + begin + oper.opr.typ:=OPR_SYMBOL; + oper.opr.symofs:=l; + oper.opr.symbol:=objectlibrary.newasmsymbol(tempstr,AB_EXTERNAL,tempsymtyp); + end + else + begin + oper.opr.typ:=OPR_CONSTANT; + oper.opr.val:=l; + end; + end; + +end. |