rai386.pas 137 KB

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