rai386.pas 138 KB

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