ra386int.pas 143 KB

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