ratti386.pas 147 KB

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