Initial revision
[AROS-Contrib.git] / development / compilers / freepascal / compiler / ra386att.pas
blob3411e712efeb031f78d2ce1cdf9d882f6532f668
2 $Id$
3 Copyright (c) 1998-2000 by Carl Eric Codere and Peter Vreman
5 Does the parsing for the AT&T styled inline assembler.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 ****************************************************************************
23 {$ifdef TP}
24 {$N+,E+}
25 {$endif TP}
26 Unit Ra386att;
27 Interface
29 uses
30 tree;
32 function assemble: ptree;
35 Implementation
37 Uses
38 globtype,
39 strings,cobjects,systems,verbose,globals,
40 files,aasm,types,symconst,symtable,scanner,cpubase,
41 {$ifdef NEWCG}
42 cgbase,
43 {$else}
44 hcodegen,
45 {$endif}
46 rautils,ra386;
48 type
49 tasmtoken = (
50 AS_NONE,AS_LABEL,AS_LLABEL,AS_STRING,AS_INTNUM,
51 AS_REALNUM,AS_COMMA,AS_LPAREN,
52 AS_RPAREN,AS_COLON,AS_DOT,AS_PLUS,AS_MINUS,AS_STAR,
53 AS_SEPARATOR,AS_ID,AS_REGISTER,AS_OPCODE,AS_SLASH,AS_DOLLAR,
54 {------------------ Assembler directives --------------------}
55 AS_DB,AS_DW,AS_DD,AS_DQ,AS_GLOBAL,
56 AS_ALIGN,AS_BALIGN,AS_P2ALIGN,AS_ASCII,
57 AS_ASCIIZ,AS_LCOMM,AS_COMM,AS_SINGLE,AS_DOUBLE,AS_EXTENDED,
58 AS_DATA,AS_TEXT,AS_END,
59 {------------------ Assembler Operators --------------------}
60 AS_TYPE,AS_MOD,AS_SHL,AS_SHR,AS_NOT,AS_AND,AS_OR,AS_XOR,AS_NOR);
62 tasmkeyword = string[10];
64 const
65 { These tokens should be modified accordingly to the modifications }
66 { in the different enumerations. }
67 firstdirective = AS_DB;
68 lastdirective = AS_END;
70 _count_asmprefixes = 5;
71 _count_asmspecialops = 25;
72 _count_asmoverrides = 3;
74 token2str : array[tasmtoken] of tasmkeyword=(
75 '','Label','LLabel','string','integer',
76 'float',',','(',
77 ')',':','.','+','-','*',
78 ';','identifier','register','opcode','/','$',
79 '.byte','.word','.long','.quad','.globl',
80 '.align','.balign','.p2align','.ascii',
81 '.asciz','.lcomm','.comm','.single','.double','.tfloat',
82 '.data','.text','END',
83 'TYPE','%','<<','>>','!','&','|','^','~');
85 const
86 newline = #10;
87 firsttoken : boolean = TRUE;
88 var
89 _asmsorted : boolean;
90 curlist : paasmoutput;
91 c : char;
92 actasmtoken : tasmtoken;
93 prevasmtoken : tasmtoken;
94 actasmpattern : string;
95 actopcode : tasmop;
96 actasmregister : tregister;
97 actopsize : topsize;
98 actcondition : tasmcond;
99 iasmops : Pdictionary;
100 iasmregs : ^reg2strtable;
103 Procedure SetupTables;
104 { creates uppercased symbol tables for speed access }
106 i : tasmop;
107 j : tregister;
108 str2opentry: pstr2opentry;
109 Begin
110 { opcodes }
111 new(iasmops,init);
112 for i:=firstop to lastop do
113 begin
114 new(str2opentry,initname(upper(att_op2str[i])));
115 str2opentry^.op:=i;
116 iasmops^.insert(str2opentry);
117 end;
118 { registers }
119 new(iasmregs);
120 for j:=firstreg to lastreg do
121 iasmregs^[j] := upper(att_reg2str[j]);
122 end;
125 {---------------------------------------------------------------------}
126 { Routines for the tokenizing }
127 {---------------------------------------------------------------------}
129 function is_asmopcode(const s: string):boolean;
130 const
131 { We need first to check the long prefixes, else we get probs
132 with things like movsbl }
133 att_sizesuffixstr : array[0..9] of string[2] = (
134 '','BW','BL','WL','B','W','L','S','Q','T'
136 att_sizesuffix : array[0..9] of topsize = (
137 S_NO,S_BW,S_BL,S_WL,S_B,S_W,S_L,S_FS,S_IQ,S_FX
139 att_sizefpusuffix : array[0..9] of topsize = (
140 S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_FL,S_FS,S_IQ,S_FX
142 att_sizefpuintsuffix : array[0..9] of topsize = (
143 S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_IL,S_IS,S_IQ,S_NO
146 str2opentry: pstr2opentry;
147 cond : string[4];
148 cnd : tasmcond;
149 len,
151 sufidx : longint;
152 Begin
153 is_asmopcode:=FALSE;
155 actopcode:=A_None;
156 actcondition:=C_None;
157 actopsize:=S_NO;
159 { search for all possible suffixes }
160 for sufidx:=low(att_sizesuffixstr) to high(att_sizesuffixstr) do
161 begin
162 len:=length(s)-length(att_sizesuffixstr[sufidx]);
163 if copy(s,len+1,length(att_sizesuffixstr[sufidx]))=att_sizesuffixstr[sufidx] then
164 begin
165 { here we search the entire table... }
166 str2opentry:=nil;
167 if {(length(s)>0) and} (len>0) then
168 str2opentry:=pstr2opentry(iasmops^.search(copy(s,1,len)));
169 if assigned(str2opentry) then
170 begin
171 actopcode:=str2opentry^.op;
172 if att_needsuffix[actopcode]=attsufFPU then
173 actopsize:=att_sizefpusuffix[sufidx]
174 else if att_needsuffix[actopcode]=attsufFPUint then
175 actopsize:=att_sizefpuintsuffix[sufidx]
176 else
177 actopsize:=att_sizesuffix[sufidx];
178 actasmtoken:=AS_OPCODE;
179 is_asmopcode:=TRUE;
180 exit;
181 end;
182 { not found, check condition opcodes }
183 j:=0;
184 while (j<CondAsmOps) do
185 begin
186 if Copy(s,1,Length(CondAsmOpStr[j]))=CondAsmOpStr[j] then
187 begin
188 cond:=Copy(s,Length(CondAsmOpStr[j])+1,len-Length(CondAsmOpStr[j]));
189 if cond<>'' then
190 begin
191 for cnd:=low(TasmCond) to high(TasmCond) do
192 if Cond=Upper(cond2str[cnd]) then
193 begin
194 actopcode:=CondASmOp[j];
195 if att_needsuffix[actopcode]=attsufFPU then
196 actopsize:=att_sizefpusuffix[sufidx]
197 else if att_needsuffix[actopcode]=attsufFPUint then
198 actopsize:=att_sizefpuintsuffix[sufidx]
199 else
200 actopsize:=att_sizesuffix[sufidx];
201 actcondition:=cnd;
202 actasmtoken:=AS_OPCODE;
203 is_asmopcode:=TRUE;
204 exit;
205 end;
206 end;
207 end;
208 inc(j);
209 end;
210 end;
211 end;
212 end;
215 Function is_asmdirective(const s: string):boolean;
217 i : tasmtoken;
218 hs : string;
219 Begin
220 { GNU as is also not casesensitive with this }
221 hs:=lower(s);
222 for i:=firstdirective to lastdirective do
223 if hs=token2str[i] then
224 begin
225 actasmtoken:=i;
226 is_asmdirective:=true;
227 exit;
228 end;
229 is_asmdirective:=false;
230 end;
233 Function is_register(const s: string):boolean;
235 i : tregister;
236 Begin
237 actasmregister:=R_NO;
238 for i:=firstreg to lastreg do
239 if s=iasmregs^[i] then
240 begin
241 actasmtoken:=AS_REGISTER;
242 actasmregister:=i;
243 is_register:=true;
244 exit;
245 end;
246 is_register:=false;
247 end;
250 Function is_locallabel(const s: string):boolean;
251 begin
252 is_locallabel:=(length(s)>=2) and (s[1]='.') and (s[2]='L');
253 end;
256 Procedure GetToken;
258 len : longint;
259 begin
260 { save old token and reset new token }
261 prevasmtoken:=actasmtoken;
262 actasmtoken:=AS_NONE;
263 { reset }
264 actasmpattern:='';
265 { while space and tab , continue scan... }
266 while c in [' ',#9] do
267 c:=current_scanner^.asmgetchar;
268 { get token pos }
269 if not (c in [newline,#13,'{',';']) then
270 current_scanner^.gettokenpos;
271 { Local Label, Label, Directive, Prefix or Opcode }
272 if firsttoken and not(c in [newline,#13,'{',';']) then
273 begin
274 firsttoken:=FALSE;
275 len:=0;
276 { directive or local label }
277 if c = '.' then
278 begin
279 inc(len);
280 actasmpattern[len]:=c;
281 { Let us point to the next character }
282 c:=current_scanner^.asmgetchar;
283 while c in ['A'..'Z','a'..'z','0'..'9','_','$'] do
284 begin
285 inc(len);
286 actasmpattern[len]:=c;
287 c:=current_scanner^.asmgetchar;
288 end;
289 actasmpattern[0]:=chr(len);
290 { this is a local label... }
291 if (c=':') and is_locallabel(actasmpattern) then
292 Begin
293 { local variables are case sensitive }
294 actasmtoken:=AS_LLABEL;
295 c:=current_scanner^.asmgetchar;
296 firsttoken:=true;
297 exit;
299 { must be a directive }
300 else
301 Begin
302 { directives are case sensitive!! }
303 if is_asmdirective(actasmpattern) then
304 exit;
305 Message1(asmr_e_not_directive_or_local_symbol,actasmpattern);
306 end;
307 end;
308 { only opcodes and global labels are allowed now. }
309 while c in ['A'..'Z','a'..'z','0'..'9','_'] do
310 begin
311 inc(len);
312 actasmpattern[len]:=c;
313 c:=current_scanner^.asmgetchar;
314 end;
315 actasmpattern[0]:=chr(len);
316 { Label ? }
317 if c = ':' then
318 begin
319 actasmtoken:=AS_LABEL;
320 { let us point to the next character }
321 c:=current_scanner^.asmgetchar;
322 firsttoken:=true;
323 exit;
324 end;
325 { Opcode ? }
326 If is_asmopcode(upper(actasmpattern)) then
327 Begin
328 uppervar(actasmpattern);
329 exit;
330 end;
331 { End of assemblerblock ? }
332 if upper(actasmpattern) = 'END' then
333 begin
334 actasmtoken:=AS_END;
335 exit;
336 end;
337 message1(asmr_e_unknown_opcode,actasmpattern);
338 actasmtoken:=AS_NONE;
340 else { else firsttoken }
341 { Here we must handle all possible cases }
342 begin
343 case c of
344 '.' : { possiblities : - local label reference , such as in jmp @local1 }
345 { - field of object/record }
346 { - directive. }
347 begin
348 if (prevasmtoken in [AS_ID,AS_RPAREN]) then
349 begin
350 c:=current_scanner^.asmgetchar;
351 actasmtoken:=AS_DOT;
352 exit;
353 end;
354 actasmpattern:=c;
355 c:=current_scanner^.asmgetchar;
356 while c in ['A'..'Z','a'..'z','0'..'9','_','$'] do
357 begin
358 actasmpattern:=actasmpattern + c;
359 c:=current_scanner^.asmgetchar;
360 end;
361 if is_asmdirective(actasmpattern) then
362 exit;
363 { local label references and directives }
364 { are case sensitive }
365 actasmtoken:=AS_ID;
366 exit;
367 end;
369 { identifier, register, prefix or directive }
370 '_','A'..'Z','a'..'z':
371 begin
372 len:=0;
373 while c in ['A'..'Z','a'..'z','0'..'9','_','$'] do
374 begin
375 inc(len);
376 actasmpattern[len]:=c;
377 c:=current_scanner^.asmgetchar;
378 end;
379 actasmpattern[0]:=chr(len);
380 uppervar(actasmpattern);
381 { Opcode, can only be when the previous was a prefix }
382 If is_prefix(actopcode) and is_asmopcode(upper(actasmpattern)) then
383 Begin
384 uppervar(actasmpattern);
385 exit;
386 end;
387 { check for end which is a reserved word unlike the opcodes }
388 if actasmpattern = 'END' then
389 Begin
390 actasmtoken:=AS_END;
391 exit;
392 end;
393 if actasmpattern = 'TYPE' then
394 Begin
395 actasmtoken:=AS_TYPE;
396 exit;
397 end;
398 actasmtoken:=AS_ID;
399 exit;
400 end;
402 '%' : { register or modulo }
403 begin
404 len:=1;
405 actasmpattern[len]:='%';
406 c:=current_scanner^.asmgetchar;
407 { to be a register there must be a letter and not a number }
408 if c in ['0'..'9'] then
409 begin
410 actasmtoken:=AS_MOD;
411 {Message(asmr_w_modulo_not_supported);}
413 else
414 begin
415 while c in ['a'..'z','A'..'Z','0'..'9'] do
416 Begin
417 inc(len);
418 actasmpattern[len]:=c;
419 c:=current_scanner^.asmgetchar;
420 end;
421 actasmpattern[0]:=chr(len);
422 uppervar(actasmpattern);
423 if (actasmpattern = '%ST') and (c='(') then
424 Begin
425 actasmpattern:=actasmpattern+c;
426 c:=current_scanner^.asmgetchar;
427 if c in ['0'..'9'] then
428 actasmpattern:=actasmpattern + c
429 else
430 Message(asmr_e_invalid_fpu_register);
431 c:=current_scanner^.asmgetchar;
432 if c <> ')' then
433 Message(asmr_e_invalid_fpu_register)
434 else
435 Begin
436 actasmpattern:=actasmpattern + c;
437 c:=current_scanner^.asmgetchar; { let us point to next character. }
438 end;
439 end;
440 if is_register(actasmpattern) then
441 exit;
442 Message(asmr_e_invalid_register);
443 actasmtoken:=AS_NONE;
444 end;
445 end;
447 '1'..'9': { integer number }
448 begin
449 len:=0;
450 while c in ['0'..'9'] do
451 Begin
452 inc(len);
453 actasmpattern[len]:=c;
454 c:=current_scanner^.asmgetchar;
455 end;
456 actasmpattern[0]:=chr(len);
457 actasmpattern:=tostr(ValDecimal(actasmpattern));
458 actasmtoken:=AS_INTNUM;
459 exit;
460 end;
461 '0' : { octal,hexa,real or binary number. }
462 begin
463 actasmpattern:=c;
464 c:=current_scanner^.asmgetchar;
465 case upcase(c) of
466 'B': { binary }
467 Begin
468 c:=current_scanner^.asmgetchar;
469 while c in ['0','1'] do
470 Begin
471 actasmpattern:=actasmpattern + c;
472 c:=current_scanner^.asmgetchar;
473 end;
474 actasmpattern:=tostr(ValBinary(actasmpattern));
475 actasmtoken:=AS_INTNUM;
476 exit;
477 end;
478 'D': { real }
479 Begin
480 c:=current_scanner^.asmgetchar;
481 { get ridd of the 0d }
482 if (c in ['+','-']) then
483 begin
484 actasmpattern:=c;
485 c:=current_scanner^.asmgetchar;
487 else
488 actasmpattern:='';
489 while c in ['0'..'9'] do
490 Begin
491 actasmpattern:=actasmpattern + c;
492 c:=current_scanner^.asmgetchar;
493 end;
494 if c='.' then
495 begin
496 actasmpattern:=actasmpattern + c;
497 c:=current_scanner^.asmgetchar;
498 while c in ['0'..'9'] do
499 Begin
500 actasmpattern:=actasmpattern + c;
501 c:=current_scanner^.asmgetchar;
502 end;
503 if upcase(c) = 'E' then
504 begin
505 actasmpattern:=actasmpattern + c;
506 c:=current_scanner^.asmgetchar;
507 if (c in ['+','-']) then
508 begin
509 actasmpattern:=actasmpattern + c;
510 c:=current_scanner^.asmgetchar;
511 end;
512 while c in ['0'..'9'] do
513 Begin
514 actasmpattern:=actasmpattern + c;
515 c:=current_scanner^.asmgetchar;
516 end;
517 end;
518 actasmtoken:=AS_REALNUM;
519 exit;
521 else
522 begin
523 Message1(asmr_e_invalid_float_const,actasmpattern+c);
524 actasmtoken:=AS_NONE;
525 end;
526 end;
527 'X': { hexadecimal }
528 Begin
529 c:=current_scanner^.asmgetchar;
530 while c in ['0'..'9','a'..'f','A'..'F'] do
531 Begin
532 actasmpattern:=actasmpattern + c;
533 c:=current_scanner^.asmgetchar;
534 end;
535 actasmpattern:=tostr(ValHexaDecimal(actasmpattern));
536 actasmtoken:=AS_INTNUM;
537 exit;
538 end;
539 '1'..'7': { octal }
540 begin
541 actasmpattern:=actasmpattern + c;
542 while c in ['0'..'7'] do
543 Begin
544 actasmpattern:=actasmpattern + c;
545 c:=current_scanner^.asmgetchar;
546 end;
547 actasmpattern:=tostr(ValOctal(actasmpattern));
548 actasmtoken:=AS_INTNUM;
549 exit;
550 end;
551 else { octal number zero value...}
552 Begin
553 actasmpattern:=tostr(ValOctal(actasmpattern));
554 actasmtoken:=AS_INTNUM;
555 exit;
556 end;
557 end; { end case }
558 end;
560 '&' :
561 begin
562 c:=current_scanner^.asmgetchar;
563 actasmtoken:=AS_AND;
564 end;
566 '''' : { char }
567 begin
568 current_scanner^.in_asm_string:=true;
569 actasmpattern:='';
570 repeat
571 c:=current_scanner^.asmgetchar;
572 case c of
573 '\' :
574 begin
575 { copy also the next char so \" is parsed correctly }
576 actasmpattern:=actasmpattern+c;
577 c:=current_scanner^.asmgetchar;
578 actasmpattern:=actasmpattern+c;
579 end;
580 '''' :
581 begin
582 c:=current_scanner^.asmgetchar;
583 break;
584 end;
585 newline:
586 Message(scan_f_string_exceeds_line);
587 else
588 actasmpattern:=actasmpattern+c;
589 end;
590 until false;
591 actasmpattern:=EscapeToPascal(actasmpattern);
592 actasmtoken:=AS_STRING;
593 current_scanner^.in_asm_string:=false;
594 exit;
595 end;
597 '"' : { string }
598 begin
599 current_scanner^.in_asm_string:=true;
600 actasmpattern:='';
601 repeat
602 c:=current_scanner^.asmgetchar;
603 case c of
604 '\' :
605 begin
606 { copy also the next char so \" is parsed correctly }
607 actasmpattern:=actasmpattern+c;
608 c:=current_scanner^.asmgetchar;
609 actasmpattern:=actasmpattern+c;
610 end;
611 '"' :
612 begin
613 c:=current_scanner^.asmgetchar;
614 break;
615 end;
616 newline:
617 Message(scan_f_string_exceeds_line);
618 else
619 actasmpattern:=actasmpattern+c;
620 end;
621 until false;
622 actasmpattern:=EscapeToPascal(actasmpattern);
623 actasmtoken:=AS_STRING;
624 current_scanner^.in_asm_string:=false;
625 exit;
626 end;
628 '$' :
629 begin
630 actasmtoken:=AS_DOLLAR;
631 c:=current_scanner^.asmgetchar;
632 exit;
633 end;
635 ',' :
636 begin
637 actasmtoken:=AS_COMMA;
638 c:=current_scanner^.asmgetchar;
639 exit;
640 end;
642 '<' :
643 begin
644 actasmtoken:=AS_SHL;
645 c:=current_scanner^.asmgetchar;
646 if c = '<' then
647 c:=current_scanner^.asmgetchar;
648 exit;
649 end;
651 '>' :
652 begin
653 actasmtoken:=AS_SHL;
654 c:=current_scanner^.asmgetchar;
655 if c = '>' then
656 c:=current_scanner^.asmgetchar;
657 exit;
658 end;
660 '|' :
661 begin
662 actasmtoken:=AS_OR;
663 c:=current_scanner^.asmgetchar;
664 exit;
665 end;
667 '^' :
668 begin
669 actasmtoken:=AS_XOR;
670 c:=current_scanner^.asmgetchar;
671 exit;
672 end;
674 '!' :
675 begin
676 Message(asmr_e_nor_not_supported);
677 c:=current_scanner^.asmgetchar;
678 actasmtoken:=AS_NONE;
679 exit;
680 end;
682 '(' :
683 begin
684 actasmtoken:=AS_LPAREN;
685 c:=current_scanner^.asmgetchar;
686 exit;
687 end;
689 ')' :
690 begin
691 actasmtoken:=AS_RPAREN;
692 c:=current_scanner^.asmgetchar;
693 exit;
694 end;
696 ':' :
697 begin
698 actasmtoken:=AS_COLON;
699 c:=current_scanner^.asmgetchar;
700 exit;
701 end;
703 '+' :
704 begin
705 actasmtoken:=AS_PLUS;
706 c:=current_scanner^.asmgetchar;
707 exit;
708 end;
710 '-' :
711 begin
712 actasmtoken:=AS_MINUS;
713 c:=current_scanner^.asmgetchar;
714 exit;
715 end;
717 '*' :
718 begin
719 actasmtoken:=AS_STAR;
720 c:=current_scanner^.asmgetchar;
721 exit;
722 end;
724 '/' :
725 begin
726 c:=current_scanner^.asmgetchar;
727 actasmtoken:=AS_SLASH;
728 exit;
729 end;
731 '{',#13,newline,';' :
732 begin
733 { the comment is read by asmgetchar }
734 c:=current_scanner^.asmgetchar;
735 firsttoken:=TRUE;
736 actasmtoken:=AS_SEPARATOR;
737 exit;
738 end;
740 else
741 current_scanner^.illegal_char(c);
742 end;
743 end;
744 end;
747 function consume(t : tasmtoken):boolean;
748 begin
749 Consume:=true;
750 if t<>actasmtoken then
751 begin
752 Message2(scan_f_syn_expected,token2str[t],token2str[actasmtoken]);
753 Consume:=false;
754 end;
755 repeat
756 gettoken;
757 until actasmtoken<>AS_NONE;
758 end;
761 procedure RecoverConsume(allowcomma:boolean);
762 begin
763 While not (actasmtoken in [AS_SEPARATOR,AS_END]) do
764 begin
765 if allowcomma and (actasmtoken=AS_COMMA) then
766 break;
767 Consume(actasmtoken);
768 end;
769 end;
772 {*****************************************************************************
773 Parsing Helpers
774 *****************************************************************************}
776 Procedure BuildRecordOffsetSize(const expr: string;var offset:longint;var size:longint);
777 { Description: This routine builds up a record offset after a AS_DOT }
778 { token is encountered. }
779 { On entry actasmtoken should be equal to AS_DOT }
781 s : string;
782 Begin
783 offset:=0;
784 size:=0;
785 s:=expr;
786 while (actasmtoken=AS_DOT) do
787 begin
788 Consume(AS_DOT);
789 if actasmtoken=AS_ID then
790 s:=s+'.'+actasmpattern;
791 if not Consume(AS_ID) then
792 begin
793 RecoverConsume(true);
794 break;
795 end;
796 end;
797 if not GetRecordOffsetSize(s,offset,size) then
798 Message(asmr_e_building_record_offset);
799 end;
802 Procedure BuildConstSymbolExpression(allowref,betweenbracket,needofs:boolean;var value:longint;var asmsym:string);
804 hs,tempstr,expr : string;
805 parenlevel,l,k : longint;
806 errorflag : boolean;
807 prevtok : tasmtoken;
808 sym : psym;
809 hl : PAsmLabel;
810 Begin
811 asmsym:='';
812 value:=0;
813 errorflag:=FALSE;
814 tempstr:='';
815 expr:='';
816 parenlevel:=0;
817 Repeat
818 Case actasmtoken of
819 AS_LPAREN:
820 Begin
821 { Exit if ref? }
822 if allowref and (prevasmtoken in [AS_INTNUM,AS_ID]) then
823 break;
824 Consume(AS_LPAREN);
825 expr:=expr + '(';
826 inc(parenlevel);
827 end;
828 AS_RPAREN:
829 Begin
830 { end of ref ? }
831 if (parenlevel=0) and betweenbracket then
832 break;
833 Consume(AS_RPAREN);
834 expr:=expr + ')';
835 dec(parenlevel);
836 end;
837 AS_SHL:
838 Begin
839 Consume(AS_SHL);
840 expr:=expr + '<';
841 end;
842 AS_SHR:
843 Begin
844 Consume(AS_SHR);
845 expr:=expr + '>';
846 end;
847 AS_SLASH:
848 Begin
849 Consume(AS_SLASH);
850 expr:=expr + '/';
851 end;
852 AS_MOD:
853 Begin
854 Consume(AS_MOD);
855 expr:=expr + '%';
856 end;
857 AS_STAR:
858 Begin
859 Consume(AS_STAR);
860 expr:=expr + '*';
861 end;
862 AS_PLUS:
863 Begin
864 Consume(AS_PLUS);
865 expr:=expr + '+';
866 end;
867 AS_MINUS:
868 Begin
869 Consume(AS_MINUS);
870 expr:=expr + '-';
871 end;
872 AS_AND:
873 Begin
874 Consume(AS_AND);
875 expr:=expr + '&';
876 end;
877 AS_NOT:
878 Begin
879 Consume(AS_NOT);
880 expr:=expr + '~';
881 end;
882 AS_XOR:
883 Begin
884 Consume(AS_XOR);
885 expr:=expr + '^';
886 end;
887 AS_OR:
888 Begin
889 Consume(AS_OR);
890 expr:=expr + '|';
891 end;
892 AS_INTNUM:
893 Begin
894 expr:=expr + actasmpattern;
895 Consume(AS_INTNUM);
896 end;
897 AS_DOLLAR:
898 begin
899 Consume(AS_DOLLAR);
900 if actasmtoken<>AS_ID then
901 Message(asmr_e_dollar_without_identifier);
902 end;
903 AS_STRING:
904 Begin
905 l:=0;
906 case Length(actasmpattern) of
908 l:=ord(actasmpattern[1]);
910 l:=ord(actasmpattern[2]) + ord(actasmpattern[1]) shl 8;
912 l:=ord(actasmpattern[3]) +
913 Ord(actasmpattern[2]) shl 8 + ord(actasmpattern[1]) shl 16;
915 l:=ord(actasmpattern[4]) + ord(actasmpattern[3]) shl 8 +
916 Ord(actasmpattern[2]) shl 16 + ord(actasmpattern[1]) shl 24;
917 else
918 Message1(asmr_e_invalid_string_as_opcode_operand,actasmpattern);
919 end;
920 str(l, tempstr);
921 expr:=expr + tempstr;
922 Consume(AS_STRING);
923 end;
924 AS_TYPE:
925 begin
926 l:=0;
927 Consume(AS_TYPE);
928 if actasmtoken<>AS_ID then
929 Message(asmr_e_type_without_identifier)
930 else
931 begin
932 tempstr:=actasmpattern;
933 Consume(AS_ID);
934 if actasmtoken=AS_DOT then
935 BuildRecordOffsetSize(tempstr,k,l)
936 else
937 begin
938 getsym(tempstr,false);
939 if assigned(srsym) then
940 begin
941 case srsym^.typ of
942 varsym :
943 l:=pvarsym(srsym)^.getsize;
944 typedconstsym :
945 l:=ptypedconstsym(srsym)^.getsize;
946 typesym :
947 l:=ptypesym(srsym)^.restype.def^.size;
948 else
949 Message(asmr_e_wrong_sym_type);
950 end;
952 else
953 Message1(sym_e_unknown_id,tempstr);
954 end;
955 end;
956 str(l, tempstr);
957 expr:=expr + tempstr;
958 end;
959 AS_ID:
960 Begin
961 hs:='';
962 tempstr:=actasmpattern;
963 prevtok:=prevasmtoken;
964 consume(AS_ID);
965 if SearchIConstant(tempstr,l) then
966 begin
967 str(l, tempstr);
968 expr:=expr + tempstr;
970 else
971 begin
972 if is_locallabel(tempstr) then
973 begin
974 CreateLocalLabel(tempstr,hl,false);
975 hs:=hl^.name
977 else
978 if SearchLabel(tempstr,hl,false) then
979 hs:=hl^.name
980 else
981 begin
982 getsym(tempstr,false);
983 sym:=srsym;
984 if assigned(sym) then
985 begin
986 case srsym^.typ of
987 varsym :
988 begin
989 if sym^.owner^.symtabletype in [localsymtable,parasymtable] then
990 Message(asmr_e_no_local_or_para_allowed);
991 hs:=pvarsym(srsym)^.mangledname;
992 end;
993 typedconstsym :
994 hs:=ptypedconstsym(srsym)^.mangledname;
995 procsym :
996 hs:=pprocsym(srsym)^.mangledname;
997 typesym :
998 begin
999 if not(ptypesym(srsym)^.restype.def^.deftype in [recorddef,objectdef]) then
1000 Message(asmr_e_wrong_sym_type);
1001 end;
1002 else
1003 Message(asmr_e_wrong_sym_type);
1004 end;
1006 else
1007 Message1(sym_e_unknown_id,tempstr);
1008 end;
1009 { symbol found? }
1010 if hs<>'' then
1011 begin
1012 if needofs and (prevtok<>AS_DOLLAR) then
1013 Message(asmr_e_need_dollar);
1014 if asmsym='' then
1015 asmsym:=hs
1016 else
1017 Message(asmr_e_cant_have_multiple_relocatable_symbols);
1018 if (expr='') or (expr[length(expr)]='+') then
1019 begin
1020 { don't remove the + if there could be a record field }
1021 if actasmtoken<>AS_DOT then
1022 delete(expr,length(expr),1);
1024 else
1025 Message(asmr_e_only_add_relocatable_symbol);
1026 end;
1027 if actasmtoken=AS_DOT then
1028 begin
1029 BuildRecordOffsetSize(tempstr,l,k);
1030 str(l, tempstr);
1031 expr:=expr + tempstr;
1033 else
1034 begin
1035 if (expr='') or (expr[length(expr)] in ['+','-','/','*']) then
1036 delete(expr,length(expr),1);
1037 end;
1038 end;
1039 { check if there are wrong operator used like / or mod etc. }
1040 if (hs<>'') and not(actasmtoken in [AS_MINUS,AS_PLUS,AS_COMMA,AS_SEPARATOR,AS_LPAREN,AS_END]) then
1041 Message(asmr_e_only_add_relocatable_symbol);
1042 end;
1043 AS_END,
1044 AS_SEPARATOR,
1045 AS_COMMA:
1046 Begin
1047 break;
1048 end;
1049 else
1050 Begin
1051 { write error only once. }
1052 if not errorflag then
1053 Message(asmr_e_invalid_constant_expression);
1054 { consume tokens until we find COMMA or SEPARATOR }
1055 Consume(actasmtoken);
1056 errorflag:=TRUE;
1057 end;
1058 end;
1059 Until false;
1060 { calculate expression }
1061 if not ErrorFlag then
1062 value:=CalculateExpression(expr)
1063 else
1064 value:=0;
1065 end;
1068 Function BuildConstExpression(allowref,betweenbracket:boolean): longint;
1070 l : longint;
1071 hs : string;
1072 begin
1073 BuildConstSymbolExpression(allowref,betweenbracket,false,l,hs);
1074 if hs<>'' then
1075 Message(asmr_e_relocatable_symbol_not_allowed);
1076 BuildConstExpression:=l;
1077 end;
1080 {****************************************************************************
1081 T386ATTOperand
1082 ****************************************************************************}
1084 type
1085 P386ATTOperand=^T386ATTOperand;
1086 T386ATTOperand=object(T386Operand)
1087 Procedure BuildOperand;virtual;
1088 private
1089 Procedure BuildReference;
1090 Procedure BuildConstant;
1091 end;
1094 Procedure T386ATTOperand.BuildReference;
1096 procedure Consume_RParen;
1097 begin
1098 if actasmtoken <> AS_RPAREN then
1099 Begin
1100 Message(asmr_e_invalid_reference_syntax);
1101 RecoverConsume(true);
1103 else
1104 begin
1105 Consume(AS_RPAREN);
1106 if not (actasmtoken in [AS_COMMA,AS_SEPARATOR,AS_END]) then
1107 Begin
1108 Message(asmr_e_invalid_reference_syntax);
1109 RecoverConsume(true);
1110 end;
1111 end;
1112 end;
1114 procedure Consume_Scale;
1116 l : longint;
1117 begin
1118 { we have to process the scaling }
1119 l:=BuildConstExpression(false,true);
1120 if ((l = 2) or (l = 4) or (l = 8) or (l = 1)) then
1121 opr.ref.scalefactor:=l
1122 else
1123 Begin
1124 Message(asmr_e_wrong_scale_factor);
1125 opr.ref.scalefactor:=0;
1126 end;
1127 end;
1129 Begin
1130 Consume(AS_LPAREN);
1131 Case actasmtoken of
1132 AS_INTNUM,
1133 AS_MINUS,
1134 AS_PLUS: { absolute offset, such as fs:(0x046c) }
1135 Begin
1136 { offset(offset) is invalid }
1137 If opr.Ref.Offset <> 0 Then
1138 Begin
1139 Message(asmr_e_invalid_reference_syntax);
1140 RecoverConsume(true);
1142 Else
1143 Begin
1144 opr.Ref.Offset:=BuildConstExpression(false,true);
1145 Consume_RParen;
1146 end;
1147 exit;
1148 End;
1149 AS_REGISTER: { (reg ... }
1150 Begin
1151 { Check if there is already a base (mostly ebp,esp) than this is
1152 not allowed,becuase it will give crashing code }
1153 if opr.ref.base<>R_NO then
1154 Message(asmr_e_cannot_index_relative_var);
1155 opr.ref.base:=actasmregister;
1156 Consume(AS_REGISTER);
1157 { can either be a register or a right parenthesis }
1158 { (reg) }
1159 if actasmtoken=AS_RPAREN then
1160 Begin
1161 Consume_RParen;
1162 exit;
1163 end;
1164 { (reg,reg .. }
1165 Consume(AS_COMMA);
1166 if actasmtoken=AS_REGISTER then
1167 Begin
1168 opr.ref.index:=actasmregister;
1169 Consume(AS_REGISTER);
1170 { check for scaling ... }
1171 case actasmtoken of
1172 AS_RPAREN:
1173 Begin
1174 Consume_RParen;
1175 exit;
1176 end;
1177 AS_COMMA:
1178 Begin
1179 Consume(AS_COMMA);
1180 Consume_Scale;
1181 Consume_RParen;
1182 end;
1183 else
1184 Begin
1185 Message(asmr_e_invalid_reference_syntax);
1186 RecoverConsume(false);
1187 end;
1188 end; { end case }
1190 else
1191 Begin
1192 Message(asmr_e_invalid_reference_syntax);
1193 RecoverConsume(false);
1194 end;
1195 end; {end case }
1196 AS_COMMA: { (, ... can either be scaling, or index }
1197 Begin
1198 Consume(AS_COMMA);
1199 { Index }
1200 if (actasmtoken=AS_REGISTER) then
1201 Begin
1202 opr.ref.index:=actasmregister;
1203 Consume(AS_REGISTER);
1204 { check for scaling ... }
1205 case actasmtoken of
1206 AS_RPAREN:
1207 Begin
1208 Consume_RParen;
1209 exit;
1210 end;
1211 AS_COMMA:
1212 Begin
1213 Consume(AS_COMMA);
1214 Consume_Scale;
1215 Consume_RParen;
1216 end;
1217 else
1218 Begin
1219 Message(asmr_e_invalid_reference_syntax);
1220 RecoverConsume(false);
1221 end;
1222 end; {end case }
1224 { Scaling }
1225 else
1226 Begin
1227 Consume_Scale;
1228 Consume_RParen;
1229 exit;
1230 end;
1231 end;
1233 else
1234 Begin
1235 Message(asmr_e_invalid_reference_syntax);
1236 RecoverConsume(false);
1237 end;
1238 end;
1239 end;
1242 Procedure T386ATTOperand.BuildConstant;
1244 l : longint;
1245 tempstr : string;
1246 begin
1247 BuildConstSymbolExpression(false,false,true,l,tempstr);
1248 if tempstr<>'' then
1249 begin
1250 opr.typ:=OPR_SYMBOL;
1251 opr.symofs:=l;
1252 opr.symbol:=newasmsymbol(tempstr);
1254 else
1255 begin
1256 opr.typ:=OPR_CONSTANT;
1257 opr.val:=l;
1258 end;
1259 end;
1262 Procedure T386ATTOperand.BuildOperand;
1264 tempstr,tempstr2,
1265 expr : string;
1266 l,k : longint;
1268 procedure AddLabelOperand(hl:pasmlabel);
1269 begin
1270 if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
1271 is_calljmp(actopcode) then
1272 begin
1273 opr.typ:=OPR_SYMBOL;
1274 opr.symbol:=hl;
1276 else
1277 begin
1278 InitRef;
1279 opr.ref.symbol:=hl;
1280 end;
1281 end;
1283 procedure MaybeRecordOffset;
1285 hasdot : boolean;
1287 toffset,
1288 tsize : longint;
1289 begin
1290 if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
1291 exit;
1292 l:=0;
1293 hasdot:=(actasmtoken=AS_DOT);
1294 if hasdot then
1295 begin
1296 if expr<>'' then
1297 begin
1298 BuildRecordOffsetSize(expr,toffset,tsize);
1299 inc(l,toffset);
1300 SetSize(tsize,true);
1301 end;
1302 end;
1303 if actasmtoken in [AS_PLUS,AS_MINUS] then
1304 inc(l,BuildConstExpression(true,false));
1305 if opr.typ=OPR_REFERENCE then
1306 begin
1307 if hasdot and (not hastype) and (opr.ref.options=ref_parafixup) then
1308 Message(asmr_e_cannot_access_field_directly_for_parameters);
1309 inc(opr.ref.offset,l)
1311 else
1312 inc(opr.val,l);
1313 end;
1315 function MaybeBuildReference:boolean;
1316 { Try to create a reference, if not a reference is found then false
1317 is returned }
1318 begin
1319 MaybeBuildReference:=true;
1320 case actasmtoken of
1321 AS_INTNUM,
1322 AS_MINUS,
1323 AS_PLUS:
1324 Begin
1325 opr.ref.offset:=BuildConstExpression(True,False);
1326 if actasmtoken<>AS_LPAREN then
1327 Message(asmr_e_invalid_reference_syntax)
1328 else
1329 BuildReference;
1330 end;
1331 AS_LPAREN:
1332 BuildReference;
1333 AS_ID: { only a variable is allowed ... }
1334 Begin
1335 tempstr:=actasmpattern;
1336 Consume(AS_ID);
1337 { typecasting? }
1338 if (actasmtoken=AS_LPAREN) and
1339 SearchType(tempstr) then
1340 begin
1341 hastype:=true;
1342 Consume(AS_LPAREN);
1343 tempstr2:=actasmpattern;
1344 Consume(AS_ID);
1345 Consume(AS_RPAREN);
1346 if not SetupVar(tempstr2,false) then
1347 Message1(sym_e_unknown_id,tempstr2);
1349 else
1350 if not SetupVar(tempstr,false) then
1351 Message1(sym_e_unknown_id,tempstr);
1352 { record.field ? }
1353 if actasmtoken=AS_DOT then
1354 begin
1355 BuildRecordOffsetSize(tempstr,l,k);
1356 inc(opr.ref.offset,l);
1357 end;
1358 case actasmtoken of
1359 AS_END,
1360 AS_SEPARATOR,
1361 AS_COMMA: ;
1362 AS_LPAREN: BuildReference;
1363 else
1364 Begin
1365 Message(asmr_e_invalid_reference_syntax);
1366 Consume(actasmtoken);
1367 end;
1368 end; {end case }
1369 end;
1370 else
1371 MaybeBuildReference:=false;
1372 end; { end case }
1373 end;
1376 tempreg : tregister;
1377 hl : PAsmLabel;
1378 Begin
1379 expr:='';
1380 case actasmtoken of
1381 AS_LPAREN: { Memory reference or constant expression }
1382 Begin
1383 InitRef;
1384 BuildReference;
1385 end;
1387 AS_DOLLAR: { Constant expression }
1388 Begin
1389 Consume(AS_DOLLAR);
1390 BuildConstant;
1391 end;
1393 AS_INTNUM,
1394 AS_MINUS,
1395 AS_PLUS:
1396 Begin
1397 { Constant memory offset }
1398 { This must absolutely be followed by ( }
1399 InitRef;
1400 opr.ref.offset:=BuildConstExpression(True,False);
1401 if actasmtoken<>AS_LPAREN then
1402 Message(asmr_e_invalid_reference_syntax)
1403 else
1404 BuildReference;
1405 end;
1407 AS_STAR: { Call from memory address }
1408 Begin
1409 Consume(AS_STAR);
1410 if actasmtoken=AS_REGISTER then
1411 begin
1412 opr.typ:=OPR_REGISTER;
1413 opr.reg:=actasmregister;
1414 size:=reg_2_opsize[actasmregister];
1415 Consume(AS_REGISTER);
1417 else
1418 begin
1419 InitRef;
1420 if not MaybeBuildReference then
1421 Message(asmr_e_syn_operand);
1422 end;
1423 { this is only allowed for call's and jmp's }
1424 if not is_calljmp(actopcode) then
1425 Message(asmr_e_syn_operand);
1426 end;
1428 AS_ID: { A constant expression, or a Variable ref. }
1429 Begin
1430 { Local Label ? }
1431 if is_locallabel(actasmpattern) then
1432 begin
1433 CreateLocalLabel(actasmpattern,hl,false);
1434 Consume(AS_ID);
1435 AddLabelOperand(hl);
1437 else
1438 { Check for label }
1439 if SearchLabel(actasmpattern,hl,false) then
1440 begin
1441 Consume(AS_ID);
1442 AddLabelOperand(hl);
1444 else
1445 { probably a variable or normal expression }
1446 { or a procedure (such as in CALL ID) }
1447 Begin
1448 { is it a constant ? }
1449 if SearchIConstant(actasmpattern,l) then
1450 Begin
1451 if not (opr.typ in [OPR_NONE,OPR_CONSTANT]) then
1452 Message(asmr_e_invalid_operand_type);
1453 BuildConstant;
1455 else
1456 begin
1457 InitRef;
1458 expr:=actasmpattern;
1459 Consume(AS_ID);
1460 { typecasting? }
1461 if (actasmtoken=AS_LPAREN) and
1462 SearchType(expr) then
1463 begin
1464 hastype:=true;
1465 Consume(AS_LPAREN);
1466 tempstr:=actasmpattern;
1467 Consume(AS_ID);
1468 Consume(AS_RPAREN);
1469 if SetupVar(tempstr,false) then
1470 begin
1471 MaybeRecordOffset;
1472 { add a constant expression? }
1473 if (actasmtoken=AS_PLUS) then
1474 begin
1475 l:=BuildConstExpression(true,false);
1476 if opr.typ=OPR_CONSTANT then
1477 inc(opr.val,l)
1478 else
1479 inc(opr.ref.offset,l);
1482 else
1483 Message1(sym_e_unknown_id,tempstr);
1485 else
1486 begin
1487 if SetupVar(expr,false) then
1488 begin
1489 MaybeRecordOffset;
1490 { add a constant expression? }
1491 if (actasmtoken=AS_PLUS) then
1492 begin
1493 l:=BuildConstExpression(true,false);
1494 if opr.typ=OPR_CONSTANT then
1495 inc(opr.val,l)
1496 else
1497 inc(opr.ref.offset,l);
1500 else
1501 Begin
1502 { look for special symbols ... }
1503 if expr = '__RESULT' then
1504 SetUpResult
1505 else
1506 if expr = '__SELF' then
1507 SetupSelf
1508 else
1509 if expr = '__OLDEBP' then
1510 SetupOldEBP
1511 else
1512 { check for direct symbolic names }
1513 { only if compiling the system unit }
1514 if (cs_compilesystem in aktmoduleswitches) then
1515 begin
1516 if not SetupDirectVar(expr) then
1517 Begin
1518 { not found, finally ... add it anyways ... }
1519 Message1(asmr_w_id_supposed_external,expr);
1520 opr.ref.symbol:=newasmsymbol(expr);
1521 end;
1523 else
1524 Message1(sym_e_unknown_id,expr);
1525 end;
1526 end;
1527 end;
1528 end;
1529 { Do we have a indexing reference, then parse it also }
1530 if actasmtoken=AS_LPAREN then
1531 begin
1532 if (opr.typ=OPR_CONSTANT) then
1533 begin
1534 l:=opr.val;
1535 opr.typ:=OPR_REFERENCE;
1536 reset_reference(opr.Ref);
1537 opr.Ref.Offset:=l;
1538 end;
1539 BuildReference;
1540 end;
1541 end;
1543 AS_REGISTER: { Register, a variable reference or a constant reference }
1544 Begin
1545 { save the type of register used. }
1546 tempreg:=actasmregister;
1547 Consume(AS_REGISTER);
1548 if actasmtoken = AS_COLON then
1549 Begin
1550 Consume(AS_COLON);
1551 InitRef;
1552 opr.ref.segment:=tempreg;
1553 { This must absolutely be followed by a reference }
1554 if not MaybeBuildReference then
1555 Begin
1556 Message(asmr_e_invalid_seg_override);
1557 Consume(actasmtoken);
1558 end;
1560 { Simple register }
1561 else if (actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
1562 Begin
1563 if not (opr.typ in [OPR_NONE,OPR_REGISTER]) then
1564 Message(asmr_e_invalid_operand_type);
1565 opr.typ:=OPR_REGISTER;
1566 opr.reg:=tempreg;
1567 size:=reg_2_opsize[tempreg];
1569 else
1570 Message(asmr_e_syn_operand);
1571 end;
1572 AS_END,
1573 AS_SEPARATOR,
1574 AS_COMMA: ;
1575 else
1576 Begin
1577 Message(asmr_e_syn_operand);
1578 Consume(actasmtoken);
1579 end;
1580 end; { end case }
1581 end;
1583 {*****************************************************************************
1584 T386ATTInstruction
1585 *****************************************************************************}
1587 type
1588 P386AttInstruction=^T386AttInstruction;
1589 T386AttInstruction=object(T386Instruction)
1590 procedure InitOperands;virtual;
1591 procedure BuildOpcode;virtual;
1592 end;
1594 procedure T386AttInstruction.InitOperands;
1596 i : longint;
1597 begin
1598 for i:=1to 3 do
1599 Operands[i]:=new(P386AttOperand,Init);
1600 end;
1603 Procedure T386AttInstruction.BuildOpCode;
1605 operandnum : longint;
1606 PrefixOp,OverrideOp: tasmop;
1607 Begin
1608 PrefixOp:=A_None;
1609 OverrideOp:=A_None;
1610 { prefix seg opcode / prefix opcode }
1611 repeat
1612 if is_prefix(actopcode) then
1613 begin
1614 PrefixOp:=ActOpcode;
1615 opcode:=ActOpcode;
1616 condition:=ActCondition;
1617 opsize:=ActOpsize;
1618 ConcatInstruction(curlist);
1619 Consume(AS_OPCODE);
1621 else
1622 if is_override(actopcode) then
1623 begin
1624 OverrideOp:=ActOpcode;
1625 opcode:=ActOpcode;
1626 condition:=ActCondition;
1627 opsize:=ActOpsize;
1628 ConcatInstruction(curlist);
1629 Consume(AS_OPCODE);
1631 else
1632 break;
1633 { allow for newline as in gas styled syntax }
1634 while actasmtoken=AS_SEPARATOR do
1635 Consume(AS_SEPARATOR);
1636 until (actasmtoken<>AS_OPCODE);
1637 { opcode }
1638 if (actasmtoken <> AS_OPCODE) then
1639 Begin
1640 Message(asmr_e_invalid_or_missing_opcode);
1641 RecoverConsume(true);
1642 exit;
1643 end;
1644 { Fill the instr object with the current state }
1645 Opcode:=ActOpcode;
1646 condition:=ActCondition;
1647 opsize:=ActOpsize;
1648 { Valid combination of prefix/override and instruction ? }
1649 if (prefixop<>A_NONE) and (NOT CheckPrefix(PrefixOp,actopcode)) then
1650 Message1(asmr_e_invalid_prefix_and_opcode,actasmpattern);
1651 if (overrideop<>A_NONE) and (NOT CheckOverride(OverrideOp,ActOpcode)) then
1652 Message1(asmr_e_invalid_override_and_opcode,actasmpattern);
1653 { We are reading operands, so opcode will be an AS_ID }
1654 operandnum:=1;
1655 Consume(AS_OPCODE);
1656 { Zero operand opcode ? }
1657 if actasmtoken in [AS_SEPARATOR,AS_END] then
1658 begin
1659 operandnum:=0;
1660 exit;
1661 end;
1662 { Read the operands }
1663 repeat
1664 case actasmtoken of
1665 AS_COMMA: { Operand delimiter }
1666 Begin
1667 if operandnum > MaxOperands then
1668 Message(asmr_e_too_many_operands)
1669 else
1670 Inc(operandnum);
1671 Consume(AS_COMMA);
1672 end;
1673 AS_SEPARATOR,
1674 AS_END : { End of asm operands for this opcode }
1675 begin
1676 break;
1677 end;
1678 else
1679 Operands[operandnum]^.BuildOperand;
1680 end; { end case }
1681 until false;
1682 Ops:=operandnum;
1683 end;
1687 Procedure BuildConstant(maxvalue: longint);
1689 asmsym,
1690 expr: string;
1691 value : longint;
1692 Begin
1693 Repeat
1694 Case actasmtoken of
1695 AS_STRING:
1696 Begin
1697 expr:=actasmpattern;
1698 if length(expr) > 1 then
1699 Message(asmr_e_string_not_allowed_as_const);
1700 Consume(AS_STRING);
1701 Case actasmtoken of
1702 AS_COMMA: Consume(AS_COMMA);
1703 AS_END,
1704 AS_SEPARATOR: ;
1705 else
1706 Message(asmr_e_invalid_string_expression);
1707 end; { end case }
1708 ConcatString(curlist,expr);
1709 end;
1710 AS_INTNUM,
1711 AS_PLUS,
1712 AS_MINUS,
1713 AS_LPAREN,
1714 AS_NOT,
1715 AS_ID :
1716 Begin
1717 BuildConstSymbolExpression(false,false,false,value,asmsym);
1718 if asmsym<>'' then
1719 begin
1720 if maxvalue<>longint($ffffffff) then
1721 Message(asmr_w_32bit_const_for_address);
1722 ConcatConstSymbol(curlist,asmsym,value)
1724 else
1725 ConcatConstant(curlist,value,maxvalue);
1726 end;
1727 AS_COMMA:
1728 Consume(AS_COMMA);
1729 AS_END,
1730 AS_SEPARATOR:
1731 break;
1732 else
1733 begin
1734 Message(asmr_e_syn_constant);
1735 RecoverConsume(false);
1737 end; { end case }
1738 Until false;
1739 end;
1742 Procedure BuildRealConstant(typ : tfloattype);
1744 expr : string;
1745 r : bestreal;
1746 code : integer;
1747 negativ : boolean;
1748 errorflag: boolean;
1749 Begin
1750 errorflag:=FALSE;
1751 Repeat
1752 negativ:=false;
1753 expr:='';
1754 if actasmtoken=AS_PLUS then
1755 Consume(AS_PLUS)
1756 else
1757 if actasmtoken=AS_MINUS then
1758 begin
1759 negativ:=true;
1760 consume(AS_MINUS);
1761 end;
1762 Case actasmtoken of
1763 AS_INTNUM:
1764 Begin
1765 expr:=actasmpattern;
1766 Consume(AS_INTNUM);
1767 if negativ then
1768 expr:='-'+expr;
1769 val(expr,r,code);
1770 if code<>0 then
1771 Begin
1772 r:=0;
1773 Message(asmr_e_invalid_float_expr);
1774 End;
1775 ConcatRealConstant(curlist,r,typ);
1776 end;
1777 AS_REALNUM:
1778 Begin
1779 expr:=actasmpattern;
1780 Consume(AS_REALNUM);
1781 { in ATT syntax you have 0d in front of the real }
1782 { should this be forced ? yes i think so, as to }
1783 { conform to gas as much as possible. }
1784 if (expr[1]='0') and (upper(expr[2])='D') then
1785 Delete(expr,1,2);
1786 if negativ then
1787 expr:='-'+expr;
1788 val(expr,r,code);
1789 if code<>0 then
1790 Begin
1791 r:=0;
1792 Message(asmr_e_invalid_float_expr);
1793 End;
1794 ConcatRealConstant(curlist,r,typ);
1795 end;
1796 AS_COMMA:
1797 begin
1798 Consume(AS_COMMA);
1799 end;
1800 AS_END,
1801 AS_SEPARATOR:
1802 begin
1803 break;
1804 end;
1805 else
1806 Begin
1807 Consume(actasmtoken);
1808 if not errorflag then
1809 Message(asmr_e_invalid_float_expr);
1810 errorflag:=TRUE;
1811 end;
1812 end;
1813 Until false;
1814 end;
1817 Procedure BuildStringConstant(asciiz: boolean);
1819 expr: string;
1820 errorflag : boolean;
1821 Begin
1822 errorflag:=FALSE;
1823 Repeat
1824 Case actasmtoken of
1825 AS_STRING:
1826 Begin
1827 expr:=actasmpattern;
1828 if asciiz then
1829 expr:=expr+#0;
1830 ConcatPasString(curlist,expr);
1831 Consume(AS_STRING);
1832 end;
1833 AS_COMMA:
1834 begin
1835 Consume(AS_COMMA);
1836 end;
1837 AS_END,
1838 AS_SEPARATOR:
1839 begin
1840 break;
1841 end;
1842 else
1843 Begin
1844 Consume(actasmtoken);
1845 if not errorflag then
1846 Message(asmr_e_invalid_string_expression);
1847 errorflag:=TRUE;
1848 end;
1849 end;
1850 Until false;
1851 end;
1854 Function Assemble: Ptree;
1856 hl : PAsmLabel;
1857 commname : string;
1858 lastsec : tsection;
1859 l1,l2 : longint;
1860 instr : T386ATTInstruction;
1861 Begin
1862 Message1(asmr_d_start_reading,'AT&T');
1863 firsttoken:=TRUE;
1864 if assigned(procinfo^.returntype.def) and
1865 (is_fpu(procinfo^.returntype.def) or
1866 ret_in_acc(procinfo^.returntype.def)) then
1867 procinfo^.funcret_state:=vs_assigned;
1868 { sets up all opcode and register tables in uppercase }
1869 if not _asmsorted then
1870 Begin
1871 SetupTables;
1872 _asmsorted:=TRUE;
1873 end;
1874 curlist:=new(paasmoutput,init);
1875 lastsec:=sec_code;
1876 { setup label linked list }
1877 new(LocalLabelList,Init);
1878 { start tokenizer }
1879 c:=current_scanner^.asmgetchar;
1880 gettoken;
1881 { main loop }
1882 repeat
1883 case actasmtoken of
1884 AS_LLABEL:
1885 Begin
1886 if CreateLocalLabel(actasmpattern,hl,true) then
1887 ConcatLabel(curlist,hl);
1888 Consume(AS_LLABEL);
1889 end;
1891 AS_LABEL:
1892 Begin
1893 if SearchLabel(upper(actasmpattern),hl,true) then
1894 ConcatLabel(curlist,hl)
1895 else
1896 Message1(asmr_e_unknown_label_identifier,actasmpattern);
1897 Consume(AS_LABEL);
1898 end;
1900 AS_DW:
1901 Begin
1902 Consume(AS_DW);
1903 BuildConstant($ffff);
1904 end;
1906 AS_DATA:
1907 Begin
1908 curlist^.Concat(new(pai_section,init(sec_data)));
1909 lastsec:=sec_data;
1910 Consume(AS_DATA);
1911 end;
1913 AS_TEXT:
1914 Begin
1915 curlist^.Concat(new(pai_section,init(sec_code)));
1916 lastsec:=sec_code;
1917 Consume(AS_TEXT);
1918 end;
1920 AS_DB:
1921 Begin
1922 Consume(AS_DB);
1923 BuildConstant($ff);
1924 end;
1926 AS_DD:
1927 Begin
1928 Consume(AS_DD);
1929 BuildConstant($ffffffff);
1930 end;
1932 AS_DQ:
1933 Begin
1934 Consume(AS_DQ);
1935 BuildRealConstant(s64comp);
1936 end;
1938 AS_SINGLE:
1939 Begin
1940 Consume(AS_SINGLE);
1941 BuildRealConstant(s32real);
1942 end;
1944 AS_DOUBLE:
1945 Begin
1946 Consume(AS_DOUBLE);
1947 BuildRealConstant(s64real);
1948 end;
1950 AS_EXTENDED:
1951 Begin
1952 Consume(AS_EXTENDED);
1953 BuildRealConstant(s80real);
1954 end;
1956 AS_GLOBAL:
1957 Begin
1958 Consume(AS_GLOBAL);
1959 if actasmtoken=AS_ID then
1960 ConcatPublic(curlist,actasmpattern);
1961 Consume(AS_ID);
1962 if actasmtoken<>AS_SEPARATOR then
1963 Consume(AS_SEPARATOR);
1964 end;
1966 AS_ALIGN:
1967 Begin
1968 Consume(AS_ALIGN);
1969 l1:=BuildConstExpression(false,false);
1970 if (target_info.target in [target_i386_GO32V1,target_i386_GO32V2]) then
1971 begin
1972 l2:=1;
1973 if (l1>=0) and (l1<=16) then
1974 while (l1>0) do
1975 begin
1976 l2:=2*l2;
1977 dec(l1);
1978 end;
1979 l1:=l2;
1980 end;
1981 ConcatAlign(curlist,l1);
1982 Message(asmr_n_align_is_target_specific);
1983 if actasmtoken<>AS_SEPARATOR then
1984 Consume(AS_SEPARATOR);
1985 end;
1987 AS_BALIGN:
1988 Begin
1989 Consume(AS_BALIGN);
1990 ConcatAlign(curlist,BuildConstExpression(false,false));
1991 if actasmtoken<>AS_SEPARATOR then
1992 Consume(AS_SEPARATOR);
1993 end;
1995 AS_P2ALIGN:
1996 Begin
1997 Consume(AS_P2ALIGN);
1998 l1:=BuildConstExpression(false,false);
1999 l2:=1;
2000 if (l1>=0) and (l1<=16) then
2001 while (l1>0) do
2002 begin
2003 l2:=2*l2;
2004 dec(l1);
2005 end;
2006 l1:=l2;
2007 ConcatAlign(curlist,l1);
2008 if actasmtoken<>AS_SEPARATOR then
2009 Consume(AS_SEPARATOR);
2010 end;
2012 AS_ASCIIZ:
2013 Begin
2014 Consume(AS_ASCIIZ);
2015 BuildStringConstant(TRUE);
2016 end;
2018 AS_ASCII:
2019 Begin
2020 Consume(AS_ASCII);
2021 BuildStringConstant(FALSE);
2022 end;
2024 AS_LCOMM:
2025 Begin
2026 Consume(AS_LCOMM);
2027 commname:=actasmpattern;
2028 Consume(AS_ID);
2029 Consume(AS_COMMA);
2030 ConcatLocalBss(commname,BuildConstExpression(false,false));
2031 if actasmtoken<>AS_SEPARATOR then
2032 Consume(AS_SEPARATOR);
2033 end;
2035 AS_COMM:
2036 Begin
2037 Consume(AS_COMM);
2038 commname:=actasmpattern;
2039 Consume(AS_ID);
2040 Consume(AS_COMMA);
2041 ConcatGlobalBss(commname,BuildConstExpression(false,false));
2042 if actasmtoken<>AS_SEPARATOR then
2043 Consume(AS_SEPARATOR);
2044 end;
2045 AS_OPCODE:
2046 Begin
2047 instr.init;
2048 instr.BuildOpcode;
2049 instr.AddReferenceSizes;
2050 instr.SetInstructionOpsize;
2051 instr.CheckOperandSizes;
2052 instr.ConcatInstruction(curlist);
2053 instr.done;
2054 end;
2056 AS_SEPARATOR:
2057 Begin
2058 Consume(AS_SEPARATOR);
2059 end;
2061 AS_END:
2062 begin
2063 break; { end assembly block }
2064 end;
2066 else
2067 Begin
2068 Message(asmr_e_syntax_error);
2069 RecoverConsume(false);
2070 end;
2071 end;
2072 until false;
2073 { Check LocalLabelList }
2074 LocalLabelList^.CheckEmitted;
2075 dispose(LocalLabelList,Done);
2076 { are we back in the code section? }
2077 if lastsec<>sec_code then
2078 begin
2079 Message(asmr_w_assembler_code_not_returned_to_text);
2080 curlist^.Concat(new(pai_section,init(sec_code)));
2081 end;
2082 { Return the list in an asmnode }
2083 assemble:=genasmnode(curlist);
2084 Message1(asmr_d_finish_reading,'AT&T');
2085 end;
2088 {*****************************************************************************
2089 Initialize
2090 *****************************************************************************}
2093 old_exit : pointer;
2095 procedure ra386att_exit;{$ifndef FPC}far;{$endif}
2096 begin
2097 if assigned(iasmops) then
2098 dispose(iasmops,done);
2099 if assigned(iasmregs) then
2100 dispose(iasmregs);
2101 exitproc:=old_exit;
2102 end;
2105 begin
2106 old_exit:=exitproc;
2107 exitproc:=@ra386att_exit;
2108 end.
2110 $Log$
2111 Revision 1.1 2002/02/19 08:23:40 sasu
2112 Initial revision
2114 Revision 1.1.2.1 2000/11/30 00:33:34 pierre
2115 * fix for web bug 1229
2117 Revision 1.1 2000/07/13 06:29:55 michael
2118 + Initial import
2120 Revision 1.85 2000/06/18 19:09:31 peter
2121 * fixed + record.field expressions
2123 Revision 1.84 2000/06/18 18:07:06 peter
2124 * use new illegal_char method
2126 Revision 1.83 2000/06/15 18:07:07 peter
2127 * fix constant parsing which gave an error when constants were used
2129 Revision 1.82 2000/06/14 19:02:41 peter
2130 * fixed TYPE with records and fields
2131 * added TYPE support for ATT reader else it wouldn't be possible to
2132 get the size of a type/variable
2134 Revision 1.81 2000/05/26 18:23:11 peter
2135 * fixed % parsing and added modulo support
2136 * changed some evaulator errors to more generic illegal expresion
2138 Revision 1.80 2000/05/23 20:36:28 peter
2139 + typecasting support for variables, but be carefull as word,byte can't
2140 be used because they are reserved assembler keywords
2142 Revision 1.79 2000/05/18 17:05:16 peter
2143 * fixed size of const parameters in asm readers
2145 Revision 1.78 2000/05/12 21:57:02 pierre
2146 + use of a dictionary object
2147 for faster opcode searching in assembler readers
2148 implemented by Kovacs Attila Zoltan
2150 Revision 1.77 2000/05/11 09:56:21 pierre
2151 * fixed several compare problems between longints and
2152 const > $80000000 that are treated as int64 constanst
2153 by Delphi reported by Kovacs Attila Zoltan
2155 Revision 1.76 2000/05/09 11:56:25 pierre
2156 * Issue an error if opcode is not found
2158 Revision 1.75 2000/05/08 13:23:03 peter
2159 * fixed reference parsing
2161 Revision 1.74 2000/04/29 12:51:33 peter
2162 * fixed offset support intel reader, the gotoffset variable was not
2163 always reset
2164 * moved check for local/para to be only used for varsym
2166 Revision 1.73 2000/04/04 13:48:44 pierre
2167 + TOperand.SetCorrectSize virtual method added
2168 to be able to change the suffix according to the instruction
2169 (FIADD word ptr w need a s as ATT suffix
2170 wheras FILD word ptr w need a w suffix :( )
2172 Revision 1.72 2000/03/15 23:10:01 pierre
2173 * fix for bug 848 (that still genrated wrong code)
2174 + better testing for variables used in assembler
2175 (gives an error if variable is not directly reachable !)
2177 Revision 1.71 2000/02/09 13:23:01 peter
2178 * log truncated
2180 Revision 1.70 2000/01/28 09:41:39 peter
2181 * fixed fpu suffix parsing for att reader
2183 Revision 1.69 2000/01/21 10:10:25 daniel
2184 * should work on linux also
2186 Revision 1.68 2000/01/21 00:46:47 peter
2187 * ifdef'd my previous fix as it broken a make cycle sometimes
2189 Revision 1.67 2000/01/20 23:35:01 peter
2190 * fixed fldl where suffix would get S_L instead of S_FL
2192 Revision 1.66 2000/01/07 01:14:34 peter
2193 * updated copyright to 2000
2195 Revision 1.65 1999/12/12 12:57:59 peter
2196 * allow para+offset
2198 Revision 1.64 1999/11/30 10:40:52 peter
2199 + ttype, tsymlist
2201 Revision 1.63 1999/11/17 17:05:03 pierre
2202 * Notes/hints changes
2204 Revision 1.62 1999/11/09 23:06:46 peter
2205 * esi_offset -> selfpointer_offset to be newcg compatible
2206 * hcogegen -> cgbase fixes for newcg
2208 Revision 1.61 1999/11/06 14:34:23 peter
2209 * truncated log to 20 revs
2211 Revision 1.60 1999/10/01 07:59:20 peter
2212 * fixed object field parsing
2214 Revision 1.59 1999/09/27 23:44:57 peter
2215 * procinfo is now a pointer
2216 * support for result setting in sub procedure
2218 Revision 1.58 1999/09/08 16:04:01 peter
2219 * better support for object fields and more error checks for
2220 field accesses which create buggy code
2222 Revision 1.57 1999/08/05 16:53:08 peter
2223 * V_Fatal=1, all other V_ are also increased
2224 * Check for local procedure when assigning procvar
2225 * fixed comment parsing because directives
2226 * oldtp mode directives better supported
2227 * added some messages to errore.msg
2229 Revision 1.56 1999/08/04 00:23:25 florian
2230 * renamed i386asm and i386base to cpuasm and cpubase
2232 Revision 1.55 1999/08/03 22:03:09 peter
2233 * moved bitmask constants to sets
2234 * some other type/const renamings
2236 Revision 1.54 1999/07/24 11:17:12 peter
2237 * suffix parsing for at&t fixed for things like movsbl
2238 * string constants are now handle correctly and also allowed in
2239 constant expressions