rai386.pas 135 KB

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