rai386.pas 137 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487
  1. {
  2. $Id$
  3. Copyright (c) 1997-98 by Carl Eric Codere
  4. Does the parsing process for the intel styled inline assembler.
  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. }
  18. Unit Rai386;
  19. {**********************************************************************}
  20. { WARNING }
  21. {**********************************************************************}
  22. { Any modification in the order or removal of terms in the tables }
  23. { in i386.pas and intasmi3.pas will BREAK the code in this unit, }
  24. { unless the appropriate changes are made to this unit. Addition }
  25. { of terms though, will not change the code herein. }
  26. {**********************************************************************}
  27. {--------------------------------------------------------------------}
  28. { LEFT TO DO: }
  29. {--------------------------------------------------------------------}
  30. { o Add support for floating point opcodes. }
  31. { o Handle module overrides also... such as crt.white or }
  32. { crt.delay and local typed constants. }
  33. { o Handle label references }
  34. { o Add support for TP styled segment overrides, when the opcode }
  35. { table will be completed. }
  36. { o Add imul,shld and shrd support with references and CL }
  37. { i386.pas requires to be updated to do this. }
  38. { o Support for (* *) tp styled comments, this support should be }
  39. { added in asmgetchar in scanner.pas (it cannot be implemented }
  40. { here without causing errors such as in : }
  41. { (* "openbrace" AComment *) }
  42. { (presently an infinite loop will be created if a (* styled }
  43. { comment is found). }
  44. { o Bugfix of ao_imm8s for IMUL. (Currently the 3 operand imul will }
  45. { be considered as invalid because I use ao_imm8 and the table }
  46. { uses ao_imm8s). }
  47. {--------------------------------------------------------------------}
  48. Interface
  49. uses
  50. tree,i386;
  51. function assemble: ptree;
  52. const
  53. { this variable is TRUE if the lookup tables have already been setup }
  54. { for fast access. On the first call to assemble the tables are setup }
  55. { and stay set up. }
  56. _asmsorted: boolean = FALSE;
  57. firstreg = R_EAX;
  58. lastreg = R_ST7;
  59. type
  60. tiasmops = array[firstop..lastop] of string[7];
  61. piasmops = ^tiasmops;
  62. var
  63. { sorted tables of opcodes }
  64. iasmops: piasmops;
  65. { uppercased tables of registers }
  66. iasmregs: array[firstreg..lastreg] of string[6];
  67. Implementation
  68. Uses
  69. aasm,globals,AsmUtils,strings,hcodegen,scanner,
  70. cobjects,verbose,types;
  71. type
  72. tinteltoken = (
  73. AS_NONE,AS_LABEL,AS_LLABEL,AS_STRING,AS_HEXNUM,AS_OCTALNUM,
  74. AS_BINNUM,AS_COMMA,AS_LBRACKET,AS_RBRACKET,AS_LPAREN,
  75. AS_RPAREN,AS_COLON,AS_DOT,AS_PLUS,AS_MINUS,AS_STAR,AS_INTNUM,
  76. AS_SEPARATOR,AS_ID,AS_REGISTER,AS_OPCODE,AS_SLASH,
  77. {------------------ Assembler directives --------------------}
  78. AS_DB,AS_DW,AS_DD,AS_END,
  79. {------------------ Assembler Operators --------------------}
  80. AS_BYTE,AS_WORD,AS_DWORD,AS_QWORD,AS_TBYTE,AS_NEAR,AS_FAR,
  81. AS_HIGH,AS_LOW,AS_OFFSET,AS_SEG,AS_TYPE,AS_PTR,AS_MOD,AS_SHL,AS_SHR,AS_NOT,
  82. AS_AND,AS_OR,AS_XOR);
  83. tasmkeyword = string[6];
  84. const
  85. { These tokens should be modified accordingly to the modifications }
  86. { in the different enumerations. }
  87. firstdirective = AS_DB;
  88. lastdirective = AS_END;
  89. firstoperator = AS_BYTE;
  90. lastoperator = AS_XOR;
  91. firstsreg = R_CS;
  92. lastsreg = R_SS;
  93. { this is a hack to accept all opcodes }
  94. { in the opcode table. }
  95. { check is done until A_POPFD }
  96. { otherwise no check. }
  97. lastop_in_table = A_POPFD;
  98. _count_asmdirectives = longint(lastdirective)-longint(firstdirective);
  99. _count_asmoperators = longint(lastoperator)-longint(firstoperator);
  100. _count_asmprefixes = 5;
  101. _count_asmspecialops = 25;
  102. _count_asmoverrides = 3;
  103. _asmdirectives : array[0.._count_asmdirectives] of tasmkeyword =
  104. ('DB','DW','DD','END');
  105. { problems with shl,shr,not,and,or and xor, they are }
  106. { context sensitive. }
  107. _asmoperators : array[0.._count_asmoperators] of tasmkeyword = (
  108. 'BYTE','WORD','DWORD','QWORD','TBYTE','NEAR','FAR','HIGH',
  109. 'LOW','OFFSET','SEG','TYPE','PTR','MOD','SHL','SHR','NOT','AND',
  110. 'OR','XOR');
  111. {------------------ Missing opcodes from std list ----------------}
  112. _asmprefixes: array[0.._count_asmprefixes] of tasmkeyword = (
  113. 'REPNE','REPE','REP','REPZ','REPNZ','LOCK');
  114. _asmoverrides: array[0.._count_asmoverrides] of tasmkeyword =
  115. ('SEGCS','SEGDS','SEGES','SEGSS');
  116. _overridetokens: array[0.._count_asmoverrides] of tregister =
  117. (R_CS,R_DS,R_ES,R_SS);
  118. _prefixtokens: array[0.._count_asmprefixes] of tasmop = (
  119. A_REPNE,A_REPE,A_REP,A_REPE,A_REPNE,A_LOCK);
  120. _specialops: array[0.._count_asmspecialops] of tasmkeyword = (
  121. 'CMPSB','CMPSW','CMPSD','INSB','INSW','INSD','OUTSB','OUTSW','OUTSD',
  122. 'SCASB','SCASW','SCASD','STOSB','STOSW','STOSD','MOVSB','MOVSW','MOVSD',
  123. 'LODSB','LODSW','LODSD','LOCK','SEGCS','SEGDS','SEGES','SEGSS');
  124. _specialopstokens: array[0.._count_asmspecialops] of tasmop = (
  125. A_CMPS,A_CMPS,A_CMPS,A_INS,A_INS,A_INS,A_OUTS,A_OUTS,A_OUTS,
  126. A_SCAS,A_SCAS,A_SCAS,A_STOS,A_STOS,A_STOS,A_MOVS,A_MOVS,A_MOVS,
  127. A_LODS,A_LODS,A_LODS,A_LOCK,A_NONE,A_NONE,A_NONE,A_NONE);
  128. {------------------------------------------------------------------}
  129. { register type definition table for easier searching }
  130. _regtypes:array[firstreg..lastreg] of longint =
  131. (ao_reg32,ao_reg32,ao_reg32,ao_reg32,ao_reg32,ao_reg32,ao_reg32,ao_reg32,
  132. ao_reg16,ao_reg16,ao_reg16,ao_reg16,ao_reg16,ao_reg16,ao_reg16,ao_reg16,
  133. ao_reg8,ao_reg8,ao_reg8,ao_reg8,ao_reg8,ao_reg8,ao_reg8,ao_reg8,
  134. ao_none,ao_sreg2,ao_sreg2,ao_sreg2,ao_sreg3,ao_sreg3,ao_sreg2,
  135. ao_floatacc,ao_floatacc,ao_floatreg,ao_floatreg,ao_floatreg,ao_floatreg,
  136. ao_floatreg,ao_floatreg,ao_floatreg);
  137. _regsizes: array[firstreg..lastreg] of topsize =
  138. (S_L,S_L,S_L,S_L,S_L,S_L,S_L,S_L,
  139. S_W,S_W,S_W,S_W,S_W,S_W,S_W,S_W,
  140. S_B,S_B,S_B,S_B,S_B,S_B,S_B,S_B,
  141. { segment register }
  142. S_W,S_W,S_W,S_W,S_W,S_W,S_W,
  143. { can also be S_S or S_T - must be checked at run-time }
  144. S_Q,S_Q,S_Q,S_Q,S_Q,S_Q,S_Q,S_Q,S_Q);
  145. _constsizes: array[S_NO..S_S] of longint =
  146. (0,ao_imm8,ao_imm16,ao_imm32,0,0,0,0,ao_imm32);
  147. const
  148. newline = #10;
  149. firsttoken : boolean = TRUE;
  150. operandnum : byte = 0;
  151. var
  152. { context for SHL,SHR,AND,NOT,OR,XOR operators }
  153. { if set to true GetToken will return these }
  154. { as operators, otherwise will return these as }
  155. { opcodes. }
  156. inexpression: boolean;
  157. p : paasmoutput;
  158. actasmtoken: tinteltoken;
  159. actasmpattern: string;
  160. c: char;
  161. Instr: TInstruction;
  162. labellist: TAsmLabelList;
  163. old_exit : pointer;
  164. Procedure SetupTables;
  165. { creates uppercased symbol tables for speed access }
  166. var
  167. i: tasmop;
  168. j: tregister;
  169. Begin
  170. Message(assem_d_creating_lookup_tables);
  171. { opcodes }
  172. new(iasmops);
  173. for i:=firstop to lastop do
  174. iasmops^[i] := upper(int_op2str[i]);
  175. { opcodes }
  176. for j:=firstreg to lastreg do
  177. iasmregs[j] := upper(int_reg2str[j]);
  178. end;
  179. procedure rai386_exit;{$ifndef FPC}far;{$endif}
  180. begin
  181. if assigned(iasmops) then
  182. dispose(iasmops);
  183. exitproc:=old_exit;
  184. end;
  185. {---------------------------------------------------------------------}
  186. { Routines for the tokenizing }
  187. {---------------------------------------------------------------------}
  188. function is_asmopcode(const s: string):Boolean;
  189. {*********************************************************************}
  190. { FUNCTION is_asmopcode(s: string):Boolean }
  191. { Description: Determines if the s string is a valid opcode }
  192. { if so returns TRUE otherwise returns FALSE. }
  193. {*********************************************************************}
  194. var
  195. i: tasmop;
  196. j: byte;
  197. Begin
  198. is_asmopcode := FALSE;
  199. for i:=firstop to lastop do
  200. begin
  201. if s = iasmops^[i] then
  202. begin
  203. is_asmopcode:=TRUE;
  204. exit;
  205. end;
  206. end;
  207. { not found yet, search for extended opcodes }
  208. for j:=0 to _count_asmspecialops do
  209. Begin
  210. if s = _specialops[j] then
  211. Begin
  212. is_asmopcode:=TRUE;
  213. exit;
  214. end;
  215. end;
  216. end;
  217. Procedure is_asmdirective(const s: string; var token: tinteltoken);
  218. {*********************************************************************}
  219. { FUNCTION is_asmdirective(s: string; var token: tinteltoken):Boolean }
  220. { Description: Determines if the s string is a valid directive }
  221. { (an operator can occur in operand fields, while a directive cannot) }
  222. { if so returns the directive token, otherwise does not change token.}
  223. {*********************************************************************}
  224. var
  225. i:byte;
  226. Begin
  227. for i:=0 to _count_asmdirectives do
  228. begin
  229. if s=_asmdirectives[i] then
  230. begin
  231. token := tinteltoken(longint(firstdirective)+i);
  232. exit;
  233. end;
  234. end;
  235. end;
  236. Procedure is_asmoperator(const s: string; var token: tinteltoken);
  237. {*********************************************************************}
  238. { FUNCTION is_asmoperator(s: string; var token: tinteltoken): Boolean}
  239. { Description: Determines if the s string is a valid operator }
  240. { (an operator can occur in operand fields, while a directive cannot) }
  241. { if so returns the operator token, otherwise does not change token. }
  242. {*********************************************************************}
  243. var
  244. i:longint;
  245. Begin
  246. for i:=0 to _count_asmoperators do
  247. begin
  248. if s=_asmoperators[i] then
  249. begin
  250. token := tinteltoken(longint(firstoperator)+i);
  251. exit;
  252. end;
  253. end;
  254. end;
  255. Procedure is_register(const s: string; var token: tinteltoken);
  256. {*********************************************************************}
  257. { PROCEDURE is_register(s: string; var token: tinteltoken); }
  258. { Description: Determines if the s string is a valid register, if }
  259. { so return token equal to A_REGISTER, otherwise does not change token}
  260. {*********************************************************************}
  261. Var
  262. i: tregister;
  263. Begin
  264. for i:=firstreg to lastreg do
  265. begin
  266. if s=iasmregs[i] then
  267. begin
  268. token := AS_REGISTER;
  269. exit;
  270. end;
  271. end;
  272. end;
  273. Function GetToken: tinteltoken;
  274. {*********************************************************************}
  275. { FUNCTION GetToken: tinteltoken; }
  276. { Description: This routine returns intel assembler tokens and }
  277. { does some minor syntax error checking. }
  278. {*********************************************************************}
  279. var
  280. j: integer;
  281. token: tinteltoken;
  282. forcelabel: boolean;
  283. errorflag : boolean;
  284. begin
  285. errorflag := FALSE;
  286. forcelabel := FALSE;
  287. actasmpattern :='';
  288. {* INIT TOKEN TO NOTHING *}
  289. token := AS_NONE;
  290. { while space and tab , continue scan... }
  291. while (c in [' ',#9]) do
  292. c := asmgetchar;
  293. { Possiblities for first token in a statement: }
  294. { Local Label, Label, Directive, Prefix or Opcode.... }
  295. if firsttoken and not (c in [newline,#13,'{',';']) then
  296. begin
  297. firsttoken := FALSE;
  298. if c = '@' then
  299. begin
  300. token := AS_LLABEL; { this is a local label }
  301. { Let us point to the next character }
  302. c := asmgetchar;
  303. end;
  304. while c in ['A'..'Z','a'..'z','0'..'9','_','@'] do
  305. begin
  306. { if there is an at_sign, then this must absolutely be a label }
  307. if c = '@' then forcelabel:=TRUE;
  308. actasmpattern := actasmpattern + c;
  309. c := asmgetchar;
  310. end;
  311. uppervar(actasmpattern);
  312. if c = ':' then
  313. begin
  314. case token of
  315. AS_NONE: token := AS_LABEL;
  316. AS_LLABEL: ; { do nothing }
  317. end; { end case }
  318. { let us point to the next character }
  319. c := asmgetchar;
  320. gettoken := token;
  321. exit;
  322. end;
  323. { Are we trying to create an identifier with }
  324. { an at-sign...? }
  325. if forcelabel then
  326. Message(assem_e_none_label_contain_at);
  327. If is_asmopcode(actasmpattern) then
  328. Begin
  329. gettoken := AS_OPCODE;
  330. { check if we are in an expression }
  331. { then continue with asm directives }
  332. if not inexpression then
  333. exit;
  334. end;
  335. is_asmdirective(actasmpattern, token);
  336. if (token <> AS_NONE) then
  337. Begin
  338. gettoken := token;
  339. exit
  340. end
  341. else
  342. begin
  343. gettoken := AS_NONE;
  344. Message1(assem_e_invalid_operand,actasmpattern);
  345. end;
  346. end
  347. else { else firsttoken }
  348. { Here we must handle all possible cases }
  349. begin
  350. case c of
  351. '@': { possiblities : - local label reference , such as in jmp @local1 }
  352. { - @Result, @Code or @Data special variables. }
  353. begin
  354. actasmpattern := c;
  355. c:= asmgetchar;
  356. while c in ['A'..'Z','a'..'z','0'..'9','_','@'] do
  357. begin
  358. actasmpattern := actasmpattern + c;
  359. c := asmgetchar;
  360. end;
  361. uppervar(actasmpattern);
  362. gettoken := AS_ID;
  363. exit;
  364. end;
  365. { identifier, register, opcode, prefix or directive }
  366. 'A'..'Z','a'..'z','_': begin
  367. actasmpattern := c;
  368. c:= asmgetchar;
  369. while c in ['A'..'Z','a'..'z','0'..'9','_'] do
  370. begin
  371. actasmpattern := actasmpattern + c;
  372. c := asmgetchar;
  373. end;
  374. uppervar(actasmpattern);
  375. If is_asmopcode(actasmpattern) then
  376. Begin
  377. gettoken := AS_OPCODE;
  378. { if we are not in a constant }
  379. { expression than this is an }
  380. { opcode. }
  381. if not inexpression then
  382. exit;
  383. end;
  384. is_register(actasmpattern, token);
  385. is_asmoperator(actasmpattern,token);
  386. is_asmdirective(actasmpattern,token);
  387. { if found }
  388. if (token <> AS_NONE) then
  389. begin
  390. gettoken := token;
  391. exit;
  392. end
  393. { this is surely an identifier }
  394. else
  395. token := AS_ID;
  396. gettoken := token;
  397. exit;
  398. end;
  399. { override operator... not supported }
  400. '&': begin
  401. Message(assem_w_override_op_not_supported);
  402. c:=asmgetchar;
  403. gettoken := AS_NONE;
  404. end;
  405. { string or character }
  406. '''' :
  407. begin
  408. actasmpattern:='';
  409. while true do
  410. begin
  411. if c = '''' then
  412. begin
  413. c:=asmgetchar;
  414. if c=newline then
  415. begin
  416. Message(scan_f_string_exceeds_line);
  417. break;
  418. end;
  419. repeat
  420. if c=''''then
  421. begin
  422. c:=asmgetchar;
  423. if c='''' then
  424. begin
  425. actasmpattern:=actasmpattern+'''';
  426. c:=asmgetchar;
  427. if c=newline then
  428. begin
  429. Message(scan_f_string_exceeds_line);
  430. break;
  431. end;
  432. end
  433. else break;
  434. end
  435. else
  436. begin
  437. actasmpattern:=actasmpattern+c;
  438. c:=asmgetchar;
  439. if c=newline then
  440. begin
  441. Message(scan_f_string_exceeds_line);
  442. break
  443. end;
  444. end;
  445. until false; { end repeat }
  446. end
  447. else break; { end if }
  448. end; { end while }
  449. token:=AS_STRING;
  450. gettoken := token;
  451. exit;
  452. end;
  453. { string or character }
  454. '"' :
  455. begin
  456. actasmpattern:='';
  457. while true do
  458. begin
  459. if c = '"' then
  460. begin
  461. c:=asmgetchar;
  462. if c=newline then
  463. begin
  464. Message(scan_f_string_exceeds_line);
  465. break;
  466. end;
  467. repeat
  468. if c='"'then
  469. begin
  470. c:=asmgetchar;
  471. if c='"' then
  472. begin
  473. actasmpattern:=actasmpattern+'"';
  474. c:=asmgetchar;
  475. if c=newline then
  476. begin
  477. Message(scan_f_string_exceeds_line);
  478. break;
  479. end;
  480. end
  481. else break;
  482. end
  483. else
  484. begin
  485. actasmpattern:=actasmpattern+c;
  486. c:=asmgetchar;
  487. if c=newline then
  488. begin
  489. Message(scan_f_string_exceeds_line);
  490. break
  491. end;
  492. end;
  493. until false; { end repeat }
  494. end
  495. else break; { end if }
  496. end; { end while }
  497. token := AS_STRING;
  498. gettoken := token;
  499. exit;
  500. end;
  501. '$' : begin
  502. c:=asmgetchar;
  503. while c in ['0'..'9','A'..'F','a'..'f'] do
  504. begin
  505. actasmpattern := actasmpattern + c;
  506. c := asmgetchar;
  507. end;
  508. gettoken := AS_HEXNUM;
  509. exit;
  510. end;
  511. ',' : begin
  512. gettoken := AS_COMMA;
  513. c:=asmgetchar;
  514. exit;
  515. end;
  516. '[' : begin
  517. gettoken := AS_LBRACKET;
  518. c:=asmgetchar;
  519. exit;
  520. end;
  521. ']' : begin
  522. gettoken := AS_RBRACKET;
  523. c:=asmgetchar;
  524. exit;
  525. end;
  526. '(' : begin
  527. gettoken := AS_LPAREN;
  528. c:=asmgetchar;
  529. exit;
  530. end;
  531. ')' : begin
  532. gettoken := AS_RPAREN;
  533. c:=asmgetchar;
  534. exit;
  535. end;
  536. ':' : begin
  537. gettoken := AS_COLON;
  538. c:=asmgetchar;
  539. exit;
  540. end;
  541. '.' : begin
  542. gettoken := AS_DOT;
  543. c:=asmgetchar;
  544. exit;
  545. end;
  546. '+' : begin
  547. gettoken := AS_PLUS;
  548. c:=asmgetchar;
  549. exit;
  550. end;
  551. '-' : begin
  552. gettoken := AS_MINUS;
  553. c:=asmgetchar;
  554. exit;
  555. end;
  556. '*' : begin
  557. gettoken := AS_STAR;
  558. c:=asmgetchar;
  559. exit;
  560. end;
  561. '/' : begin
  562. gettoken := AS_SLASH;
  563. c:=asmgetchar;
  564. exit;
  565. end;
  566. '0'..'9': begin
  567. { this flag indicates if there was an error }
  568. { if so, then we use a default value instead.}
  569. errorflag := false;
  570. actasmpattern := c;
  571. c := asmgetchar;
  572. { Get the possible characters }
  573. while c in ['0'..'9','A'..'F','a'..'f'] do
  574. begin
  575. actasmpattern := actasmpattern + c;
  576. c:= asmgetchar;
  577. end;
  578. { Get ending character }
  579. uppervar(actasmpattern);
  580. c:=upcase(c);
  581. { possibly a binary number. }
  582. if (actasmpattern[length(actasmpattern)] = 'B') and (c <> 'H') then
  583. Begin
  584. { Delete the last binary specifier }
  585. delete(actasmpattern,length(actasmpattern),1);
  586. for j:=1 to length(actasmpattern) do
  587. if not (actasmpattern[j] in ['0','1']) then
  588. begin
  589. Message1(assem_e_error_in_binary_const,actasmpattern);
  590. errorflag := TRUE;
  591. end;
  592. { if error, then suppose a binary value of zero. }
  593. if errorflag then
  594. actasmpattern := '0';
  595. gettoken := AS_BINNUM;
  596. exit;
  597. end
  598. else
  599. Begin
  600. case c of
  601. 'O': Begin
  602. for j:=1 to length(actasmpattern) do
  603. if not (actasmpattern[j] in ['0'..'7']) then
  604. begin
  605. Message1(assem_e_error_in_octal_const,actasmpattern);
  606. errorflag := TRUE;
  607. end;
  608. { if error, then suppose an octal value of zero. }
  609. if errorflag then
  610. actasmpattern := '0';
  611. gettoken := AS_OCTALNUM;
  612. c := asmgetchar;
  613. exit;
  614. end;
  615. 'H': Begin
  616. for j:=1 to length(actasmpattern) do
  617. if not (actasmpattern[j] in ['0'..'9','A'..'F']) then
  618. begin
  619. Message1(assem_e_error_in_hex_const,actasmpattern);
  620. errorflag := TRUE;
  621. end;
  622. { if error, then suppose an hex value of zero. }
  623. if errorflag then
  624. actasmpattern := '0';
  625. gettoken := AS_HEXNUM;
  626. c := asmgetchar;
  627. exit;
  628. end;
  629. else { must be an integer number }
  630. begin
  631. for j:=1 to length(actasmpattern) do
  632. if not (actasmpattern[j] in ['0'..'9']) then
  633. begin
  634. Message1(assem_e_error_in_integer_const,actasmpattern);
  635. errorflag := TRUE;
  636. end;
  637. { if error, then suppose an int value of zero. }
  638. if errorflag then
  639. actasmpattern := '0';
  640. gettoken := AS_INTNUM;
  641. exit;
  642. end;
  643. end; { end case }
  644. end; { end if }
  645. end;
  646. ';','{',#13,newline : begin
  647. c:=asmgetchar;
  648. firsttoken := TRUE;
  649. gettoken:=AS_SEPARATOR;
  650. end;
  651. else
  652. Begin
  653. Message(scan_f_illegal_char);
  654. end;
  655. end; { end case }
  656. end; { end else if }
  657. end;
  658. {---------------------------------------------------------------------}
  659. { Routines for the output }
  660. {---------------------------------------------------------------------}
  661. { returns an appropriate ao_xxxx flag indicating the type }
  662. { of operand. }
  663. function findtype(Var Opr: TOperand): longint;
  664. Begin
  665. With Opr do
  666. Begin
  667. case operandtype of
  668. OPR_REFERENCE: Begin
  669. if assigned(ref.symbol) then
  670. { check if in local label list }
  671. { if so then it is considered }
  672. { as a displacement. }
  673. Begin
  674. if labellist.search(ref.symbol^) <> nil then
  675. findtype := ao_disp
  676. else
  677. findtype := ao_mem; { probably a mem ref. }
  678. end
  679. else
  680. findtype := ao_mem;
  681. end;
  682. OPR_CONSTANT: Begin
  683. { check if there is not already a default size }
  684. if opr.size <> S_NO then
  685. Begin
  686. findtype := _constsizes[opr.size];
  687. exit;
  688. end;
  689. if val < $ff then
  690. Begin
  691. findtype := ao_imm8;
  692. opr.size := S_B;
  693. end
  694. else if val < $ffff then
  695. Begin
  696. findtype := ao_imm16;
  697. opr.size := S_W;
  698. end
  699. else
  700. Begin
  701. findtype := ao_imm32;
  702. opr.size := S_L;
  703. end
  704. end;
  705. OPR_REGISTER: Begin
  706. findtype := _regtypes[reg];
  707. exit;
  708. end;
  709. OPR_NONE: Begin
  710. findtype := 0;
  711. end;
  712. else
  713. Begin
  714. Message(assem_f_internal_error_in_findtype);
  715. end;
  716. end;
  717. end;
  718. end;
  719. Procedure ConcatLabeledInstr(var instr: TInstruction);
  720. Begin
  721. if (instr.getinstruction in [A_JO,A_JNO,A_JB,A_JC,A_JNAE,
  722. A_JNB,A_JNC,A_JAE,A_JE,A_JZ,A_JNE,A_JNZ,A_JBE,A_JNA,A_JNBE,
  723. A_JA,A_JS,A_JNS,A_JP,A_JPE,A_JNP,A_JPO,A_JL,A_JNGE,A_JNL,A_JGE,
  724. A_JLE,A_JNG,A_JNLE,A_JG,A_JCXZ,A_JECXZ,A_LOOP,A_LOOPZ,A_LOOPE,
  725. A_LOOPNZ,A_LOOPNE,A_MOV,A_JMP,A_CALL]) then
  726. Begin
  727. if instr.numops > 1 then
  728. Message(assem_e_invalid_labeled_opcode)
  729. else if instr.operands[1].operandtype <> OPR_LABINSTR then
  730. Message(assem_e_invalid_labeled_opcode)
  731. else if (instr.operands[1].operandtype = OPR_LABINSTR) and
  732. (instr.numops = 1) then
  733. if assigned(instr.operands[1].hl) then
  734. ConcatLabel(p,instr.getinstruction, instr.operands[1].hl)
  735. else
  736. Message(assem_f_internal_error_in_findtype);
  737. end
  738. else if instr.getinstruction = A_MOV then
  739. Begin
  740. { MOV to rel8 }
  741. end
  742. else
  743. Message(assem_e_invalid_operand);
  744. end;
  745. Procedure HandleExtend(var instr: TInstruction);
  746. { Handles MOVZX, MOVSX ... }
  747. var
  748. instruc: tasmop;
  749. opsize: topsize;
  750. Begin
  751. instruc:=instr.getinstruction;
  752. { return the old types ..}
  753. { these tokens still point to valid intel strings, }
  754. { but we must convert them to TRUE intel tokens }
  755. if instruc in [A_MOVSB,A_MOVSBL,A_MOVSBW,A_MOVSWL] then
  756. instruc := A_MOVSX;
  757. if instruc in [A_MOVZB,A_MOVZWL] then
  758. instruc := A_MOVZX;
  759. With instr do
  760. Begin
  761. if operands[1].size = S_B then
  762. Begin
  763. if operands[2].size = S_L then
  764. opsize := S_BL
  765. else
  766. if operands[2].size = S_W then
  767. opsize := S_BW
  768. else
  769. begin
  770. Message(assem_e_invalid_size_movzx);
  771. exit;
  772. end;
  773. end
  774. else
  775. if operands[1].size = S_W then
  776. Begin
  777. if operands[2].size = S_L then
  778. opsize := S_WL
  779. else
  780. begin
  781. Message(assem_e_invalid_size_movzx);
  782. exit;
  783. end;
  784. end
  785. else
  786. begin
  787. Message(assem_e_invalid_size_movzx);
  788. exit;
  789. end;
  790. if operands[1].operandtype = OPR_REGISTER then
  791. Begin
  792. if operands[2].operandtype <> OPR_REGISTER then
  793. Message(assem_e_invalid_opcode)
  794. else
  795. p^.concat(new(pai386,op_reg_reg(instruc,opsize,
  796. operands[1].reg,operands[2].reg)));
  797. end
  798. else
  799. if operands[1].operandtype = OPR_REFERENCE then
  800. Begin
  801. if operands[2].operandtype <> OPR_REGISTER then
  802. Message(assem_e_invalid_opcode)
  803. else
  804. p^.concat(new(pai386,op_ref_reg(instruc,opsize,
  805. newreference(operands[1].ref),operands[2].reg)));
  806. end
  807. end; { end with }
  808. end;
  809. Procedure ConcatOpCode(var instr: TInstruction);
  810. {*********************************************************************}
  811. { First Pass: }
  812. { if instr = Lxxx with a 16bit offset, we emit an error. }
  813. { If the instruction is INS,IN,OUT,OUTS,RCL,ROL,RCR,ROR, }
  814. { SAL,SAR,SHL,SHR,SHLD,SHRD,DIV,IDIV,BT,BTC,BTR,BTS,INT, }
  815. { RET,ENTER,SCAS,CMPS,STOS,LODS,FNSTSW,FSTSW. }
  816. { set up the optypes variables manually, as well as setting }
  817. { operand sizes. }
  818. { Second pass: }
  819. { Check if the combination of opcodes and operands are valid, using }
  820. { the opcode table. }
  821. { Third pass: }
  822. { If there was no error on the 2nd pass , then we check the }
  823. { following: }
  824. { - If this is a 0 operand opcode }
  825. { we verify if it is a string opcode, if so we emit a size also}
  826. { otherwise simply emit the opcode by itself. }
  827. { - If this is a 1 operand opcode, and it is a reference, we make }
  828. { sure that the operand size is valid; we emit the opcode. }
  829. { - If this is a two operand opcode }
  830. { o if the opcode is MOVSX or MOVZX then we handle it specially }
  831. { o we check the operand types (most important combinations): }
  832. { if reg,reg we make sure that both registers are of the }
  833. { same size. }
  834. { if reg,ref or ref,reg we check if the symbol name is }
  835. { assigned, if so a size must be specified and compared }
  836. { to the register size, both must be equal. If there is }
  837. { no symbol name, then we check : }
  838. { if refsize = NO_SIZE then OPCODE_SIZE = regsize }
  839. { else if refsize = regsize then OPCODE_SIZE = regsize}
  840. { else error. }
  841. { if no_error emit the opcode. }
  842. { if ref,const or const,ref if ref does not have any size }
  843. { then error, otherwise emit the opcode. }
  844. { - If this is a three operand opcode: }
  845. { imul,shld,and shrd -> check them manually. }
  846. {*********************************************************************}
  847. var
  848. fits : boolean;
  849. i: longint;
  850. opsize: topsize;
  851. optyp1, optyp2, optyp3: longint;
  852. instruc: tasmop;
  853. Begin
  854. fits := FALSE;
  855. for i:=1 to instr.numops do
  856. Begin
  857. case instr.operands[i].operandtype of
  858. OPR_REGISTER: instr.operands[i].size :=
  859. _regsizes[instr.operands[i].reg];
  860. end; { end case }
  861. end; { endif }
  862. { setup specific instructions for first pass }
  863. instruc := instr.getinstruction;
  864. if (instruc in [A_LEA,A_LDS,A_LSS,A_LES,A_LFS,A_LGS]) then
  865. Begin
  866. if instr.operands[1].size <> S_L then
  867. Begin
  868. Message(assem_e_16bit_base_in_32bit_segment);
  869. exit;
  870. end; { endif }
  871. end;
  872. With instr do
  873. Begin
  874. for i:=1 to numops do
  875. Begin
  876. With operands[i] do
  877. Begin
  878. { check for 16-bit bases/indexes and emit an error. }
  879. { we cannot only emit a warning since gas does not }
  880. { accept 16-bit indexes and bases. }
  881. if (operandtype = OPR_REFERENCE) and
  882. ((ref.base <> R_NO) or
  883. (ref.index <> R_NO)) then
  884. Begin
  885. { index or base defined. }
  886. if (ref.base <> R_NO) then
  887. Begin
  888. if not (ref.base in
  889. [R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESI,R_EDI,R_ESP]) then
  890. Message(assem_e_16bit_base_in_32bit_segment);
  891. end;
  892. { index or base defined. }
  893. if (ref.index <> R_NO) then
  894. Begin
  895. if not (ref.index in
  896. [R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESI,R_EDI,R_ESP]) then
  897. Message(assem_e_16bit_index_in_32bit_segment);
  898. end;
  899. end;
  900. { Check for constants without bases/indexes in memory }
  901. { references. }
  902. if (operandtype = OPR_REFERENCE) and
  903. (ref.base = R_NO) and
  904. (ref.index = R_NO) and
  905. (ref.symbol = nil) and
  906. (ref.offset <> 0) then
  907. Begin
  908. ref.isintvalue := TRUE;
  909. Message(assem_e_const_ref_not_allowed);
  910. end;
  911. opinfo := findtype(operands[i]);
  912. end; { end with }
  913. end; {endfor}
  914. { TAKE CARE OF SPECIAL OPCODES, TAKE CARE OF THEM INDIVUALLY. }
  915. { ALL THE REST ARE TAKEN CARE BY OPCODE TABLE AND THIRD PASS. }
  916. if instruc = A_FST then
  917. Begin
  918. end
  919. else
  920. if instruc = A_FILD then
  921. Begin
  922. end
  923. else
  924. if instruc = A_FLD then
  925. Begin
  926. {A_FLDS,A_FLDL,A_FLDT}
  927. end
  928. else
  929. if instruc = A_FIST then
  930. Begin
  931. {A_FISTQ,A_FISTS,A_FISTL}
  932. end
  933. else
  934. if instruc = A_FWAIT then
  935. FWaitWarning
  936. else
  937. if instruc = A_MOVSX then
  938. Begin
  939. { change the instruction to conform to GAS }
  940. if operands[1].size = S_W then
  941. Begin
  942. addinstr(A_MOVSBW)
  943. end
  944. else
  945. if operands[1].size = S_L then
  946. Begin
  947. if operands[2].size = S_B then
  948. addinstr(A_MOVSBL)
  949. else
  950. addinstr(A_MOVSWL);
  951. end;
  952. instruc := getinstruction; { reload instruction }
  953. end
  954. else
  955. if instruc = A_MOVZX then
  956. Begin
  957. { change the instruction to conform to GAS }
  958. if operands[1].size = S_W then
  959. Begin
  960. addinstr(A_MOVZB)
  961. end
  962. else
  963. if operands[1].size = S_L then
  964. Begin
  965. if operands[2].size = S_B then
  966. addinstr(A_MOVZB)
  967. else
  968. addinstr(A_MOVZWL);
  969. end;
  970. instruc := getinstruction; { reload instruction }
  971. end
  972. else
  973. if (instruc in [A_BT,A_BTC,A_BTR,A_BTS]) then
  974. Begin
  975. if numops = 2 then
  976. Begin
  977. if (operands[2].operandtype = OPR_CONSTANT)
  978. and (operands[2].val <= $ff) then
  979. Begin
  980. operands[2].opinfo := ao_imm8;
  981. { no operand size if using constant. }
  982. operands[2].size := S_NO;
  983. fits := TRUE;
  984. end
  985. end
  986. else
  987. Begin
  988. Message(assem_e_invalid_opcode_and_operand);
  989. exit;
  990. end;
  991. end
  992. else
  993. if instruc = A_ENTER then
  994. Begin
  995. if numops =2 then
  996. Begin
  997. if (operands[1].operandtype = OPR_CONSTANT) and
  998. (operands[1].val <= $ffff) then
  999. Begin
  1000. operands[1].opinfo := ao_imm16;
  1001. end { endif }
  1002. end { endif }
  1003. else
  1004. Begin
  1005. Message(assem_e_invalid_opcode_and_operand);
  1006. exit;
  1007. end
  1008. end { endif }
  1009. else
  1010. { Handle special opcodes for the opcode }
  1011. { table. Set them up correctly. }
  1012. if (instruc in [A_IN,A_INS]) then
  1013. Begin
  1014. if numops =2 then
  1015. Begin
  1016. if (operands[2].operandtype = OPR_REGISTER) and (operands[2].reg = R_DX)
  1017. then
  1018. Begin
  1019. operands[2].opinfo := ao_inoutportreg;
  1020. if (operands[1].operandtype = OPR_REGISTER) and
  1021. (operands[1].reg in [R_EAX,R_AX,R_AL]) and
  1022. (instruc = A_IN) then
  1023. Begin
  1024. operands[1].opinfo := ao_acc;
  1025. end
  1026. end
  1027. else
  1028. if (operands[2].operandtype = OPR_CONSTANT) and (operands[2].val <= $ff)
  1029. and (instruc = A_IN) then
  1030. Begin
  1031. operands[2].opinfo := ao_imm8;
  1032. operands[2].size := S_B;
  1033. if (operands[1].operandtype = OPR_REGISTER) and
  1034. (operands[1].reg in [R_EAX,R_AX,R_AL]) and
  1035. (instruc = A_IN) then
  1036. Begin
  1037. operands[1].opinfo := ao_acc;
  1038. end
  1039. end;
  1040. end
  1041. else
  1042. if not ((numops=0) and (instruc=A_INS)) then
  1043. Begin
  1044. Message(assem_e_invalid_opcode_and_operand);
  1045. exit;
  1046. end;
  1047. end
  1048. else
  1049. if (instruc in [A_OUT,A_OUTS]) then
  1050. Begin
  1051. if numops =2 then
  1052. Begin
  1053. if (operands[1].operandtype = OPR_REGISTER) and (operands[1].reg = R_DX)
  1054. then
  1055. Begin
  1056. operands[1].opinfo := ao_inoutportreg;
  1057. if (operands[2].operandtype = OPR_REGISTER) and
  1058. (operands[2].reg in [R_EAX,R_AX,R_AL]) and
  1059. (instruc = A_OUT) then
  1060. Begin
  1061. operands[2].opinfo := ao_acc;
  1062. fits := TRUE;
  1063. end
  1064. end
  1065. else
  1066. if (operands[1].operandtype = OPR_CONSTANT) and (operands[1].val <= $ff)
  1067. and (instruc = A_OUT) then
  1068. Begin
  1069. operands[1].opinfo := ao_imm8;
  1070. operands[1].size := S_B;
  1071. if (operands[2].operandtype = OPR_REGISTER) and
  1072. (operands[2].reg in [R_EAX,R_AX,R_AL]) and
  1073. (instruc = A_OUT) then
  1074. Begin
  1075. operands[2].opinfo := ao_acc;
  1076. fits := TRUE;
  1077. end
  1078. end;
  1079. end
  1080. else
  1081. if not ((numops=0) and (instruc=A_OUTS)) then
  1082. Begin
  1083. Message(assem_e_invalid_opcode_and_operand);
  1084. exit;
  1085. end;
  1086. end
  1087. else
  1088. if instruc in [A_RCL,A_RCR,A_ROL,A_ROR,A_SAL,A_SAR,A_SHL,A_SHR] then
  1089. { if RCL,ROL,... }
  1090. Begin
  1091. if numops =2 then
  1092. Begin
  1093. if (operands[2].operandtype = OPR_REGISTER) and (operands[2].reg = R_CL)
  1094. then
  1095. Begin
  1096. operands[2].opinfo := ao_shiftcount
  1097. end
  1098. else
  1099. if (operands[2].operandtype = OPR_CONSTANT) and
  1100. (operands[2].val <= $ff) then
  1101. Begin
  1102. operands[2].opinfo := ao_imm8;
  1103. operands[2].size := S_B;
  1104. end;
  1105. end
  1106. else { if numops = 2 }
  1107. Begin
  1108. Message(assem_e_invalid_opcode_and_operand);
  1109. exit;
  1110. end;
  1111. end
  1112. { endif ROL,RCL ... }
  1113. else
  1114. if instruc in [A_DIV, A_IDIV] then
  1115. Begin
  1116. if (operands[1].operandtype = OPR_REGISTER) and
  1117. (operands[1].reg in [R_AL,R_AX,R_EAX]) then
  1118. operands[1].opinfo := ao_acc;
  1119. end
  1120. else
  1121. if (instruc = A_FNSTSW) or (instruc = A_FSTSW) then
  1122. Begin
  1123. if numops = 1 then
  1124. Begin
  1125. if (operands[1].operandtype = OPR_REGISTER) and
  1126. (operands[1].reg = R_AX) then
  1127. operands[1].opinfo := ao_acc;
  1128. end
  1129. else
  1130. Begin
  1131. Message(assem_e_invalid_opcode_and_operand);
  1132. exit;
  1133. end;
  1134. end
  1135. else
  1136. if (instruc = A_SHLD) or (instruc = A_SHRD) then
  1137. { these instruction are fully parsed individually on pass three }
  1138. { so we just do a summary checking here. }
  1139. Begin
  1140. if numops = 3 then
  1141. Begin
  1142. if (operands[3].operandtype = OPR_CONSTANT)
  1143. and (operands[3].val <= $ff) then
  1144. Begin
  1145. operands[3].opinfo := ao_imm8;
  1146. operands[3].size := S_B;
  1147. end;
  1148. end
  1149. else
  1150. Begin
  1151. Message(assem_e_invalid_opcode_and_operand);
  1152. exit;
  1153. end;
  1154. end
  1155. else
  1156. if instruc = A_INT then
  1157. Begin
  1158. if numops = 1 then
  1159. Begin
  1160. if (operands[1].operandtype = OPR_CONSTANT) and
  1161. (operands[1].val <= $ff) then
  1162. operands[1].opinfo := ao_imm8;
  1163. end
  1164. end
  1165. else
  1166. if instruc = A_RET then
  1167. Begin
  1168. if numops =1 then
  1169. Begin
  1170. if (operands[1].operandtype = OPR_CONSTANT) and
  1171. (operands[1].val <= $ffff) then
  1172. operands[1].opinfo := ao_imm16;
  1173. end
  1174. end; { endif }
  1175. { all string instructions have default memory }
  1176. { location which are ignored. Take care of }
  1177. { those. }
  1178. { Here could be added the code for segment }
  1179. { overrides. }
  1180. if instruc in [A_SCAS,A_CMPS,A_STOS,A_LODS] then
  1181. Begin
  1182. if numops =1 then
  1183. Begin
  1184. if (operands[1].operandtype = OPR_REFERENCE) and
  1185. (assigned(operands[1].ref.symbol)) then
  1186. Freemem(operands[1].ref.symbol,length(operands[1].ref.symbol^)+1);
  1187. operands[1].operandtype := OPR_NONE;
  1188. numops := 0;
  1189. end;
  1190. end; { endif }
  1191. if instruc in [A_INS,A_MOVS,A_OUTS] then
  1192. Begin
  1193. if numops =2 then
  1194. Begin
  1195. if (operands[1].operandtype = OPR_REFERENCE) and
  1196. (assigned(operands[1].ref.symbol)) then
  1197. Freemem(operands[1].ref.symbol,length(operands[1].ref.symbol^)+1);
  1198. if (operands[2].operandtype = OPR_REFERENCE) and
  1199. (assigned(operands[2].ref.symbol)) then
  1200. Freemem(operands[2].ref.symbol,length(operands[1].ref.symbol^)+1);
  1201. operands[1].operandtype := OPR_NONE;
  1202. operands[2].operandtype := OPR_NONE;
  1203. numops := 0;
  1204. end;
  1205. end;
  1206. { handle parameter for segment overrides }
  1207. if instruc = A_XLAT then
  1208. Begin
  1209. { handle special TP syntax case for XLAT }
  1210. { here we accept XLAT, XLATB and XLAT m8 }
  1211. if (numops = 1) or (numops = 0) then
  1212. Begin
  1213. if (operands[1].operandtype = OPR_REFERENCE) and
  1214. (assigned(operands[1].ref.symbol)) then
  1215. Freemem(operands[1].ref.symbol,length(operands[1].ref.symbol^)+1);
  1216. operands[1].operandtype := OPR_NONE;
  1217. numops := 0;
  1218. { always a byte for XLAT }
  1219. instr.stropsize := S_B;
  1220. end;
  1221. end;
  1222. { swap the destination and source }
  1223. { to put in AT&T style direction }
  1224. { only if there are 2/3 operand }
  1225. { numbers. }
  1226. if (instruc <> A_ENTER) then
  1227. SwapOperands(instr);
  1228. { copy them to local variables }
  1229. { for faster access }
  1230. optyp1:=operands[1].opinfo;
  1231. optyp2:=operands[2].opinfo;
  1232. optyp3:=operands[3].opinfo;
  1233. end; { end with }
  1234. { after reading the operands }
  1235. { search the instruction }
  1236. { setup startvalue from cache }
  1237. if ins_cache[instruc]<>-1 then
  1238. i:=ins_cache[instruc]
  1239. else i:=0;
  1240. { this makes cpu.pp uncompilable, but i think this code should be }
  1241. { inserted in the system unit anyways. }
  1242. if (instruc >= lastop_in_table) and
  1243. ((cs_compilesystem in aktswitches) or (opt_processors > globals.i386)) then
  1244. begin
  1245. Message(assem_w_opcode_not_in_table);
  1246. fits:=true;
  1247. end
  1248. else while not(fits) do
  1249. begin
  1250. { set the instruction cache, if the instruction }
  1251. { occurs the first time }
  1252. if (it[i].i=instruc) and (ins_cache[instruc]=-1) then
  1253. ins_cache[instruc]:=i;
  1254. if (it[i].i=instruc) and (instr.numops=it[i].ops) then
  1255. begin
  1256. { first fit }
  1257. case instr.numops of
  1258. 0 : begin
  1259. fits:=true;
  1260. break;
  1261. end;
  1262. 1 :
  1263. Begin
  1264. if (optyp1 and it[i].o1)<>0 then
  1265. Begin
  1266. fits:=true;
  1267. break;
  1268. end;
  1269. { I consider sign-extended 8bit value to }
  1270. { be equal to immediate 8bit therefore }
  1271. { convert... }
  1272. if (optyp1 = ao_imm8) then
  1273. Begin
  1274. { check if this is a simple sign extend. }
  1275. if (it[i].o1<>ao_imm8s) then
  1276. Begin
  1277. fits:=true;
  1278. break;
  1279. end;
  1280. end;
  1281. end;
  1282. 2 : if ((optyp1 and it[i].o1)<>0) and
  1283. ((optyp2 and it[i].o2)<>0) then
  1284. Begin
  1285. fits:=true;
  1286. break;
  1287. end
  1288. { if the operands can be swaped }
  1289. { then swap them }
  1290. else if ((it[i].m and af_d)<>0) and
  1291. ((optyp1 and it[i].o2)<>0) and
  1292. ((optyp2 and it[i].o1)<>0) then
  1293. begin
  1294. { swap the destination and source }
  1295. { to put in AT&T style direction }
  1296. { What does this mean !!!! ???????????????????????? }
  1297. { if (output_format in [of_o,of_att]) then }
  1298. { ???????????? }
  1299. { SwapOperands(instr); }
  1300. fits:=true;
  1301. break;
  1302. end;
  1303. 3 : if ((optyp1 and it[i].o1)<>0) and
  1304. ((optyp2 and it[i].o2)<>0) and
  1305. ((optyp3 and it[i].o3)<>0) then
  1306. Begin
  1307. fits:=true;
  1308. break;
  1309. end;
  1310. end; { end case }
  1311. end; { endif }
  1312. if it[i].i=A_NONE then
  1313. begin
  1314. { NO MATCH! }
  1315. Message(assem_e_invalid_opcode_and_operand);
  1316. exit;
  1317. end;
  1318. inc(i);
  1319. end; { end while }
  1320. { We add the opcode to the opcode linked list }
  1321. if fits then
  1322. Begin
  1323. if instr.getprefix <> A_NONE then
  1324. Begin
  1325. p^.concat(new(pai386,op_none(instr.getprefix,S_NO)));
  1326. end;
  1327. case instr.numops of
  1328. 0:
  1329. if instr.stropsize <> S_NO then
  1330. { is this a string operation opcode or xlat then check }
  1331. { the size of the operation. }
  1332. p^.concat(new(pai386,op_none(instruc,instr.stropsize)))
  1333. else
  1334. p^.concat(new(pai386,op_none(instruc,S_NO)));
  1335. 1: Begin
  1336. case instr.operands[1].operandtype of
  1337. { all one operand opcodes with constant have no defined sizes }
  1338. { at least that is what it seems in the tasm 2.0 manual. }
  1339. OPR_CONSTANT: p^.concat(new(pai386,op_const(instruc,
  1340. S_NO, instr.operands[1].val)));
  1341. { the size of the operand can be determined by the as,nasm and }
  1342. { tasm. }
  1343. { Even though normally gas should not be trusted, v2.8.1 }
  1344. { has been *extensively* tested to assure that the output }
  1345. { is indeed correct with the following opcodes: push,pop,inc,dec}
  1346. { neg and not. }
  1347. OPR_REGISTER: p^.concat(new(pai386,op_reg(instruc,
  1348. S_NO,instr.operands[1].reg)));
  1349. { this is where it gets a bit more complicated... }
  1350. OPR_REFERENCE:
  1351. if instr.operands[1].size <> S_NO then
  1352. Begin
  1353. p^.concat(new(pai386,op_ref(instruc,
  1354. instr.operands[1].size,newreference(instr.operands[1].ref))));
  1355. end
  1356. else
  1357. Begin
  1358. { special jmp and call case with }
  1359. { symbolic references. }
  1360. if instruc in [A_CALL,A_JMP] then
  1361. Begin
  1362. p^.concat(new(pai386,op_ref(instruc,
  1363. S_NO,newreference(instr.operands[1].ref))));
  1364. end
  1365. else
  1366. Message(assem_e_invalid_opcode_and_operand);
  1367. end;
  1368. OPR_NONE: Begin
  1369. Message(assem_f_internal_error_in_concatopcode);
  1370. end;
  1371. else
  1372. Begin
  1373. Message(assem_f_internal_error_in_concatopcode);
  1374. end;
  1375. end;
  1376. end;
  1377. 2:
  1378. Begin
  1379. if instruc in [A_MOVSX,A_MOVZX,A_MOVSB,A_MOVSBL,A_MOVSBW,
  1380. A_MOVSWL,A_MOVZB,A_MOVZWL] then
  1381. { movzx and movsx }
  1382. HandleExtend(instr)
  1383. else
  1384. { other instructions }
  1385. Begin
  1386. With instr do
  1387. Begin
  1388. { source }
  1389. opsize := operands[1].size;
  1390. case operands[1].operandtype of
  1391. { reg,reg }
  1392. { reg,ref }
  1393. OPR_REGISTER:
  1394. Begin
  1395. case operands[2].operandtype of
  1396. OPR_REGISTER:
  1397. { see info in ratti386.pas, about the problem }
  1398. { which can cause gas here. }
  1399. if (opsize = operands[2].size) then
  1400. begin
  1401. p^.concat(new(pai386,op_reg_reg(instruc,
  1402. opsize,operands[1].reg,operands[2].reg)));
  1403. end
  1404. else
  1405. { these do not require any size specification. }
  1406. if (instruc in [A_IN,A_OUT,A_SAL,A_SAR,A_SHL,A_SHR,A_ROL,
  1407. A_ROR,A_RCR,A_RCL]) then
  1408. { outs and ins are already taken care by }
  1409. { the first pass. }
  1410. p^.concat(new(pai386,op_reg_reg(instruc,
  1411. S_NO,operands[1].reg,operands[2].reg)))
  1412. else
  1413. Begin
  1414. Message(assem_e_invalid_opcode_and_operand);
  1415. end;
  1416. OPR_REFERENCE:
  1417. { variable name. }
  1418. { here we must check the instruction type }
  1419. { before deciding if to use and compare }
  1420. { any sizes. }
  1421. if assigned(operands[2].ref.symbol) then
  1422. Begin
  1423. if (opsize = operands[2].size) or (instruc in
  1424. [A_RCL,A_RCR,A_ROL,A_ROR,A_SAL,A_SAR,A_SHR,A_SHL]) then
  1425. p^.concat(new(pai386,op_reg_ref(instruc,
  1426. opsize,operands[1].reg,newreference(operands[2].ref))))
  1427. else
  1428. Message(assem_e_invalid_size_in_ref);
  1429. end
  1430. else
  1431. Begin
  1432. { register reference }
  1433. { possiblities:1) local variable which }
  1434. { has been replaced by bp and offset }
  1435. { in this case size should be valid }
  1436. { 2) Indirect register }
  1437. { adressing, 1st operand determines }
  1438. { size. }
  1439. if (opsize = operands[2].size) or (operands[2].size = S_NO) then
  1440. p^.concat(new(pai386,op_reg_ref(instruc,
  1441. opsize,operands[1].reg,newreference(operands[2].ref))))
  1442. else
  1443. Message(assem_e_invalid_size_in_ref);
  1444. end;
  1445. OPR_CONSTANT: { const,reg }
  1446. Begin { OUT const,reg }
  1447. if (instruc = A_OUT) and (opsize = S_B) then
  1448. p^.concat(new(pai386,op_reg_const(instruc,
  1449. opsize,operands[1].reg,operands[2].val)))
  1450. else
  1451. Message(assem_e_invalid_size_in_ref);
  1452. end;
  1453. else { else case }
  1454. Begin
  1455. Message(assem_f_internal_error_in_concatopcode);
  1456. end;
  1457. end; { end inner case }
  1458. end;
  1459. { const,reg }
  1460. { const,const }
  1461. { const,ref }
  1462. OPR_CONSTANT:
  1463. case instr.operands[2].operandtype of
  1464. { constant, constant does not have a specific size. }
  1465. OPR_CONSTANT:
  1466. p^.concat(new(pai386,op_const_const(instruc,
  1467. S_NO,operands[1].val,operands[2].val)));
  1468. OPR_REFERENCE:
  1469. Begin
  1470. if (operands[1].val <= $ff) and
  1471. (operands[2].size in [S_B,S_W,S_L,S_Q,S_S]) then
  1472. p^.concat(new(pai386,op_const_ref(instruc,
  1473. operands[2].size,operands[1].val,
  1474. newreference(operands[2].ref))))
  1475. else
  1476. if (operands[1].val <= $ffff) and
  1477. (operands[2].size in [S_W,S_L,S_Q,S_S]) then
  1478. p^.concat(new(pai386,op_const_ref(instruc,
  1479. operands[2].size,operands[1].val,
  1480. newreference(operands[2].ref))))
  1481. else
  1482. if (operands[1].val <= $7fffffff) and
  1483. (operands[2].size in [S_L,S_Q,S_S]) then
  1484. p^.concat(new(pai386,op_const_ref(instruc,
  1485. operands[2].size,operands[1].val,
  1486. newreference(operands[2].ref))))
  1487. else
  1488. Message(assem_e_invalid_size_in_ref);
  1489. end;
  1490. OPR_REGISTER:
  1491. Begin
  1492. { size of opcode determined by register }
  1493. if (operands[1].val <= $ff) and
  1494. (operands[2].size in [S_B,S_W,S_L,S_Q,S_S]) then
  1495. p^.concat(new(pai386,op_const_reg(instruc,
  1496. operands[2].size,operands[1].val,
  1497. operands[2].reg)))
  1498. else
  1499. if (operands[1].val <= $ffff) and
  1500. (operands[2].size in [S_W,S_L,S_Q,S_S]) then
  1501. p^.concat(new(pai386,op_const_reg(instruc,
  1502. operands[2].size,operands[1].val,
  1503. operands[2].reg)))
  1504. else
  1505. if (operands[1].val <= $7fffffff) and
  1506. (operands[2].size in [S_L,S_Q,S_S]) then
  1507. p^.concat(new(pai386,op_const_reg(instruc,
  1508. operands[2].size,operands[1].val,
  1509. operands[2].reg)))
  1510. else
  1511. Message(assem_e_invalid_opcode_size);
  1512. end;
  1513. else
  1514. Begin
  1515. Message(assem_f_internal_error_in_concatopcode);
  1516. end;
  1517. end; { end case }
  1518. { ref,reg }
  1519. { ref,ref }
  1520. OPR_REFERENCE:
  1521. case instr.operands[2].operandtype of
  1522. OPR_REGISTER:
  1523. if assigned(operands[1].ref.symbol) then
  1524. { global variable }
  1525. Begin
  1526. if instruc in [A_LEA,A_LDS,A_LES,A_LFS,A_LGS,A_LSS]
  1527. then
  1528. p^.concat(new(pai386,op_ref_reg(instruc,
  1529. S_NO,newreference(operands[1].ref),
  1530. operands[2].reg)))
  1531. else
  1532. if (opsize = operands[2].size) then
  1533. p^.concat(new(pai386,op_ref_reg(instruc,
  1534. opsize,newreference(operands[1].ref),
  1535. operands[2].reg)))
  1536. else
  1537. Begin
  1538. Message(assem_e_invalid_opcode_and_operand);
  1539. end;
  1540. end
  1541. else
  1542. Begin
  1543. { register reference }
  1544. { possiblities:1) local variable which }
  1545. { has been replaced by bp and offset }
  1546. { in this case size should be valid }
  1547. { 2) Indirect register }
  1548. { adressing, 2nd operand determines }
  1549. { size. }
  1550. if (opsize = operands[2].size) or (opsize = S_NO) then
  1551. Begin
  1552. p^.concat(new(pai386,op_ref_reg(instruc,
  1553. operands[2].size,newreference(operands[1].ref),
  1554. operands[2].reg)));
  1555. end
  1556. else
  1557. Message(assem_e_invalid_size_in_ref);
  1558. end;
  1559. OPR_REFERENCE: { special opcodes }
  1560. p^.concat(new(pai386,op_ref_ref(instruc,
  1561. opsize,newreference(operands[1].ref),
  1562. newreference(operands[2].ref))));
  1563. else
  1564. Begin
  1565. Message(assem_f_internal_error_in_concatopcode);
  1566. end;
  1567. end; { end inner case }
  1568. end; { end case }
  1569. end; { end with }
  1570. end; {end if movsx... }
  1571. end;
  1572. 3: Begin
  1573. { only imul, shld and shrd }
  1574. { middle must be a register }
  1575. if (instruc in [A_SHLD,A_SHRD]) and (instr.operands[2].operandtype =
  1576. OPR_REGISTER) then
  1577. Begin
  1578. case instr.operands[2].size of
  1579. S_W: if instr.operands[1].operandtype = OPR_CONSTANT then
  1580. Begin
  1581. if instr.operands[1].val <= $ff then
  1582. Begin
  1583. if instr.operands[3].size in [S_W] then
  1584. Begin
  1585. case instr.operands[3].operandtype of
  1586. OPR_REFERENCE: { MISSING !!!! } ;
  1587. OPR_REGISTER: p^.concat(new(pai386,
  1588. op_const_reg_reg(instruc, S_W,
  1589. instr.operands[1].val, instr.operands[2].reg,
  1590. instr.operands[3].reg)));
  1591. else
  1592. Message(assem_e_invalid_opcode_and_operand);
  1593. Message(assem_e_invalid_opcode_and_operand);
  1594. end;
  1595. end
  1596. else
  1597. Message(assem_e_invalid_opcode_and_operand);
  1598. end;
  1599. end
  1600. else
  1601. Message(assem_e_invalid_opcode_and_operand);
  1602. S_L: if instr.operands[1].operandtype = OPR_CONSTANT then
  1603. Begin
  1604. if instr.operands[1].val <= $ff then
  1605. Begin
  1606. if instr.operands[3].size in [S_L] then
  1607. Begin
  1608. case instr.operands[3].operandtype of
  1609. OPR_REFERENCE: { MISSING !!!! } ;
  1610. OPR_REGISTER: p^.concat(new(pai386,
  1611. op_const_reg_reg(instruc, S_L,
  1612. instr.operands[1].val, instr.operands[2].reg,
  1613. instr.operands[3].reg)));
  1614. else
  1615. Message(assem_e_invalid_opcode_and_operand);
  1616. end;
  1617. end
  1618. else
  1619. Message(assem_e_invalid_opcode_and_operand);
  1620. end;
  1621. end
  1622. else
  1623. Message(assem_e_invalid_opcode_and_operand);
  1624. else
  1625. Message(assem_e_invalid_opcode_and_operand);
  1626. end; { end case }
  1627. end
  1628. else
  1629. if (instruc in [A_IMUL]) and (instr.operands[3].operandtype
  1630. = OPR_REGISTER) then
  1631. Begin
  1632. case instr.operands[3].size of
  1633. S_W: if instr.operands[1].operandtype = OPR_CONSTANT then
  1634. Begin
  1635. if instr.operands[1].val <= $ffff then
  1636. Begin
  1637. if instr.operands[2].size in [S_W] then
  1638. Begin
  1639. case instr.operands[2].operandtype of
  1640. OPR_REFERENCE: { MISSING !!!! } ;
  1641. OPR_REGISTER: p^.concat(new(pai386,
  1642. op_const_reg_reg(instruc, S_W,
  1643. instr.operands[1].val, instr.operands[2].reg,
  1644. instr.operands[3].reg)));
  1645. else
  1646. Message(assem_e_invalid_opcode_and_operand);
  1647. end; { end case }
  1648. end
  1649. else
  1650. Message(assem_e_invalid_opcode_and_operand);
  1651. end;
  1652. end
  1653. else
  1654. Message(assem_e_invalid_opcode_and_operand);
  1655. S_L: if instr.operands[1].operandtype = OPR_CONSTANT then
  1656. Begin
  1657. if instr.operands[1].val <= $7fffffff then
  1658. Begin
  1659. if instr.operands[2].size in [S_L] then
  1660. Begin
  1661. case instr.operands[2].operandtype of
  1662. OPR_REFERENCE: { MISSING !!!! } ;
  1663. OPR_REGISTER: p^.concat(new(pai386,
  1664. op_const_reg_reg(instruc, S_L,
  1665. instr.operands[1].val, instr.operands[2].reg,
  1666. instr.operands[3].reg)));
  1667. else
  1668. Message(assem_e_invalid_opcode_and_operand);
  1669. end; { end case }
  1670. end
  1671. else
  1672. Message(assem_e_invalid_opcode_and_operand);
  1673. end;
  1674. end
  1675. else
  1676. Message(assem_e_invalid_opcode_and_operand);
  1677. else
  1678. Message(assem_e_invalid_middle_sized_operand);
  1679. end; { end case }
  1680. end { endif }
  1681. else
  1682. Message(assem_e_invalid_three_operand_opcode);
  1683. end;
  1684. end; { end case }
  1685. end;
  1686. end;
  1687. {---------------------------------------------------------------------}
  1688. { Routines for the parsing }
  1689. {---------------------------------------------------------------------}
  1690. procedure consume(t : tinteltoken);
  1691. begin
  1692. if t<>actasmtoken then
  1693. Message(assem_e_syntax_error);
  1694. actasmtoken:=gettoken;
  1695. { if the token must be ignored, then }
  1696. { get another token to parse. }
  1697. if actasmtoken = AS_NONE then
  1698. actasmtoken := gettoken;
  1699. end;
  1700. function findregister(const s : string): tregister;
  1701. {*********************************************************************}
  1702. { FUNCTION findregister(s: string):tasmop; }
  1703. { Description: Determines if the s string is a valid register, }
  1704. { if so returns correct tregister token, or R_NO if not found. }
  1705. {*********************************************************************}
  1706. var
  1707. i: tregister;
  1708. begin
  1709. findregister := R_NO;
  1710. for i:=firstreg to lastreg do
  1711. if s = iasmregs[i] then
  1712. Begin
  1713. findregister := i;
  1714. exit;
  1715. end;
  1716. end;
  1717. function findoverride(const s: string; var reg:tregister): boolean;
  1718. var
  1719. i: byte;
  1720. begin
  1721. findoverride := FALSE;
  1722. reg := R_NO;
  1723. for i:=0 to _count_asmoverrides do
  1724. Begin
  1725. if s = _asmoverrides[i] then
  1726. begin
  1727. reg := _overridetokens[i];
  1728. findoverride := TRUE;
  1729. exit;
  1730. end;
  1731. end;
  1732. end;
  1733. function findprefix(const s: string; var token: tasmop): boolean;
  1734. var i: byte;
  1735. Begin
  1736. findprefix := FALSE;
  1737. for i:=0 to _count_asmprefixes do
  1738. Begin
  1739. if s = _asmprefixes[i] then
  1740. begin
  1741. token := _prefixtokens[i];
  1742. findprefix := TRUE;
  1743. exit;
  1744. end;
  1745. end;
  1746. end;
  1747. function findsegment(const s:string): tregister;
  1748. {*********************************************************************}
  1749. { FUNCTION findsegment(s: string):tasmop; }
  1750. { Description: Determines if the s string is a valid segment register}
  1751. { if so returns correct tregister token, or R_NO if not found. }
  1752. {*********************************************************************}
  1753. var
  1754. i: tregister;
  1755. Begin
  1756. findsegment := R_DEFAULT_SEG;
  1757. for i:=firstsreg to lastsreg do
  1758. if s = iasmregs[i] then
  1759. Begin
  1760. findsegment := i;
  1761. exit;
  1762. end;
  1763. end;
  1764. function findopcode(const s: string): tasmop;
  1765. {*********************************************************************}
  1766. { FUNCTION findopcode(s: string): tasmop; }
  1767. { Description: Determines if the s string is a valid opcode }
  1768. { if so returns correct tasmop token. }
  1769. {*********************************************************************}
  1770. var
  1771. i: tasmop;
  1772. j: byte;
  1773. Begin
  1774. findopcode := A_NONE;
  1775. for i:=firstop to lastop do
  1776. if s = iasmops^[i] then
  1777. begin
  1778. findopcode:=i;
  1779. exit;
  1780. end;
  1781. { not found yet, search for extended opcodes }
  1782. { now, in this case, we must use the suffix }
  1783. { to determine the size of the instruction }
  1784. for j:=0 to _count_asmspecialops do
  1785. Begin
  1786. if s = _specialops[j] then
  1787. Begin
  1788. findopcode := _specialopstokens[j];
  1789. { set the size }
  1790. case s[length(s)] of
  1791. 'B': instr.stropsize := S_B;
  1792. 'D': instr.stropsize := S_L;
  1793. 'W': instr.stropsize := S_W;
  1794. end;
  1795. exit;
  1796. end;
  1797. end;
  1798. end;
  1799. Function CheckPrefix(prefix: tasmop; opcode:tasmop): Boolean;
  1800. { Checks if the prefix is valid with the following instruction }
  1801. { return false if not, otherwise true }
  1802. Begin
  1803. CheckPrefix := TRUE;
  1804. Case prefix of
  1805. A_REP,A_REPNE,A_REPE: if not (opcode in [A_SCAS,A_INS,A_OUTS,A_MOVS,
  1806. A_CMPS,A_LODS,A_STOS]) then
  1807. Begin
  1808. CheckPrefix := FALSE;
  1809. exit;
  1810. end;
  1811. A_LOCK: if not (opcode in [A_BT,A_BTS,A_BTR,A_BTC,A_XCHG,A_ADD,A_OR,
  1812. A_ADC,A_SBB,A_AND,A_SUB,A_XOR,A_NOT,A_NEG,A_INC,A_DEC]) then
  1813. Begin
  1814. CheckPrefix := FALSE;
  1815. Exit;
  1816. end;
  1817. A_NONE: exit; { no prefix here }
  1818. else
  1819. CheckPrefix := FALSE;
  1820. end; { end case }
  1821. end;
  1822. Procedure InitAsmRef(var instr: TInstruction);
  1823. {*********************************************************************}
  1824. { Description: This routine first check if the instruction is of }
  1825. { type OPR_NONE, or OPR_REFERENCE , if not it gives out an error. }
  1826. { If the operandtype = OPR_NONE or <> OPR_REFERENCE then it sets up }
  1827. { the operand type to OPR_REFERENCE, as well as setting up the ref }
  1828. { to point to the default segment. }
  1829. {*********************************************************************}
  1830. Begin
  1831. With instr do
  1832. Begin
  1833. case operands[operandnum].operandtype of
  1834. OPR_REFERENCE: exit;
  1835. OPR_NONE: ;
  1836. else
  1837. Message(assem_e_invalid_operand_type);
  1838. end;
  1839. operands[operandnum].operandtype := OPR_REFERENCE;
  1840. operands[operandnum].ref.segment := R_DEFAULT_SEG;
  1841. end;
  1842. end;
  1843. Function CheckOverride(segreg: tregister; var instr: TInstruction): Boolean;
  1844. { Check if the override is valid, and if so then }
  1845. { update the instr variable accordingly. }
  1846. Begin
  1847. CheckOverride := FALSE;
  1848. if instr.getinstruction in [A_MOVS,A_XLAT,A_CMPS] then
  1849. Begin
  1850. CheckOverride := TRUE;
  1851. Message(assem_e_segment_override_not_supported);
  1852. end
  1853. end;
  1854. Function CalculateExpression(expression: string): longint;
  1855. var
  1856. expr: TExprParse;
  1857. Begin
  1858. expr.Init;
  1859. CalculateExpression := expr.Evaluate(expression);
  1860. expr.Done;
  1861. end;
  1862. Function BuildRefExpression: longint;
  1863. {*********************************************************************}
  1864. { FUNCTION BuildExpression: longint }
  1865. { Description: This routine calculates a constant expression to }
  1866. { a given value. The return value is the value calculated from }
  1867. { the expression. }
  1868. { The following tokens (not strings) are recognized: }
  1869. { (,),SHL,SHR,/,*,NOT,OR,XOR,AND,MOD,+/-,numbers,ID to constants. }
  1870. {*********************************************************************}
  1871. { ENTRY: On entry the token should be any valid expression token. }
  1872. { EXIT: On Exit the token points to any token after the closing }
  1873. { RBRACKET }
  1874. { ERROR RECOVERY: Tries to find COMMA or SEPARATOR token by consuming }
  1875. { invalid tokens. }
  1876. {*********************************************************************}
  1877. var tempstr: string;
  1878. expr: string;
  1879. l : longint;
  1880. errorflag : boolean;
  1881. Begin
  1882. errorflag := FALSE;
  1883. tempstr := '';
  1884. expr := '';
  1885. { tell tokenizer that we are in }
  1886. { an expression. }
  1887. inexpression := TRUE;
  1888. Repeat
  1889. Case actasmtoken of
  1890. AS_LPAREN: Begin
  1891. Consume(AS_LPAREN);
  1892. expr := expr + '(';
  1893. end;
  1894. AS_RPAREN: Begin
  1895. Consume(AS_RPAREN);
  1896. expr := expr + ')';
  1897. end;
  1898. AS_SHL: Begin
  1899. Consume(AS_SHL);
  1900. expr := expr + '<';
  1901. end;
  1902. AS_SHR: Begin
  1903. Consume(AS_SHR);
  1904. expr := expr + '>';
  1905. end;
  1906. AS_SLASH: Begin
  1907. Consume(AS_SLASH);
  1908. expr := expr + '/';
  1909. end;
  1910. AS_MOD: Begin
  1911. Consume(AS_MOD);
  1912. expr := expr + '%';
  1913. end;
  1914. AS_STAR: Begin
  1915. Consume(AS_STAR);
  1916. expr := expr + '*';
  1917. end;
  1918. AS_PLUS: Begin
  1919. Consume(AS_PLUS);
  1920. expr := expr + '+';
  1921. end;
  1922. AS_MINUS: Begin
  1923. Consume(AS_MINUS);
  1924. expr := expr + '-';
  1925. end;
  1926. AS_AND: Begin
  1927. Consume(AS_AND);
  1928. expr := expr + '&';
  1929. end;
  1930. AS_NOT: Begin
  1931. Consume(AS_NOT);
  1932. expr := expr + '~';
  1933. end;
  1934. AS_XOR: Begin
  1935. Consume(AS_XOR);
  1936. expr := expr + '^';
  1937. end;
  1938. AS_OR: Begin
  1939. Consume(AS_OR);
  1940. expr := expr + '|';
  1941. end;
  1942. { End of reference }
  1943. AS_RBRACKET: Begin
  1944. if not ErrorFlag then
  1945. BuildRefExpression := CalculateExpression(expr)
  1946. else
  1947. BuildRefExpression := 0;
  1948. Consume(AS_RBRACKET);
  1949. { no longer in an expression }
  1950. inexpression := FALSE;
  1951. exit;
  1952. end;
  1953. AS_ID:
  1954. Begin
  1955. if NOT SearchIConstant(actasmpattern,l) then
  1956. Begin
  1957. Message1(assem_e_invalid_const_symbol,actasmpattern);
  1958. l := 0;
  1959. end;
  1960. str(l, tempstr);
  1961. expr := expr + tempstr;
  1962. Consume(AS_ID);
  1963. end;
  1964. AS_INTNUM: Begin
  1965. expr := expr + actasmpattern;
  1966. Consume(AS_INTNUM);
  1967. end;
  1968. AS_BINNUM: Begin
  1969. tempstr := BinaryToDec(actasmpattern);
  1970. if tempstr = '' then
  1971. Message(assem_f_error_converting_bin);
  1972. expr:=expr+tempstr;
  1973. Consume(AS_BINNUM);
  1974. end;
  1975. AS_HEXNUM: Begin
  1976. tempstr := HexToDec(actasmpattern);
  1977. if tempstr = '' then
  1978. Message(assem_f_error_converting_hex);
  1979. expr:=expr+tempstr;
  1980. Consume(AS_HEXNUM);
  1981. end;
  1982. AS_OCTALNUM: Begin
  1983. tempstr := OctalToDec(actasmpattern);
  1984. if tempstr = '' then
  1985. Message(assem_f_error_converting_octal);
  1986. expr:=expr+tempstr;
  1987. Consume(AS_OCTALNUM);
  1988. end;
  1989. else
  1990. Begin
  1991. { write error only once. }
  1992. if not errorflag then
  1993. Message(assem_e_invalid_constant_expression);
  1994. BuildRefExpression := 0;
  1995. if actasmtoken in [AS_COMMA,AS_SEPARATOR] then exit;
  1996. { consume tokens until we find COMMA or SEPARATOR }
  1997. Consume(actasmtoken);
  1998. errorflag := TRUE;
  1999. end;
  2000. end;
  2001. Until false;
  2002. end;
  2003. Procedure BuildRecordOffset(var instr: TInstruction; varname: string);
  2004. {*********************************************************************}
  2005. { PROCEDURE BuildRecordOffset(var Instr: TInstruction) }
  2006. { Description: This routine takes care of field specifiers of records }
  2007. { and/or variables in asm operands. It updates the offset accordingly}
  2008. {*********************************************************************}
  2009. { ENTRY: On entry the token should be DOT. }
  2010. { name: should be the name of the variable to be expanded. '' if }
  2011. { no variabled specified. }
  2012. { EXIT: On Exit the token points to SEPARATOR or COMMA. }
  2013. { ERROR RECOVERY: Tries to find COMMA or SEPARATOR token by consuming }
  2014. { invalid tokens. }
  2015. {*********************************************************************}
  2016. var
  2017. firstpass: boolean;
  2018. offset: longint;
  2019. basetypename : string;
  2020. Begin
  2021. basetypename := '';
  2022. firstpass := TRUE;
  2023. { // .ID[REG].ID ... // }
  2024. { // .ID.ID... // }
  2025. Consume(AS_DOT);
  2026. Repeat
  2027. case actasmtoken of
  2028. AS_ID: Begin
  2029. InitAsmRef(instr);
  2030. { // var_name.typefield.typefield // }
  2031. if (varname <> '') then
  2032. Begin
  2033. if not GetVarOffset(varname,actasmpattern,offset) then
  2034. Begin
  2035. Message1(assem_e_unknown_id,actasmpattern);
  2036. end
  2037. else
  2038. Inc(instr.operands[operandnum].ref.offset,Offset);
  2039. end
  2040. else
  2041. { [ref].var_name.typefield.typefield ... }
  2042. { [ref].var_name[reg] }
  2043. if not assigned(instr.operands[operandnum].ref.symbol) and
  2044. firstpass then
  2045. Begin
  2046. if not CreateVarInstr(instr,actasmpattern,operandnum) then
  2047. Begin
  2048. { type field ? }
  2049. basetypename := actasmpattern;
  2050. end
  2051. else
  2052. varname := actasmpattern;
  2053. end
  2054. else
  2055. if firstpass then
  2056. { [ref].typefield.typefield ... }
  2057. { where the first typefield must specifiy the base }
  2058. { object or record type. }
  2059. Begin
  2060. basetypename := actasmpattern;
  2061. end
  2062. else
  2063. { [ref].typefield.typefield ... }
  2064. { basetpyename is already set up... now look for fields. }
  2065. Begin
  2066. if not GetTypeOffset(basetypename,actasmpattern,Offset) then
  2067. Begin
  2068. Message1(assem_e_unknown_id,actasmpattern);
  2069. end
  2070. else
  2071. Inc(instr.operands[operandnum].ref.offset,Offset);
  2072. end;
  2073. Consume(AS_ID);
  2074. { Take care of index register on this variable }
  2075. if actasmtoken = AS_LBRACKET then
  2076. Begin
  2077. Consume(AS_LBRACKET);
  2078. Case actasmtoken of
  2079. AS_REGISTER: Begin
  2080. if instr.operands[operandnum].ref.index <> R_NO then
  2081. Message(assem_e_defining_index_more_than_once);
  2082. instr.operands[operandnum].ref.index :=
  2083. findregister(actasmpattern);
  2084. Consume(AS_REGISTER);
  2085. end;
  2086. else
  2087. Begin
  2088. { add offsets , assuming these are constant expressions... }
  2089. Inc(instr.operands[operandnum].ref.offset,BuildRefExpression);
  2090. end;
  2091. end;
  2092. Consume(AS_RBRACKET);
  2093. end;
  2094. { Here we should either have AS_DOT, AS_SEPARATOR or AS_COMMA }
  2095. if actasmtoken = AS_DOT then
  2096. Consume(AS_DOT);
  2097. firstpass := FALSE;
  2098. Offset := 0;
  2099. end;
  2100. AS_SEPARATOR: exit;
  2101. AS_COMMA: exit;
  2102. else
  2103. Begin
  2104. Message(assem_e_invalid_field_specifier);
  2105. Consume(actasmtoken);
  2106. firstpass := FALSE;
  2107. end;
  2108. end; { end case }
  2109. Until (actasmtoken = AS_SEPARATOR) or (actasmtoken = AS_COMMA);
  2110. end;
  2111. Function BuildExpression: longint;
  2112. {*********************************************************************}
  2113. { FUNCTION BuildExpression: longint }
  2114. { Description: This routine calculates a constant expression to }
  2115. { a given value. The return value is the value calculated from }
  2116. { the expression. }
  2117. { The following tokens (not strings) are recognized: }
  2118. { (,),SHL,SHR,/,*,NOT,OR,XOR,AND,MOD,+/-,numbers,ID to constants. }
  2119. {*********************************************************************}
  2120. { ENTRY: On entry the token should be any valid expression token. }
  2121. { EXIT: On Exit the token points to either COMMA or SEPARATOR }
  2122. { ERROR RECOVERY: Tries to find COMMA or SEPARATOR token by consuming }
  2123. { invalid tokens. }
  2124. {*********************************************************************}
  2125. var expr: string;
  2126. tempstr: string;
  2127. l : longint;
  2128. errorflag: boolean;
  2129. Begin
  2130. errorflag := FALSE;
  2131. expr := '';
  2132. tempstr := '';
  2133. { tell tokenizer that we are in an expression. }
  2134. inexpression := TRUE;
  2135. Repeat
  2136. Case actasmtoken of
  2137. AS_LPAREN: Begin
  2138. Consume(AS_LPAREN);
  2139. expr := expr + '(';
  2140. end;
  2141. AS_RPAREN: Begin
  2142. Consume(AS_RPAREN);
  2143. expr := expr + ')';
  2144. end;
  2145. AS_SHL: Begin
  2146. Consume(AS_SHL);
  2147. expr := expr + '<';
  2148. end;
  2149. AS_SHR: Begin
  2150. Consume(AS_SHR);
  2151. expr := expr + '>';
  2152. end;
  2153. AS_SLASH: Begin
  2154. Consume(AS_SLASH);
  2155. expr := expr + '/';
  2156. end;
  2157. AS_MOD: Begin
  2158. Consume(AS_MOD);
  2159. expr := expr + '%';
  2160. end;
  2161. AS_STAR: Begin
  2162. Consume(AS_STAR);
  2163. expr := expr + '*';
  2164. end;
  2165. AS_PLUS: Begin
  2166. Consume(AS_PLUS);
  2167. expr := expr + '+';
  2168. end;
  2169. AS_MINUS: Begin
  2170. Consume(AS_MINUS);
  2171. expr := expr + '-';
  2172. end;
  2173. AS_AND: Begin
  2174. Consume(AS_AND);
  2175. expr := expr + '&';
  2176. end;
  2177. AS_NOT: Begin
  2178. Consume(AS_NOT);
  2179. expr := expr + '~';
  2180. end;
  2181. AS_XOR: Begin
  2182. Consume(AS_XOR);
  2183. expr := expr + '^';
  2184. end;
  2185. AS_OR: Begin
  2186. Consume(AS_OR);
  2187. expr := expr + '|';
  2188. end;
  2189. AS_ID: Begin
  2190. if NOT SearchIConstant(actasmpattern,l) then
  2191. Begin
  2192. Message1(assem_e_invalid_const_symbol,actasmpattern);
  2193. l := 0;
  2194. end;
  2195. str(l, tempstr);
  2196. expr := expr + tempstr;
  2197. Consume(AS_ID);
  2198. end;
  2199. AS_INTNUM: Begin
  2200. expr := expr + actasmpattern;
  2201. Consume(AS_INTNUM);
  2202. end;
  2203. AS_BINNUM: Begin
  2204. tempstr := BinaryToDec(actasmpattern);
  2205. if tempstr = '' then
  2206. Message(assem_f_error_converting_bin);
  2207. expr:=expr+tempstr;
  2208. Consume(AS_BINNUM);
  2209. end;
  2210. AS_HEXNUM: Begin
  2211. tempstr := HexToDec(actasmpattern);
  2212. if tempstr = '' then
  2213. Message(assem_f_error_converting_hex);
  2214. expr:=expr+tempstr;
  2215. Consume(AS_HEXNUM);
  2216. end;
  2217. AS_OCTALNUM: Begin
  2218. tempstr := OctalToDec(actasmpattern);
  2219. if tempstr = '' then
  2220. Message(assem_f_error_converting_octal);
  2221. expr:=expr+tempstr;
  2222. Consume(AS_OCTALNUM);
  2223. end;
  2224. { go to next term }
  2225. AS_COMMA: Begin
  2226. if not ErrorFlag then
  2227. BuildExpression := CalculateExpression(expr)
  2228. else
  2229. BuildExpression := 0;
  2230. inexpression := FALSE;
  2231. Exit;
  2232. end;
  2233. { go to next symbol }
  2234. AS_SEPARATOR: Begin
  2235. if not ErrorFlag then
  2236. BuildExpression := CalculateExpression(expr)
  2237. else
  2238. BuildExpression := 0;
  2239. inexpression := FALSE;
  2240. Exit;
  2241. end;
  2242. else
  2243. Begin
  2244. { only write error once. }
  2245. if not errorflag then
  2246. Message(assem_e_invalid_constant_expression);
  2247. { consume tokens until we find COMMA or SEPARATOR }
  2248. Consume(actasmtoken);
  2249. errorflag := TRUE;
  2250. End;
  2251. end;
  2252. Until false;
  2253. end;
  2254. Procedure BuildScaling(Var instr: TInstruction);
  2255. {*********************************************************************}
  2256. { Takes care of parsing expression starting from the scaling value }
  2257. { up to and including possible field specifiers. }
  2258. { EXIT CONDITION: On exit the routine should point to AS_SEPARATOR }
  2259. { or AS_COMMA. On entry should point to AS_STAR token. }
  2260. {*********************************************************************}
  2261. var str:string;
  2262. l: longint;
  2263. code: integer;
  2264. Begin
  2265. Consume(AS_STAR);
  2266. if (instr.operands[operandnum].ref.scalefactor <> 0)
  2267. and (instr.operands[operandnum].ref.scalefactor <> 1) then
  2268. Begin
  2269. Message(assem_f_internal_error_in_buildscale);
  2270. end;
  2271. case actasmtoken of
  2272. AS_INTNUM: str := actasmpattern;
  2273. AS_HEXNUM: str := HexToDec(actasmpattern);
  2274. AS_BINNUM: str := BinaryToDec(actasmpattern);
  2275. AS_OCTALNUM: str := OctalToDec(actasmpattern);
  2276. else
  2277. Message(assem_e_syntax_error);
  2278. end;
  2279. val(str, l, code);
  2280. if code <> 0 then
  2281. Message(assem_e_invalid_scaling_factor);
  2282. if ((l = 2) or (l = 4) or (l = 8) or (l = 1)) and (code = 0) then
  2283. begin
  2284. instr.operands[operandnum].ref.scalefactor := l;
  2285. end
  2286. else
  2287. Begin
  2288. Message(assem_e_invalid_scaling_value);
  2289. instr.operands[operandnum].ref.scalefactor := 0;
  2290. end;
  2291. if instr.operands[operandnum].ref.index = R_NO then
  2292. Begin
  2293. Message(assem_e_scaling_value_only_allowed_with_index);
  2294. instr.operands[operandnum].ref.scalefactor := 0;
  2295. end;
  2296. { Consume the scaling number }
  2297. Consume(actasmtoken);
  2298. case actasmtoken of
  2299. { // [...*SCALING-expr] ... // }
  2300. AS_MINUS: Begin
  2301. if instr.operands[operandnum].ref.offset <> 0 then
  2302. Message(assem_f_internal_error_in_buildscale);
  2303. instr.operands[operandnum].ref.offset :=
  2304. BuildRefExpression;
  2305. end;
  2306. { // [...*SCALING+expr] ... // }
  2307. AS_PLUS: Begin
  2308. if instr.operands[operandnum].ref.offset <> 0 then
  2309. Message(assem_f_internal_error_in_buildscale);
  2310. instr.operands[operandnum].ref.offset :=
  2311. BuildRefExpression;
  2312. end;
  2313. { // [...*SCALING] ... // }
  2314. AS_RBRACKET: Consume(AS_RBRACKET);
  2315. else
  2316. Message(assem_e_invalid_scaling_value);
  2317. end;
  2318. { // .Field.Field ... or separator/comma // }
  2319. Case actasmtoken of
  2320. AS_DOT: BuildRecordOffset(instr,'');
  2321. AS_COMMA, AS_SEPARATOR: ;
  2322. else
  2323. Message(assem_e_syntax_error);
  2324. end;
  2325. end;
  2326. Procedure BuildReference(var instr: TInstruction);
  2327. {*********************************************************************}
  2328. { EXIT CONDITION: On exit the routine should point to either the }
  2329. { AS_COMMA or AS_SEPARATOR token. }
  2330. { On entry: contains the register after the opening bracket if any. }
  2331. {*********************************************************************}
  2332. var
  2333. reg:string;
  2334. segreg: boolean;
  2335. negative: boolean;
  2336. expr: string;
  2337. Begin
  2338. expr := '';
  2339. if instr.operands[operandnum].operandtype <> OPR_REFERENCE then
  2340. Begin
  2341. Message(assem_e_syn_no_ref_with_brackets);
  2342. InitAsmRef(instr);
  2343. consume(AS_REGISTER);
  2344. end
  2345. else
  2346. Begin
  2347. { save the reg }
  2348. reg := actasmpattern;
  2349. { is the syntax of the form: [REG:REG...] }
  2350. consume(AS_REGISTER);
  2351. if actasmtoken = AS_COLON then
  2352. begin
  2353. segreg := TRUE;
  2354. Message(assem_e_expression_form_not_supported);
  2355. if instr.operands[operandnum].ref.segment <> R_NO then
  2356. Message(assem_e_defining_seg_more_than_once);
  2357. instr.operands[operandnum].ref.segment := findsegment(reg);
  2358. { Here we should process the syntax of the form }
  2359. { [reg:reg...] }
  2360. {!!!!!!!!!!!!!!!!!!!!!!!! }
  2361. end
  2362. { This is probably of the following syntax: }
  2363. { SREG:[REG...] where SReg: is optional. }
  2364. { Therefore we immediately say that reg }
  2365. { is the base. }
  2366. else
  2367. Begin
  2368. if instr.operands[operandnum].ref.base <> R_NO then
  2369. Message(assem_e_defining_base_more_than_once);
  2370. instr.operands[operandnum].ref.base := findregister(reg);
  2371. end;
  2372. { we process this type of syntax immediately... }
  2373. case actasmtoken of
  2374. { // REG:[REG].Field.Field ... // }
  2375. { // REG:[REG].Field[REG].Field... // }
  2376. AS_RBRACKET: Begin
  2377. Consume(AS_RBRACKET);
  2378. { check for record fields }
  2379. if actasmtoken = AS_DOT then
  2380. BuildRecordOffset(instr,'');
  2381. if (actasmtoken = AS_SEPARATOR) or (actasmtoken = AS_COMMA) then
  2382. exit
  2383. else
  2384. Message(assem_e_syn_reference);
  2385. end;
  2386. { // REG:[REG +/- ...].Field.Field ... // }
  2387. AS_PLUS,AS_MINUS: Begin
  2388. if actasmtoken = AS_MINUS then
  2389. Begin
  2390. expr := '-';
  2391. negative := TRUE
  2392. end
  2393. else
  2394. Begin
  2395. negative := FALSE;
  2396. expr := '+';
  2397. end;
  2398. Consume(actasmtoken);
  2399. { // REG:[REG+REG+/-...].Field.Field // }
  2400. if actasmtoken = AS_REGISTER then
  2401. Begin
  2402. if negative then
  2403. Message(assem_e_negative_index_register);
  2404. if instr.operands[operandnum].ref.index <> R_NO then
  2405. Message(assem_e_defining_index_more_than_once);
  2406. instr.operands[operandnum].ref.index := findregister(actasmpattern);
  2407. Consume(AS_REGISTER);
  2408. case actasmtoken of
  2409. AS_RBRACKET: { // REG:[REG+REG].Field.Field... // }
  2410. Begin
  2411. Consume(AS_RBRACKET);
  2412. Case actasmtoken of
  2413. AS_DOT: BuildRecordOffset(instr,'');
  2414. AS_COMMA,AS_SEPARATOR: exit;
  2415. else
  2416. Message(assem_e_syntax_error);
  2417. end
  2418. end;
  2419. AS_PLUS,AS_MINUS: { // REG:[REG+REG+/-expr].Field.Field... // }
  2420. Begin
  2421. if instr.operands[operandnum].ref.offset <> 0 then
  2422. Message(assem_f_internal_error_in_buildreference);
  2423. instr.operands[operandnum].ref.offset :=
  2424. BuildRefExpression;
  2425. case actasmtoken of
  2426. AS_DOT: BuildRecordOffset(instr,'');
  2427. AS_COMMA,AS_SEPARATOR: ;
  2428. else
  2429. Message(assem_e_syntax_error);
  2430. end; { end case }
  2431. end;
  2432. AS_STAR: Begin { // REG:[REG+REG*SCALING...].Field.Field... // }
  2433. BuildScaling(instr);
  2434. end;
  2435. else
  2436. Begin
  2437. Message(assem_e_syntax_error);
  2438. end;
  2439. end; { end case }
  2440. end
  2441. else if actasmtoken = AS_STAR then
  2442. { // REG:[REG*SCALING ... ] // }
  2443. Begin
  2444. BuildScaling(instr);
  2445. end
  2446. else
  2447. { // REG:[REG+expr].Field.Field // }
  2448. Begin
  2449. if instr.operands[operandnum].ref.offset <> 0 then
  2450. Message(assem_f_internal_error_in_buildreference);
  2451. instr.operands[operandnum].ref.offset := BuildRefExpression;
  2452. case actasmtoken of
  2453. AS_DOT: BuildRecordOffset(instr,'');
  2454. AS_COMMA,AS_SEPARATOR: ;
  2455. else
  2456. Message(assem_e_syntax_error);
  2457. end; { end case }
  2458. end; { end if }
  2459. end; { end this case }
  2460. { // REG:[REG*scaling] ... // }
  2461. AS_STAR: Begin
  2462. BuildScaling(instr);
  2463. end;
  2464. end;
  2465. end; { end outer if }
  2466. end;
  2467. Procedure BuildBracketExpression(var Instr: TInstruction; var_prefix: boolean);
  2468. {*********************************************************************}
  2469. { PROCEDURE BuildBracketExpression }
  2470. { Description: This routine builds up an expression after a LBRACKET }
  2471. { token is encountered. }
  2472. { On entry actasmtoken should be equal to AS_LBRACKET. }
  2473. { var_prefix : Should be set to true if variable identifier has }
  2474. { been defined, such as in ID[ }
  2475. {*********************************************************************}
  2476. { EXIT CONDITION: On exit the routine should point to either the }
  2477. { AS_COMMA or AS_SEPARATOR token. }
  2478. {*********************************************************************}
  2479. var
  2480. l:longint;
  2481. Begin
  2482. Consume(AS_LBRACKET);
  2483. initAsmRef(instr);
  2484. Case actasmtoken of
  2485. { // Constant reference expression OR variable reference expression // }
  2486. AS_ID: Begin
  2487. if actasmpattern[1] = '@' then
  2488. Message(assem_e_local_symbol_not_allowed_as_ref);
  2489. if SearchIConstant(actasmpattern,l) then
  2490. Begin
  2491. { if there was a variable prefix then }
  2492. { add to offset }
  2493. If var_prefix then
  2494. Begin
  2495. Inc(instr.operands[operandnum].ref.offset, BuildRefExpression);
  2496. end
  2497. else
  2498. instr.operands[operandnum].ref.offset :=BuildRefExpression;
  2499. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2500. Message(assem_e_invalid_operand_in_bracket_expression);
  2501. end
  2502. else if NOT var_prefix then
  2503. Begin
  2504. InitAsmRef(instr);
  2505. if not CreateVarInstr(instr,actasmpattern,operandnum) then
  2506. Message1(assem_e_unknown_id,actasmpattern);
  2507. Consume(AS_ID);
  2508. { is there a constant expression following }
  2509. { the variable name? }
  2510. if actasmtoken <> AS_RBRACKET then
  2511. Begin
  2512. Inc(instr.operands[operandnum].ref.offset, BuildRefExpression);
  2513. end
  2514. else
  2515. Consume(AS_RBRACKET);
  2516. end
  2517. else
  2518. Message1(assem_e_invalid_symbol_name,actasmpattern);
  2519. end;
  2520. { Here we handle the special case in tp where }
  2521. { the + operator is allowed with reg and var }
  2522. { references, such as in mov al, byte ptr [+bx] }
  2523. AS_PLUS: Begin
  2524. Consume(AS_PLUS);
  2525. Case actasmtoken of
  2526. AS_REGISTER: Begin
  2527. BuildReference(instr);
  2528. end;
  2529. AS_ID: Begin
  2530. if actasmpattern[1] = '@' then
  2531. Message(assem_e_local_symbol_not_allowed_as_ref);
  2532. if SearchIConstant(actasmpattern,l) then
  2533. Begin
  2534. { if there was a variable prefix then }
  2535. { add to offset }
  2536. If var_prefix then
  2537. Begin
  2538. Inc(instr.operands[operandnum].ref.offset,
  2539. BuildRefExpression);
  2540. end
  2541. else
  2542. instr.operands[operandnum].ref.offset :=
  2543. BuildRefExpression;
  2544. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2545. Message(assem_e_invalid_operand_in_bracket_expression);
  2546. end
  2547. else if NOT var_prefix then
  2548. Begin
  2549. InitAsmRef(instr);
  2550. if not CreateVarInstr(instr,actasmpattern,operandnum) then
  2551. Message1(assem_e_unknown_id,actasmpattern);
  2552. Consume(AS_ID);
  2553. { is there a constant expression following }
  2554. { the variable name? }
  2555. if actasmtoken <> AS_RBRACKET then
  2556. Begin
  2557. Inc(instr.operands[operandnum].ref.offset,
  2558. BuildRefExpression);
  2559. end
  2560. else
  2561. Consume(AS_RBRACKET);
  2562. end
  2563. else
  2564. Message1(assem_e_invalid_symbol_name,actasmpattern);
  2565. end;
  2566. { // Constant reference expression // }
  2567. AS_INTNUM,AS_BINNUM,AS_OCTALNUM,
  2568. AS_HEXNUM: Begin
  2569. { if there was a variable prefix then }
  2570. { add to offset instead. }
  2571. If var_prefix then
  2572. Begin
  2573. Inc(instr.operands[operandnum].ref.offset, BuildRefExpression);
  2574. end
  2575. else
  2576. Begin
  2577. instr.operands[operandnum].ref.offset :=BuildRefExpression;
  2578. end;
  2579. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2580. Message(assem_e_invalid_operand_in_bracket_expression);
  2581. end;
  2582. else
  2583. Message(assem_e_syntax_error);
  2584. end;
  2585. end;
  2586. { // Constant reference expression // }
  2587. AS_MINUS,AS_NOT,AS_LPAREN:
  2588. Begin
  2589. { if there was a variable prefix then }
  2590. { add to offset instead. }
  2591. If var_prefix then
  2592. Begin
  2593. Inc(instr.operands[operandnum].ref.offset, BuildRefExpression);
  2594. end
  2595. else
  2596. Begin
  2597. instr.operands[operandnum].ref.offset :=BuildRefExpression;
  2598. end;
  2599. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2600. Message(assem_e_invalid_operand_in_bracket_expression);
  2601. end;
  2602. { // Constant reference expression // }
  2603. AS_INTNUM,AS_OCTALNUM,AS_BINNUM,AS_HEXNUM: Begin
  2604. { if there was a variable prefix then }
  2605. { add to offset instead. }
  2606. If var_prefix then
  2607. Begin
  2608. Inc(instr.operands[operandnum].ref.offset, BuildRefExpression);
  2609. end
  2610. else
  2611. Begin
  2612. instr.operands[operandnum].ref.offset :=BuildRefExpression;
  2613. end;
  2614. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2615. Message(assem_e_invalid_operand_in_bracket_expression);
  2616. end;
  2617. { // Variable reference expression // }
  2618. AS_REGISTER: BuildReference(instr);
  2619. else
  2620. Begin
  2621. Message(assem_e_invalid_reference_syntax);
  2622. while (actasmtoken <> AS_SEPARATOR) do
  2623. Consume(actasmtoken);
  2624. end;
  2625. end; { end case }
  2626. end;
  2627. Procedure BuildOperand(var instr: TInstruction);
  2628. {*********************************************************************}
  2629. { EXIT CONDITION: On exit the routine should point to either the }
  2630. { AS_COMMA or AS_SEPARATOR token. }
  2631. {*********************************************************************}
  2632. var
  2633. tempstr: string;
  2634. expr: string;
  2635. lab: Pasmlabel;
  2636. l : longint;
  2637. hl: plabel;
  2638. Begin
  2639. tempstr := '';
  2640. expr := '';
  2641. case actasmtoken of
  2642. { // Constant expression // }
  2643. AS_PLUS,AS_MINUS,AS_NOT,AS_LPAREN:
  2644. Begin
  2645. if not (instr.operands[operandnum].operandtype in [OPR_NONE,OPR_CONSTANT]) then
  2646. Message(assem_e_invalid_operand_type);
  2647. instr.operands[operandnum].operandtype := OPR_CONSTANT;
  2648. instr.operands[operandnum].val :=BuildExpression;
  2649. end;
  2650. { // Constant expression // }
  2651. AS_STRING: Begin
  2652. if not (instr.operands[operandnum].operandtype in [OPR_NONE]) then
  2653. Message(assem_e_invalid_operand_type);
  2654. instr.operands[operandnum].operandtype := OPR_CONSTANT;
  2655. if not PadZero(actasmpattern,4) then
  2656. Message1(assem_e_invalid_string_as_opcode_operand,actasmpattern);
  2657. instr.operands[operandnum].val :=
  2658. ord(actasmpattern[4]) + ord(actasmpattern[3]) shl 8 +
  2659. Ord(actasmpattern[2]) shl 16 + ord(actasmpattern[1])
  2660. shl 24;
  2661. Consume(AS_STRING);
  2662. Case actasmtoken of
  2663. AS_COMMA, AS_SEPARATOR: ;
  2664. else
  2665. Message(assem_e_invalid_string_expression);
  2666. end; { end case }
  2667. end;
  2668. { // Constant expression // }
  2669. AS_INTNUM,AS_BINNUM,
  2670. AS_OCTALNUM,
  2671. AS_HEXNUM: Begin
  2672. if not (instr.operands[operandnum].operandtype in [OPR_NONE,OPR_CONSTANT]) then
  2673. Message(assem_e_invalid_operand_type);
  2674. instr.operands[operandnum].operandtype := OPR_CONSTANT;
  2675. instr.operands[operandnum].val :=BuildExpression;
  2676. end;
  2677. { // A constant expression, or a Variable ref. // }
  2678. AS_ID: Begin
  2679. if actasmpattern[1] = '@' then
  2680. { // Label or Special symbol reference // }
  2681. Begin
  2682. if actasmpattern = '@RESULT' then
  2683. Begin
  2684. InitAsmRef(instr);
  2685. SetUpResult(instr,operandnum);
  2686. end
  2687. else
  2688. if (actasmpattern = '@CODE') or (actasmpattern = '@DATA') then
  2689. Message(assem_w_CODE_and_DATA_not_supported)
  2690. else
  2691. Begin
  2692. delete(actasmpattern,1,1);
  2693. if actasmpattern = '' then
  2694. Message(assem_e_null_label_ref_not_allowed);
  2695. lab := labellist.search(actasmpattern);
  2696. { check if the label is already defined }
  2697. { if so, we then check if the plabel is }
  2698. { non-nil, if so we add it to instruction }
  2699. if assigned(lab) then
  2700. Begin
  2701. if assigned(lab^.lab) then
  2702. Begin
  2703. instr.operands[operandnum].operandtype := OPR_LABINSTR;
  2704. instr.operands[operandnum].hl := lab^.lab;
  2705. instr.labeled := TRUE;
  2706. end;
  2707. end
  2708. else
  2709. { the label does not exist, create it }
  2710. { emit the opcode, but set that the }
  2711. { label has not been emitted }
  2712. Begin
  2713. getlabel(hl);
  2714. labellist.insert(actasmpattern,hl,FALSE);
  2715. instr.operands[operandnum].operandtype := OPR_LABINSTR;
  2716. instr.operands[operandnum].hl := hl;
  2717. instr.labeled := TRUE;
  2718. end;
  2719. end;
  2720. Consume(AS_ID);
  2721. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2722. Begin
  2723. Message(assem_e_syntax_error);
  2724. end;
  2725. end
  2726. { probably a variable or normal expression }
  2727. { or a procedure (such as in CALL ID) }
  2728. else
  2729. Begin
  2730. { is it a constant ? }
  2731. if SearchIConstant(actasmpattern,l) then
  2732. Begin
  2733. if not (instr.operands[operandnum].operandtype in [OPR_NONE,OPR_CONSTANT]) then
  2734. Message(assem_e_invalid_operand_type);
  2735. instr.operands[operandnum].operandtype := OPR_CONSTANT;
  2736. instr.operands[operandnum].val :=BuildExpression;
  2737. end
  2738. else { is it a label variable ? }
  2739. Begin
  2740. { // ID[ , ID.Field.Field or simple ID // }
  2741. { check if this is a label, if so then }
  2742. { emit it as a label. }
  2743. if SearchLabel(actasmpattern,hl) then
  2744. Begin
  2745. instr.operands[operandnum].operandtype := OPR_LABINSTR;
  2746. instr.operands[operandnum].hl := hl;
  2747. instr.labeled := TRUE;
  2748. Consume(AS_ID);
  2749. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2750. Message(assem_e_syntax_error);
  2751. end
  2752. else
  2753. { is it a normal variable ? }
  2754. Begin
  2755. initAsmRef(instr);
  2756. if not CreateVarInstr(instr,actasmpattern,operandnum) then
  2757. Begin
  2758. { not a variable.. }
  2759. { check special variables.. }
  2760. if actasmpattern = 'SELF' then
  2761. { special self variable }
  2762. Begin
  2763. if assigned(procinfo._class) then
  2764. Begin
  2765. instr.operands[operandnum].ref.offset := procinfo.ESI_offset;
  2766. instr.operands[operandnum].ref.base := procinfo.framepointer;
  2767. end
  2768. else
  2769. Message(assem_e_cannot_use_SELF_outside_a_method);
  2770. end
  2771. else
  2772. Message1(assem_e_unknown_id,actasmpattern);
  2773. end;
  2774. expr := actasmpattern;
  2775. Consume(AS_ID);
  2776. case actasmtoken of
  2777. AS_LBRACKET: { indexing }
  2778. BuildBracketExpression(instr,TRUE);
  2779. AS_DOT: BuildRecordOffset(instr,expr);
  2780. AS_SEPARATOR,AS_COMMA: ;
  2781. else
  2782. Message(assem_e_syntax_error);
  2783. end;
  2784. end;
  2785. end;
  2786. end;
  2787. end;
  2788. { // Register, a variable reference or a constant reference // }
  2789. AS_REGISTER: Begin
  2790. { save the type of register used. }
  2791. tempstr := actasmpattern;
  2792. Consume(AS_REGISTER);
  2793. if actasmtoken = AS_COLON then
  2794. Begin
  2795. Consume(AS_COLON);
  2796. if actasmtoken <> AS_LBRACKET then
  2797. Message(assem_e_syn_start_with_bracket)
  2798. else
  2799. Begin
  2800. initAsmRef(instr);
  2801. instr.operands[operandnum].ref.segment := findsegment(tempstr);
  2802. BuildBracketExpression(instr,false);
  2803. end;
  2804. end
  2805. { // Simple register // }
  2806. else if (actasmtoken = AS_SEPARATOR) or (actasmtoken = AS_COMMA) then
  2807. Begin
  2808. if not (instr.operands[operandnum].operandtype in [OPR_NONE,OPR_REGISTER]) then
  2809. Message(assem_e_invalid_operand_type);
  2810. instr.operands[operandnum].operandtype := OPR_REGISTER;
  2811. instr.operands[operandnum].reg := findregister(tempstr);
  2812. end
  2813. else
  2814. Message1(assem_e_syn_register,tempstr);
  2815. end;
  2816. { // a variable reference, register ref. or a constant reference // }
  2817. AS_LBRACKET: Begin
  2818. BuildBracketExpression(instr,false);
  2819. end;
  2820. { // Unsupported // }
  2821. AS_SEG,AS_OFFSET: Begin
  2822. Message(assem_e_SEG_and_OFFSET_not_supported);
  2823. Consume(actasmtoken);
  2824. { error recovery }
  2825. While not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) do
  2826. Consume(actasmtoken);
  2827. end;
  2828. AS_SEPARATOR, AS_COMMA: ;
  2829. else
  2830. Message(assem_e_syn_opcode_operand);
  2831. end; { end case }
  2832. end;
  2833. Procedure BuildConstant(maxvalue: longint);
  2834. {*********************************************************************}
  2835. { PROCEDURE BuildConstant }
  2836. { Description: This routine takes care of parsing a DB,DD,or DW }
  2837. { line and adding those to the assembler node. Expressions, range- }
  2838. { checking are fullly taken care of. }
  2839. { maxvalue: $ff -> indicates that this is a DB node. }
  2840. { $ffff -> indicates that this is a DW node. }
  2841. { $ffffffff -> indicates that this is a DD node. }
  2842. {*********************************************************************}
  2843. { EXIT CONDITION: On exit the routine should point to AS_SEPARATOR. }
  2844. {*********************************************************************}
  2845. var
  2846. strlength: byte;
  2847. expr: string;
  2848. value : longint;
  2849. Begin
  2850. strlength := 0; { assume it is a DB }
  2851. Repeat
  2852. Case actasmtoken of
  2853. AS_STRING: Begin
  2854. if maxvalue = $ffff then
  2855. strlength := 2
  2856. else if maxvalue = $ffffffff then
  2857. strlength := 4;
  2858. if strlength <> 0 then
  2859. { DD and DW cases }
  2860. Begin
  2861. if Not PadZero(actasmpattern,strlength) then
  2862. Message(scan_f_string_exceeds_line);
  2863. end;
  2864. expr := actasmpattern;
  2865. Consume(AS_STRING);
  2866. Case actasmtoken of
  2867. AS_COMMA: Consume(AS_COMMA);
  2868. AS_SEPARATOR: ;
  2869. else
  2870. Message(assem_e_invalid_string_expression);
  2871. end; { end case }
  2872. ConcatString(p,expr);
  2873. end;
  2874. AS_INTNUM,AS_BINNUM,
  2875. AS_OCTALNUM,AS_HEXNUM:
  2876. Begin
  2877. value:=BuildExpression;
  2878. ConcatConstant(p,value,maxvalue);
  2879. end;
  2880. AS_ID:
  2881. Begin
  2882. value:=BuildExpression;
  2883. if value > maxvalue then
  2884. Begin
  2885. Message(assem_e_expression_out_of_bounds);
  2886. { assuming a value of maxvalue }
  2887. value := maxvalue;
  2888. end;
  2889. ConcatConstant(p,value,maxvalue);
  2890. end;
  2891. { These terms can start an assembler expression }
  2892. AS_PLUS,AS_MINUS,AS_LPAREN,AS_NOT: Begin
  2893. value := BuildExpression;
  2894. ConcatConstant(p,value,maxvalue);
  2895. end;
  2896. AS_COMMA: BEGIN
  2897. Consume(AS_COMMA);
  2898. END;
  2899. AS_SEPARATOR: ;
  2900. else
  2901. Begin
  2902. Message(assem_f_internal_error_in_buildconstant);
  2903. end;
  2904. end; { end case }
  2905. Until actasmtoken = AS_SEPARATOR;
  2906. end;
  2907. Procedure BuildOpCode;
  2908. {*********************************************************************}
  2909. { PROCEDURE BuildOpcode; }
  2910. { Description: Parses the intel opcode and operands, and writes it }
  2911. { in the TInstruction object. }
  2912. {*********************************************************************}
  2913. { EXIT CONDITION: On exit the routine should point to AS_SEPARATOR. }
  2914. { On ENTRY: Token should point to AS_OPCODE }
  2915. {*********************************************************************}
  2916. var asmtok: tasmop;
  2917. op: tasmop;
  2918. expr: string;
  2919. segreg: tregister;
  2920. Begin
  2921. expr := '';
  2922. asmtok := A_NONE; { assmume no prefix }
  2923. segreg := R_NO; { assume no segment override }
  2924. { // prefix seg opcode // }
  2925. { // prefix opcode // }
  2926. if findprefix(actasmpattern,asmtok) then
  2927. Begin
  2928. { standard opcode prefix }
  2929. if asmtok <> A_NONE then
  2930. instr.addprefix(asmtok);
  2931. Consume(AS_OPCODE);
  2932. if findoverride(actasmpattern,segreg) then
  2933. Begin
  2934. Consume(AS_OPCODE);
  2935. Message(assem_w_repeat_prefix_and_seg_override);
  2936. end;
  2937. end
  2938. else
  2939. { // seg prefix opcode // }
  2940. { // seg opcode // }
  2941. if findoverride(actasmpattern,segreg) then
  2942. Begin
  2943. Consume(AS_OPCODE);
  2944. if findprefix(actasmpattern,asmtok) then
  2945. Begin
  2946. { standard opcode prefix }
  2947. Message(assem_w_repeat_prefix_and_seg_override);
  2948. if asmtok <> A_NONE then
  2949. instr.addprefix(asmtok);
  2950. Consume(AS_OPCODE);
  2951. end;
  2952. end;
  2953. { // opcode // }
  2954. if (actasmtoken <> AS_OPCODE) then
  2955. Begin
  2956. Message(assem_e_invalid_or_missing_opcode);
  2957. { error recovery }
  2958. While not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) do
  2959. Consume(actasmtoken);
  2960. exit;
  2961. end
  2962. else
  2963. Begin
  2964. op := findopcode(actasmpattern);
  2965. instr.addinstr(op);
  2966. { // Valid combination of prefix and instruction ? // }
  2967. if (asmtok <> A_NONE) and (NOT CheckPrefix(asmtok,op)) then
  2968. Message1(assem_e_invalid_prefix_and_opcode,actasmpattern);
  2969. { // Valid combination of segment override // }
  2970. if (segreg <> R_NO) and (NOT CheckOverride(segreg,instr)) then
  2971. Message1(assem_e_invalid_override_and_opcode,actasmpattern);
  2972. Consume(AS_OPCODE);
  2973. { // Zero operand opcode ? // }
  2974. if actasmtoken = AS_SEPARATOR then
  2975. exit
  2976. else
  2977. operandnum := 1;
  2978. end;
  2979. While actasmtoken <> AS_SEPARATOR do
  2980. Begin
  2981. case actasmtoken of
  2982. { // Operand delimiter // }
  2983. AS_COMMA: Begin
  2984. if operandnum > MaxOperands then
  2985. Message(assem_e_too_many_operands)
  2986. else
  2987. Inc(operandnum);
  2988. Consume(AS_COMMA);
  2989. end;
  2990. { // Typecast, Constant Expression, Type Specifier // }
  2991. AS_DWORD,AS_BYTE,AS_WORD,AS_TBYTE,AS_QWORD: Begin
  2992. Case actasmtoken of
  2993. AS_DWORD: instr.operands[operandnum].size := S_L;
  2994. AS_WORD: instr.operands[operandnum].size := S_W;
  2995. AS_BYTE: instr.operands[operandnum].size := S_B;
  2996. AS_QWORD: instr.operands[operandnum].size := S_Q;
  2997. AS_TBYTE: instr.operands[operandnum].size := S_X;
  2998. end;
  2999. Consume(actasmtoken);
  3000. Case actasmtoken of
  3001. { // Reference // }
  3002. AS_PTR: Begin
  3003. initAsmRef(instr);
  3004. Consume(AS_PTR);
  3005. BuildOperand(instr);
  3006. end;
  3007. { // Possibly a typecast or a constant // }
  3008. { // expression. // }
  3009. AS_LPAREN: Begin
  3010. if actasmtoken = AS_ID then
  3011. Begin
  3012. { Case vartype of }
  3013. { LOCAL: Replace by offset and }
  3014. { BP in treference. }
  3015. { GLOBAL: Replace by mangledname}
  3016. { in symbol of treference }
  3017. { Check if next token = RPAREN }
  3018. { otherwise syntax error. }
  3019. initAsmRef(instr);
  3020. if not CreateVarInstr(instr,actasmpattern,
  3021. operandnum) then
  3022. Begin
  3023. Message1(assem_e_unknown_id,actasmpattern);
  3024. end;
  3025. end
  3026. else
  3027. begin
  3028. instr.operands[operandnum].operandtype := OPR_CONSTANT;
  3029. instr.operands[operandnum].val := BuildExpression;
  3030. end;
  3031. end;
  3032. else
  3033. BuildOperand(instr);
  3034. end; { end case }
  3035. end;
  3036. { // Type specifier // }
  3037. AS_NEAR,AS_FAR: Begin
  3038. if actasmtoken = AS_NEAR then
  3039. Message(assem_w_near_ignored)
  3040. else
  3041. Message(assem_w_far_ignored);
  3042. Consume(actasmtoken);
  3043. if actasmtoken = AS_PTR then
  3044. begin
  3045. initAsmRef(instr);
  3046. Consume(AS_PTR);
  3047. end;
  3048. BuildOperand(instr);
  3049. end;
  3050. { // End of asm operands for this opcode // }
  3051. AS_SEPARATOR: ;
  3052. { // Constant expression // }
  3053. AS_LPAREN: Begin
  3054. instr.operands[operandnum].operandtype := OPR_CONSTANT;
  3055. instr.operands[operandnum].val := BuildExpression;
  3056. end;
  3057. else
  3058. BuildOperand(instr);
  3059. end; { end case }
  3060. end; { end while }
  3061. end;
  3062. Function Assemble: Ptree;
  3063. {*********************************************************************}
  3064. { PROCEDURE Assemble; }
  3065. { Description: Parses the intel assembler syntax, parsing is done }
  3066. { according to the rules in the Turbo Pascal manual. }
  3067. {*********************************************************************}
  3068. Var
  3069. hl: plabel;
  3070. labelptr: pasmlabel;
  3071. Begin
  3072. Message(assem_d_start_intel);
  3073. inexpression := FALSE;
  3074. firsttoken := TRUE;
  3075. operandnum := 0;
  3076. if assigned(procinfo.retdef) and
  3077. (is_fpu(procinfo.retdef) or
  3078. ret_in_acc(procinfo.retdef)) then
  3079. procinfo.funcret_is_valid:=true;
  3080. { sets up all opcode and register tables in uppercase }
  3081. if not _asmsorted then
  3082. Begin
  3083. SetupTables;
  3084. _asmsorted := TRUE;
  3085. end;
  3086. p:=new(paasmoutput,init);
  3087. { setup label linked list }
  3088. labellist.init;
  3089. c:=asmgetchar;
  3090. actasmtoken:=gettoken;
  3091. while actasmtoken<>AS_END do
  3092. Begin
  3093. case actasmtoken of
  3094. AS_LLABEL: Begin
  3095. labelptr := labellist.search(actasmpattern);
  3096. if not assigned(labelptr) then
  3097. Begin
  3098. getlabel(hl);
  3099. labellist.insert(actasmpattern,hl,TRUE);
  3100. ConcatLabel(p,A_LABEL,hl);
  3101. end
  3102. else
  3103. { the label has already been inserted into the }
  3104. { label list, either as an intruction label (in }
  3105. { this case it has not been emitted), or as a }
  3106. { duplicate local symbol (in this case it has }
  3107. { already been emitted). }
  3108. Begin
  3109. if labelptr^.emitted then
  3110. Message1(assem_e_dup_local_sym,'@'+labelptr^.name^)
  3111. else
  3112. Begin
  3113. if assigned(labelptr^.lab) then
  3114. ConcatLabel(p,A_LABEL,labelptr^.lab);
  3115. labelptr^.emitted := TRUE;
  3116. end;
  3117. end;
  3118. Consume(AS_LLABEL);
  3119. end;
  3120. AS_LABEL: Begin
  3121. if SearchLabel(actasmpattern,hl) then
  3122. ConcatLabel(p,A_LABEL, hl)
  3123. else
  3124. Message1(assem_e_unknown_label_identifer,actasmpattern);
  3125. Consume(AS_LABEL);
  3126. end;
  3127. AS_DW: Begin
  3128. Consume(AS_DW);
  3129. BuildConstant($ffff);
  3130. end;
  3131. AS_DB: Begin
  3132. Consume(AS_DB);
  3133. BuildConstant($ff);
  3134. end;
  3135. AS_DD: Begin
  3136. Consume(AS_DD);
  3137. BuildConstant($ffffffff);
  3138. end;
  3139. AS_OPCODE: Begin
  3140. instr.init;
  3141. BuildOpcode;
  3142. instr.numops := operandnum;
  3143. if instr.labeled then
  3144. ConcatLabeledInstr(instr)
  3145. else
  3146. ConcatOpCode(instr);
  3147. end;
  3148. AS_SEPARATOR:Begin
  3149. Consume(AS_SEPARATOR);
  3150. { let us go back to the first operand }
  3151. operandnum := 0;
  3152. end;
  3153. AS_END: ; { end assembly block }
  3154. else
  3155. Begin
  3156. Message(assem_e_assemble_node_syntax_error);
  3157. { error recovery }
  3158. Consume(actasmtoken);
  3159. end;
  3160. end; { end case }
  3161. end; { end while }
  3162. { check if there were undefined symbols. }
  3163. { if so, then list each of those undefined }
  3164. { labels. }
  3165. if assigned(labellist.First) then
  3166. Begin
  3167. labelptr := labellist.First;
  3168. if labellist.First <> nil then
  3169. Begin
  3170. { first label }
  3171. if not labelptr^.emitted then
  3172. Message1(assem_e_unknown_local_sym,'@'+labelptr^.name^);
  3173. { other labels ... }
  3174. While (labelptr^.Next <> nil) do
  3175. Begin
  3176. labelptr := labelptr^.Next;
  3177. if not labelptr^.emitted then
  3178. Message1(assem_e_unknown_local_sym,'@'+labelptr^.name^);
  3179. end;
  3180. end;
  3181. end;
  3182. assemble := genasmnode(p);
  3183. labellist.done;
  3184. Message(assem_d_finish_intel);
  3185. end;
  3186. Begin
  3187. old_exit:=exitproc;
  3188. exitproc:=@rai386_exit;
  3189. end.
  3190. {
  3191. $Log$
  3192. Revision 1.3 1998-04-08 16:58:06 pierre
  3193. * several bugfixes
  3194. ADD ADC and AND are also sign extended
  3195. nasm output OK (program still crashes at end
  3196. and creates wrong assembler files !!)
  3197. procsym types sym in tdef removed !!
  3198. Revision 1.2 1998/03/31 15:21:01 florian
  3199. * fix of out (intel syntax) applied
  3200. Revision 1.1.1.1 1998/03/25 11:18:15 root
  3201. * Restored version
  3202. Revision 1.19 1998/03/24 21:48:34 florian
  3203. * just a couple of fixes applied:
  3204. - problem with fixed16 solved
  3205. - internalerror 10005 problem fixed
  3206. - patch for assembler reading
  3207. - small optimizer fix
  3208. - mem is now supported
  3209. Revision 1.18 1998/03/10 01:17:26 peter
  3210. * all files have the same header
  3211. * messages are fully implemented, EXTDEBUG uses Comment()
  3212. + AG... files for the Assembler generation
  3213. Revision 1.17 1998/03/09 12:58:12 peter
  3214. * FWait warning is only showed for Go32V2 and $E+
  3215. * opcode tables moved to i386.pas/m68k.pas to reduce circular uses (and
  3216. for m68k the same tables are removed)
  3217. + $E for i386
  3218. Revision 1.16 1998/03/04 17:33:56 michael
  3219. + Changed ifdef FPK to ifdef FPC
  3220. Revision 1.15 1998/03/03 22:38:26 peter
  3221. * the last 3 files
  3222. Revision 1.14 1998/03/02 01:49:15 peter
  3223. * renamed target_DOS to target_GO32V1
  3224. + new verbose system, merged old errors and verbose units into one new
  3225. verbose.pas, so errors.pas is obsolete
  3226. Revision 1.13 1998/02/13 10:35:38 daniel
  3227. * Made Motorola version compilable.
  3228. * Fixed optimizer
  3229. Revision 1.12 1998/02/12 11:50:36 daniel
  3230. Yes! Finally! After three retries, my patch!
  3231. Changes:
  3232. Complete rewrite of psub.pas.
  3233. Added support for DLL's.
  3234. Compiler requires less memory.
  3235. Platform units for each platform.
  3236. Revision 1.11 1998/02/07 18:02:36 carl
  3237. + fwait warning for emulation
  3238. Revision 1.10 1998/01/19 03:11:40 carl
  3239. * bugfix number 78
  3240. Revision 1.9 1998/01/09 19:22:51 carl
  3241. * bugfix of __ID variable names
  3242. Revision 1.8 1997/12/09 14:00:25 carl
  3243. * bugfix of intr reg,reg instructions, size must always be specified
  3244. under gas (ref: DJGPP FAQ)
  3245. * bugfix of concatopcode with fits init twice!
  3246. + unknown instr. only poermitted when compiling system unit and/or
  3247. target processor > i386
  3248. Revision 1.7 1997/12/04 12:20:50 pierre
  3249. +* MMX instructions added to att output with a warning that
  3250. GNU as version >= 2.81 is needed
  3251. bug in reading of reals under att syntax corrected
  3252. Revision 1.6 1997/11/28 18:14:45 pierre
  3253. working version with several bug fixes
  3254. Revision 1.5 1997/11/28 15:43:20 florian
  3255. Fixed stack ajustment bug, 0.9.8 compiles now 0.9.8 without problems.
  3256. Revision 1.4 1997/11/28 15:31:59 carl
  3257. * uncommented firstop and lastop. (otherwise can cause bugs)
  3258. Revision 1.3 1997/11/28 14:26:22 florian
  3259. Fixed some bugs
  3260. Revision 1.2 1997/11/28 12:03:53 michael
  3261. Changed comment delimiters to braces, causes problems with 0.9.1
  3262. Changed use of ord to typecast with longint.
  3263. Made boolean expressions non-redundant.
  3264. Revision 1.1.1.1 1997/11/27 08:33:00 michael
  3265. FPC Compiler CVS start
  3266. Pre-CVS log:
  3267. CEC Carl-Eric Codere
  3268. FK Florian Klaempfl
  3269. PM Pierre Muller
  3270. + feature added
  3271. - removed
  3272. * bug fixed or changed
  3273. 9th november 1997:
  3274. + first working version with main distribution line of FPC (CEC)
  3275. 12th november 1997:
  3276. * bugfix of CALL and JMP with symbolic references. (CEC)
  3277. 13th november 1997:
  3278. * too many bugfixes/improvements to name... (CEC)
  3279. * Fixed range check, line numbering, missing operand checking
  3280. bugs - range checking must be off to compile under tp. (CEC)
  3281. + speed improvement of 30% over old version with global look up tables.
  3282. 14th november 1997:
  3283. + added support for record/object offsets. (CEC)
  3284. * fixed bug regarding ENTER and push imm8 instruction(CEC)
  3285. + fixed conflicts with fpu instructions. (CEC).
  3286. }