ratti386.pas 148 KB

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