asmutils.pas 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705
  1. {
  2. $Id$
  3. Copyright (c) 1998 Carl Eric Codere
  4. This unit implements some support routines for assembler parsing
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. **********************************************************************}
  17. Unit AsmUtils;
  18. {*************************************************************************}
  19. { This unit implements some objects as well as utilities which will be }
  20. { used by all inline assembler parsers (non-processor specific). }
  21. { }
  22. { Main routines/objects herein: }
  23. { o Object TExprParse is a simple expression parser to resolve assembler }
  24. { expressions. (Based generally on some code by Thai Tran from SWAG). }
  25. { o Object TInstruction is a simple object used for instructions }
  26. { o Record TOperand is a simple record used to store information on }
  27. { each operand. }
  28. { o String conversion routines from octal,binary and hex to decimal. }
  29. { o A linked list object/record for local labels }
  30. { o Routines for retrieving symbols (local and global) }
  31. { o Object for a linked list of strings (with duplicate strings not }
  32. { allowed). }
  33. { o Non-processor dependant routines for adding instructions to the }
  34. { instruction list. }
  35. {*************************************************************************}
  36. {--------------------------------------------------------------------}
  37. { LEFT TO DO: }
  38. { o Fix the remaining bugs in the expression parser, such as with }
  39. { 4+-3 }
  40. { o Add support for local typed constants search. }
  41. { o Add support for private/protected fields in method assembler }
  42. { routines. }
  43. {--------------------------------------------------------------------}
  44. Interface
  45. Uses
  46. symtable,aasm,hcodegen,verbose,systems,globals,files,strings,
  47. cobjects,
  48. {$ifdef i386}
  49. i386;
  50. {$endif}
  51. {$ifdef m68k}
  52. m68k;
  53. {$endif}
  54. Const
  55. RPNMax = 10; { I think you only need 4, but just to be safe }
  56. OpMax = 25;
  57. maxoperands = 3; { Maximum operands for assembler instructions }
  58. Type
  59. {---------------------------------------------------------------------}
  60. { Label Management types }
  61. {---------------------------------------------------------------------}
  62. PAsmLabel = ^TAsmLabel;
  63. PString = ^String;
  64. { Each local label has this structure associated with it }
  65. TAsmLabel = record
  66. name: PString; { pointer to a pascal string name of label }
  67. lab: PLabel; { pointer to a label as defined in FPC }
  68. emitted: boolean; { as the label itself been emitted ? }
  69. next: PAsmLabel; { next node }
  70. end;
  71. TAsmLabelList = Object
  72. public
  73. First: PAsmLabel;
  74. Constructor Init;
  75. Destructor Done;
  76. Procedure Insert(s:string; lab: PLabel; emitted: boolean);
  77. Function Search(const s: string): PAsmLabel;
  78. private
  79. Last: PAsmLabel;
  80. Function NewPasStr(s:string): PString;
  81. end;
  82. {---------------------------------------------------------------------}
  83. { Instruction management types }
  84. {---------------------------------------------------------------------}
  85. toperandtype = (OPR_NONE,OPR_REFERENCE,OPR_CONSTANT,OPR_REGISTER,OPR_LABINSTR,
  86. OPR_REGLIST);
  87. { When the TReference field isintvalue = TRUE }
  88. { then offset points to an ABSOLUTE address }
  89. { otherwise isintvalue should always be false }
  90. { Special cases: }
  91. { For the M68k Target, size is UNUSED, the }
  92. { opcode determines the size of the }
  93. { instruction. }
  94. { DIVS/DIVU/MULS/MULU of the form dn,dn:dn }
  95. { is stored as three operands!! }
  96. { Each instruction operand can be of this type }
  97. TOperand = record
  98. size: topsize;
  99. opinfo: longint; { ao_xxxx flags }
  100. case operandtype:toperandtype of
  101. { the size of the opr_none field should be at least equal to each }
  102. { other field as to facilitate initialization. }
  103. OPR_NONE: (l: array[1..sizeof(treference)] of byte);
  104. OPR_REFERENCE: (ref:treference);
  105. OPR_CONSTANT: (val: longint);
  106. OPR_REGISTER: (reg:tregister);
  107. OPR_LABINSTR: (hl: plabel);
  108. { Register list such as in the movem instruction }
  109. OPR_REGLIST: (list: set of tregister);
  110. end;
  111. TInstruction = object
  112. public
  113. operands: array[1..maxoperands] of TOperand;
  114. { if numops = zero, a size may still be valid in operands[1] }
  115. { it still should be checked. }
  116. numops: byte;
  117. { set to TRUE if the instruction is labeled. }
  118. labeled: boolean;
  119. { This is used for instructions such A_CMPSB... etc, to determine }
  120. { the size of the instruction. }
  121. stropsize: topsize;
  122. procedure init;
  123. { sets up the prefix field with the instruction pointed to in s }
  124. procedure addprefix(tok: tasmop);
  125. { sets up the instruction with the instruction pointed to in s }
  126. procedure addinstr(tok: tasmop);
  127. { get the current instruction of this object }
  128. function getinstruction: tasmop;
  129. { get the current prefix of this instruction }
  130. function getprefix: tasmop;
  131. private
  132. prefix: tasmop;
  133. instruction: tasmop;
  134. end;
  135. {---------------------------------------------------------------------}
  136. { Expression parser types }
  137. {---------------------------------------------------------------------}
  138. { expression parser error codes }
  139. texpr_error =
  140. (zero_divide, { divide by zero. }
  141. stack_overflow, { stack overflow. }
  142. stack_underflow, { stack underflow. }
  143. invalid_number, { invalid conversion }
  144. invalid_op); { invalid operator }
  145. TExprOperator = record
  146. ch: char; { operator }
  147. is_prefix: boolean; { was it a prefix, possible prefixes are +,- and not }
  148. end;
  149. String15 = String[15];
  150. {**********************************************************************}
  151. { The following operators are supported: }
  152. { '+' : addition }
  153. { '-' : subtraction }
  154. { '*' : multiplication }
  155. { '/' : modulo division }
  156. { '^' : exclusive or }
  157. { '<' : shift left }
  158. { '>' : shift right }
  159. { '&' : bitwise and }
  160. { '|' : bitwise or }
  161. { '~' : bitwise complement }
  162. { '%' : modulo division }
  163. { nnn: longint numbers }
  164. { ( and ) parenthesis }
  165. {**********************************************************************}
  166. TExprParse = Object
  167. public
  168. Constructor Init;
  169. Destructor Done;
  170. Function Evaluate(Expr: String): longint;
  171. Procedure Error(anerror: texpr_error); virtual;
  172. Function Priority(_Operator: Char): Integer; virtual;
  173. private
  174. RPNStack : Array[1..RPNMax] of longint; { Stack For RPN calculator }
  175. RPNTop : Integer;
  176. OpStack : Array[1..OpMax] of TExprOperator; { Operator stack For conversion }
  177. OpTop : Integer;
  178. Procedure RPNPush(Num: Longint);
  179. Function RPNPop: Longint;
  180. Procedure RPNCalc(token: String15; prefix: boolean);
  181. Procedure OpPush(_Operator: char; prefix: boolean);
  182. { In reality returns TExprOperaotr }
  183. Procedure OpPop(var _Operator:TExprOperator);
  184. end;
  185. {---------------------------------------------------------------------}
  186. { String routines }
  187. {---------------------------------------------------------------------}
  188. {*********************************************************************}
  189. { PROCEDURE PadZero; }
  190. { Description: Makes sure that the string specified is of the given }
  191. { length, by padding it with binary zeros, or truncating if necessary}
  192. { Remark: The return value is determined BEFORE any eventual padding.}
  193. { Return Value: TRUE = if length of string s was <= then n }
  194. { FALSE = if length of string s was > then n }
  195. {*********************************************************************}
  196. Function PadZero(Var s: String; n: byte): Boolean;
  197. { Converts an Hex digit string to a Decimal string }
  198. { Returns '' if there was an error. }
  199. Function HexToDec(const S:String): String;
  200. { Converts a binary digit string to a Decimal string }
  201. { Returns '' if there was an error. }
  202. Function BinaryToDec(const S:String): String;
  203. { Converts an octal digit string to a Decimal string }
  204. { Returns '' if there was an error. }
  205. Function OctalToDec(const S:String): String;
  206. { Converts a string containing C styled escape sequences to }
  207. { a pascal style string. }
  208. Function EscapeToPascal(const s:string): string;
  209. Procedure ConcatPasString(p : paasmoutput;s:string);
  210. { Writes the string s directly to the assembler output }
  211. Procedure ConcatDirect(p : paasmoutput;s:string);
  212. {---------------------------------------------------------------------}
  213. { Symbol helper routines }
  214. {---------------------------------------------------------------------}
  215. Function GetTypeOffset(const base: string; const field: string;
  216. Var Offset: longint):boolean;
  217. Function GetVarOffset(const base: string; const field: string;
  218. Var Offset: longint):boolean;
  219. Function SearchIConstant(const s:string; var l:longint): boolean;
  220. Function SearchLabel(const s: string; var hl: plabel): boolean;
  221. Function CreateVarInstr(var Instr: TInstruction; const hs:string;
  222. operandnum:byte):boolean;
  223. {*********************************************************************}
  224. { FUNCTION NewPasStr(s:string): PString }
  225. { Description: This routine allocates a string on the heap and }
  226. { returns a pointer to the allocated string. }
  227. { }
  228. { Remarks: The string allocated should not be modified, since it's }
  229. { length will be less then 255. }
  230. { Remarks: It is assumed that HeapError will be called if an }
  231. { allocation fails. }
  232. {*********************************************************************}
  233. Function newpasstr(s: string): Pointer;
  234. Procedure SetupResult(Var Instr:TInstruction; operandnum: byte);
  235. Procedure FWaitWarning;
  236. {---------------------------------------------------------------------}
  237. { Instruction generation routines }
  238. {---------------------------------------------------------------------}
  239. { swaps in the case of a 2/3 operand opcode the destination and the }
  240. { source as to put it in AT&T style instruction format. }
  241. Procedure SwapOperands(Var instr: TInstruction);
  242. Procedure ConcatLabel(p : paasmoutput;op : tasmop;var l : plabel);
  243. Procedure ConcatConstant(p : paasmoutput;value: longint; maxvalue: longint);
  244. Procedure ConcatRealConstant(p : paasmoutput;value: bestreal; real_typ : tfloattype);
  245. Procedure ConcatString(p : paasmoutput;s:string);
  246. Procedure ConcatPublic(p:paasmoutput;const s : string);
  247. Procedure ConcatLocal(p:paasmoutput;const s : string);
  248. Procedure ConcatGlobalBss(const s : string;size : longint);
  249. Procedure ConcatLocalBss(const s : string;size : longint);
  250. { add to list of external labels }
  251. Procedure ConcatExternal(const s : string;typ : texternal_typ);
  252. { add to internal list of labels }
  253. Procedure ConcatInternal(const s : string;typ : texternal_typ);
  254. Implementation
  255. {*************************************************************************}
  256. { Expression Parser }
  257. {*************************************************************************}
  258. Constructor TExprParse.Init;
  259. Begin
  260. end;
  261. Procedure TExprParse.Error(anerror:texpr_error);
  262. var
  263. t : tmsgconst;
  264. Begin
  265. case anerror of
  266. zero_divide: t:=assem_f_ev_zero_divide;
  267. stack_overflow: t:=assem_f_ev_stack_overflow;
  268. stack_underflow: t:=assem_f_ev_stack_underflow;
  269. invalid_number: t:=assem_f_ev_invalid_number;
  270. invalid_op: t:=assem_f_ev_invalid_op;
  271. else
  272. t:=assem_f_ev_unknown;
  273. end;
  274. Message(t);
  275. end;
  276. Procedure TExprParse.RPNPush(Num : longint); { Add an operand to the top of the RPN stack }
  277. begin
  278. if RPNTop < RPNMax then
  279. begin
  280. Inc(RPNTop);
  281. RPNStack[RPNTop] := Num;
  282. end
  283. else
  284. Error(stack_overflow); { Put some error handler here }
  285. end;
  286. Function TExprParse.RPNPop : longint; { Get the operand at the top of the RPN stack }
  287. begin
  288. if RPNTop > 0 then
  289. begin
  290. RPNPop := RPNStack[RPNTop];
  291. Dec(RPNTop);
  292. end
  293. else { Put some error handler here }
  294. Error(stack_underflow);
  295. end;
  296. Procedure TExprParse.RPNCalc(Token : String15; prefix:boolean); { RPN Calculator }
  297. Var
  298. Temp : longint;
  299. LocalError : Integer;
  300. begin
  301. { Write(Token, ' '); This just outputs the RPN expression }
  302. if (Length(Token) = 1) and (Token[1] in ['+', '-', '*', '/','&','|','%','^','~','<','>']) then
  303. Case Token[1] of { Handle operators }
  304. '+' : Begin
  305. if prefix then
  306. else
  307. RPNPush(RPNPop + RPNPop);
  308. end;
  309. '-' : Begin
  310. if prefix then
  311. RPNPush(-(RPNPop))
  312. else
  313. RPNPush(RPNPop - RPNPop);
  314. end;
  315. '*' : RPNPush(RPNPop * RPNPop);
  316. '&' : RPNPush(RPNPop AND RPNPop);
  317. '|' : RPNPush(RPNPop OR RPNPop);
  318. '~' : RPNPush(NOT RPNPop);
  319. '<' : RPNPush(RPNPop SHL RPNPop);
  320. '>' : RPNPush(RPNPop SHR RPNPop);
  321. '%' : begin
  322. Temp := RPNPop;
  323. if Temp <> 0 then
  324. RPNPush(RPNPop mod Temp)
  325. else Error(zero_divide); { Handle divide by zero error }
  326. end;
  327. '^' : RPNPush(RPNPop XOR RPNPop);
  328. '/' :
  329. begin
  330. Temp := RPNPop;
  331. if Temp <> 0 then
  332. RPNPush(RPNPop div Temp)
  333. else Error(zero_divide);{ Handle divide by 0 error }
  334. end;
  335. end
  336. else
  337. begin { Convert String to number and add to stack }
  338. if token='-2147483648' then
  339. begin
  340. temp:=$80000000;
  341. localerror:=0;
  342. end
  343. else
  344. Val(Token, Temp, LocalError);
  345. if LocalError = 0 then
  346. RPNPush(Temp)
  347. else Error(invalid_number);{ Handle error }
  348. end;
  349. end;
  350. Procedure TExprParse.OpPush(_Operator : char;prefix: boolean); { Add an operator onto top of the stack }
  351. begin
  352. if OpTop < OpMax then
  353. begin
  354. Inc(OpTop);
  355. OpStack[OpTop].ch := _Operator;
  356. OpStack[OpTop].is_prefix := prefix;
  357. end
  358. else Error(stack_overflow); { Put some error handler here }
  359. end;
  360. Procedure TExprParse.OpPop(var _Operator:TExprOperator); { Get operator at the top of the stack }
  361. begin
  362. if OpTop > 0 then
  363. begin
  364. _Operator := OpStack[OpTop];
  365. Dec(OpTop);
  366. end
  367. else Error(stack_underflow); { Put some error handler here }
  368. end;
  369. Function TExprParse.Priority(_Operator : Char) : Integer; { Return priority of operator }
  370. { The greater the priority, the higher the precedence }
  371. begin
  372. Case _Operator OF
  373. '(' : Priority := 0;
  374. '+', '-' : Priority := 1;
  375. '*', '/','%','<','>' : Priority := 2;
  376. '|','&','^','~': Priority := 0;
  377. else Error(invalid_op);{ More error handling }
  378. end;
  379. end;
  380. Function TExprParse.Evaluate(Expr : String):longint;
  381. Var
  382. I : Integer;
  383. Token : String15;
  384. opr: TExprOperator;
  385. begin
  386. OpTop := 0; { Reset stacks }
  387. RPNTop := 0;
  388. Token := '';
  389. For I := 1 to Length(Expr) DO
  390. if Expr[I] in ['0'..'9'] then
  391. begin { Build multi-digit numbers }
  392. Token := Token + Expr[I];
  393. if I = Length(Expr) then { Send last one to calculator }
  394. RPNCalc(Token,false);
  395. end
  396. else
  397. if Expr[I] in ['+', '-', '*', '/', '(', ')','^','&','|','%','~','<','>'] then
  398. begin
  399. if Token <> '' then
  400. begin { Send last built number to calc. }
  401. RPNCalc(Token,false);
  402. Token := '';
  403. end;
  404. Case Expr[I] OF
  405. '(' : OpPush('(',false);
  406. ')' :
  407. begin
  408. While OpStack[OpTop].ch <> '(' DO
  409. Begin
  410. OpPop(opr);
  411. RPNCalc(opr.ch,opr.is_prefix);
  412. end;
  413. OpPop(opr); { Pop off and ignore the '(' }
  414. end;
  415. '+','-','~': Begin
  416. While (OpTop > 0) AND
  417. (Priority(Expr[I]) <= Priority(OpStack[OpTop].ch)) DO
  418. Begin
  419. OpPop(opr);
  420. RPNCalc(opr.ch,opr.is_prefix);
  421. end;
  422. { if start of expression then surely a prefix }
  423. { or if previous char was also an operator }
  424. { push it and don't evaluate normally }
  425. { workaround for -2147483648 }
  426. if (expr[I]='-') and (expr[i+1] in ['0'..'9']) then
  427. begin
  428. token:='-';
  429. expr[i]:='+';
  430. end;
  431. if (I = 1) or (not (Expr[I-1] in ['0'..'9','(',')'])) then
  432. OpPush(Expr[I],true)
  433. else
  434. OpPush(Expr[I],false);
  435. end;
  436. '*', '/','^','|','&','%','<','>' :
  437. begin
  438. While (OpTop > 0) AND
  439. (Priority(Expr[I]) <= Priority(OpStack[OpTop].ch)) DO
  440. Begin
  441. OpPop(opr);
  442. RPNCalc(opr.ch,opr.is_prefix);
  443. end;
  444. OpPush(Expr[I],false);
  445. end;
  446. end; { Case }
  447. end
  448. else Error(invalid_op);
  449. { Handle bad input error }
  450. While OpTop > 0 do { Pop off the remaining operators }
  451. Begin
  452. OpPop(opr);
  453. RPNCalc(opr.ch,opr.is_prefix);
  454. end;
  455. { The result is stored on the top of the stack }
  456. Evaluate := RPNPop;
  457. end;
  458. Destructor TExprParse.Done;
  459. Begin
  460. end;
  461. {*************************************************************************}
  462. { String conversions/utils }
  463. {*************************************************************************}
  464. Function newpasstr(s: string): Pointer;
  465. Var
  466. StrPtr: PString;
  467. Begin
  468. GetMem(StrPtr, length(s)+1);
  469. Move(s,StrPtr^,length(s)+1);
  470. newpasstr:= Strptr;
  471. end;
  472. Function EscapeToPascal(const s:string): string;
  473. { converts a C styled string - which contains escape }
  474. { characters to a pascal style string. }
  475. var
  476. i,j: word;
  477. str: string;
  478. temp: string;
  479. value: byte;
  480. code: integer;
  481. Begin
  482. str:='';
  483. i:=1;
  484. j:=1;
  485. repeat
  486. if s[i] = '\' then
  487. Begin
  488. Inc(i);
  489. if i > 255 then
  490. Begin
  491. EscapeToPascal:=str;
  492. exit;
  493. end;
  494. case s[i] of
  495. '\': insert('\',str,j);
  496. 'b': insert(#08,str,j);
  497. 'f': insert(#12,str,j);
  498. 'n': insert(#10,str,j);
  499. 'r': insert(#13,str,j);
  500. 't': insert(#09,str,j);
  501. '"': insert('"',str,j);
  502. { octal number }
  503. '0'..'7': Begin
  504. temp:=s[i];
  505. temp:=temp+s[i+1];
  506. temp:=temp+s[i+2];
  507. inc(i,2);
  508. val(octaltodec(temp),value,code);
  509. if (code <> 0) then
  510. Message(assem_w_invalid_numeric);
  511. insert(chr(value),str,j);
  512. end;
  513. { hexadecimal number }
  514. 'x': Begin
  515. temp:=s[i+1];
  516. temp:=temp+s[i+2];
  517. inc(i,2);
  518. val(hextodec(temp),value,code);
  519. if (code <> 0) then
  520. Message(assem_w_invalid_numeric);
  521. insert(chr(value),str,j);
  522. end;
  523. else
  524. Begin
  525. Message1(assem_e_escape_seq_ignored,s[i]);
  526. insert(s[i],str,j);
  527. end;
  528. end; {end case }
  529. Inc(i);
  530. end
  531. else
  532. Begin
  533. Insert(s[i],str,j);
  534. Inc(i);
  535. if i > 255 then
  536. Begin
  537. EscapeToPascal:=str;
  538. exit;
  539. end;
  540. end;
  541. Inc(j);
  542. until (i > length(s)) or (j > 255);
  543. EscapeToPascal:=str;
  544. end;
  545. Function OctalToDec(const S:String): String;
  546. { Converts an octal string to a Decimal string }
  547. { Returns '' if there was an error. }
  548. var vs: longint;
  549. c: byte;
  550. st: string;
  551. Begin
  552. vs := 0;
  553. for c:=1 to length(s) do
  554. begin
  555. case s[c] of
  556. '0': vs:=vs shl 3;
  557. '1': vs:=vs shl 3+1;
  558. '2': vs:=vs shl 3+2;
  559. '3': vs:=vs shl 3+3;
  560. '4': vs:=vs shl 3+4;
  561. '5': vs:=vs shl 3+5;
  562. '6': vs:=vs shl 3+6;
  563. '7': vs:=vs shl 3+7;
  564. else
  565. begin
  566. OctalToDec := '';
  567. exit;
  568. end;
  569. end;
  570. end;
  571. str(vs,st);
  572. OctalToDec := st;
  573. end;
  574. Function BinaryToDec(const S:String): String;
  575. { Converts a binary string to a Decimal string }
  576. { Returns '' if there was an error. }
  577. var vs: longint;
  578. c: byte;
  579. st: string;
  580. Begin
  581. vs := 0;
  582. for c:=1 to length(s) do
  583. begin
  584. if s[c] = '0' then
  585. vs:=vs shl 1
  586. else
  587. if s[c]='1' then
  588. vs:=vs shl 1+1
  589. else
  590. begin
  591. BinaryToDec := '';
  592. exit;
  593. end;
  594. end;
  595. str(vs,st);
  596. BinaryToDec := st;
  597. end;
  598. Function HexToDec(const S:String): String;
  599. var vs: longint;
  600. c: byte;
  601. st: string;
  602. Begin
  603. vs := 0;
  604. for c:=1 to length(s) do
  605. begin
  606. case upcase(s[c]) of
  607. '0': vs:=vs shl 4;
  608. '1': vs:=vs shl 4+1;
  609. '2': vs:=vs shl 4+2;
  610. '3': vs:=vs shl 4+3;
  611. '4': vs:=vs shl 4+4;
  612. '5': vs:=vs shl 4+5;
  613. '6': vs:=vs shl 4+6;
  614. '7': vs:=vs shl 4+7;
  615. '8': vs:=vs shl 4+8;
  616. '9': vs:=vs shl 4+9;
  617. 'A': vs:=vs shl 4+10;
  618. 'B': vs:=vs shl 4+11;
  619. 'C': vs:=vs shl 4+12;
  620. 'D': vs:=vs shl 4+13;
  621. 'E': vs:=vs shl 4+14;
  622. 'F': vs:=vs shl 4+15;
  623. else
  624. begin
  625. HexToDec := '';
  626. exit;
  627. end;
  628. end;
  629. end;
  630. str(vs,st);
  631. HexToDec := st;
  632. end;
  633. Function PadZero(Var s: String; n: byte): Boolean;
  634. Begin
  635. PadZero := TRUE;
  636. { Do some error checking first }
  637. if Length(s) = n then
  638. exit
  639. else
  640. if Length(s) > n then
  641. Begin
  642. PadZero := FALSE;
  643. delete(s,n+1,length(s));
  644. exit;
  645. end
  646. else
  647. PadZero := TRUE;
  648. { Fill it up with the specified character }
  649. fillchar(s[length(s)+1],n-1,#0);
  650. s[0] := chr(n);
  651. end;
  652. {*************************************************************************}
  653. { Instruction utilities }
  654. {*************************************************************************}
  655. Procedure TInstruction.init;
  656. var
  657. k: integer;
  658. Begin
  659. numops := 0;
  660. labeled := FALSE;
  661. stropsize := S_NO;
  662. prefix := A_NONE;
  663. instruction := A_NONE;
  664. for k:=1 to maxoperands do
  665. begin
  666. operands[k].size := S_NO;
  667. operands[k].operandtype := OPR_NONE;
  668. { init to zeros }
  669. fillchar(operands[k].l, sizeof(operands[k].l),#0);
  670. end;
  671. end;
  672. Procedure TInstruction.addprefix(tok: tasmop);
  673. Begin
  674. if tok = A_NONE then
  675. Message(assem_e_syn_prefix_not_found);
  676. if Prefix = A_NONE then
  677. Prefix := tok
  678. else
  679. Message(assem_e_syn_try_add_more_prefix);
  680. end;
  681. Procedure TInstruction.addinstr(tok: tasmop);
  682. Begin
  683. if tok = A_NONE then
  684. Message(assem_e_syn_opcode_not_found);
  685. Instruction := tok;
  686. end;
  687. function TInstruction.getinstruction: tasmop;
  688. Begin
  689. getinstruction := Instruction;
  690. end;
  691. { get the current prefix of this instruction }
  692. function TInstruction.getprefix: tasmop;
  693. Begin
  694. getprefix := prefix;
  695. end;
  696. {*************************************************************************}
  697. { Local label utilities }
  698. {*************************************************************************}
  699. Constructor TAsmLabelList.Init;
  700. Begin
  701. First := nil;
  702. Last := nil;
  703. end;
  704. Procedure TAsmLabelList.Insert(s:string; lab: PLabel; emitted: boolean);
  705. {*********************************************************************}
  706. { Description: Insert a node at the end of the list with lab and }
  707. { and the name in s. The name is allocated on the heap. }
  708. { Duplicates are not allowed. }
  709. { Indicate in emitted if this label itself has been emitted, or is it}
  710. { a simple labeled instruction? }
  711. {*********************************************************************}
  712. Begin
  713. if search(s) = nil then
  714. Begin
  715. if First = nil then
  716. Begin
  717. New(First);
  718. Last := First;
  719. end
  720. else
  721. Begin
  722. New(Last^.Next);
  723. Last := Last^.Next;
  724. end;
  725. Last^.name := NewPasStr(s);
  726. Last^.Lab := lab;
  727. Last^.Next := nil;
  728. Last^.emitted := emitted;
  729. end;
  730. end;
  731. Function TAsmLabelList.Search(const s: string): PAsmLabel;
  732. {*********************************************************************}
  733. { Description: This routine searches for a label named s in the }
  734. { linked list, returns a pointer to the label if found, otherwise }
  735. { returns nil. }
  736. {*********************************************************************}
  737. Var
  738. asmlab: PAsmLabel;
  739. Begin
  740. asmlab := First;
  741. if First = nil then
  742. Begin
  743. Search := nil;
  744. exit;
  745. end;
  746. While (asmlab^.name^ <> s) and (asmlab^.Next <> nil) do
  747. asmlab := asmlab^.Next;
  748. if asmlab^.name^ = s then
  749. search := asmlab
  750. else
  751. search := nil;
  752. end;
  753. Destructor TAsmLabelList.Done;
  754. {*********************************************************************}
  755. { Description: This routine takes care of deallocating all nodes }
  756. { in the linked list, as well as deallocating the string pointers }
  757. { of these nodes. }
  758. { }
  759. { Remark: The PLabel field is NOT freed, the compiler takes care of }
  760. { this. }
  761. {*********************************************************************}
  762. Var
  763. temp: PAsmLabel;
  764. temp1: PAsmLabel;
  765. Begin
  766. temp := First;
  767. while temp <> nil do
  768. Begin
  769. Freemem(Temp^.name, length(Temp^.name^)+1);
  770. Temp1 := Temp^.Next;
  771. Dispose(Temp);
  772. Temp := Temp1;
  773. { The plabel could be deleted here, but let us not do }
  774. { it, FPC will do it instead. }
  775. end;
  776. end;
  777. Function TAsmLabelList.newpasstr(s: string): PString;
  778. {*********************************************************************}
  779. { FUNCTION NewPasStr(s:string): PString }
  780. { Description: This routine allocates a string on the heap and }
  781. { returns a pointer to the allocated string. }
  782. { }
  783. { Remarks: The string allocated should not be modified, since it's }
  784. { length will be less then 255. }
  785. { Remarks: It is assumed that HeapError will be called if an }
  786. { allocation fails. }
  787. {*********************************************************************}
  788. Var
  789. StrPtr: PString;
  790. Begin
  791. GetMem(StrPtr, length(s)+1);
  792. Move(s,StrPtr^,length(s)+1);
  793. newpasstr:= Strptr;
  794. end;
  795. {*************************************************************************}
  796. { Symbol table helper routines }
  797. {*************************************************************************}
  798. Procedure SwapOperands(Var instr: TInstruction);
  799. Var
  800. tempopr: TOperand;
  801. Begin
  802. if instr.numops = 2 then
  803. Begin
  804. tempopr := instr.operands[1];
  805. instr.operands[1] := instr.operands[2];
  806. instr.operands[2] := tempopr;
  807. end
  808. else
  809. if instr.numops = 3 then
  810. Begin
  811. tempopr := instr.operands[1];
  812. instr.operands[1] := instr.operands[3];
  813. instr.operands[3] := tempopr;
  814. end;
  815. end;
  816. Function SearchIConstant(const s:string; var l:longint): boolean;
  817. {**********************************************************************}
  818. { Description: Searches for a CONSTANT of name s in either the local }
  819. { symbol list, then in the global symbol list, and returns the value }
  820. { of that constant in l. Returns TRUE if successfull, if not found, }
  821. { or if the constant is not of correct type, then returns FALSE }
  822. { Remarks: Also handle TRUE and FALSE returning in those cases 1 and 0 }
  823. { respectively. }
  824. {**********************************************************************}
  825. var
  826. sym: psym;
  827. Begin
  828. SearchIConstant := FALSE;
  829. { check for TRUE or FALSE reserved words first }
  830. if s = 'TRUE' then
  831. Begin
  832. SearchIConstant := TRUE;
  833. l := 1;
  834. end
  835. else
  836. if s = 'FALSE' then
  837. Begin
  838. SearchIConstant := TRUE;
  839. l := 0;
  840. end
  841. else
  842. if assigned(aktprocsym) then
  843. Begin
  844. if assigned(aktprocsym^.definition) then
  845. Begin
  846. { Check the local constants }
  847. if assigned(aktprocsym^.definition^.localst) then
  848. sym := aktprocsym^.definition^.localst^.search(s)
  849. else
  850. sym := nil;
  851. if assigned(sym) then
  852. Begin
  853. if (sym^.typ = constsym) and (pconstsym(sym)^.consttype in
  854. [constord,constint,constchar,constbool]) then
  855. Begin
  856. l:=pconstsym(sym)^.value;
  857. SearchIConstant := TRUE;
  858. exit;
  859. end;
  860. end;
  861. end;
  862. end;
  863. { Check the global constants }
  864. getsym(s,false);
  865. if srsym <> nil then
  866. Begin
  867. if (srsym^.typ=constsym) and (pconstsym(srsym)^.consttype in
  868. [constord,constint,constchar,constbool]) then
  869. Begin
  870. l:=pconstsym(srsym)^.value;
  871. SearchIConstant := TRUE;
  872. exit;
  873. end;
  874. end;
  875. end;
  876. Procedure SetupResult(Var Instr:TInstruction; operandnum: byte);
  877. {**********************************************************************}
  878. { Description: This routine changes the correct fields and correct }
  879. { offset in the reference, so that it points to the __RESULT or }
  880. { @Result variable (depending on the inline asm). }
  881. { Resturns a reference with all correct offset correctly set up. }
  882. { The Operand should already point to a treference on entry. }
  883. {**********************************************************************}
  884. Begin
  885. { replace by correct offset. }
  886. if assigned(procinfo.retdef) and
  887. (procinfo.retdef<>pdef(voiddef)) then
  888. begin
  889. instr.operands[operandnum].ref.offset := procinfo.retoffset;
  890. instr.operands[operandnum].ref.base := procinfo.framepointer;
  891. { always assume that the result is valid. }
  892. procinfo.funcret_is_valid:=true;
  893. end
  894. else
  895. Message(assem_e_invalid_symbol_ref);
  896. end;
  897. Procedure FWaitWarning;
  898. begin
  899. if (target_info.target=target_GO32V2) and (cs_fp_emulation in aktswitches) then
  900. Message(assem_w_fwait_emu_prob);
  901. end;
  902. Function GetVarOffset(const base: string; const field: string;
  903. Var Offset: longint):boolean;
  904. { search and returns the offset of records/objects of the base }
  905. { with field name setup in field. }
  906. { returns 0 if not found. }
  907. { used when base is a variable or a typed constant name. }
  908. var
  909. sym:psym;
  910. p: psym;
  911. Begin
  912. GetVarOffset := FALSE;
  913. Offset := 0;
  914. { local list }
  915. if assigned(aktprocsym) then
  916. begin
  917. if assigned(aktprocsym^.definition^.localst) then
  918. sym:=aktprocsym^.definition^.localst^.search(base)
  919. else
  920. sym:=nil;
  921. if assigned(sym) then
  922. begin
  923. { field of local record variable. }
  924. if (sym^.typ=varsym) and (pvarsym(sym)^.definition^.deftype=recorddef) then
  925. begin
  926. p:=pvarsym(precdef(pvarsym(sym)^.definition)^.symtable^.search(field));
  927. if assigned(pvarsym(p)) then
  928. Begin
  929. Offset := pvarsym(p)^.address;
  930. GetVarOffset := TRUE;
  931. Exit;
  932. end;
  933. end;
  934. end
  935. else
  936. begin
  937. { field of local record parameter to routine. }
  938. if assigned(aktprocsym^.definition^.parast) then
  939. sym:=aktprocsym^.definition^.parast^.search(base)
  940. else
  941. sym:=nil;
  942. if assigned(sym) then
  943. begin
  944. if (sym^.typ=varsym) and (pvarsym(sym)^.definition^.deftype=recorddef)
  945. then
  946. begin
  947. p:=pvarsym(precdef(pvarsym(sym)^.definition)^.symtable^.search(field));
  948. if assigned(p) then
  949. Begin
  950. Offset := pvarsym(p)^.address;
  951. GetVarOffset := TRUE;
  952. Exit;
  953. end;
  954. end; { endif }
  955. end; {endif }
  956. end; { endif }
  957. end;
  958. { not found.. .now look for global variables. }
  959. getsym(base,false);
  960. sym:=srsym;
  961. if assigned(sym) then
  962. Begin
  963. { field of global record variable. }
  964. if (sym^.typ=varsym) and (pvarsym(sym)^.definition^.deftype=recorddef) then
  965. begin
  966. p:=pvarsym(precdef(pvarsym(sym)^.definition)^.symtable^.search(field));
  967. if assigned(p) then
  968. Begin
  969. Offset := pvarsym(p)^.address;
  970. GetVarOffset := TRUE;
  971. Exit;
  972. end;
  973. end
  974. else
  975. { field of global record type constant. }
  976. if (sym^.typ=typedconstsym) and (ptypedconstsym(sym)^.definition^.deftype=recorddef)
  977. then
  978. begin
  979. p:=pvarsym(precdef(pvarsym(sym)^.definition)^.symtable^.search(field));
  980. if assigned(p) then
  981. Begin
  982. Offset := pvarsym(p)^.address;
  983. GetVarOffset := TRUE;
  984. Exit;
  985. end;
  986. end
  987. end; { end looking for global variables .. }
  988. end;
  989. Function GetTypeOffset(const base: string; const field: string;
  990. Var Offset: longint):boolean;
  991. { search and returns the offset of records/objects of the base }
  992. { with field name setup in field. }
  993. { returns 0 if not found. }
  994. { used when base is a variable or a typed constant name. }
  995. var
  996. sym:psym;
  997. p: psym;
  998. Begin
  999. Offset := 0;
  1000. GetTypeOffset := FALSE;
  1001. { local list }
  1002. if assigned(aktprocsym) then
  1003. begin
  1004. if assigned(aktprocsym^.definition^.localst) then
  1005. sym:=aktprocsym^.definition^.localst^.search(base)
  1006. else
  1007. sym:=nil;
  1008. if assigned(sym) then
  1009. begin
  1010. { field of local record type. }
  1011. if (sym^.typ=typesym) and (ptypesym(sym)^.definition^.deftype=recorddef) then
  1012. begin
  1013. p:=precdef(ptypesym(sym)^.definition)^.symtable^.search(field);
  1014. if assigned(p) then
  1015. Begin
  1016. Offset := pvarsym(p)^.address;
  1017. GetTypeOffset := TRUE;
  1018. Exit;
  1019. end;
  1020. end;
  1021. end
  1022. else
  1023. begin
  1024. { field of local record type to routine. }
  1025. if assigned(aktprocsym^.definition^.parast) then
  1026. sym:=aktprocsym^.definition^.parast^.search(base)
  1027. else
  1028. sym:=nil;
  1029. if assigned(sym) then
  1030. begin
  1031. if (sym^.typ=typesym) and (ptypesym(sym)^.definition^.deftype=recorddef)
  1032. then
  1033. begin
  1034. p:=precdef(ptypesym(sym)^.definition)^.symtable^.search(field);
  1035. if assigned(p) then
  1036. Begin
  1037. Offset := pvarsym(p)^.address;
  1038. GetTypeOffset := TRUE;
  1039. Exit;
  1040. end;
  1041. end; { endif }
  1042. end; {endif }
  1043. end; { endif }
  1044. end;
  1045. { not found.. .now look for global types. }
  1046. getsym(base,false);
  1047. sym:=srsym;
  1048. if assigned(sym) then
  1049. Begin
  1050. { field of global record types. }
  1051. if (sym^.typ=typesym) and (ptypesym(sym)^.definition^.deftype=recorddef) then
  1052. begin
  1053. p:=precdef(ptypesym(sym)^.definition)^.symtable^.search(field);
  1054. if assigned(p) then
  1055. Begin
  1056. Offset := pvarsym(p)^.address;
  1057. GetTypeOffset := TRUE;
  1058. Exit;
  1059. end
  1060. end
  1061. else
  1062. { public field names of objects }
  1063. if (sym^.typ=typesym) and (ptypesym(sym)^.definition^.deftype=objectdef)then
  1064. begin
  1065. if assigned(pobjectdef(ptypesym(sym)^.definition)^.publicsyms) then
  1066. Begin
  1067. p:=pobjectdef(ptypesym(sym)^.definition)^.publicsyms^.search(field);
  1068. if assigned(p) then
  1069. Begin
  1070. Offset := pvarsym(p)^.address;
  1071. GetTypeOffset := TRUE;
  1072. Exit;
  1073. end
  1074. end;
  1075. end;
  1076. end; { end looking for global variables .. }
  1077. end;
  1078. Function CreateVarInstr(var Instr: TInstruction; const hs:string;operandnum:byte): Boolean;
  1079. { search and sets up the correct fields in the Instr record }
  1080. { for the NON-constant identifier passed to the routine. }
  1081. { if not found returns FALSE. }
  1082. var
  1083. sym:psym;
  1084. l: longint;
  1085. Begin
  1086. CreateVarInstr := FALSE;
  1087. { are we in a routine ? }
  1088. if assigned(aktprocsym) then
  1089. begin
  1090. if assigned(aktprocsym^.definition^.localst) then
  1091. { search the local list for the name of this variable. }
  1092. sym:=aktprocsym^.definition^.localst^.search(hs)
  1093. else
  1094. sym:=nil;
  1095. if assigned(sym) then
  1096. begin
  1097. if sym^.typ=varsym then
  1098. begin
  1099. { we always assume in asm statements that }
  1100. { that the variable is valid. }
  1101. pvarsym(sym)^.is_valid:=1;
  1102. instr.operands[operandnum].ref.base := procinfo.framepointer;
  1103. instr.operands[operandnum].ref.offset := - (pvarsym(sym)^.address);
  1104. { the current size is NOT overriden if it already }
  1105. { exists, such as in the case of a byte ptr, in }
  1106. { front of the identifier. }
  1107. if instr.operands[operandnum].size = S_NO then
  1108. Begin
  1109. case pvarsym(sym)^.getsize of
  1110. 1: instr.operands[operandnum].size := S_B;
  1111. 2: instr.operands[operandnum].size := S_W{ could be S_IS};
  1112. 4: instr.operands[operandnum].size := S_L{ could be S_IL or S_FS};
  1113. 8: instr.operands[operandnum].size := S_IQ{ could be S_D or S_FL};
  1114. extended_size: instr.operands[operandnum].size := S_FX;
  1115. else
  1116. { this is in the case where the instruction is LEA }
  1117. { or something like that, in that case size is not }
  1118. { important. }
  1119. instr.operands[operandnum].size := S_NO;
  1120. end; { end case }
  1121. end;
  1122. { ok, finished for thir variable. }
  1123. CreateVarInstr := TRUE;
  1124. Exit;
  1125. end
  1126. else
  1127. { call to local function }
  1128. if (sym^.typ=procsym) then
  1129. begin
  1130. { free the memory before changing the symbol name. }
  1131. if assigned(instr.operands[operandnum].ref.symbol) then
  1132. FreeMem(instr.operands[operandnum].ref.symbol,
  1133. length(instr.operands[operandnum].ref.symbol^)+1);
  1134. instr.operands[operandnum].ref.symbol:=newpasstr(pprocsym(sym)^.definition^.mangledname);
  1135. CreateVarInstr := TRUE;
  1136. Exit;
  1137. end
  1138. { else
  1139. if (sym^.typ = typedconstsym) then
  1140. Begin}
  1141. { UGH????? pprocsym??? }
  1142. { instr.operands[operandnum].ref.symbol:=newpasstr(pprocsym(sym)^.definition^.mangledname);}
  1143. {* the current size is NOT overriden if it already *}
  1144. {* exists, such as in the case of a byte ptr, in *}
  1145. {* front of the identifier. *}
  1146. { if instr.operands[operandnum].size = S_NO then
  1147. Begin
  1148. case ptypedconstsym(sym)^.definition^.size of
  1149. 1: instr.operands[operandnum].size := S_B;
  1150. 2: instr.operands[operandnum].size := S_W;
  1151. 4: instr.operands[operandnum].size := S_L;
  1152. 8: instr.operands[operandnum].size := S_IQ;
  1153. extended_size: instr.operands[operandnum].size := S_FX;
  1154. else}
  1155. {* this is in the case where the instruction is LEA *}
  1156. {* or something like that, in that case size is not *}
  1157. {* important. *}
  1158. { instr.operands[operandnum].size := S_NO;}
  1159. { end;} {* end case *}
  1160. { end;}
  1161. {* ok, finished for this variable. *}
  1162. { CreateVarInstr := TRUE;
  1163. Exit;
  1164. end }
  1165. end;
  1166. { now check for parameters passed to routine }
  1167. { else}
  1168. begin
  1169. if assigned(aktprocsym^.definition^.parast) then
  1170. sym:=aktprocsym^.definition^.parast^.search(hs)
  1171. else
  1172. sym:=nil;
  1173. if assigned(sym) then
  1174. begin
  1175. if sym^.typ=varsym then
  1176. begin
  1177. l:=pvarsym(sym)^.address;
  1178. { set offset }
  1179. inc(l,aktprocsym^.definition^.parast^.call_offset);
  1180. pvarsym(sym)^.is_valid:=1;
  1181. instr.operands[operandnum].ref.base := procinfo.framepointer;
  1182. instr.operands[operandnum].ref.offset := l;
  1183. { the current size is NOT overriden if it already }
  1184. { exists, such as in the case of a byte ptr, in }
  1185. { front of the identifier. }
  1186. if instr.operands[operandnum].size = S_NO then
  1187. Begin
  1188. case pvarsym(sym)^.getsize of
  1189. 1: instr.operands[operandnum].size := S_B;
  1190. 2: instr.operands[operandnum].size := S_W;
  1191. 4: instr.operands[operandnum].size := S_L;
  1192. 8: instr.operands[operandnum].size := S_IQ;
  1193. extended_size: instr.operands[operandnum].size := S_FX;
  1194. else
  1195. { this is in the case where the instruction is LEA }
  1196. { or something like that, in that case size is not }
  1197. { important. }
  1198. instr.operands[operandnum].size := S_NO;
  1199. end; { end case }
  1200. end; { endif }
  1201. CreateVarInstr := TRUE;
  1202. Exit;
  1203. end; { endif }
  1204. end; {endif }
  1205. end; { endif }
  1206. end;
  1207. { not found.. .now look for global variables. }
  1208. getsym(hs,false);
  1209. sym:=srsym;
  1210. if assigned(sym) then
  1211. Begin
  1212. if (sym^.typ = varsym) or (sym^.typ = typedconstsym) then
  1213. Begin
  1214. { free the memory before changing the symbol name. }
  1215. if assigned(instr.operands[operandnum].ref.symbol) then
  1216. FreeMem(instr.operands[operandnum].ref.symbol,
  1217. length(instr.operands[operandnum].ref.symbol^)+1);
  1218. instr.operands[operandnum].ref.symbol:=newpasstr(sym^.mangledname);
  1219. { the current size is NOT overriden if it already }
  1220. { exists, such as in the case of a byte ptr, in }
  1221. { front of the identifier. }
  1222. if (instr.operands[operandnum].size = S_NO) and (sym^.typ = varsym) then
  1223. Begin
  1224. case pvarsym(sym)^.getsize of
  1225. 1: instr.operands[operandnum].size := S_B;
  1226. 2: instr.operands[operandnum].size := S_W;
  1227. 4: instr.operands[operandnum].size := S_L;
  1228. 8: instr.operands[operandnum].size := S_IQ;
  1229. else
  1230. { this is in the case where the instruction is LEA }
  1231. { or something like that, in that case size is not }
  1232. { important. }
  1233. instr.operands[operandnum].size := S_NO;
  1234. end;
  1235. end
  1236. else
  1237. if (instr.operands[operandnum].size = S_NO) and (sym^.typ = typedconstsym) then
  1238. Begin
  1239. { only these are valid sizes, otherwise prefixes are }
  1240. { required. }
  1241. case ptypedconstsym(sym)^.definition^.size of
  1242. 1: instr.operands[operandnum].size := S_B;
  1243. 2: instr.operands[operandnum].size := S_W;
  1244. 4: instr.operands[operandnum].size := S_L;
  1245. 8: instr.operands[operandnum].size := S_IQ;
  1246. else
  1247. { this is in the case where the instruction is LEA }
  1248. { or something like that, in that case size is not }
  1249. { important. }
  1250. instr.operands[operandnum].size := S_NO;
  1251. end;
  1252. end; { endif }
  1253. CreateVarInstr := TRUE;
  1254. Exit;
  1255. end;
  1256. if (sym^.typ=procsym) then
  1257. begin
  1258. if assigned(pprocsym(sym)^.definition^.nextoverloaded) then
  1259. Message(assem_w_calling_overload_func);
  1260. { free the memory before changing the symbol name. }
  1261. if assigned(instr.operands[operandnum].ref.symbol) then
  1262. FreeMem(instr.operands[operandnum].ref.symbol,
  1263. length(instr.operands[operandnum].ref.symbol^)+1);
  1264. instr.operands[operandnum].ref.symbol:=
  1265. newpasstr(pprocsym(sym)^.definition^.mangledname);
  1266. CreateVarInstr := TRUE;
  1267. Exit;
  1268. end;
  1269. end; { end looking for global variables .. }
  1270. end;
  1271. Function SearchLabel(const s: string; var hl: plabel): boolean;
  1272. {**********************************************************************}
  1273. { Description: Searches for a pascal label definition, first in the }
  1274. { local symbol list and then in the global symbol list. If found then }
  1275. { return pointer to label and return true, otherwise returns false. }
  1276. {**********************************************************************}
  1277. var
  1278. sym: psym;
  1279. Begin
  1280. SearchLabel := FALSE;
  1281. if assigned(aktprocsym) then
  1282. Begin
  1283. { Check the local constants }
  1284. if assigned(aktprocsym^.definition) then
  1285. Begin
  1286. if assigned(aktprocsym^.definition^.localst) then
  1287. sym := aktprocsym^.definition^.localst^.search(s)
  1288. else
  1289. sym := nil;
  1290. if assigned(sym) then
  1291. Begin
  1292. if (sym^.typ = labelsym) then
  1293. Begin
  1294. hl:=plabelsym(sym)^.number;
  1295. SearchLabel := TRUE;
  1296. exit;
  1297. end;
  1298. end;
  1299. end;
  1300. end;
  1301. { Check the global label symbols... }
  1302. getsym(s,false);
  1303. if srsym <> nil then
  1304. Begin
  1305. if (srsym^.typ=labelsym) then
  1306. Begin
  1307. hl:=plabelsym(srsym)^.number;
  1308. SearchLabel:= TRUE;
  1309. exit;
  1310. end;
  1311. end;
  1312. end;
  1313. {*************************************************************************}
  1314. { Instruction Generation Utilities }
  1315. {*************************************************************************}
  1316. Procedure ConcatString(p : paasmoutput;s:string);
  1317. {*********************************************************************}
  1318. { PROCEDURE ConcatString(s:string); }
  1319. { Description: This routine adds the character chain pointed to in }
  1320. { s to the instruction linked list. }
  1321. {*********************************************************************}
  1322. Var
  1323. pc: PChar;
  1324. Begin
  1325. getmem(pc,length(s)+1);
  1326. p^.concat(new(pai_string,init_length_pchar(strpcopy(pc,s),length(s))));
  1327. end;
  1328. Procedure ConcatPasString(p : paasmoutput;s:string);
  1329. {*********************************************************************}
  1330. { PROCEDURE ConcatPasString(s:string); }
  1331. { Description: This routine adds the character chain pointed to in }
  1332. { s to the instruction linked list, contrary to ConcatString it }
  1333. { uses a pascal style string, so it conserves null characters. }
  1334. {*********************************************************************}
  1335. Begin
  1336. p^.concat(new(pai_string,init(s)));
  1337. end;
  1338. Procedure ConcatDirect(p : paasmoutput;s:string);
  1339. {*********************************************************************}
  1340. { PROCEDURE ConcatDirect(s:string) }
  1341. { Description: This routine output the string directly to the asm }
  1342. { output, it is only sed when writing special labels in AT&T mode, }
  1343. { and should not be used without due consideration, since it may }
  1344. { cause problems. }
  1345. {*********************************************************************}
  1346. Var
  1347. pc: PChar;
  1348. Begin
  1349. getmem(pc,length(s)+1);
  1350. p^.concat(new(pai_direct,init(strpcopy(pc,s))));
  1351. end;
  1352. Procedure ConcatConstant(p: paasmoutput; value: longint; maxvalue: longint);
  1353. {*********************************************************************}
  1354. { PROCEDURE ConcatConstant(value: longint; maxvalue: longint); }
  1355. { Description: This routine adds the value constant to the current }
  1356. { instruction linked list. }
  1357. { maxvalue -> indicates the size of the data to initialize: }
  1358. { $ff -> create a byte node. }
  1359. { $ffff -> create a word node. }
  1360. { $ffffffff -> create a dword node. }
  1361. {*********************************************************************}
  1362. Begin
  1363. if value > maxvalue then
  1364. Begin
  1365. Message(assem_e_constant_out_of_bounds);
  1366. { assuming a value of maxvalue }
  1367. value := maxvalue;
  1368. end;
  1369. if maxvalue = $ff then
  1370. p^.concat(new(pai_const,init_8bit(byte(value))))
  1371. else
  1372. if maxvalue = $ffff then
  1373. p^.concat(new(pai_const,init_16bit(word(value))))
  1374. else
  1375. if maxvalue = $ffffffff then
  1376. p^.concat(new(pai_const,init_32bit(longint(value))));
  1377. end;
  1378. Procedure ConcatRealConstant(p : paasmoutput;value: bestreal; real_typ : tfloattype);
  1379. {***********************************************************************}
  1380. { PROCEDURE ConcatRealConstant(value: bestreal; real_typ : tfloattype); }
  1381. { Description: This routine adds the value constant to the current }
  1382. { instruction linked list. }
  1383. { real_typ -> indicates the type of the real data to initialize: }
  1384. { s32real -> create a single node. }
  1385. { s64real -> create a double node. }
  1386. { s80real -> create an extended node. }
  1387. { s64bit -> create a comp node. }
  1388. { f32bit -> create a fixed node. (not used normally) }
  1389. {***********************************************************************}
  1390. Begin
  1391. case real_typ of
  1392. s32real : p^.concat(new(pai_single,init(value)));
  1393. s64real : p^.concat(new(pai_double,init(value)));
  1394. s80real : p^.concat(new(pai_extended,init(value)));
  1395. s64bit : p^.concat(new(pai_comp,init(value)));
  1396. f32bit : p^.concat(new(pai_const,init_32bit(trunc(value*$10000))));
  1397. end;
  1398. end;
  1399. Procedure ConcatLabel(p: paasmoutput;op : tasmop;var l : plabel);
  1400. {*********************************************************************}
  1401. { PROCEDURE ConcatLabel }
  1402. { Description: This routine either emits a label or a labeled }
  1403. { instruction to the linked list of instructions. }
  1404. {*********************************************************************}
  1405. begin
  1406. if op=A_LABEL then
  1407. p^.concat(new(pai_label,init(l)))
  1408. else
  1409. p^.concat(new(pai_labeled,init(op,l)))
  1410. end;
  1411. procedure ConcatPublic(p:paasmoutput;const s : string);
  1412. {*********************************************************************}
  1413. { PROCEDURE ConcatPublic }
  1414. { Description: This routine emits an global definition to the }
  1415. { linked list of instructions.(used by AT&T styled asm) }
  1416. {*********************************************************************}
  1417. begin
  1418. p^.concat(new(pai_symbol,init_global(s)));
  1419. { concat_internal(s,EXT_NEAR); done in aasm }
  1420. end;
  1421. procedure ConcatLocal(p:paasmoutput;const s : string);
  1422. {*********************************************************************}
  1423. { PROCEDURE ConcatLocal }
  1424. { Description: This routine emits an local definition to the }
  1425. { linked list of instructions. }
  1426. {*********************************************************************}
  1427. begin
  1428. p^.concat(new(pai_symbol,init(s)));
  1429. { concat_internal(s,EXT_NEAR); done in aasm }
  1430. end;
  1431. Procedure ConcatGlobalBss(const s : string;size : longint);
  1432. {*********************************************************************}
  1433. { PROCEDURE ConcatGlobalBss }
  1434. { Description: This routine emits an global datablock to the }
  1435. { linked list of instructions. }
  1436. {*********************************************************************}
  1437. begin
  1438. bsssegment^.concat(new(pai_datablock,init_global(s,size)));
  1439. { concat_internal(s,EXT_NEAR); done in aasm }
  1440. end;
  1441. Procedure ConcatLocalBss(const s : string;size : longint);
  1442. {*********************************************************************}
  1443. { PROCEDURE ConcatLocalBss }
  1444. { Description: This routine emits a local datablcok to the }
  1445. { linked list of instructions. }
  1446. {*********************************************************************}
  1447. begin
  1448. bsssegment^.concat(new(pai_datablock,init(s,size)));
  1449. { concat_internal(s,EXT_NEAR); done in aasm }
  1450. end;
  1451. { add to list of external labels }
  1452. Procedure ConcatExternal(const s : string;typ : texternal_typ);
  1453. {*********************************************************************}
  1454. { PROCEDURE ConcatExternal }
  1455. { Description: This routine emits an external definition to the }
  1456. { linked list of instructions.(used by AT&T styled asm) }
  1457. {*********************************************************************}
  1458. { check if in internal list and remove it there }
  1459. var p : pai_external;
  1460. begin
  1461. p:=search_assembler_symbol(internals,s,typ);
  1462. if p<>nil then internals^.remove(p);
  1463. concat_external(s,typ);
  1464. end;
  1465. { add to internal list of labels }
  1466. Procedure ConcatInternal(const s : string;typ : texternal_typ);
  1467. {*********************************************************************}
  1468. { PROCEDURE ConcatInternal }
  1469. { Description: This routine emits an internal definition of a symbol }
  1470. { (used by AT&T styled asm for undefined labels) }
  1471. {*********************************************************************}
  1472. begin
  1473. concat_internal(s,typ);
  1474. end;
  1475. end.
  1476. {
  1477. $Log$
  1478. Revision 1.2 1998-04-29 10:33:43 pierre
  1479. + added some code for ansistring (not complete nor working yet)
  1480. * corrected operator overloading
  1481. * corrected nasm output
  1482. + started inline procedures
  1483. + added starstarn : use ** for exponentiation (^ gave problems)
  1484. + started UseTokenInfo cond to get accurate positions
  1485. Revision 1.1.1.1 1998/03/25 11:18:12 root
  1486. * Restored version
  1487. Revision 1.15 1998/03/10 01:17:14 peter
  1488. * all files have the same header
  1489. * messages are fully implemented, EXTDEBUG uses Comment()
  1490. + AG... files for the Assembler generation
  1491. Revision 1.14 1998/03/09 12:58:10 peter
  1492. * FWait warning is only showed for Go32V2 and $E+
  1493. * opcode tables moved to i386.pas/m68k.pas to reduce circular uses (and
  1494. for m68k the same tables are removed)
  1495. + $E for i386
  1496. Revision 1.13 1998/03/03 16:45:16 peter
  1497. + message support for assembler parsers
  1498. Revision 1.12 1998/03/02 01:48:02 peter
  1499. * renamed target_DOS to target_GO32V1
  1500. + new verbose system, merged old errors and verbose units into one new
  1501. verbose.pas, so errors.pas is obsolete
  1502. Revision 1.11 1998/02/13 10:34:34 daniel
  1503. * Made Motorola version compilable.
  1504. * Fixed optimizer
  1505. Revision 1.10 1998/01/09 19:21:19 carl
  1506. + added support for m68k
  1507. Revision 1.7 1997/12/14 22:43:17 florian
  1508. + command line switch -Xs for DOS (passes -s to the linker to strip symbols from
  1509. executable)
  1510. * some changes of Carl-Eric implemented
  1511. Revision 1.5 1997/12/09 13:23:54 carl
  1512. + less processor specific
  1513. - moved searching for externals/internal symbols from CreateVarInstr to
  1514. ratti386.pas (this would cause invalid stuff in rai386.pas!)
  1515. Revision 1.4 1997/12/04 12:20:39 pierre
  1516. +* MMX instructions added to att output with a warning that
  1517. GNU as version >= 2.81 is needed
  1518. bug in reading of reals under att syntax corrected
  1519. Revision 1.3 1997/12/01 17:42:49 pierre
  1520. + added some more functionnality to the assembler parser
  1521. Revision 1.2 1997/11/27 17:55:11 carl
  1522. * made it compile under bp (one comment was nested)
  1523. Revision 1.1.1.1 1997/11/27 08:32:50 michael
  1524. FPC Compiler CVS start
  1525. Pre-CVS log:
  1526. CEC Carl-Eric Codere
  1527. FK Florian Klaempfl
  1528. PM Pierre Muller
  1529. + feature added
  1530. - removed
  1531. * bug fixed or changed
  1532. 11th november 1997:
  1533. * fixed problems when using reserved words TRUE and FALSE (CEC).
  1534. 22th november 1997:
  1535. * changed operator (reserved word) into _operator (PM).
  1536. }