ra386int.pas 141 KB

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