rai386.pas 136 KB

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