ra386int.pas 141 KB

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