ra386int.pas 141 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573
  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. 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. Begin
  718. if (instr.getinstruction in [A_JO,A_JNO,A_JB,A_JC,A_JNAE,
  719. A_JNB,A_JNC,A_JAE,A_JE,A_JZ,A_JNE,A_JNZ,A_JBE,A_JNA,A_JNBE,
  720. A_JA,A_JS,A_JNS,A_JP,A_JPE,A_JNP,A_JPO,A_JL,A_JNGE,A_JNL,A_JGE,
  721. A_JLE,A_JNG,A_JNLE,A_JG,A_JCXZ,A_JECXZ,A_LOOP,A_LOOPZ,A_LOOPE,
  722. A_LOOPNZ,A_LOOPNE,A_MOV,A_JMP,A_CALL]) then
  723. Begin
  724. if instr.numops > 1 then
  725. Message(assem_e_invalid_labeled_opcode)
  726. else if instr.operands[1].operandtype <> OPR_LABINSTR then
  727. Message(assem_e_invalid_labeled_opcode)
  728. else if (instr.operands[1].operandtype = OPR_LABINSTR) and
  729. (instr.numops = 1) then
  730. if assigned(instr.operands[1].hl) then
  731. ConcatLabel(p,instr.getinstruction, instr.operands[1].hl)
  732. else
  733. Message(assem_f_internal_error_in_findtype);
  734. end
  735. else if instr.getinstruction = A_MOV then
  736. Begin
  737. { MOV to rel8 }
  738. end
  739. else
  740. Message1(assem_e_invalid_operand,'');
  741. end;
  742. Procedure HandleExtend(var instr: TInstruction);
  743. { Handles MOVZX, MOVSX ... }
  744. var
  745. instruc: tasmop;
  746. opsize: topsize;
  747. Begin
  748. instruc:=instr.getinstruction;
  749. { return the old types ..}
  750. { these tokens still point to valid intel strings, }
  751. { but we must convert them to TRUE intel tokens }
  752. if instruc in [A_MOVSB,A_MOVSBL,A_MOVSBW,A_MOVSWL] then
  753. instruc := A_MOVSX;
  754. if instruc in [A_MOVZB,A_MOVZWL] then
  755. instruc := A_MOVZX;
  756. With instr do
  757. Begin
  758. if operands[1].size = S_B then
  759. Begin
  760. if operands[2].size = S_L then
  761. opsize := S_BL
  762. else
  763. if operands[2].size = S_W then
  764. opsize := S_BW
  765. else
  766. begin
  767. Message(assem_e_invalid_size_movzx);
  768. exit;
  769. end;
  770. end
  771. else
  772. if operands[1].size = S_W then
  773. Begin
  774. if operands[2].size = S_L then
  775. opsize := S_WL
  776. else
  777. begin
  778. Message(assem_e_invalid_size_movzx);
  779. exit;
  780. end;
  781. end
  782. else
  783. begin
  784. Message(assem_e_invalid_size_movzx);
  785. exit;
  786. end;
  787. if operands[1].operandtype = OPR_REGISTER then
  788. Begin
  789. if operands[2].operandtype <> OPR_REGISTER then
  790. Message(assem_e_invalid_opcode)
  791. else
  792. p^.concat(new(pai386,op_reg_reg(instruc,opsize,
  793. operands[1].reg,operands[2].reg)));
  794. end
  795. else
  796. if operands[1].operandtype = OPR_REFERENCE then
  797. Begin
  798. if operands[2].operandtype <> OPR_REGISTER then
  799. Message(assem_e_invalid_opcode)
  800. else
  801. p^.concat(new(pai386,op_ref_reg(instruc,opsize,
  802. newreference(operands[1].ref),operands[2].reg)));
  803. end
  804. end; { end with }
  805. end;
  806. Procedure ConcatOpCode(var instr: TInstruction);
  807. {*********************************************************************}
  808. { First Pass: }
  809. { if instr = Lxxx with a 16bit offset, we emit an error. }
  810. { If the instruction is INS,IN,OUT,OUTS,RCL,ROL,RCR,ROR, }
  811. { SAL,SAR,SHL,SHR,SHLD,SHRD,DIV,IDIV,BT,BTC,BTR,BTS,INT, }
  812. { RET,ENTER,SCAS,CMPS,STOS,LODS,FNSTSW,FSTSW. }
  813. { set up the optypes variables manually, as well as setting }
  814. { operand sizes. }
  815. { Second pass: }
  816. { Check if the combination of opcodes and operands are valid, using }
  817. { the opcode table. }
  818. { Third pass: }
  819. { If there was no error on the 2nd pass , then we check the }
  820. { following: }
  821. { - If this is a 0 operand opcode }
  822. { we verify if it is a string opcode, if so we emit a size also}
  823. { otherwise simply emit the opcode by itself. }
  824. { - If this is a 1 operand opcode, and it is a reference, we make }
  825. { sure that the operand size is valid; we emit the opcode. }
  826. { - If this is a two operand opcode }
  827. { o if the opcode is MOVSX or MOVZX then we handle it specially }
  828. { o we check the operand types (most important combinations): }
  829. { if reg,reg we make sure that both registers are of the }
  830. { same size. }
  831. { if reg,ref or ref,reg we check if the symbol name is }
  832. { assigned, if so a size must be specified and compared }
  833. { to the register size, both must be equal. If there is }
  834. { no symbol name, then we check : }
  835. { if refsize = NO_SIZE then OPCODE_SIZE = regsize }
  836. { else if refsize = regsize then OPCODE_SIZE = regsize}
  837. { else error. }
  838. { if no_error emit the opcode. }
  839. { if ref,const or const,ref if ref does not have any size }
  840. { then error, otherwise emit the opcode. }
  841. { - If this is a three operand opcode: }
  842. { imul,shld,and shrd -> check them manually. }
  843. {*********************************************************************}
  844. var
  845. fits : boolean;
  846. i: longint;
  847. opsize: topsize;
  848. optyp1, optyp2, optyp3: longint;
  849. instruc: tasmop;
  850. Begin
  851. fits := FALSE;
  852. for i:=1 to instr.numops do
  853. Begin
  854. case instr.operands[i].operandtype of
  855. OPR_REGISTER: instr.operands[i].size :=
  856. _regsizes[instr.operands[i].reg];
  857. end; { end case }
  858. end; { endif }
  859. { setup specific instructions for first pass }
  860. instruc := instr.getinstruction;
  861. if (instruc in [A_LEA,A_LDS,A_LSS,A_LES,A_LFS,A_LGS]) then
  862. Begin
  863. if instr.operands[1].size <> S_L then
  864. Begin
  865. Message(assem_e_16bit_base_in_32bit_segment);
  866. exit;
  867. end; { endif }
  868. { In this case the size of the reference is not taken into account! }
  869. instr.operands[2].size := S_NO;
  870. end;
  871. With instr do
  872. Begin
  873. for i:=1 to numops do
  874. Begin
  875. With operands[i] do
  876. Begin
  877. { check for 16-bit bases/indexes and emit an error. }
  878. { we cannot only emit a warning since gas does not }
  879. { accept 16-bit indexes and bases. }
  880. if (operandtype = OPR_REFERENCE) and
  881. ((ref.base <> R_NO) or
  882. (ref.index <> R_NO)) then
  883. Begin
  884. { index or base defined. }
  885. if (ref.base <> R_NO) then
  886. Begin
  887. if not (ref.base in
  888. [R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESI,R_EDI,R_ESP]) then
  889. Message(assem_e_16bit_base_in_32bit_segment);
  890. end;
  891. { index or base defined. }
  892. if (ref.index <> R_NO) then
  893. Begin
  894. if not (ref.index in
  895. [R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESI,R_EDI,R_ESP]) then
  896. Message(assem_e_16bit_index_in_32bit_segment);
  897. end;
  898. end;
  899. { Check for constants without bases/indexes in memory }
  900. { references. }
  901. if (operandtype = OPR_REFERENCE) and
  902. (ref.base = R_NO) and
  903. (ref.index = R_NO) and
  904. (ref.symbol = nil) and
  905. (ref.offset <> 0) then
  906. Begin
  907. ref.isintvalue := TRUE;
  908. Message(assem_e_const_ref_not_allowed);
  909. end;
  910. opinfo := findtype(operands[i]);
  911. end; { end with }
  912. end; {endfor}
  913. { TAKE CARE OF SPECIAL OPCODES, TAKE CARE OF THEM INDIVUALLY. }
  914. { ALL THE REST ARE TAKEN CARE BY OPCODE TABLE AND THIRD PASS. }
  915. if instruc = A_FST then
  916. Begin
  917. end
  918. else
  919. if instruc = A_FILD then
  920. Begin
  921. end
  922. else
  923. if instruc = A_FLD then
  924. Begin
  925. {A_FLDS,A_FLDL,A_FLDT}
  926. end
  927. else
  928. if instruc = A_FIST then
  929. Begin
  930. {A_FISTQ,A_FISTS,A_FISTL}
  931. end
  932. else
  933. if instruc = A_FWAIT then
  934. FWaitWarning
  935. else
  936. if instruc = A_MOVSX then
  937. Begin
  938. { change the instruction to conform to GAS }
  939. if operands[1].size = S_W then
  940. Begin
  941. addinstr(A_MOVSBW)
  942. end
  943. else
  944. if operands[1].size = S_L then
  945. Begin
  946. if operands[2].size = S_B then
  947. addinstr(A_MOVSBL)
  948. else
  949. addinstr(A_MOVSWL);
  950. end;
  951. instruc := getinstruction; { reload instruction }
  952. end
  953. else
  954. if instruc = A_MOVZX then
  955. Begin
  956. { change the instruction to conform to GAS }
  957. if operands[1].size = S_W then
  958. Begin
  959. addinstr(A_MOVZB)
  960. end
  961. else
  962. if operands[1].size = S_L then
  963. Begin
  964. if operands[2].size = S_B then
  965. addinstr(A_MOVZB)
  966. else
  967. addinstr(A_MOVZWL);
  968. end;
  969. instruc := getinstruction; { reload instruction }
  970. end
  971. else
  972. if (instruc in [A_BT,A_BTC,A_BTR,A_BTS]) then
  973. Begin
  974. if numops = 2 then
  975. Begin
  976. if (operands[2].operandtype = OPR_CONSTANT)
  977. and (operands[2].val <= $ff) then
  978. Begin
  979. operands[2].opinfo := ao_imm8;
  980. { no operand size if using constant. }
  981. operands[2].size := S_NO;
  982. fits := TRUE;
  983. end
  984. end
  985. else
  986. Begin
  987. Message(assem_e_invalid_opcode_and_operand);
  988. exit;
  989. end;
  990. end
  991. else
  992. if instruc = A_ENTER then
  993. Begin
  994. if numops =2 then
  995. Begin
  996. if (operands[1].operandtype = OPR_CONSTANT) and
  997. (operands[1].val <= $ffff) then
  998. Begin
  999. operands[1].opinfo := ao_imm16;
  1000. end { endif }
  1001. end { endif }
  1002. else
  1003. Begin
  1004. Message(assem_e_invalid_opcode_and_operand);
  1005. exit;
  1006. end
  1007. end { endif }
  1008. else
  1009. { Handle special opcodes for the opcode }
  1010. { table. Set them up correctly. }
  1011. if (instruc in [A_IN,A_INS]) then
  1012. Begin
  1013. if numops =2 then
  1014. Begin
  1015. if (operands[2].operandtype = OPR_REGISTER) and (operands[2].reg = R_DX)
  1016. then
  1017. Begin
  1018. operands[2].opinfo := ao_inoutportreg;
  1019. if (operands[1].operandtype = OPR_REGISTER) and
  1020. (operands[1].reg in [R_EAX,R_AX,R_AL]) and
  1021. (instruc = A_IN) then
  1022. Begin
  1023. operands[1].opinfo := ao_acc;
  1024. case operands[1].reg of
  1025. R_EAX: operands[1].size := S_L;
  1026. R_AX: operands[1].size := S_W;
  1027. R_AL: operands[1].size := S_B;
  1028. end;
  1029. end
  1030. end
  1031. else
  1032. if (operands[2].operandtype = OPR_CONSTANT) and (operands[2].val <= $ff)
  1033. and (instruc = A_IN) then
  1034. Begin
  1035. operands[2].opinfo := ao_imm8;
  1036. operands[2].size := S_B;
  1037. if (operands[1].operandtype = OPR_REGISTER) and
  1038. (operands[1].reg in [R_EAX,R_AX,R_AL]) and
  1039. (instruc = A_IN) then
  1040. Begin
  1041. operands[1].opinfo := ao_acc;
  1042. end
  1043. end;
  1044. end
  1045. else
  1046. if not ((numops=0) and (instruc=A_INS)) then
  1047. Begin
  1048. Message(assem_e_invalid_opcode_and_operand);
  1049. exit;
  1050. end;
  1051. end
  1052. else
  1053. if (instruc in [A_OUT,A_OUTS]) then
  1054. Begin
  1055. if numops =2 then
  1056. Begin
  1057. if (operands[1].operandtype = OPR_REGISTER) and (operands[1].reg = R_DX)
  1058. then
  1059. Begin
  1060. operands[1].opinfo := ao_inoutportreg;
  1061. if (operands[2].operandtype = OPR_REGISTER) and
  1062. (operands[2].reg in [R_EAX,R_AX,R_AL]) and
  1063. (instruc = A_OUT) then
  1064. Begin
  1065. operands[2].opinfo := ao_acc;
  1066. fits := TRUE;
  1067. end
  1068. end
  1069. else
  1070. if (operands[1].operandtype = OPR_CONSTANT) and (operands[1].val <= $ff)
  1071. and (instruc = A_OUT) then
  1072. Begin
  1073. operands[1].opinfo := ao_imm8;
  1074. operands[1].size := S_B;
  1075. if (operands[2].operandtype = OPR_REGISTER) and
  1076. (operands[2].reg in [R_EAX,R_AX,R_AL]) and
  1077. (instruc = A_OUT) then
  1078. Begin
  1079. operands[2].opinfo := ao_acc;
  1080. case operands[2].reg of
  1081. R_EAX: operands[2].size := S_L;
  1082. R_AX: operands[2].size := S_W;
  1083. R_AL: operands[2].size := S_B;
  1084. end;
  1085. fits := TRUE;
  1086. end
  1087. end;
  1088. end
  1089. else
  1090. if not ((numops=0) and (instruc=A_OUTS)) then
  1091. Begin
  1092. Message(assem_e_invalid_opcode_and_operand);
  1093. exit;
  1094. end;
  1095. end
  1096. else
  1097. if instruc in [A_RCL,A_RCR,A_ROL,A_ROR,A_SAL,A_SAR,A_SHL,A_SHR] then
  1098. { if RCL,ROL,... }
  1099. Begin
  1100. if numops =2 then
  1101. Begin
  1102. if (operands[2].operandtype = OPR_REGISTER) and (operands[2].reg = R_CL)
  1103. then
  1104. Begin
  1105. operands[2].opinfo := ao_shiftcount
  1106. end
  1107. else
  1108. if (operands[2].operandtype = OPR_CONSTANT) and
  1109. (operands[2].val <= $ff) then
  1110. Begin
  1111. operands[2].opinfo := ao_imm8;
  1112. operands[2].size := S_B;
  1113. end;
  1114. end
  1115. else { if numops = 2 }
  1116. Begin
  1117. Message(assem_e_invalid_opcode_and_operand);
  1118. exit;
  1119. end;
  1120. end
  1121. { endif ROL,RCL ... }
  1122. else
  1123. if instruc in [A_DIV, A_IDIV] then
  1124. Begin
  1125. if (operands[1].operandtype = OPR_REGISTER) and
  1126. (operands[1].reg in [R_AL,R_AX,R_EAX]) then
  1127. operands[1].opinfo := ao_acc;
  1128. end
  1129. else
  1130. if (instruc = A_FNSTSW) or (instruc = A_FSTSW) then
  1131. Begin
  1132. if numops = 1 then
  1133. Begin
  1134. if (operands[1].operandtype = OPR_REGISTER) and
  1135. (operands[1].reg = R_AX) then
  1136. operands[1].opinfo := ao_acc;
  1137. end
  1138. else
  1139. Begin
  1140. Message(assem_e_invalid_opcode_and_operand);
  1141. exit;
  1142. end;
  1143. end
  1144. else
  1145. if (instruc = A_SHLD) or (instruc = A_SHRD) then
  1146. { these instruction are fully parsed individually on pass three }
  1147. { so we just do a summary checking here. }
  1148. Begin
  1149. if numops = 3 then
  1150. Begin
  1151. if (operands[3].operandtype = OPR_CONSTANT)
  1152. and (operands[3].val <= $ff) then
  1153. Begin
  1154. operands[3].opinfo := ao_imm8;
  1155. operands[3].size := S_B;
  1156. end;
  1157. end
  1158. else
  1159. Begin
  1160. Message(assem_e_invalid_opcode_and_operand);
  1161. exit;
  1162. end;
  1163. end
  1164. else
  1165. if instruc = A_INT then
  1166. Begin
  1167. if numops = 1 then
  1168. Begin
  1169. if (operands[1].operandtype = OPR_CONSTANT) and
  1170. (operands[1].val <= $ff) then
  1171. operands[1].opinfo := ao_imm8;
  1172. end
  1173. end
  1174. else
  1175. if instruc = A_RET then
  1176. Begin
  1177. if numops =1 then
  1178. Begin
  1179. if (operands[1].operandtype = OPR_CONSTANT) and
  1180. (operands[1].val <= $ffff) then
  1181. operands[1].opinfo := ao_imm16;
  1182. end
  1183. end; { endif }
  1184. { all string instructions have default memory }
  1185. { location which are ignored. Take care of }
  1186. { those. }
  1187. { Here could be added the code for segment }
  1188. { overrides. }
  1189. if instruc in [A_SCAS,A_CMPS,A_STOS,A_LODS] then
  1190. Begin
  1191. if numops =1 then
  1192. Begin
  1193. if (operands[1].operandtype = OPR_REFERENCE) and
  1194. (assigned(operands[1].ref.symbol)) then
  1195. Freemem(operands[1].ref.symbol,length(operands[1].ref.symbol^)+1);
  1196. operands[1].operandtype := OPR_NONE;
  1197. numops := 0;
  1198. end;
  1199. end; { endif }
  1200. if instruc in [A_INS,A_MOVS,A_OUTS] then
  1201. Begin
  1202. if numops =2 then
  1203. Begin
  1204. if (operands[1].operandtype = OPR_REFERENCE) and
  1205. (assigned(operands[1].ref.symbol)) then
  1206. Freemem(operands[1].ref.symbol,length(operands[1].ref.symbol^)+1);
  1207. if (operands[2].operandtype = OPR_REFERENCE) and
  1208. (assigned(operands[2].ref.symbol)) then
  1209. Freemem(operands[2].ref.symbol,length(operands[1].ref.symbol^)+1);
  1210. operands[1].operandtype := OPR_NONE;
  1211. operands[2].operandtype := OPR_NONE;
  1212. numops := 0;
  1213. end;
  1214. end;
  1215. { handle parameter for segment overrides }
  1216. if instruc = A_XLAT then
  1217. Begin
  1218. { handle special TP syntax case for XLAT }
  1219. { here we accept XLAT, XLATB and XLAT m8 }
  1220. if (numops = 1) or (numops = 0) then
  1221. Begin
  1222. if (operands[1].operandtype = OPR_REFERENCE) and
  1223. (assigned(operands[1].ref.symbol)) then
  1224. Freemem(operands[1].ref.symbol,length(operands[1].ref.symbol^)+1);
  1225. operands[1].operandtype := OPR_NONE;
  1226. numops := 0;
  1227. { always a byte for XLAT }
  1228. instr.stropsize := S_B;
  1229. end;
  1230. end;
  1231. { swap the destination and source }
  1232. { to put in AT&T style direction }
  1233. { only if there are 2/3 operand }
  1234. { numbers. }
  1235. if (instruc <> A_ENTER) then
  1236. SwapOperands(instr);
  1237. { copy them to local variables }
  1238. { for faster access }
  1239. optyp1:=operands[1].opinfo;
  1240. optyp2:=operands[2].opinfo;
  1241. optyp3:=operands[3].opinfo;
  1242. end; { end with }
  1243. { after reading the operands }
  1244. { search the instruction }
  1245. { setup startvalue from cache }
  1246. if ins_cache[instruc]<>-1 then
  1247. i:=ins_cache[instruc]
  1248. else i:=0;
  1249. { this makes cpu.pp uncompilable, but i think this code should be }
  1250. { inserted in the system unit anyways. }
  1251. if (instruc >= lastop_in_table) then
  1252. begin
  1253. Message1(assem_w_opcode_not_in_table,upper(int_op2str[instruc]));
  1254. fits:=true;
  1255. end
  1256. else while not(fits) do
  1257. begin
  1258. { set the instruction cache, if the instruction }
  1259. { occurs the first time }
  1260. if (it[i].i=instruc) and (ins_cache[instruc]=-1) then
  1261. ins_cache[instruc]:=i;
  1262. if (it[i].i=instruc) and (instr.numops=it[i].ops) then
  1263. begin
  1264. { first fit }
  1265. case instr.numops of
  1266. 0 : begin
  1267. fits:=true;
  1268. break;
  1269. end;
  1270. 1 :
  1271. Begin
  1272. if (optyp1 and it[i].o1)<>0 then
  1273. Begin
  1274. fits:=true;
  1275. break;
  1276. end;
  1277. { I consider sign-extended 8bit value to }
  1278. { be equal to immediate 8bit therefore }
  1279. { convert... }
  1280. if (optyp1 = ao_imm8) then
  1281. Begin
  1282. { check if this is a simple sign extend. }
  1283. if (it[i].o1<>ao_imm8s) then
  1284. Begin
  1285. fits:=true;
  1286. break;
  1287. end;
  1288. end;
  1289. end;
  1290. 2 : if ((optyp1 and it[i].o1)<>0) and
  1291. ((optyp2 and it[i].o2)<>0) then
  1292. Begin
  1293. fits:=true;
  1294. break;
  1295. end
  1296. { if the operands can be swaped }
  1297. { then swap them }
  1298. else if ((it[i].m and af_d)<>0) and
  1299. ((optyp1 and it[i].o2)<>0) and
  1300. ((optyp2 and it[i].o1)<>0) then
  1301. begin
  1302. { swap the destination and source }
  1303. { to put in AT&T style direction }
  1304. { What does this mean !!!! ???????????????????????? }
  1305. { if (output_format in [of_o,of_att]) then }
  1306. { ???????????? }
  1307. { SwapOperands(instr); }
  1308. fits:=true;
  1309. break;
  1310. end;
  1311. 3 : if ((optyp1 and it[i].o1)<>0) and
  1312. ((optyp2 and it[i].o2)<>0) and
  1313. ((optyp3 and it[i].o3)<>0) then
  1314. Begin
  1315. fits:=true;
  1316. break;
  1317. end;
  1318. end; { end case }
  1319. end; { endif }
  1320. if it[i].i=A_NONE then
  1321. begin
  1322. { NO MATCH! }
  1323. Message(assem_e_invalid_opcode_and_operand);
  1324. exit;
  1325. end;
  1326. inc(i);
  1327. end; { end while }
  1328. { We add the opcode to the opcode linked list }
  1329. if fits then
  1330. Begin
  1331. if instr.getprefix <> A_NONE then
  1332. Begin
  1333. p^.concat(new(pai386,op_none(instr.getprefix,S_NO)));
  1334. end;
  1335. case instr.numops of
  1336. 0:
  1337. if instr.stropsize <> S_NO then
  1338. { is this a string operation opcode or xlat then check }
  1339. { the size of the operation. }
  1340. p^.concat(new(pai386,op_none(instruc,instr.stropsize)))
  1341. else
  1342. p^.concat(new(pai386,op_none(instruc,S_NO)));
  1343. 1: Begin
  1344. case instr.operands[1].operandtype of
  1345. { all one operand opcodes with constant have no defined sizes }
  1346. { at least that is what it seems in the tasm 2.0 manual. }
  1347. OPR_CONSTANT: p^.concat(new(pai386,op_const(instruc,
  1348. S_NO, instr.operands[1].val)));
  1349. OPR_REGISTER: if instruc in [A_INC,A_DEC, A_NEG,A_NOT] then
  1350. Begin
  1351. p^.concat(new(pai386,op_reg(instruc,
  1352. instr.operands[1].size,instr.operands[1].reg)));
  1353. end
  1354. else
  1355. p^.concat(new(pai386,op_reg(instruc,
  1356. S_NO,instr.operands[1].reg)));
  1357. { this is where it gets a bit more complicated... }
  1358. OPR_REFERENCE:
  1359. if instr.operands[1].size <> S_NO then
  1360. Begin
  1361. p^.concat(new(pai386,op_ref(instruc,
  1362. instr.operands[1].size,newreference(instr.operands[1].ref))));
  1363. end
  1364. else
  1365. Begin
  1366. { special jmp and call case with }
  1367. { symbolic references. }
  1368. if instruc in [A_CALL,A_JMP] then
  1369. Begin
  1370. p^.concat(new(pai386,op_ref(instruc,
  1371. S_NO,newreference(instr.operands[1].ref))));
  1372. end
  1373. else
  1374. Message(assem_e_invalid_opcode_and_operand);
  1375. end;
  1376. OPR_SYMBOL: Begin
  1377. p^.concat(new(pai386,op_csymbol(instruc,
  1378. instr.stropsize, newcsymbol(instr.operands[1].symbol^,0))));
  1379. End;
  1380. OPR_NONE: Begin
  1381. Message(assem_f_internal_error_in_concatopcode);
  1382. end;
  1383. else
  1384. Begin
  1385. Message(assem_f_internal_error_in_concatopcode);
  1386. end;
  1387. end;
  1388. end;
  1389. 2:
  1390. Begin
  1391. if instruc in [A_MOVSX,A_MOVZX,A_MOVSB,A_MOVSBL,A_MOVSBW,
  1392. A_MOVSWL,A_MOVZB,A_MOVZWL] then
  1393. { movzx and movsx }
  1394. HandleExtend(instr)
  1395. else
  1396. { other instructions }
  1397. Begin
  1398. With instr do
  1399. Begin
  1400. { source }
  1401. opsize := operands[1].size;
  1402. case operands[1].operandtype of
  1403. { reg,reg }
  1404. { reg,ref }
  1405. OPR_REGISTER:
  1406. Begin
  1407. case operands[2].operandtype of
  1408. OPR_REGISTER:
  1409. Begin
  1410. { see info in ratti386.pas, about the problem }
  1411. { which can cause gas here. }
  1412. if (opsize = operands[2].size) then
  1413. begin
  1414. p^.concat(new(pai386,op_reg_reg(instruc,
  1415. opsize,operands[1].reg,operands[2].reg)));
  1416. end
  1417. else
  1418. if instruc = A_IN then
  1419. p^.concat(new(pai386,op_reg_reg(instruc,
  1420. operands[2].size,operands[1].reg,operands[2].reg)))
  1421. else
  1422. if instruc = A_OUT then
  1423. p^.concat(new(pai386,op_reg_reg(instruc,
  1424. operands[1].size,operands[1].reg,operands[2].reg)))
  1425. else
  1426. { these do not require any size specification. }
  1427. if (instruc in [A_SAL,A_SAR,A_SHL,A_SHR,A_ROL,
  1428. A_ROR,A_RCR,A_RCL]) then
  1429. { outs and ins are already taken care by }
  1430. { the first pass. }
  1431. p^.concat(new(pai386,op_reg_reg(instruc,
  1432. S_NO,operands[1].reg,operands[2].reg)))
  1433. else
  1434. Message(assem_e_invalid_opcode_and_operand);
  1435. end;
  1436. OPR_REFERENCE:
  1437. { variable name. }
  1438. { here we must check the instruction type }
  1439. { before deciding if to use and compare }
  1440. { any sizes. }
  1441. if assigned(operands[2].ref.symbol) then
  1442. Begin
  1443. if (opsize = operands[2].size) or (instruc in
  1444. [A_RCL,A_RCR,A_ROL,A_ROR,A_SAL,A_SAR,A_SHR,A_SHL]) then
  1445. p^.concat(new(pai386,op_reg_ref(instruc,
  1446. opsize,operands[1].reg,newreference(operands[2].ref))))
  1447. else
  1448. Message(assem_e_invalid_size_in_ref);
  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. if instruc in [A_LEA,A_LDS,A_LES,A_LFS,A_LGS,A_LSS]
  1549. then
  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
  1563. else
  1564. Begin
  1565. { register reference }
  1566. { possiblities:1) local variable which }
  1567. { has been replaced by bp and offset }
  1568. { in this case size should be valid }
  1569. { 2) Indirect register }
  1570. { adressing, 2nd operand determines }
  1571. { size. }
  1572. if (opsize = operands[2].size) or (opsize = S_NO) then
  1573. Begin
  1574. p^.concat(new(pai386,op_ref_reg(instruc,
  1575. operands[2].size,newreference(operands[1].ref),
  1576. operands[2].reg)));
  1577. end
  1578. else
  1579. Message(assem_e_invalid_size_in_ref);
  1580. end;
  1581. OPR_REFERENCE: { special opcodes }
  1582. p^.concat(new(pai386,op_ref_ref(instruc,
  1583. opsize,newreference(operands[1].ref),
  1584. newreference(operands[2].ref))));
  1585. else
  1586. Begin
  1587. Message(assem_f_internal_error_in_concatopcode);
  1588. end;
  1589. end; { end inner case }
  1590. end; { end case }
  1591. end; { end with }
  1592. end; {end if movsx... }
  1593. end;
  1594. 3: Begin
  1595. { only imul, shld and shrd }
  1596. { middle must be a register }
  1597. if (instruc in [A_SHLD,A_SHRD]) and (instr.operands[2].operandtype =
  1598. OPR_REGISTER) then
  1599. Begin
  1600. case instr.operands[2].size of
  1601. S_W: if instr.operands[1].operandtype = OPR_CONSTANT then
  1602. Begin
  1603. if instr.operands[1].val <= $ff then
  1604. Begin
  1605. if instr.operands[3].size in [S_W] then
  1606. Begin
  1607. case instr.operands[3].operandtype of
  1608. OPR_REFERENCE: { MISSING !!!! } ;
  1609. OPR_REGISTER: p^.concat(new(pai386,
  1610. op_const_reg_reg(instruc, S_W,
  1611. instr.operands[1].val, instr.operands[2].reg,
  1612. instr.operands[3].reg)));
  1613. else
  1614. Message(assem_e_invalid_opcode_and_operand);
  1615. Message(assem_e_invalid_opcode_and_operand);
  1616. end;
  1617. end
  1618. else
  1619. Message(assem_e_invalid_opcode_and_operand);
  1620. end;
  1621. end
  1622. else
  1623. Message(assem_e_invalid_opcode_and_operand);
  1624. S_L: if instr.operands[1].operandtype = OPR_CONSTANT then
  1625. Begin
  1626. if instr.operands[1].val <= $ff then
  1627. Begin
  1628. if instr.operands[3].size in [S_L] then
  1629. Begin
  1630. case instr.operands[3].operandtype of
  1631. OPR_REFERENCE: { MISSING !!!! } ;
  1632. OPR_REGISTER: p^.concat(new(pai386,
  1633. op_const_reg_reg(instruc, S_L,
  1634. instr.operands[1].val, instr.operands[2].reg,
  1635. instr.operands[3].reg)));
  1636. else
  1637. Message(assem_e_invalid_opcode_and_operand);
  1638. end;
  1639. end
  1640. else
  1641. Message(assem_e_invalid_opcode_and_operand);
  1642. end;
  1643. end
  1644. else
  1645. Message(assem_e_invalid_opcode_and_operand);
  1646. else
  1647. Message(assem_e_invalid_opcode_and_operand);
  1648. end; { end case }
  1649. end
  1650. else
  1651. if (instruc in [A_IMUL]) and (instr.operands[3].operandtype
  1652. = OPR_REGISTER) then
  1653. Begin
  1654. case instr.operands[3].size of
  1655. S_W: if instr.operands[1].operandtype = OPR_CONSTANT then
  1656. Begin
  1657. if instr.operands[1].val <= $ffff then
  1658. Begin
  1659. if instr.operands[2].size in [S_W] then
  1660. Begin
  1661. case instr.operands[2].operandtype of
  1662. OPR_REFERENCE: { MISSING !!!! } ;
  1663. OPR_REGISTER: p^.concat(new(pai386,
  1664. op_const_reg_reg(instruc, S_W,
  1665. instr.operands[1].val, instr.operands[2].reg,
  1666. instr.operands[3].reg)));
  1667. else
  1668. Message(assem_e_invalid_opcode_and_operand);
  1669. end; { end case }
  1670. end
  1671. else
  1672. Message(assem_e_invalid_opcode_and_operand);
  1673. end;
  1674. end
  1675. else
  1676. Message(assem_e_invalid_opcode_and_operand);
  1677. S_L: if instr.operands[1].operandtype = OPR_CONSTANT then
  1678. Begin
  1679. if instr.operands[1].val <= $7fffffff then
  1680. Begin
  1681. if instr.operands[2].size in [S_L] then
  1682. Begin
  1683. case instr.operands[2].operandtype of
  1684. OPR_REFERENCE: { MISSING !!!! } ;
  1685. OPR_REGISTER: p^.concat(new(pai386,
  1686. op_const_reg_reg(instruc, S_L,
  1687. instr.operands[1].val, instr.operands[2].reg,
  1688. instr.operands[3].reg)));
  1689. else
  1690. Message(assem_e_invalid_opcode_and_operand);
  1691. end; { end case }
  1692. end
  1693. else
  1694. Message(assem_e_invalid_opcode_and_operand);
  1695. end;
  1696. end
  1697. else
  1698. Message(assem_e_invalid_opcode_and_operand);
  1699. else
  1700. Message(assem_e_invalid_middle_sized_operand);
  1701. end; { end case }
  1702. end { endif }
  1703. else
  1704. Message(assem_e_invalid_three_operand_opcode);
  1705. end;
  1706. end; { end case }
  1707. end;
  1708. end;
  1709. {---------------------------------------------------------------------}
  1710. { Routines for the parsing }
  1711. {---------------------------------------------------------------------}
  1712. procedure consume(t : tinteltoken);
  1713. begin
  1714. if t<>actasmtoken then
  1715. Message(assem_e_syntax_error);
  1716. actasmtoken:=gettoken;
  1717. { if the token must be ignored, then }
  1718. { get another token to parse. }
  1719. if actasmtoken = AS_NONE then
  1720. actasmtoken := gettoken;
  1721. end;
  1722. function findregister(const s : string): tregister;
  1723. {*********************************************************************}
  1724. { FUNCTION findregister(s: string):tasmop; }
  1725. { Description: Determines if the s string is a valid register, }
  1726. { if so returns correct tregister token, or R_NO if not found. }
  1727. {*********************************************************************}
  1728. var
  1729. i: tregister;
  1730. begin
  1731. findregister := R_NO;
  1732. for i:=firstreg to lastreg do
  1733. if s = iasmregs[i] then
  1734. Begin
  1735. findregister := i;
  1736. exit;
  1737. end;
  1738. end;
  1739. function findoverride(const s: string; var reg:tregister): boolean;
  1740. var
  1741. i: byte;
  1742. begin
  1743. findoverride := FALSE;
  1744. reg := R_NO;
  1745. for i:=0 to _count_asmoverrides do
  1746. Begin
  1747. if s = _asmoverrides[i] then
  1748. begin
  1749. reg := _overridetokens[i];
  1750. findoverride := TRUE;
  1751. exit;
  1752. end;
  1753. end;
  1754. end;
  1755. function findprefix(const s: string; var token: tasmop): boolean;
  1756. var i: byte;
  1757. Begin
  1758. findprefix := FALSE;
  1759. for i:=0 to _count_asmprefixes do
  1760. Begin
  1761. if s = _asmprefixes[i] then
  1762. begin
  1763. token := _prefixtokens[i];
  1764. findprefix := TRUE;
  1765. exit;
  1766. end;
  1767. end;
  1768. end;
  1769. function findsegment(const s:string): tregister;
  1770. {*********************************************************************}
  1771. { FUNCTION findsegment(s: string):tasmop; }
  1772. { Description: Determines if the s string is a valid segment register}
  1773. { if so returns correct tregister token, or R_NO if not found. }
  1774. {*********************************************************************}
  1775. var
  1776. i: tregister;
  1777. Begin
  1778. findsegment := R_DEFAULT_SEG;
  1779. for i:=firstsreg to lastsreg do
  1780. if s = iasmregs[i] then
  1781. Begin
  1782. findsegment := i;
  1783. exit;
  1784. end;
  1785. end;
  1786. function findopcode(const s: string): tasmop;
  1787. {*********************************************************************}
  1788. { FUNCTION findopcode(s: string): tasmop; }
  1789. { Description: Determines if the s string is a valid opcode }
  1790. { if so returns correct tasmop token. }
  1791. {*********************************************************************}
  1792. var
  1793. i: tasmop;
  1794. j: byte;
  1795. Begin
  1796. findopcode := A_NONE;
  1797. for i:=firstop to lastop do
  1798. if s = iasmops^[i] then
  1799. begin
  1800. findopcode:=i;
  1801. exit;
  1802. end;
  1803. { not found yet, search for extended opcodes }
  1804. { now, in this case, we must use the suffix }
  1805. { to determine the size of the instruction }
  1806. for j:=0 to _count_asmspecialops do
  1807. Begin
  1808. if s = _specialops[j] then
  1809. Begin
  1810. findopcode := _specialopstokens[j];
  1811. { set the size }
  1812. case s[length(s)] of
  1813. 'B': instr.stropsize := S_B;
  1814. 'D': instr.stropsize := S_L;
  1815. 'W': instr.stropsize := S_W;
  1816. end;
  1817. exit;
  1818. end;
  1819. end;
  1820. end;
  1821. Function CheckPrefix(prefix: tasmop; opcode:tasmop): Boolean;
  1822. { Checks if the prefix is valid with the following instruction }
  1823. { return false if not, otherwise true }
  1824. Begin
  1825. CheckPrefix := TRUE;
  1826. Case prefix of
  1827. A_REP,A_REPNE,A_REPE: if not (opcode in [A_SCAS,A_INS,A_OUTS,A_MOVS,
  1828. A_CMPS,A_LODS,A_STOS]) then
  1829. Begin
  1830. CheckPrefix := FALSE;
  1831. exit;
  1832. end;
  1833. A_LOCK: if not (opcode in [A_BT,A_BTS,A_BTR,A_BTC,A_XCHG,A_ADD,A_OR,
  1834. A_ADC,A_SBB,A_AND,A_SUB,A_XOR,A_NOT,A_NEG,A_INC,A_DEC]) then
  1835. Begin
  1836. CheckPrefix := FALSE;
  1837. Exit;
  1838. end;
  1839. A_NONE: exit; { no prefix here }
  1840. else
  1841. CheckPrefix := FALSE;
  1842. end; { end case }
  1843. end;
  1844. Procedure InitAsmRef(var instr: TInstruction);
  1845. {*********************************************************************}
  1846. { Description: This routine first check if the instruction is of }
  1847. { type OPR_NONE, or OPR_REFERENCE , if not it gives out an error. }
  1848. { If the operandtype = OPR_NONE or <> OPR_REFERENCE then it sets up }
  1849. { the operand type to OPR_REFERENCE, as well as setting up the ref }
  1850. { to point to the default segment. }
  1851. {*********************************************************************}
  1852. Begin
  1853. With instr do
  1854. Begin
  1855. case operands[operandnum].operandtype of
  1856. OPR_REFERENCE: exit;
  1857. OPR_NONE: ;
  1858. else
  1859. Message(assem_e_invalid_operand_type);
  1860. end;
  1861. operands[operandnum].operandtype := OPR_REFERENCE;
  1862. operands[operandnum].ref.segment := R_DEFAULT_SEG;
  1863. end;
  1864. end;
  1865. Function CheckOverride(segreg: tregister; var instr: TInstruction): Boolean;
  1866. { Check if the override is valid, and if so then }
  1867. { update the instr variable accordingly. }
  1868. Begin
  1869. CheckOverride := FALSE;
  1870. if instr.getinstruction in [A_MOVS,A_XLAT,A_CMPS] then
  1871. Begin
  1872. CheckOverride := TRUE;
  1873. Message(assem_e_segment_override_not_supported);
  1874. end
  1875. end;
  1876. Function CalculateExpression(expression: string): longint;
  1877. var
  1878. expr: TExprParse;
  1879. Begin
  1880. expr.Init;
  1881. CalculateExpression := expr.Evaluate(expression);
  1882. expr.Done;
  1883. end;
  1884. Procedure GetRecordOffsetSize(const expr: string;var offset:longint;var size:longint);
  1885. {*********************************************************************}
  1886. { PROCEDURE GetRecordOffsetSize }
  1887. { Description: This routine builds up a record offset after a AS_DOT }
  1888. { token is encountered. }
  1889. { On entry actasmtoken should be equal to AS_DOT }
  1890. {*********************************************************************}
  1891. { EXIT CONDITION: On exit the routine should point to either the }
  1892. { AS_COMMA or AS_SEPARATOR token. }
  1893. { Warning: This is called recursively. }
  1894. {*********************************************************************}
  1895. var
  1896. toffset,tsize : longint;
  1897. Begin
  1898. offset:=0;
  1899. size:=0;
  1900. Consume(AS_DOT);
  1901. if actasmtoken = AS_ID then
  1902. Begin
  1903. if not GetTypeOffsetSize(expr,actasmpattern,toffset,tsize) and
  1904. not GetVarOffsetSize(expr,actasmpattern,toffset,tsize) then
  1905. begin
  1906. Message(assem_e_syntax_error);
  1907. toffset:=0;
  1908. tsize:=0;
  1909. end;
  1910. inc(offset,toffset);
  1911. size:=tsize;
  1912. Consume(AS_ID);
  1913. case actasmtoken of
  1914. AS_SEPARATOR,
  1915. AS_COMMA : exit;
  1916. AS_DOT : begin
  1917. GetRecordOffsetSize(expr,toffset,tsize);
  1918. inc(offset,toffset);
  1919. size:=tsize;
  1920. end;
  1921. else
  1922. Begin
  1923. Message(assem_e_syntax_error);
  1924. repeat
  1925. consume(actasmtoken)
  1926. until (actasmtoken = AS_SEPARATOR) or (actasmtoken = AS_COMMA);
  1927. exit;
  1928. end;
  1929. end;
  1930. end
  1931. else
  1932. Begin
  1933. Message(assem_e_syntax_error);
  1934. repeat
  1935. consume(actasmtoken)
  1936. until (actasmtoken = AS_SEPARATOR) or (actasmtoken = AS_COMMA);
  1937. end;
  1938. end;
  1939. Function BuildRefExpression: longint;
  1940. {*********************************************************************}
  1941. { FUNCTION BuildExpression: longint }
  1942. { Description: This routine calculates a constant expression to }
  1943. { a given value. The return value is the value calculated from }
  1944. { the expression. }
  1945. { The following tokens (not strings) are recognized: }
  1946. { (,),SHL,SHR,/,*,NOT,OR,XOR,AND,MOD,+/-,numbers,ID to constants. }
  1947. {*********************************************************************}
  1948. { ENTRY: On entry the token should be any valid expression token. }
  1949. { EXIT: On Exit the token points to any token after the closing }
  1950. { RBRACKET }
  1951. { ERROR RECOVERY: Tries to find COMMA or SEPARATOR token by consuming }
  1952. { invalid tokens. }
  1953. {*********************************************************************}
  1954. var tempstr: string;
  1955. expr: string;
  1956. l,k : longint;
  1957. errorflag : boolean;
  1958. Begin
  1959. errorflag := FALSE;
  1960. tempstr := '';
  1961. expr := '';
  1962. { tell tokenizer that we are in }
  1963. { an expression. }
  1964. inexpression := TRUE;
  1965. Repeat
  1966. Case actasmtoken of
  1967. AS_LPAREN: Begin
  1968. Consume(AS_LPAREN);
  1969. expr := expr + '(';
  1970. end;
  1971. AS_RPAREN: Begin
  1972. Consume(AS_RPAREN);
  1973. expr := expr + ')';
  1974. end;
  1975. AS_SHL: Begin
  1976. Consume(AS_SHL);
  1977. expr := expr + '<';
  1978. end;
  1979. AS_SHR: Begin
  1980. Consume(AS_SHR);
  1981. expr := expr + '>';
  1982. end;
  1983. AS_SLASH: Begin
  1984. Consume(AS_SLASH);
  1985. expr := expr + '/';
  1986. end;
  1987. AS_MOD: Begin
  1988. Consume(AS_MOD);
  1989. expr := expr + '%';
  1990. end;
  1991. AS_STAR: Begin
  1992. Consume(AS_STAR);
  1993. expr := expr + '*';
  1994. end;
  1995. AS_PLUS: Begin
  1996. Consume(AS_PLUS);
  1997. expr := expr + '+';
  1998. end;
  1999. AS_MINUS: Begin
  2000. Consume(AS_MINUS);
  2001. expr := expr + '-';
  2002. end;
  2003. AS_AND: Begin
  2004. Consume(AS_AND);
  2005. expr := expr + '&';
  2006. end;
  2007. AS_NOT: Begin
  2008. Consume(AS_NOT);
  2009. expr := expr + '~';
  2010. end;
  2011. AS_XOR: Begin
  2012. Consume(AS_XOR);
  2013. expr := expr + '^';
  2014. end;
  2015. AS_OR: Begin
  2016. Consume(AS_OR);
  2017. expr := expr + '|';
  2018. end;
  2019. { End of reference }
  2020. AS_RBRACKET: Begin
  2021. if not ErrorFlag then
  2022. BuildRefExpression := CalculateExpression(expr)
  2023. else
  2024. BuildRefExpression := 0;
  2025. Consume(AS_RBRACKET);
  2026. { no longer in an expression }
  2027. inexpression := FALSE;
  2028. exit;
  2029. end;
  2030. AS_ID:
  2031. Begin
  2032. tempstr:=actasmpattern;
  2033. consume(AS_ID);
  2034. if actasmtoken=AS_DOT then
  2035. begin
  2036. GetRecordOffsetSize(tempstr,l,k);
  2037. str(l, tempstr);
  2038. expr := expr + tempstr;
  2039. end
  2040. else
  2041. begin
  2042. if SearchIConstant(tempstr,l) then
  2043. begin
  2044. str(l, tempstr);
  2045. expr := expr + tempstr;
  2046. end
  2047. else
  2048. Message1(assem_e_invalid_const_symbol,tempstr);
  2049. end;
  2050. end;
  2051. AS_INTNUM: Begin
  2052. expr := expr + actasmpattern;
  2053. Consume(AS_INTNUM);
  2054. end;
  2055. AS_BINNUM: Begin
  2056. tempstr := BinaryToDec(actasmpattern);
  2057. if tempstr = '' then
  2058. Message(assem_f_error_converting_bin);
  2059. expr:=expr+tempstr;
  2060. Consume(AS_BINNUM);
  2061. end;
  2062. AS_HEXNUM: Begin
  2063. tempstr := HexToDec(actasmpattern);
  2064. if tempstr = '' then
  2065. Message(assem_f_error_converting_hex);
  2066. expr:=expr+tempstr;
  2067. Consume(AS_HEXNUM);
  2068. end;
  2069. AS_OCTALNUM: Begin
  2070. tempstr := OctalToDec(actasmpattern);
  2071. if tempstr = '' then
  2072. Message(assem_f_error_converting_octal);
  2073. expr:=expr+tempstr;
  2074. Consume(AS_OCTALNUM);
  2075. end;
  2076. else
  2077. Begin
  2078. { write error only once. }
  2079. if not errorflag then
  2080. Message(assem_e_invalid_constant_expression);
  2081. BuildRefExpression := 0;
  2082. if actasmtoken in [AS_COMMA,AS_SEPARATOR] then exit;
  2083. { consume tokens until we find COMMA or SEPARATOR }
  2084. Consume(actasmtoken);
  2085. errorflag := TRUE;
  2086. end;
  2087. end;
  2088. Until false;
  2089. end;
  2090. Procedure BuildRecordOffset(var instr: TInstruction; varname: string);
  2091. {*********************************************************************}
  2092. { PROCEDURE BuildRecordOffset(var Instr: TInstruction) }
  2093. { Description: This routine takes care of field specifiers of records }
  2094. { and/or variables in asm operands. It updates the offset accordingly}
  2095. {*********************************************************************}
  2096. { ENTRY: On entry the token should be DOT. }
  2097. { name: should be the name of the variable to be expanded. '' if }
  2098. { no variabled specified. }
  2099. { EXIT: On Exit the token points to SEPARATOR or COMMA. }
  2100. { ERROR RECOVERY: Tries to find COMMA or SEPARATOR token by consuming }
  2101. { invalid tokens. }
  2102. {*********************************************************************}
  2103. var
  2104. firstpass: boolean;
  2105. offset: longint;
  2106. tsize,toffset : longint;
  2107. basetypename : string;
  2108. Begin
  2109. basetypename := '';
  2110. firstpass := TRUE;
  2111. { // .ID[REG].ID ... // }
  2112. { // .ID.ID... // }
  2113. Consume(AS_DOT);
  2114. Repeat
  2115. case actasmtoken of
  2116. AS_ID: Begin
  2117. { we must reset the operand size - since only the last field }
  2118. { will give us the size of the operand. }
  2119. { instr.opsize := S_NO;}
  2120. InitAsmRef(instr);
  2121. { // var_name.typefield.typefield // }
  2122. if (varname <> '') then
  2123. Begin
  2124. if GetVarOffsetSize(varname,actasmpattern,toffset,tsize) then
  2125. Begin
  2126. Inc(instr.operands[operandnum].ref.offset,tOffset);
  2127. SetOperandSize(instr,operandnum,tsize);
  2128. end
  2129. else
  2130. Message1(assem_e_unknown_id,actasmpattern);
  2131. end
  2132. else
  2133. { [ref].var_name.typefield.typefield ... }
  2134. { [ref].var_name[reg] }
  2135. if not assigned(instr.operands[operandnum].ref.symbol) and
  2136. firstpass then
  2137. Begin
  2138. if not CreateVarInstr(instr,actasmpattern,operandnum) then
  2139. Begin
  2140. { type field ? }
  2141. basetypename := actasmpattern;
  2142. end
  2143. else
  2144. varname := actasmpattern;
  2145. end
  2146. else
  2147. if firstpass then
  2148. { [ref].typefield.typefield ... }
  2149. { where the first typefield must specifiy the base }
  2150. { object or record type. }
  2151. Begin
  2152. basetypename := actasmpattern;
  2153. end
  2154. else
  2155. { [ref].typefield.typefield ... }
  2156. { basetpyename is already set up... now look for fields. }
  2157. Begin
  2158. if GetTypeOffsetSize(basetypename,actasmpattern,tOffset,Tsize) then
  2159. Begin
  2160. Inc(instr.operands[operandnum].ref.offset,tOffset);
  2161. SetOperandSize(instr,operandnum,Tsize);
  2162. end
  2163. else
  2164. Message1(assem_e_unknown_id,actasmpattern);
  2165. end;
  2166. Consume(AS_ID);
  2167. { Take care of index register on this variable }
  2168. if actasmtoken = AS_LBRACKET then
  2169. Begin
  2170. Consume(AS_LBRACKET);
  2171. Case actasmtoken of
  2172. AS_REGISTER: Begin
  2173. if instr.operands[operandnum].ref.index <> R_NO then
  2174. Message(assem_e_defining_index_more_than_once);
  2175. instr.operands[operandnum].ref.index :=
  2176. findregister(actasmpattern);
  2177. Consume(AS_REGISTER);
  2178. end;
  2179. else
  2180. Begin
  2181. { add offsets , assuming these are constant expressions... }
  2182. Inc(instr.operands[operandnum].ref.offset,BuildRefExpression);
  2183. end;
  2184. end;
  2185. Consume(AS_RBRACKET);
  2186. end;
  2187. { Here we should either have AS_DOT, AS_SEPARATOR or AS_COMMA }
  2188. if actasmtoken = AS_DOT then
  2189. Consume(AS_DOT);
  2190. firstpass := FALSE;
  2191. Offset := 0;
  2192. end;
  2193. AS_SEPARATOR: exit;
  2194. AS_COMMA: exit;
  2195. else
  2196. Begin
  2197. Message(assem_e_invalid_field_specifier);
  2198. Consume(actasmtoken);
  2199. firstpass := FALSE;
  2200. end;
  2201. end; { end case }
  2202. Until (actasmtoken = AS_SEPARATOR) or (actasmtoken = AS_COMMA);
  2203. end;
  2204. Function BuildExpression: longint;
  2205. {*********************************************************************}
  2206. { FUNCTION BuildExpression: longint }
  2207. { Description: This routine calculates a constant expression to }
  2208. { a given value. The return value is the value calculated from }
  2209. { the expression. }
  2210. { The following tokens (not strings) are recognized: }
  2211. { (,),SHL,SHR,/,*,NOT,OR,XOR,AND,MOD,+/-,numbers,ID to constants. }
  2212. {*********************************************************************}
  2213. { ENTRY: On entry the token should be any valid expression token. }
  2214. { EXIT: On Exit the token points to either COMMA or SEPARATOR }
  2215. { ERROR RECOVERY: Tries to find COMMA or SEPARATOR token by consuming }
  2216. { invalid tokens. }
  2217. {*********************************************************************}
  2218. var expr: string;
  2219. tempstr: string;
  2220. l,k : longint;
  2221. errorflag: boolean;
  2222. Begin
  2223. errorflag := FALSE;
  2224. expr := '';
  2225. tempstr := '';
  2226. { tell tokenizer that we are in an expression. }
  2227. inexpression := TRUE;
  2228. Repeat
  2229. Case actasmtoken of
  2230. AS_LPAREN: Begin
  2231. Consume(AS_LPAREN);
  2232. expr := expr + '(';
  2233. end;
  2234. AS_RPAREN: Begin
  2235. Consume(AS_RPAREN);
  2236. expr := expr + ')';
  2237. end;
  2238. AS_SHL: Begin
  2239. Consume(AS_SHL);
  2240. expr := expr + '<';
  2241. end;
  2242. AS_SHR: Begin
  2243. Consume(AS_SHR);
  2244. expr := expr + '>';
  2245. end;
  2246. AS_SLASH: Begin
  2247. Consume(AS_SLASH);
  2248. expr := expr + '/';
  2249. end;
  2250. AS_MOD: Begin
  2251. Consume(AS_MOD);
  2252. expr := expr + '%';
  2253. end;
  2254. AS_STAR: Begin
  2255. Consume(AS_STAR);
  2256. expr := expr + '*';
  2257. end;
  2258. AS_PLUS: Begin
  2259. Consume(AS_PLUS);
  2260. expr := expr + '+';
  2261. end;
  2262. AS_MINUS: Begin
  2263. Consume(AS_MINUS);
  2264. expr := expr + '-';
  2265. end;
  2266. AS_AND: Begin
  2267. Consume(AS_AND);
  2268. expr := expr + '&';
  2269. end;
  2270. AS_NOT: Begin
  2271. Consume(AS_NOT);
  2272. expr := expr + '~';
  2273. end;
  2274. AS_XOR: Begin
  2275. Consume(AS_XOR);
  2276. expr := expr + '^';
  2277. end;
  2278. AS_OR: Begin
  2279. Consume(AS_OR);
  2280. expr := expr + '|';
  2281. end;
  2282. AS_ID: Begin
  2283. tempstr:=actasmpattern;
  2284. consume(AS_ID);
  2285. if actasmtoken=AS_DOT then
  2286. begin
  2287. GetRecordOffsetSize(tempstr,l,k);
  2288. str(l, tempstr);
  2289. expr := expr + tempstr;
  2290. end
  2291. else
  2292. begin
  2293. if SearchIConstant(tempstr,l) then
  2294. begin
  2295. str(l, tempstr);
  2296. expr := expr + tempstr;
  2297. end
  2298. else
  2299. Message1(assem_e_invalid_const_symbol,actasmpattern);
  2300. end;
  2301. end;
  2302. AS_INTNUM: Begin
  2303. expr := expr + actasmpattern;
  2304. Consume(AS_INTNUM);
  2305. end;
  2306. AS_BINNUM: Begin
  2307. tempstr := BinaryToDec(actasmpattern);
  2308. if tempstr = '' then
  2309. Message(assem_f_error_converting_bin);
  2310. expr:=expr+tempstr;
  2311. Consume(AS_BINNUM);
  2312. end;
  2313. AS_HEXNUM: Begin
  2314. tempstr := HexToDec(actasmpattern);
  2315. if tempstr = '' then
  2316. Message(assem_f_error_converting_hex);
  2317. expr:=expr+tempstr;
  2318. Consume(AS_HEXNUM);
  2319. end;
  2320. AS_OCTALNUM: Begin
  2321. tempstr := OctalToDec(actasmpattern);
  2322. if tempstr = '' then
  2323. Message(assem_f_error_converting_octal);
  2324. expr:=expr+tempstr;
  2325. Consume(AS_OCTALNUM);
  2326. end;
  2327. { go to next term }
  2328. AS_COMMA: Begin
  2329. if not ErrorFlag then
  2330. BuildExpression := CalculateExpression(expr)
  2331. else
  2332. BuildExpression := 0;
  2333. inexpression := FALSE;
  2334. Exit;
  2335. end;
  2336. { go to next symbol }
  2337. AS_SEPARATOR: Begin
  2338. if not ErrorFlag then
  2339. BuildExpression := CalculateExpression(expr)
  2340. else
  2341. BuildExpression := 0;
  2342. inexpression := FALSE;
  2343. Exit;
  2344. end;
  2345. else
  2346. Begin
  2347. { only write error once. }
  2348. if not errorflag then
  2349. Message(assem_e_invalid_constant_expression);
  2350. { consume tokens until we find COMMA or SEPARATOR }
  2351. Consume(actasmtoken);
  2352. errorflag := TRUE;
  2353. End;
  2354. end;
  2355. Until false;
  2356. end;
  2357. Procedure BuildScaling(Var instr: TInstruction);
  2358. {*********************************************************************}
  2359. { Takes care of parsing expression starting from the scaling value }
  2360. { up to and including possible field specifiers. }
  2361. { EXIT CONDITION: On exit the routine should point to AS_SEPARATOR }
  2362. { or AS_COMMA. On entry should point to AS_STAR token. }
  2363. {*********************************************************************}
  2364. var str:string;
  2365. l: longint;
  2366. code: integer;
  2367. Begin
  2368. Consume(AS_STAR);
  2369. if (instr.operands[operandnum].ref.scalefactor <> 0)
  2370. and (instr.operands[operandnum].ref.scalefactor <> 1) then
  2371. Begin
  2372. Message(assem_f_internal_error_in_buildscale);
  2373. end;
  2374. case actasmtoken of
  2375. AS_INTNUM: str := actasmpattern;
  2376. AS_HEXNUM: str := HexToDec(actasmpattern);
  2377. AS_BINNUM: str := BinaryToDec(actasmpattern);
  2378. AS_OCTALNUM: str := OctalToDec(actasmpattern);
  2379. else
  2380. Message(assem_e_syntax_error);
  2381. end;
  2382. val(str, l, code);
  2383. if code <> 0 then
  2384. Message(assem_e_invalid_scaling_factor);
  2385. if ((l = 2) or (l = 4) or (l = 8) or (l = 1)) and (code = 0) then
  2386. begin
  2387. instr.operands[operandnum].ref.scalefactor := l;
  2388. end
  2389. else
  2390. Begin
  2391. Message(assem_e_invalid_scaling_value);
  2392. instr.operands[operandnum].ref.scalefactor := 0;
  2393. end;
  2394. if instr.operands[operandnum].ref.index = R_NO then
  2395. Begin
  2396. Message(assem_e_scaling_value_only_allowed_with_index);
  2397. instr.operands[operandnum].ref.scalefactor := 0;
  2398. end;
  2399. { Consume the scaling number }
  2400. Consume(actasmtoken);
  2401. case actasmtoken of
  2402. { // [...*SCALING-expr] ... // }
  2403. AS_MINUS: Begin
  2404. if instr.operands[operandnum].ref.offset <> 0 then
  2405. Message(assem_f_internal_error_in_buildscale);
  2406. instr.operands[operandnum].ref.offset :=
  2407. BuildRefExpression;
  2408. end;
  2409. { // [...*SCALING+expr] ... // }
  2410. AS_PLUS: Begin
  2411. if instr.operands[operandnum].ref.offset <> 0 then
  2412. Message(assem_f_internal_error_in_buildscale);
  2413. instr.operands[operandnum].ref.offset :=
  2414. BuildRefExpression;
  2415. end;
  2416. { // [...*SCALING] ... // }
  2417. AS_RBRACKET: Consume(AS_RBRACKET);
  2418. else
  2419. Message(assem_e_invalid_scaling_value);
  2420. end;
  2421. { // .Field.Field ... or separator/comma // }
  2422. Case actasmtoken of
  2423. AS_DOT: BuildRecordOffset(instr,'');
  2424. AS_COMMA, AS_SEPARATOR: ;
  2425. else
  2426. Message(assem_e_syntax_error);
  2427. end;
  2428. end;
  2429. Procedure BuildReference(var instr: TInstruction);
  2430. {*********************************************************************}
  2431. { EXIT CONDITION: On exit the routine should point to either the }
  2432. { AS_COMMA or AS_SEPARATOR token. }
  2433. { On entry: contains the register after the opening bracket if any. }
  2434. {*********************************************************************}
  2435. var
  2436. reg:string;
  2437. segreg: boolean;
  2438. negative: boolean;
  2439. expr: string;
  2440. Begin
  2441. expr := '';
  2442. if instr.operands[operandnum].operandtype <> OPR_REFERENCE then
  2443. Begin
  2444. Message(assem_e_syn_no_ref_with_brackets);
  2445. InitAsmRef(instr);
  2446. consume(AS_REGISTER);
  2447. end
  2448. else
  2449. Begin
  2450. { save the reg }
  2451. reg := actasmpattern;
  2452. { is the syntax of the form: [REG:REG...] }
  2453. consume(AS_REGISTER);
  2454. if actasmtoken = AS_COLON then
  2455. begin
  2456. segreg := TRUE;
  2457. Message(assem_e_expression_form_not_supported);
  2458. if instr.operands[operandnum].ref.segment <> R_NO then
  2459. Message(assem_e_defining_seg_more_than_once);
  2460. instr.operands[operandnum].ref.segment := findsegment(reg);
  2461. { Here we should process the syntax of the form }
  2462. { [reg:reg...] }
  2463. {!!!!!!!!!!!!!!!!!!!!!!!! }
  2464. end
  2465. { This is probably of the following syntax: }
  2466. { SREG:[REG...] where SReg: is optional. }
  2467. { Therefore we immediately say that reg }
  2468. { is the base. }
  2469. else
  2470. Begin
  2471. if instr.operands[operandnum].ref.base <> R_NO then
  2472. Message(assem_e_defining_base_more_than_once);
  2473. instr.operands[operandnum].ref.base := findregister(reg);
  2474. end;
  2475. { we process this type of syntax immediately... }
  2476. case actasmtoken of
  2477. { // REG:[REG].Field.Field ... // }
  2478. { // REG:[REG].Field[REG].Field... // }
  2479. AS_RBRACKET: Begin
  2480. Consume(AS_RBRACKET);
  2481. { check for record fields }
  2482. if actasmtoken = AS_DOT then
  2483. BuildRecordOffset(instr,'');
  2484. if (actasmtoken = AS_SEPARATOR) or (actasmtoken = AS_COMMA) then
  2485. exit
  2486. else
  2487. Message(assem_e_syn_reference);
  2488. end;
  2489. { // REG:[REG +/- ...].Field.Field ... // }
  2490. AS_PLUS,AS_MINUS: Begin
  2491. if actasmtoken = AS_MINUS then
  2492. Begin
  2493. expr := '-';
  2494. negative := TRUE
  2495. end
  2496. else
  2497. Begin
  2498. negative := FALSE;
  2499. expr := '+';
  2500. end;
  2501. Consume(actasmtoken);
  2502. { // REG:[REG+REG+/-...].Field.Field // }
  2503. if actasmtoken = AS_REGISTER then
  2504. Begin
  2505. if negative then
  2506. Message(assem_e_negative_index_register);
  2507. if instr.operands[operandnum].ref.index <> R_NO then
  2508. Message(assem_e_defining_index_more_than_once);
  2509. instr.operands[operandnum].ref.index := findregister(actasmpattern);
  2510. Consume(AS_REGISTER);
  2511. case actasmtoken of
  2512. AS_RBRACKET: { // REG:[REG+REG].Field.Field... // }
  2513. Begin
  2514. Consume(AS_RBRACKET);
  2515. Case actasmtoken of
  2516. AS_DOT: BuildRecordOffset(instr,'');
  2517. AS_COMMA,AS_SEPARATOR: exit;
  2518. else
  2519. Message(assem_e_syntax_error);
  2520. end
  2521. end;
  2522. AS_PLUS,AS_MINUS: { // REG:[REG+REG+/-expr... // }
  2523. Begin
  2524. if instr.operands[operandnum].ref.offset <> 0 then
  2525. Message(assem_f_internal_error_in_buildreference);
  2526. instr.operands[operandnum].ref.offset :=
  2527. BuildRefExpression;
  2528. case actasmtoken of
  2529. AS_DOT: BuildRecordOffset(instr,'');
  2530. AS_COMMA,AS_SEPARATOR: ;
  2531. else
  2532. Message(assem_e_syntax_error);
  2533. end; { end case }
  2534. end;
  2535. AS_STAR: Begin { // REG:[REG+REG*SCALING...].Field.Field... // }
  2536. BuildScaling(instr);
  2537. end;
  2538. else
  2539. Begin
  2540. Message(assem_e_syntax_error);
  2541. end;
  2542. end; { end case }
  2543. end
  2544. else if actasmtoken = AS_STAR then
  2545. { // REG:[REG*SCALING ... ] // }
  2546. Begin
  2547. BuildScaling(instr);
  2548. end
  2549. else
  2550. { // REG:[REG+expr].Field.Field // }
  2551. Begin
  2552. if instr.operands[operandnum].ref.offset <> 0 then
  2553. Message(assem_f_internal_error_in_buildreference);
  2554. instr.operands[operandnum].ref.offset := BuildRefExpression;
  2555. case actasmtoken of
  2556. AS_DOT: BuildRecordOffset(instr,'');
  2557. AS_COMMA,AS_SEPARATOR: ;
  2558. else
  2559. Message(assem_e_syntax_error);
  2560. end; { end case }
  2561. end; { end if }
  2562. end; { end this case }
  2563. { // REG:[REG*scaling] ... // }
  2564. AS_STAR: Begin
  2565. BuildScaling(instr);
  2566. end;
  2567. end;
  2568. end; { end outer if }
  2569. end;
  2570. Procedure BuildBracketExpression(var Instr: TInstruction; var_prefix: boolean);
  2571. {*********************************************************************}
  2572. { PROCEDURE BuildBracketExpression }
  2573. { Description: This routine builds up an expression after a LBRACKET }
  2574. { token is encountered. }
  2575. { On entry actasmtoken should be equal to AS_LBRACKET. }
  2576. { var_prefix : Should be set to true if variable identifier has }
  2577. { been defined, such as in ID[ }
  2578. {*********************************************************************}
  2579. { EXIT CONDITION: On exit the routine should point to either the }
  2580. { AS_COMMA or AS_SEPARATOR token. }
  2581. {*********************************************************************}
  2582. var
  2583. l:longint;
  2584. Begin
  2585. Consume(AS_LBRACKET);
  2586. initAsmRef(instr);
  2587. Case actasmtoken of
  2588. { // Constant reference expression OR variable reference expression // }
  2589. AS_ID: Begin
  2590. if actasmpattern[1] = '@' then
  2591. Message(assem_e_local_symbol_not_allowed_as_ref);
  2592. if SearchIConstant(actasmpattern,l) then
  2593. Begin
  2594. { if there was a variable prefix then }
  2595. { add to offset }
  2596. If var_prefix then
  2597. Begin
  2598. Inc(instr.operands[operandnum].ref.offset, BuildRefExpression);
  2599. end
  2600. else
  2601. instr.operands[operandnum].ref.offset :=BuildRefExpression;
  2602. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2603. Message(assem_e_invalid_operand_in_bracket_expression);
  2604. end
  2605. else if NOT var_prefix then
  2606. Begin
  2607. InitAsmRef(instr);
  2608. if not CreateVarInstr(instr,actasmpattern,operandnum) then
  2609. Message1(assem_e_unknown_id,actasmpattern);
  2610. Consume(AS_ID);
  2611. { is there a constant expression following }
  2612. { the variable name? }
  2613. if actasmtoken <> AS_RBRACKET then
  2614. Begin
  2615. Inc(instr.operands[operandnum].ref.offset, BuildRefExpression);
  2616. end
  2617. else
  2618. Consume(AS_RBRACKET);
  2619. end
  2620. else
  2621. Message1(assem_e_invalid_symbol_name,actasmpattern);
  2622. end;
  2623. { Here we handle the special case in tp where }
  2624. { the + operator is allowed with reg and var }
  2625. { references, such as in mov al, byte ptr [+bx] }
  2626. AS_PLUS: Begin
  2627. Consume(AS_PLUS);
  2628. Case actasmtoken of
  2629. AS_REGISTER: Begin
  2630. BuildReference(instr);
  2631. end;
  2632. AS_ID: Begin
  2633. if actasmpattern[1] = '@' then
  2634. Message(assem_e_local_symbol_not_allowed_as_ref);
  2635. if SearchIConstant(actasmpattern,l) then
  2636. Begin
  2637. { if there was a variable prefix then }
  2638. { add to offset }
  2639. If var_prefix then
  2640. Begin
  2641. Inc(instr.operands[operandnum].ref.offset,
  2642. BuildRefExpression);
  2643. end
  2644. else
  2645. instr.operands[operandnum].ref.offset :=
  2646. BuildRefExpression;
  2647. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2648. Message(assem_e_invalid_operand_in_bracket_expression);
  2649. end
  2650. else if NOT var_prefix then
  2651. Begin
  2652. InitAsmRef(instr);
  2653. if not CreateVarInstr(instr,actasmpattern,operandnum) then
  2654. Message1(assem_e_unknown_id,actasmpattern);
  2655. Consume(AS_ID);
  2656. { is there a constant expression following }
  2657. { the variable name? }
  2658. if actasmtoken <> AS_RBRACKET then
  2659. Begin
  2660. Inc(instr.operands[operandnum].ref.offset,
  2661. BuildRefExpression);
  2662. end
  2663. else
  2664. Consume(AS_RBRACKET);
  2665. end
  2666. else
  2667. Message1(assem_e_invalid_symbol_name,actasmpattern);
  2668. end;
  2669. { // Constant reference expression // }
  2670. AS_INTNUM,AS_BINNUM,AS_OCTALNUM,
  2671. AS_HEXNUM: Begin
  2672. { if there was a variable prefix then }
  2673. { add to offset instead. }
  2674. If var_prefix then
  2675. Begin
  2676. Inc(instr.operands[operandnum].ref.offset, BuildRefExpression);
  2677. end
  2678. else
  2679. Begin
  2680. instr.operands[operandnum].ref.offset :=BuildRefExpression;
  2681. end;
  2682. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2683. Message(assem_e_invalid_operand_in_bracket_expression);
  2684. end;
  2685. else
  2686. Message(assem_e_syntax_error);
  2687. end;
  2688. end;
  2689. { // Constant reference expression // }
  2690. AS_MINUS,AS_NOT,AS_LPAREN:
  2691. Begin
  2692. { if there was a variable prefix then }
  2693. { add to offset instead. }
  2694. If var_prefix then
  2695. Begin
  2696. Inc(instr.operands[operandnum].ref.offset, BuildRefExpression);
  2697. end
  2698. else
  2699. Begin
  2700. instr.operands[operandnum].ref.offset :=BuildRefExpression;
  2701. end;
  2702. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2703. Message(assem_e_invalid_operand_in_bracket_expression);
  2704. end;
  2705. { // Constant reference expression // }
  2706. AS_INTNUM,AS_OCTALNUM,AS_BINNUM,AS_HEXNUM: Begin
  2707. { if there was a variable prefix then }
  2708. { add to offset instead. }
  2709. If var_prefix then
  2710. Begin
  2711. Inc(instr.operands[operandnum].ref.offset, BuildRefExpression);
  2712. end
  2713. else
  2714. Begin
  2715. instr.operands[operandnum].ref.offset :=BuildRefExpression;
  2716. end;
  2717. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2718. Message(assem_e_invalid_operand_in_bracket_expression);
  2719. end;
  2720. { // Variable reference expression // }
  2721. AS_REGISTER: BuildReference(instr);
  2722. else
  2723. Begin
  2724. Message(assem_e_invalid_reference_syntax);
  2725. while (actasmtoken <> AS_SEPARATOR) do
  2726. Consume(actasmtoken);
  2727. end;
  2728. end; { end case }
  2729. end;
  2730. Procedure BuildOperand(var instr: TInstruction);
  2731. {*********************************************************************}
  2732. { EXIT CONDITION: On exit the routine should point to either the }
  2733. { AS_COMMA or AS_SEPARATOR token. }
  2734. {*********************************************************************}
  2735. var
  2736. tempstr: string;
  2737. expr: string;
  2738. lab: Pasmlabel;
  2739. l : longint;
  2740. hl: plabel;
  2741. Begin
  2742. tempstr := '';
  2743. expr := '';
  2744. case actasmtoken of
  2745. { // Constant expression // }
  2746. AS_PLUS,AS_MINUS,AS_NOT,AS_LPAREN:
  2747. Begin
  2748. if not (instr.operands[operandnum].operandtype in [OPR_NONE,OPR_CONSTANT]) then
  2749. Message(assem_e_invalid_operand_type);
  2750. instr.operands[operandnum].operandtype := OPR_CONSTANT;
  2751. instr.operands[operandnum].val :=BuildExpression;
  2752. end;
  2753. { // Constant expression // }
  2754. AS_STRING: Begin
  2755. if not (instr.operands[operandnum].operandtype in [OPR_NONE]) then
  2756. Message(assem_e_invalid_operand_type);
  2757. instr.operands[operandnum].operandtype := OPR_CONSTANT;
  2758. if not PadZero(actasmpattern,4) then
  2759. Message1(assem_e_invalid_string_as_opcode_operand,actasmpattern);
  2760. instr.operands[operandnum].val :=
  2761. ord(actasmpattern[4]) + ord(actasmpattern[3]) shl 8 +
  2762. Ord(actasmpattern[2]) shl 16 + ord(actasmpattern[1])
  2763. shl 24;
  2764. Consume(AS_STRING);
  2765. Case actasmtoken of
  2766. AS_COMMA, AS_SEPARATOR: ;
  2767. else
  2768. Message(assem_e_invalid_string_expression);
  2769. end; { end case }
  2770. end;
  2771. { // Constant expression // }
  2772. AS_INTNUM,AS_BINNUM,
  2773. AS_OCTALNUM,
  2774. AS_HEXNUM: Begin
  2775. if not (instr.operands[operandnum].operandtype in [OPR_NONE,OPR_CONSTANT]) then
  2776. Message(assem_e_invalid_operand_type);
  2777. instr.operands[operandnum].operandtype := OPR_CONSTANT;
  2778. instr.operands[operandnum].val :=BuildExpression;
  2779. end;
  2780. { // A constant expression, or a Variable ref. // }
  2781. AS_ID: Begin
  2782. if actasmpattern[1] = '@' then
  2783. { // Label or Special symbol reference // }
  2784. Begin
  2785. if actasmpattern = '@RESULT' then
  2786. Begin
  2787. InitAsmRef(instr);
  2788. SetUpResult(instr,operandnum);
  2789. end
  2790. else
  2791. if (actasmpattern = '@CODE') or (actasmpattern = '@DATA') then
  2792. Message(assem_w_CODE_and_DATA_not_supported)
  2793. else
  2794. Begin
  2795. delete(actasmpattern,1,1);
  2796. if actasmpattern = '' then
  2797. Message(assem_e_null_label_ref_not_allowed);
  2798. lab := labellist.search(actasmpattern);
  2799. { check if the label is already defined }
  2800. { if so, we then check if the plabel is }
  2801. { non-nil, if so we add it to instruction }
  2802. if assigned(lab) then
  2803. Begin
  2804. if assigned(lab^.lab) then
  2805. Begin
  2806. instr.operands[operandnum].operandtype := OPR_LABINSTR;
  2807. instr.operands[operandnum].hl := lab^.lab;
  2808. instr.labeled := TRUE;
  2809. end;
  2810. end
  2811. else
  2812. { the label does not exist, create it }
  2813. { emit the opcode, but set that the }
  2814. { label has not been emitted }
  2815. Begin
  2816. getlabel(hl);
  2817. labellist.insert(actasmpattern,hl,FALSE);
  2818. instr.operands[operandnum].operandtype := OPR_LABINSTR;
  2819. instr.operands[operandnum].hl := hl;
  2820. instr.labeled := TRUE;
  2821. end;
  2822. end;
  2823. Consume(AS_ID);
  2824. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2825. Begin
  2826. Message(assem_e_syntax_error);
  2827. end;
  2828. end
  2829. { probably a variable or normal expression }
  2830. { or a procedure (such as in CALL ID) }
  2831. else
  2832. Begin
  2833. { is it a constant ? }
  2834. if SearchIConstant(actasmpattern,l) then
  2835. Begin
  2836. if not (instr.operands[operandnum].operandtype in [OPR_NONE,OPR_CONSTANT]) then
  2837. Message(assem_e_invalid_operand_type);
  2838. instr.operands[operandnum].operandtype := OPR_CONSTANT;
  2839. instr.operands[operandnum].val :=BuildExpression;
  2840. end
  2841. else { is it a label variable ? }
  2842. Begin
  2843. { // ID[ , ID.Field.Field or simple ID // }
  2844. { check if this is a label, if so then }
  2845. { emit it as a label. }
  2846. if SearchLabel(actasmpattern,hl) then
  2847. Begin
  2848. instr.operands[operandnum].operandtype := OPR_LABINSTR;
  2849. instr.operands[operandnum].hl := hl;
  2850. instr.labeled := TRUE;
  2851. Consume(AS_ID);
  2852. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2853. Message(assem_e_syntax_error);
  2854. end
  2855. else
  2856. { is it a normal variable ? }
  2857. Begin
  2858. initAsmRef(instr);
  2859. if not CreateVarInstr(instr,actasmpattern,operandnum) then
  2860. Begin
  2861. { not a variable.. }
  2862. { check special variables.. }
  2863. if actasmpattern = 'SELF' then
  2864. { special self variable }
  2865. Begin
  2866. if assigned(procinfo._class) then
  2867. Begin
  2868. instr.operands[operandnum].ref.offset := procinfo.ESI_offset;
  2869. instr.operands[operandnum].ref.base := procinfo.framepointer;
  2870. end
  2871. else
  2872. Message(assem_e_cannot_use_SELF_outside_a_method);
  2873. end
  2874. else
  2875. Message1(assem_e_unknown_id,actasmpattern);
  2876. end;
  2877. expr := actasmpattern;
  2878. Consume(AS_ID);
  2879. case actasmtoken of
  2880. AS_LBRACKET: { indexing }
  2881. BuildBracketExpression(instr,TRUE);
  2882. AS_DOT: BuildRecordOffset(instr,expr);
  2883. AS_SEPARATOR,AS_COMMA: ;
  2884. else
  2885. Message(assem_e_syntax_error);
  2886. end;
  2887. end;
  2888. end;
  2889. end;
  2890. end;
  2891. { // Register, a variable reference or a constant reference // }
  2892. AS_REGISTER: Begin
  2893. { save the type of register used. }
  2894. tempstr := actasmpattern;
  2895. Consume(AS_REGISTER);
  2896. if actasmtoken = AS_COLON then
  2897. Begin
  2898. Consume(AS_COLON);
  2899. if actasmtoken <> AS_LBRACKET then
  2900. Message(assem_e_syn_start_with_bracket)
  2901. else
  2902. Begin
  2903. initAsmRef(instr);
  2904. instr.operands[operandnum].ref.segment := findsegment(tempstr);
  2905. BuildBracketExpression(instr,false);
  2906. end;
  2907. end
  2908. { // Simple register // }
  2909. else if (actasmtoken = AS_SEPARATOR) or (actasmtoken = AS_COMMA) then
  2910. Begin
  2911. if not (instr.operands[operandnum].operandtype in [OPR_NONE,OPR_REGISTER]) then
  2912. Message(assem_e_invalid_operand_type);
  2913. instr.operands[operandnum].operandtype := OPR_REGISTER;
  2914. instr.operands[operandnum].reg := findregister(tempstr);
  2915. end
  2916. else
  2917. Message1(assem_e_syn_register,tempstr);
  2918. end;
  2919. { // a variable reference, register ref. or a constant reference // }
  2920. AS_LBRACKET: Begin
  2921. BuildBracketExpression(instr,false);
  2922. end;
  2923. { // Unsupported // }
  2924. AS_SEG,AS_OFFSET: Begin
  2925. Message(assem_e_SEG_and_OFFSET_not_supported);
  2926. Consume(actasmtoken);
  2927. { error recovery }
  2928. While not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) do
  2929. Consume(actasmtoken);
  2930. end;
  2931. AS_SEPARATOR, AS_COMMA: ;
  2932. else
  2933. Message(assem_e_syn_opcode_operand);
  2934. end; { end case }
  2935. end;
  2936. Procedure BuildConstant(maxvalue: longint);
  2937. {*********************************************************************}
  2938. { PROCEDURE BuildConstant }
  2939. { Description: This routine takes care of parsing a DB,DD,or DW }
  2940. { line and adding those to the assembler node. Expressions, range- }
  2941. { checking are fullly taken care of. }
  2942. { maxvalue: $ff -> indicates that this is a DB node. }
  2943. { $ffff -> indicates that this is a DW node. }
  2944. { $ffffffff -> indicates that this is a DD node. }
  2945. {*********************************************************************}
  2946. { EXIT CONDITION: On exit the routine should point to AS_SEPARATOR. }
  2947. {*********************************************************************}
  2948. var
  2949. strlength: byte;
  2950. expr: string;
  2951. value : longint;
  2952. Begin
  2953. strlength := 0; { assume it is a DB }
  2954. Repeat
  2955. Case actasmtoken of
  2956. AS_STRING: Begin
  2957. if maxvalue = $ffff then
  2958. strlength := 2
  2959. else if maxvalue = $ffffffff then
  2960. strlength := 4;
  2961. if strlength <> 0 then
  2962. { DD and DW cases }
  2963. Begin
  2964. if Not PadZero(actasmpattern,strlength) then
  2965. Message(scan_f_string_exceeds_line);
  2966. end;
  2967. expr := actasmpattern;
  2968. Consume(AS_STRING);
  2969. Case actasmtoken of
  2970. AS_COMMA: Consume(AS_COMMA);
  2971. AS_SEPARATOR: ;
  2972. else
  2973. Message(assem_e_invalid_string_expression);
  2974. end; { end case }
  2975. ConcatString(p,expr);
  2976. end;
  2977. AS_INTNUM,AS_BINNUM,
  2978. AS_OCTALNUM,AS_HEXNUM:
  2979. Begin
  2980. value:=BuildExpression;
  2981. ConcatConstant(p,value,maxvalue);
  2982. end;
  2983. AS_ID:
  2984. Begin
  2985. value:=BuildExpression;
  2986. if value > maxvalue then
  2987. Begin
  2988. Message(assem_e_expression_out_of_bounds);
  2989. { assuming a value of maxvalue }
  2990. value := maxvalue;
  2991. end;
  2992. ConcatConstant(p,value,maxvalue);
  2993. end;
  2994. { These terms can start an assembler expression }
  2995. AS_PLUS,AS_MINUS,AS_LPAREN,AS_NOT: Begin
  2996. value := BuildExpression;
  2997. ConcatConstant(p,value,maxvalue);
  2998. end;
  2999. AS_COMMA: BEGIN
  3000. Consume(AS_COMMA);
  3001. END;
  3002. AS_SEPARATOR: ;
  3003. else
  3004. Begin
  3005. Message(assem_f_internal_error_in_buildconstant);
  3006. end;
  3007. end; { end case }
  3008. Until actasmtoken = AS_SEPARATOR;
  3009. end;
  3010. Procedure BuildOpCode;
  3011. {*********************************************************************}
  3012. { PROCEDURE BuildOpcode; }
  3013. { Description: Parses the intel opcode and operands, and writes it }
  3014. { in the TInstruction object. }
  3015. {*********************************************************************}
  3016. { EXIT CONDITION: On exit the routine should point to AS_SEPARATOR. }
  3017. { On ENTRY: Token should point to AS_OPCODE }
  3018. {*********************************************************************}
  3019. var asmtok: tasmop;
  3020. op: tasmop;
  3021. expr: string;
  3022. segreg: tregister;
  3023. Begin
  3024. expr := '';
  3025. asmtok := A_NONE; { assmume no prefix }
  3026. segreg := R_NO; { assume no segment override }
  3027. { // prefix seg opcode // }
  3028. { // prefix opcode // }
  3029. if findprefix(actasmpattern,asmtok) then
  3030. Begin
  3031. { standard opcode prefix }
  3032. if asmtok <> A_NONE then
  3033. instr.addprefix(asmtok);
  3034. Consume(AS_OPCODE);
  3035. if findoverride(actasmpattern,segreg) then
  3036. Begin
  3037. Consume(AS_OPCODE);
  3038. Message(assem_w_repeat_prefix_and_seg_override);
  3039. end;
  3040. end
  3041. else
  3042. { // seg prefix opcode // }
  3043. { // seg opcode // }
  3044. if findoverride(actasmpattern,segreg) then
  3045. Begin
  3046. Consume(AS_OPCODE);
  3047. if findprefix(actasmpattern,asmtok) then
  3048. Begin
  3049. { standard opcode prefix }
  3050. Message(assem_w_repeat_prefix_and_seg_override);
  3051. if asmtok <> A_NONE then
  3052. instr.addprefix(asmtok);
  3053. Consume(AS_OPCODE);
  3054. end;
  3055. end;
  3056. { // opcode // }
  3057. if (actasmtoken <> AS_OPCODE) then
  3058. Begin
  3059. Message(assem_e_invalid_or_missing_opcode);
  3060. { error recovery }
  3061. While not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) do
  3062. Consume(actasmtoken);
  3063. exit;
  3064. end
  3065. else
  3066. Begin
  3067. op := findopcode(actasmpattern);
  3068. instr.addinstr(op);
  3069. { // Valid combination of prefix and instruction ? // }
  3070. if (asmtok <> A_NONE) and (NOT CheckPrefix(asmtok,op)) then
  3071. Message1(assem_e_invalid_prefix_and_opcode,actasmpattern);
  3072. { // Valid combination of segment override // }
  3073. if (segreg <> R_NO) and (NOT CheckOverride(segreg,instr)) then
  3074. Message1(assem_e_invalid_override_and_opcode,actasmpattern);
  3075. Consume(AS_OPCODE);
  3076. { // Zero operand opcode ? // }
  3077. if actasmtoken = AS_SEPARATOR then
  3078. exit
  3079. else
  3080. operandnum := 1;
  3081. end;
  3082. While actasmtoken <> AS_SEPARATOR do
  3083. Begin
  3084. case actasmtoken of
  3085. { // Operand delimiter // }
  3086. AS_COMMA: Begin
  3087. if operandnum > MaxOperands then
  3088. Message(assem_e_too_many_operands)
  3089. else
  3090. Inc(operandnum);
  3091. Consume(AS_COMMA);
  3092. end;
  3093. { // Typecast, Constant Expression, Type Specifier // }
  3094. AS_DWORD,AS_BYTE,AS_WORD,AS_TBYTE,AS_QWORD: Begin
  3095. { tell that the instruction was overriden }
  3096. { so we will NEVER override the opsize }
  3097. instr.operands[operandnum].overriden := TRUE;
  3098. Case actasmtoken of
  3099. AS_DWORD: instr.operands[operandnum].size := S_L;
  3100. AS_WORD: instr.operands[operandnum].size := S_W;
  3101. AS_BYTE: instr.operands[operandnum].size := S_B;
  3102. AS_QWORD: instr.operands[operandnum].size := S_IQ;
  3103. AS_TBYTE: instr.operands[operandnum].size := S_FX;
  3104. end;
  3105. Consume(actasmtoken);
  3106. Case actasmtoken of
  3107. { // Reference // }
  3108. AS_PTR: Begin
  3109. initAsmRef(instr);
  3110. Consume(AS_PTR);
  3111. BuildOperand(instr);
  3112. end;
  3113. { // Possibly a typecast or a constant // }
  3114. { // expression. // }
  3115. AS_LPAREN: Begin
  3116. if actasmtoken = AS_ID then
  3117. Begin
  3118. { Case vartype of }
  3119. { LOCAL: Replace by offset and }
  3120. { BP in treference. }
  3121. { GLOBAL: Replace by mangledname}
  3122. { in symbol of treference }
  3123. { Check if next token = RPAREN }
  3124. { otherwise syntax error. }
  3125. initAsmRef(instr);
  3126. if not CreateVarInstr(instr,actasmpattern,
  3127. operandnum) then
  3128. Begin
  3129. Message1(assem_e_unknown_id,actasmpattern);
  3130. end;
  3131. end
  3132. else
  3133. begin
  3134. instr.operands[operandnum].operandtype := OPR_CONSTANT;
  3135. instr.operands[operandnum].val := BuildExpression;
  3136. end;
  3137. end;
  3138. else
  3139. BuildOperand(instr);
  3140. end; { end case }
  3141. end;
  3142. { // Type specifier // }
  3143. AS_NEAR,AS_FAR: Begin
  3144. if actasmtoken = AS_NEAR then
  3145. Message(assem_w_near_ignored)
  3146. else
  3147. Message(assem_w_far_ignored);
  3148. Consume(actasmtoken);
  3149. if actasmtoken = AS_PTR then
  3150. begin
  3151. initAsmRef(instr);
  3152. Consume(AS_PTR);
  3153. end;
  3154. BuildOperand(instr);
  3155. end;
  3156. { // End of asm operands for this opcode // }
  3157. AS_SEPARATOR: ;
  3158. { // Constant expression // }
  3159. AS_LPAREN: Begin
  3160. instr.operands[operandnum].operandtype := OPR_CONSTANT;
  3161. instr.operands[operandnum].val := BuildExpression;
  3162. end;
  3163. else
  3164. BuildOperand(instr);
  3165. end; { end case }
  3166. end; { end while }
  3167. end;
  3168. Function Assemble: Ptree;
  3169. {*********************************************************************}
  3170. { PROCEDURE Assemble; }
  3171. { Description: Parses the intel assembler syntax, parsing is done }
  3172. { according to the rules in the Turbo Pascal manual. }
  3173. {*********************************************************************}
  3174. Var
  3175. hl: plabel;
  3176. labelptr: pasmlabel;
  3177. Begin
  3178. Message(assem_d_start_intel);
  3179. inexpression := FALSE;
  3180. firsttoken := TRUE;
  3181. operandnum := 0;
  3182. if assigned(procinfo.retdef) and
  3183. (is_fpu(procinfo.retdef) or
  3184. ret_in_acc(procinfo.retdef)) then
  3185. procinfo.funcret_is_valid:=true;
  3186. { sets up all opcode and register tables in uppercase }
  3187. if not _asmsorted then
  3188. Begin
  3189. SetupTables;
  3190. _asmsorted := TRUE;
  3191. end;
  3192. p:=new(paasmoutput,init);
  3193. { setup label linked list }
  3194. labellist.init;
  3195. c:=current_scanner^.asmgetchar;
  3196. actasmtoken:=gettoken;
  3197. while actasmtoken<>AS_END do
  3198. Begin
  3199. case actasmtoken of
  3200. AS_LLABEL: Begin
  3201. labelptr := labellist.search(actasmpattern);
  3202. if not assigned(labelptr) then
  3203. Begin
  3204. getlabel(hl);
  3205. labellist.insert(actasmpattern,hl,TRUE);
  3206. ConcatLabel(p,A_LABEL,hl);
  3207. end
  3208. else
  3209. { the label has already been inserted into the }
  3210. { label list, either as an intruction label (in }
  3211. { this case it has not been emitted), or as a }
  3212. { duplicate local symbol (in this case it has }
  3213. { already been emitted). }
  3214. Begin
  3215. if labelptr^.emitted then
  3216. Message1(assem_e_dup_local_sym,'@'+labelptr^.name^)
  3217. else
  3218. Begin
  3219. if assigned(labelptr^.lab) then
  3220. ConcatLabel(p,A_LABEL,labelptr^.lab);
  3221. labelptr^.emitted := TRUE;
  3222. end;
  3223. end;
  3224. Consume(AS_LLABEL);
  3225. end;
  3226. AS_LABEL: Begin
  3227. if SearchLabel(actasmpattern,hl) then
  3228. ConcatLabel(p,A_LABEL, hl)
  3229. else
  3230. Message1(assem_e_unknown_label_identifer,actasmpattern);
  3231. Consume(AS_LABEL);
  3232. end;
  3233. AS_DW: Begin
  3234. Consume(AS_DW);
  3235. BuildConstant($ffff);
  3236. end;
  3237. AS_DB: Begin
  3238. Consume(AS_DB);
  3239. BuildConstant($ff);
  3240. end;
  3241. AS_DD: Begin
  3242. Consume(AS_DD);
  3243. BuildConstant($ffffffff);
  3244. end;
  3245. AS_OPCODE: Begin
  3246. instr.init;
  3247. BuildOpcode;
  3248. instr.numops := operandnum;
  3249. if instr.labeled then
  3250. ConcatLabeledInstr(instr)
  3251. else
  3252. ConcatOpCode(instr);
  3253. instr.done;
  3254. end;
  3255. AS_SEPARATOR:Begin
  3256. Consume(AS_SEPARATOR);
  3257. { let us go back to the first operand }
  3258. operandnum := 0;
  3259. end;
  3260. AS_END: ; { end assembly block }
  3261. else
  3262. Begin
  3263. Message(assem_e_assemble_node_syntax_error);
  3264. { error recovery }
  3265. Consume(actasmtoken);
  3266. end;
  3267. end; { end case }
  3268. end; { end while }
  3269. { check if there were undefined symbols. }
  3270. { if so, then list each of those undefined }
  3271. { labels. }
  3272. if assigned(labellist.First) then
  3273. Begin
  3274. labelptr := labellist.First;
  3275. if labellist.First <> nil then
  3276. Begin
  3277. { first label }
  3278. if not labelptr^.emitted then
  3279. Message1(assem_e_unknown_local_sym,'@'+labelptr^.name^);
  3280. { other labels ... }
  3281. While (labelptr^.Next <> nil) do
  3282. Begin
  3283. labelptr := labelptr^.Next;
  3284. if not labelptr^.emitted then
  3285. Message1(assem_e_unknown_local_sym,'@'+labelptr^.name^);
  3286. end;
  3287. end;
  3288. end;
  3289. assemble := genasmnode(p);
  3290. labellist.done;
  3291. Message(assem_d_finish_intel);
  3292. end;
  3293. procedure ra386int_exit;{$ifndef FPC}far;{$endif}
  3294. begin
  3295. if assigned(iasmops) then
  3296. dispose(iasmops);
  3297. exitproc:=old_exit;
  3298. end;
  3299. begin
  3300. old_exit:=exitproc;
  3301. exitproc:=@ra386int_exit;
  3302. end.
  3303. {
  3304. $Log$
  3305. Revision 1.11 1998-11-13 10:12:11 peter
  3306. * constant fixes
  3307. Revision 1.10 1998/11/05 23:48:27 peter
  3308. * recordtype.field support in constant expressions
  3309. * fixed imul for oa_imm8 which was not allowed
  3310. * fixed reading of local typed constants
  3311. * fixed comment reading which is not any longer a separator
  3312. Revision 1.9 1998/10/13 16:50:17 pierre
  3313. * undid some changes of Peter that made the compiler wrong
  3314. for m68k (I had to reinsert some ifdefs)
  3315. * removed several memory leaks under m68k
  3316. * removed the meory leaks for assembler readers
  3317. * cross compiling shoud work again better
  3318. ( crosscompiling sysamiga works
  3319. but as68k still complain about some code !)
  3320. Revision 1.8 1998/10/07 04:29:44 carl
  3321. * Concatlabel now gives output on error
  3322. * in/out bugfix (still ins/outs left to fix)
  3323. Revision 1.7 1998/09/02 01:23:40 carl
  3324. * bugfix of operand overrides, VERY stupid bugfix BTW...
  3325. Revision 1.6 1998/08/27 00:42:17 carl
  3326. * bugfix of leal problem
  3327. * bugfix of using overrides with record offsets
  3328. * bugfix if using records to load values
  3329. Revision 1.5 1998/08/21 08:45:53 pierre
  3330. * better line info for asm statements
  3331. Revision 1.4 1998/07/14 14:47:00 peter
  3332. * released NEWINPUT
  3333. Revision 1.3 1998/07/07 11:20:09 peter
  3334. + NEWINPUT for a better inputfile and scanner object
  3335. Revision 1.2 1998/06/24 14:06:38 peter
  3336. * fixed the name changes
  3337. Revision 1.1 1998/06/23 14:00:18 peter
  3338. * renamed RA* units
  3339. Revision 1.11 1998/06/16 08:56:28 peter
  3340. + targetcpu
  3341. * cleaner pmodules for newppu
  3342. Revision 1.10 1998/06/12 10:32:33 pierre
  3343. * column problem hopefully solved
  3344. + C vars declaration changed
  3345. Revision 1.9 1998/05/31 14:13:32 peter
  3346. * fixed call bugs with assembler readers
  3347. + OPR_SYMBOL to hold a symbol in the asm parser
  3348. * fixed staticsymtable vars which were acessed through %ebp instead of
  3349. name
  3350. Revision 1.8 1998/05/30 14:31:07 peter
  3351. + $ASMMODE
  3352. Revision 1.7 1998/05/28 16:32:05 carl
  3353. * bugfix with operands main branch version (patched manually)
  3354. Revision 1.6 1998/05/23 01:21:26 peter
  3355. + aktasmmode, aktoptprocessor, aktoutputformat
  3356. + smartlink per module $SMARTLINK-/+ (like MMX) and moved to aktswitches
  3357. + $LIBNAME to set the library name where the unit will be put in
  3358. * splitted cgi386 a bit (codeseg to large for bp7)
  3359. * nasm, tasm works again. nasm moved to ag386nsm.pas
  3360. Revision 1.5 1998/05/20 09:42:36 pierre
  3361. + UseTokenInfo now default
  3362. * unit in interface uses and implementation uses gives error now
  3363. * only one error for unknown symbol (uses lastsymknown boolean)
  3364. the problem came from the label code !
  3365. + first inlined procedures and function work
  3366. (warning there might be allowed cases were the result is still wrong !!)
  3367. * UseBrower updated gives a global list of all position of all used symbols
  3368. with switch -gb
  3369. Revision 1.4 1998/04/29 10:34:03 pierre
  3370. + added some code for ansistring (not complete nor working yet)
  3371. * corrected operator overloading
  3372. * corrected nasm output
  3373. + started inline procedures
  3374. + added starstarn : use ** for exponentiation (^ gave problems)
  3375. + started UseTokenInfo cond to get accurate positions
  3376. Revision 1.3 1998/04/08 16:58:06 pierre
  3377. * several bugfixes
  3378. ADD ADC and AND are also sign extended
  3379. nasm output OK (program still crashes at end
  3380. and creates wrong assembler files !!)
  3381. procsym types sym in tdef removed !!
  3382. }