rasm.pas 85 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Carl Eric Codere
  4. This unit does the parsing process for the motorola 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 Rasm;
  19. {**********************************************************************}
  20. { WARNING }
  21. {**********************************************************************}
  22. { Any modification in the order or removal of terms in the tables }
  23. { in m68k.pas and asmo68k.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 sized indexing such as in d0.l }
  31. { presently only (an,dn) is supported for indexing -- }
  32. { size defaults to LONG. }
  33. { o Add support for MC68020 opcodes. }
  34. { o Add support for MC68020 adressing modes. }
  35. { o Add operand checking with m68k opcode table in ConcatOpCode }
  36. { o Add Floating point support }
  37. {---------------------------------------------------------------------------}
  38. Interface
  39. Uses
  40. globtype,cpubase,tree;
  41. function assemble: ptree;
  42. const
  43. { this variable is TRUE if the lookup tables have already been setup }
  44. { for fast access. On the first call to assemble the tables are setup }
  45. { and stay set up. }
  46. _asmsorted: boolean = FALSE;
  47. firstasmreg = R_D0;
  48. lastasmreg = R_FPSR;
  49. type
  50. tiasmops = array[firstop..lastop] of string[7];
  51. piasmops = ^tiasmops;
  52. tasmkeyword = string[6];
  53. var
  54. { sorted tables of opcodes }
  55. iasmops: piasmops;
  56. { uppercased tables of registers }
  57. iasmregs: array[firstasmreg..lastasmreg] of string[6];
  58. Implementation
  59. uses
  60. files,globals,systems,RAUtils,strings,hcodegen,scanner,aasm,
  61. cpuasm,cobjects,verbose,symconst,symtable;
  62. type
  63. tmotorolatoken = (
  64. AS_NONE,AS_LABEL,AS_LLABEL,AS_STRING,AS_HEXNUM,AS_OCTALNUM,
  65. AS_BINNUM,AS_COMMA,AS_LBRACKET,AS_RBRACKET,AS_LPAREN,
  66. AS_RPAREN,AS_COLON,AS_DOT,AS_PLUS,AS_MINUS,AS_STAR,AS_INTNUM,
  67. AS_SEPARATOR,AS_ID,AS_REGISTER,AS_OPCODE,AS_SLASH,AS_APPT,AS_REALNUM,
  68. AS_ALIGN,
  69. {------------------ Assembler directives --------------------}
  70. AS_DB,AS_DW,AS_DD,AS_XDEF,AS_END,
  71. {------------------ Assembler Operators --------------------}
  72. AS_MOD,AS_SHL,AS_SHR,AS_NOT,AS_AND,AS_OR,AS_XOR);
  73. const
  74. firstdirective = AS_DB;
  75. lastdirective = AS_END;
  76. firstoperator = AS_MOD;
  77. lastoperator = AS_XOR;
  78. _count_asmdirectives = longint(lastdirective)-longint(firstdirective);
  79. _count_asmoperators = longint(lastoperator)-longint(firstoperator);
  80. _asmdirectives : array[0.._count_asmdirectives] of tasmkeyword =
  81. ('DC.B','DC.W','DC.L','XDEF','END');
  82. { problems with shl,shr,not,and,or and xor, they are }
  83. { context sensitive. }
  84. _asmoperators : array[0.._count_asmoperators] of tasmkeyword = (
  85. 'MOD','SHL','SHR','NOT','AND','OR','XOR');
  86. const
  87. newline = #10;
  88. firsttoken : boolean = TRUE;
  89. operandnum : byte = 0;
  90. var
  91. p : paasmoutput;
  92. actasmtoken: tmotorolatoken;
  93. actasmpattern: string;
  94. c: char;
  95. Instr: TInstruction;
  96. old_exit : pointer;
  97. Procedure SetupTables;
  98. { creates uppercased symbol tables for speed access }
  99. var
  100. i: tasmop;
  101. j: tregister;
  102. Begin
  103. {Message(asmr_d_creating_lookup_tables);}
  104. { opcodes }
  105. new(iasmops);
  106. for i:=firstop to lastop do
  107. iasmops^[i] := upper(mot_op2str[i]);
  108. { opcodes }
  109. for j:=firstasmreg to lastasmreg do
  110. iasmregs[j] := upper(mot_reg2str[j]);
  111. end;
  112. {---------------------------------------------------------------------}
  113. { Routines for the tokenizing }
  114. {---------------------------------------------------------------------}
  115. function is_asmopcode(s: string):Boolean;
  116. {*********************************************************************}
  117. { FUNCTION is_asmopcode(s: string):Boolean }
  118. { Description: Determines if the s string is a valid opcode }
  119. { if so returns TRUE otherwise returns FALSE. }
  120. { Remark: Suffixes are also checked, as long as they are valid. }
  121. {*********************************************************************}
  122. var
  123. i: tasmop;
  124. j: byte;
  125. Begin
  126. is_asmopcode := FALSE;
  127. { first of all we remove the suffix }
  128. j:=pos('.',s);
  129. if j<>0 then
  130. delete(s,j,2);
  131. for i:=firstop to lastop do
  132. begin
  133. if s = iasmops^[i] then
  134. begin
  135. is_asmopcode:=TRUE;
  136. exit;
  137. end;
  138. end;
  139. end;
  140. Procedure is_asmdirective(const s: string; var token: tmotorolatoken);
  141. {*********************************************************************}
  142. { FUNCTION is_asmdirective(s: string; var token: tinteltoken):Boolean }
  143. { Description: Determines if the s string is a valid directive }
  144. { (an operator can occur in operand fields, while a directive cannot) }
  145. { if so returns the directive token, otherwise does not change token.}
  146. {*********************************************************************}
  147. var
  148. i:byte;
  149. Begin
  150. for i:=0 to _count_asmdirectives do
  151. begin
  152. if s=_asmdirectives[i] then
  153. begin
  154. token := tmotorolatoken(longint(firstdirective)+i);
  155. exit;
  156. end;
  157. end;
  158. end;
  159. Procedure is_register(const s: string; var token: tmotorolatoken);
  160. {*********************************************************************}
  161. { PROCEDURE is_register(s: string; var token: tinteltoken); }
  162. { Description: Determines if the s string is a valid register, if }
  163. { so return token equal to A_REGISTER, otherwise does not change token}
  164. {*********************************************************************}
  165. Var
  166. i: tregister;
  167. Begin
  168. for i:=firstasmreg to lastasmreg do
  169. begin
  170. if s=iasmregs[i] then
  171. begin
  172. token := AS_REGISTER;
  173. exit;
  174. end;
  175. end;
  176. { take care of other name for sp }
  177. if s = 'A7' then
  178. begin
  179. token:=AS_REGISTER;
  180. exit;
  181. end;
  182. end;
  183. Function GetToken: tmotorolatoken;
  184. {*********************************************************************}
  185. { FUNCTION GetToken: tinteltoken; }
  186. { Description: This routine returns intel assembler tokens and }
  187. { does some minor syntax error checking. }
  188. {*********************************************************************}
  189. var
  190. token: tmotorolatoken;
  191. forcelabel: boolean;
  192. begin
  193. forcelabel := FALSE;
  194. actasmpattern :='';
  195. {* INIT TOKEN TO NOTHING *}
  196. token := AS_NONE;
  197. { while space and tab , continue scan... }
  198. while c in [' ',#9] do
  199. c:=current_scanner^.asmgetchar;
  200. if not (c in [newline,#13,'{',';']) then
  201. current_scanner^.gettokenpos;
  202. { Possiblities for first token in a statement: }
  203. { Local Label, Label, Directive, Prefix or Opcode.... }
  204. if firsttoken and not (c in [newline,#13,'{',';']) then
  205. begin
  206. firsttoken := FALSE;
  207. if c = '@' then
  208. begin
  209. token := AS_LLABEL; { this is a local label }
  210. { Let us point to the next character }
  211. c := current_scanner^.asmgetchar;
  212. end;
  213. while c in ['A'..'Z','a'..'z','0'..'9','_','@','.'] do
  214. begin
  215. { if there is an at_sign, then this must absolutely be a label }
  216. if c = '@' then forcelabel:=TRUE;
  217. actasmpattern := actasmpattern + c;
  218. c := current_scanner^.asmgetchar;
  219. end;
  220. uppervar(actasmpattern);
  221. if c = ':' then
  222. begin
  223. case token of
  224. AS_NONE: token := AS_LABEL;
  225. AS_LLABEL: ; { do nothing }
  226. end; { end case }
  227. { let us point to the next character }
  228. c := current_scanner^.asmgetchar;
  229. gettoken := token;
  230. exit;
  231. end;
  232. { Are we trying to create an identifier with }
  233. { an at-sign...? }
  234. if forcelabel then
  235. Message(asmr_e_none_label_contain_at);
  236. If is_asmopcode(actasmpattern) then
  237. Begin
  238. gettoken := AS_OPCODE;
  239. exit;
  240. end;
  241. is_asmdirective(actasmpattern, token);
  242. if (token <> AS_NONE) then
  243. Begin
  244. gettoken := token;
  245. exit
  246. end
  247. else
  248. begin
  249. gettoken := AS_NONE;
  250. Message1(asmr_e_invalid_or_missing_opcode,actasmpattern);
  251. end;
  252. end
  253. else { else firsttoken }
  254. { Here we must handle all possible cases }
  255. begin
  256. case c of
  257. '@': { possiblities : - local label reference , such as in jmp @local1 }
  258. { - @Result, @Code or @Data special variables. }
  259. begin
  260. actasmpattern := c;
  261. c:= current_scanner^.asmgetchar;
  262. while c in ['A'..'Z','a'..'z','0'..'9','_','@','.'] do
  263. begin
  264. actasmpattern := actasmpattern + c;
  265. c := current_scanner^.asmgetchar;
  266. end;
  267. uppervar(actasmpattern);
  268. gettoken := AS_ID;
  269. exit;
  270. end;
  271. { identifier, register, opcode, prefix or directive }
  272. 'A'..'Z','a'..'z','_': begin
  273. actasmpattern := c;
  274. c:= current_scanner^.asmgetchar;
  275. while c in ['A'..'Z','a'..'z','0'..'9','_','.'] do
  276. begin
  277. actasmpattern := actasmpattern + c;
  278. c := current_scanner^.asmgetchar;
  279. end;
  280. uppervar(actasmpattern);
  281. If is_asmopcode(actasmpattern) then
  282. Begin
  283. gettoken := AS_OPCODE;
  284. exit;
  285. end;
  286. is_register(actasmpattern, token);
  287. {is_asmoperator(actasmpattern,token);}
  288. is_asmdirective(actasmpattern,token);
  289. { if found }
  290. if (token <> AS_NONE) then
  291. begin
  292. gettoken := token;
  293. exit;
  294. end
  295. { this is surely an identifier }
  296. else
  297. token := AS_ID;
  298. gettoken := token;
  299. exit;
  300. end;
  301. { override operator... not supported }
  302. '&': begin
  303. c:=current_scanner^.asmgetchar;
  304. gettoken := AS_AND;
  305. end;
  306. { string or character }
  307. '''' :
  308. begin
  309. actasmpattern:='';
  310. while true do
  311. begin
  312. if c = '''' then
  313. begin
  314. c:=current_scanner^.asmgetchar;
  315. if c=newline then
  316. begin
  317. Message(scan_f_string_exceeds_line);
  318. break;
  319. end;
  320. repeat
  321. if c=''''then
  322. begin
  323. c:=current_scanner^.asmgetchar;
  324. if c='''' then
  325. begin
  326. actasmpattern:=actasmpattern+'''';
  327. c:=current_scanner^.asmgetchar;
  328. if c=newline then
  329. begin
  330. Message(scan_f_string_exceeds_line);
  331. break;
  332. end;
  333. end
  334. else break;
  335. end
  336. else
  337. begin
  338. actasmpattern:=actasmpattern+c;
  339. c:=current_scanner^.asmgetchar;
  340. if c=newline then
  341. begin
  342. Message(scan_f_string_exceeds_line);
  343. break
  344. end;
  345. end;
  346. until false; { end repeat }
  347. end
  348. else break; { end if }
  349. end; { end while }
  350. token:=AS_STRING;
  351. gettoken := token;
  352. exit;
  353. end;
  354. '$' : begin
  355. c:=current_scanner^.asmgetchar;
  356. while c in ['0'..'9','A'..'F','a'..'f'] do
  357. begin
  358. actasmpattern := actasmpattern + c;
  359. c := current_scanner^.asmgetchar;
  360. end;
  361. gettoken := AS_HEXNUM;
  362. exit;
  363. end;
  364. ',' : begin
  365. gettoken := AS_COMMA;
  366. c:=current_scanner^.asmgetchar;
  367. exit;
  368. end;
  369. '(' : begin
  370. gettoken := AS_LPAREN;
  371. c:=current_scanner^.asmgetchar;
  372. exit;
  373. end;
  374. ')' : begin
  375. gettoken := AS_RPAREN;
  376. c:=current_scanner^.asmgetchar;
  377. exit;
  378. end;
  379. ':' : begin
  380. gettoken := AS_COLON;
  381. c:=current_scanner^.asmgetchar;
  382. exit;
  383. end;
  384. { '.' : begin
  385. gettoken := AS_DOT;
  386. c:=current_scanner^.asmgetchar;
  387. exit;
  388. end; }
  389. '+' : begin
  390. gettoken := AS_PLUS;
  391. c:=current_scanner^.asmgetchar;
  392. exit;
  393. end;
  394. '-' : begin
  395. gettoken := AS_MINUS;
  396. c:=current_scanner^.asmgetchar;
  397. exit;
  398. end;
  399. '*' : begin
  400. gettoken := AS_STAR;
  401. c:=current_scanner^.asmgetchar;
  402. exit;
  403. end;
  404. '/' : begin
  405. gettoken := AS_SLASH;
  406. c:=current_scanner^.asmgetchar;
  407. exit;
  408. end;
  409. '<' : begin
  410. c := current_scanner^.asmgetchar;
  411. { invalid characters }
  412. if c <> '<' then
  413. Message(asmr_e_invalid_char_smaller);
  414. { still assume << }
  415. gettoken := AS_SHL;
  416. c := current_scanner^.asmgetchar;
  417. exit;
  418. end;
  419. '>' : begin
  420. c := current_scanner^.asmgetchar;
  421. { invalid characters }
  422. if c <> '>' then
  423. Message(asmr_e_invalid_char_greater);
  424. { still assume << }
  425. gettoken := AS_SHR;
  426. c := current_scanner^.asmgetchar;
  427. exit;
  428. end;
  429. '|' : begin
  430. gettoken := AS_OR;
  431. c := current_scanner^.asmgetchar;
  432. exit;
  433. end;
  434. '^' : begin
  435. gettoken := AS_XOR;
  436. c := current_scanner^.asmgetchar;
  437. exit;
  438. end;
  439. '#' : begin
  440. gettoken:=AS_APPT;
  441. c:=current_scanner^.asmgetchar;
  442. exit;
  443. end;
  444. '%' : begin
  445. c:=current_scanner^.asmgetchar;
  446. while c in ['0','1'] do
  447. Begin
  448. actasmpattern := actasmpattern + c;
  449. c := current_scanner^.asmgetchar;
  450. end;
  451. gettoken := AS_BINNUM;
  452. exit;
  453. end;
  454. { integer number }
  455. '0'..'9': begin
  456. actasmpattern := c;
  457. c := current_scanner^.asmgetchar;
  458. while c in ['0'..'9'] do
  459. Begin
  460. actasmpattern := actasmpattern + c;
  461. c:= current_scanner^.asmgetchar;
  462. end;
  463. gettoken := AS_INTNUM;
  464. exit;
  465. end;
  466. ';' : begin
  467. repeat
  468. c:=current_scanner^.asmgetchar;
  469. until c=newline;
  470. firsttoken := TRUE;
  471. gettoken:=AS_SEPARATOR;
  472. end;
  473. '{',#13,newline : begin
  474. c:=current_scanner^.asmgetchar;
  475. firsttoken := TRUE;
  476. gettoken:=AS_SEPARATOR;
  477. end;
  478. else
  479. Begin
  480. Message(scan_f_illegal_char);
  481. end;
  482. end; { end case }
  483. end; { end else if }
  484. end;
  485. {---------------------------------------------------------------------}
  486. { Routines for the parsing }
  487. {---------------------------------------------------------------------}
  488. procedure consume(t : tmotorolatoken);
  489. begin
  490. if t<>actasmtoken then
  491. Message(asmr_e_syntax_error);
  492. actasmtoken:=gettoken;
  493. { if the token must be ignored, then }
  494. { get another token to parse. }
  495. if actasmtoken = AS_NONE then
  496. actasmtoken := gettoken;
  497. end;
  498. function findregister(const s : string): tregister;
  499. {*********************************************************************}
  500. { FUNCTION findregister(s: string):tasmop; }
  501. { Description: Determines if the s string is a valid register, }
  502. { if so returns correct tregister token, or R_NO if not found. }
  503. {*********************************************************************}
  504. var
  505. i: tregister;
  506. begin
  507. findregister := R_NO;
  508. for i:=firstasmreg to lastasmreg do
  509. if s = iasmregs[i] then
  510. Begin
  511. findregister := i;
  512. exit;
  513. end;
  514. if s = 'A7' then
  515. Begin
  516. findregister := R_SP;
  517. exit;
  518. end;
  519. end;
  520. function findopcode(s: string): tasmop;
  521. {*********************************************************************}
  522. { FUNCTION findopcode(s: string): tasmop; }
  523. { Description: Determines if the s string is a valid opcode }
  524. { if so returns correct tasmop token. }
  525. {*********************************************************************}
  526. var
  527. i: tasmop;
  528. j: byte;
  529. op_size: string;
  530. Begin
  531. findopcode := A_NONE;
  532. j:=pos('.',s);
  533. if j<>0 then
  534. begin
  535. op_size:=copy(s,j+1,1);
  536. case op_size[1] of
  537. { For the motorola only opsize size is used to }
  538. { determine the size of the operands. }
  539. 'B': instr.opsize := S_B;
  540. 'W': instr.opsize := S_W;
  541. 'L': instr.opsize := S_L;
  542. 'S': instr.opsize := S_FS;
  543. 'D': instr.opsize := S_FL;
  544. 'X': instr.opsize := S_FX;
  545. else
  546. Message1(asmr_e_unknown_opcode,s);
  547. end;
  548. { delete everything starting from dot }
  549. delete(s,j,length(s));
  550. end;
  551. for i:=firstop to lastop do
  552. if s = iasmops^[i] then
  553. begin
  554. findopcode:=i;
  555. exit;
  556. end;
  557. end;
  558. Procedure InitAsmRef(var instr: TInstruction);
  559. {*********************************************************************}
  560. { Description: This routine first check if the instruction is of }
  561. { type OPR_NONE, or OPR_REFERENCE , if not it gives out an error. }
  562. { If the operandtype = OPR_NONE or <> OPR_REFERENCE then it sets up }
  563. { the operand type to OPR_REFERENCE, as well as setting up the ref }
  564. { to point to the default segment. }
  565. {*********************************************************************}
  566. Begin
  567. With instr do
  568. Begin
  569. case operands[operandnum]^.opr.typ of
  570. OPR_REFERENCE: exit;
  571. OPR_NONE: ;
  572. else
  573. Message(asmr_e_invalid_operand_type);
  574. end;
  575. operands[operandnum]^.opr.ref.direction := dir_none;
  576. operands[operandnum]^.opr.typ := OPR_REFERENCE;
  577. operands[operandnum]^.opr.ref.segment := R_DEFAULT_SEG;
  578. end;
  579. end;
  580. Function CalculateExpression(expression: string): longint;
  581. var
  582. expr: TExprParse;
  583. Begin
  584. expr.Init;
  585. CalculateExpression := expr.Evaluate(expression);
  586. expr.Done;
  587. end;
  588. Procedure ConcatOpCode(var instr: TInstruction);
  589. var
  590. fits : boolean;
  591. instruc: tasmop;
  592. Begin
  593. fits := FALSE;
  594. { setup specific instructions for first pass }
  595. instruc := instr.opcode;
  596. { Setup special operands }
  597. { Convert to general form as to conform to the m68k opcode table }
  598. if (instruc = A_ADDA) or (instruc = A_ADDI)
  599. then instruc := A_ADD
  600. else
  601. { CMPM excluded because of GAS v1.34 BUG }
  602. if (instruc = A_CMPA) or
  603. (instruc = A_CMPI) then
  604. instruc := A_CMP
  605. else
  606. if instruc = A_EORI then
  607. instruc := A_EOR
  608. else
  609. if instruc = A_MOVEA then
  610. instruc := A_MOVE
  611. else
  612. if instruc = A_ORI then
  613. instruc := A_OR
  614. else
  615. if (instruc = A_SUBA) or (instruc = A_SUBI) then
  616. instruc := A_SUB;
  617. { Setup operand types }
  618. (*
  619. in instruc <> A_MOVEM then
  620. Begin
  621. while not(fits) do
  622. begin
  623. { set the instruction cache, if the instruction }
  624. { occurs the first time }
  625. if (it[i].i=instruc) and (ins_cache[instruc]=-1) then
  626. ins_cache[instruc]:=i;
  627. if (it[i].i=instruc) and (instr.ops=it[i].ops) then
  628. begin
  629. { first fit }
  630. case instr.ops of
  631. 0 : begin
  632. fits:=true;
  633. break;
  634. end;
  635. 1 :
  636. Begin
  637. if (optyp1 and it[i].o1)<>0 then
  638. Begin
  639. fits:=true;
  640. break;
  641. end;
  642. end;
  643. 2 : if ((optyp1 and it[i].o1)<>0) and
  644. ((optyp2 and it[i].o2)<>0) then
  645. Begin
  646. fits:=true;
  647. break;
  648. end
  649. 3 : if ((optyp1 and it[i].o1)<>0) and
  650. ((optyp2 and it[i].o2)<>0) and
  651. ((optyp3 and it[i].o3)<>0) then
  652. Begin
  653. fits:=true;
  654. break;
  655. end;
  656. end; { end case }
  657. end; { endif }
  658. if it[i].i=A_NONE then
  659. begin
  660. { NO MATCH! }
  661. Message(asmr_e_invalid_combination_opcode_and_operand);
  662. exit;
  663. end;
  664. inc(i);
  665. end; { end while }
  666. *)
  667. fits:=TRUE;
  668. { We add the opcode to the opcode linked list }
  669. if fits then
  670. Begin
  671. case instr.ops of
  672. 0:
  673. if instr.opsize <> S_NO then
  674. p^.concat(new(paicpu,op_none(instruc,instr.opsize)))
  675. else
  676. p^.concat(new(paicpu,op_none(instruc,S_NO)));
  677. 1: Begin
  678. case instr.operands[1]^.opr.typ of
  679. OPR_SYMBOL: Begin
  680. p^.concat(new(paicpu,op_sym_ofs(instruc,
  681. instr.opsize, instr.operands[1]^.opr.symbol,instr.operands[1]^.opr.symofs)));
  682. end;
  683. OPR_CONSTANT: Begin
  684. p^.concat(new(paicpu,op_const(instruc,
  685. instr.opsize, instr.operands[1]^.opr.val)));
  686. end;
  687. OPR_REGISTER: p^.concat(new(paicpu,op_reg(instruc,
  688. instr.opsize,instr.operands[1]^.opr.reg)));
  689. OPR_REFERENCE:
  690. if instr.opsize <> S_NO then
  691. Begin
  692. p^.concat(new(paicpu,op_ref(instruc,
  693. instr.opsize,newreference(instr.operands[1]^.opr.ref))));
  694. end
  695. else
  696. Begin
  697. { special jmp and call case with }
  698. { symbolic references. }
  699. if instruc in [A_BSR,A_JMP,A_JSR,A_BRA,A_PEA] then
  700. Begin
  701. p^.concat(new(paicpu,op_ref(instruc,
  702. S_NO,newreference(instr.operands[1]^.opr.ref))));
  703. end
  704. else
  705. Message(asmr_e_invalid_opcode_and_operand);
  706. end;
  707. OPR_NONE: Begin
  708. Message(asmr_e_invalid_opcode_and_operand);
  709. end;
  710. else
  711. Begin
  712. Message(asmr_e_invalid_opcode_and_operand);
  713. end;
  714. end;
  715. end;
  716. 2:
  717. Begin
  718. With instr do
  719. Begin
  720. { source }
  721. case operands[1]^.opr.typ of
  722. { reg,reg }
  723. { reg,ref }
  724. OPR_REGISTER:
  725. Begin
  726. case operands[2]^.opr.typ of
  727. OPR_REGISTER:
  728. Begin
  729. p^.concat(new(paicpu,op_reg_reg(instruc,
  730. opsize,operands[1]^.opr.reg,operands[2]^.opr.reg)));
  731. end;
  732. OPR_REFERENCE:
  733. p^.concat(new(paicpu,op_reg_ref(instruc,
  734. opsize,operands[1]^.opr.reg,newreference(operands[2]^.opr.ref))));
  735. else { else case }
  736. Begin
  737. Message(asmr_e_invalid_opcode_and_operand);
  738. end;
  739. end; { end second operand case for OPR_REGISTER }
  740. end;
  741. { reglist, ref }
  742. OPR_REGLIST:
  743. Begin
  744. case operands[2]^.opr.typ of
  745. OPR_REFERENCE :
  746. p^.concat(new(paicpu,op_reglist_ref(instruc,
  747. opsize,operands[1]^.opr.reglist^,newreference(operands[2]^.opr.ref))));
  748. else
  749. Begin
  750. Message(asmr_e_invalid_opcode_and_operand);
  751. end;
  752. end; { end second operand case for OPR_REGLIST }
  753. end;
  754. { const,reg }
  755. { const,const }
  756. { const,ref }
  757. OPR_CONSTANT:
  758. case instr.operands[2]^.opr.typ of
  759. { constant, constant does not have a specific size. }
  760. OPR_CONSTANT:
  761. p^.concat(new(paicpu,op_const_const(instruc,
  762. S_NO,operands[1]^.opr.val,operands[2]^.opr.val)));
  763. OPR_REFERENCE:
  764. Begin
  765. p^.concat(new(paicpu,op_const_ref(instruc,
  766. opsize,operands[1]^.opr.val,
  767. newreference(operands[2]^.opr.ref))))
  768. end;
  769. OPR_REGISTER:
  770. Begin
  771. p^.concat(new(paicpu,op_const_reg(instruc,
  772. opsize,operands[1]^.opr.val,
  773. operands[2]^.opr.reg)))
  774. end;
  775. else
  776. Begin
  777. Message(asmr_e_invalid_opcode_and_operand);
  778. end;
  779. end; { end second operand case for OPR_CONSTANT }
  780. { ref,reg }
  781. { ref,ref }
  782. OPR_REFERENCE:
  783. case instr.operands[2]^.opr.typ of
  784. OPR_REGISTER:
  785. Begin
  786. p^.concat(new(paicpu,op_ref_reg(instruc,
  787. opsize,newreference(operands[1]^.opr.ref),
  788. operands[2]^.opr.reg)));
  789. end;
  790. OPR_REGLIST:
  791. Begin
  792. p^.concat(new(paicpu,op_ref_reglist(instruc,
  793. opsize,newreference(operands[1]^.opr.ref),
  794. operands[2]^.opr.reglist^)));
  795. end;
  796. OPR_REFERENCE: { special opcodes }
  797. p^.concat(new(paicpu,op_ref_ref(instruc,
  798. opsize,newreference(operands[1]^.opr.ref),
  799. newreference(operands[2]^.opr.ref))));
  800. else
  801. Begin
  802. Message(asmr_e_invalid_opcode_and_operand);
  803. end;
  804. end; { end second operand case for OPR_REFERENCE }
  805. OPR_SYMBOL: case operands[2]^.opr.typ of
  806. OPR_REFERENCE:
  807. Begin
  808. p^.concat(new(paicpu,op_sym_ofs_ref(instruc,
  809. opsize,instr.operands[1]^.opr.symbol,instr.operands[1]^.opr.symofs,
  810. newreference(operands[2]^.opr.ref))))
  811. end;
  812. OPR_REGISTER:
  813. Begin
  814. p^.concat(new(paicpu,op_sym_ofs_reg(instruc,
  815. opsize,instr.operands[1]^.opr.symbol,instr.operands[1]^.opr.symofs,
  816. operands[2]^.opr.reg)))
  817. end;
  818. else
  819. Begin
  820. Message(asmr_e_invalid_opcode_and_operand);
  821. end;
  822. end; { end second operand case for OPR_SYMBOL }
  823. else
  824. Begin
  825. Message(asmr_e_invalid_opcode_and_operand);
  826. end;
  827. end; { end first operand case }
  828. end; { end with }
  829. end;
  830. 3: Begin
  831. if (instruc = A_DIVSL) or (instruc = A_DIVUL) or (instruc = A_MULU)
  832. or (instruc = A_MULS) or (instruc = A_DIVS) or (instruc = A_DIVU) then
  833. Begin
  834. if (instr.operands[1]^.opr.typ <> OPR_REGISTER)
  835. or (instr.operands[2]^.opr.typ <> OPR_REGISTER)
  836. or (instr.operands[3]^.opr.typ <> OPR_REGISTER) then
  837. Begin
  838. Message(asmr_e_invalid_opcode_and_operand);
  839. end
  840. else
  841. Begin
  842. p^.concat(new(paicpu, op_reg_reg_reg(instruc,instr.opsize,
  843. instr.operands[1]^.opr.reg,instr.operands[2]^.opr.reg,instr.operands[3]^.opr.reg)));
  844. end;
  845. end
  846. else
  847. Message(asmr_e_invalid_opcode_and_operand);
  848. end;
  849. end; { end case }
  850. end;
  851. end;
  852. Procedure ConcatLabeledInstr(var instr: TInstruction);
  853. Begin
  854. if ((instr.opcode >= A_BCC) and (instr.opcode <= A_BVS))
  855. or (instr.opcode = A_BRA) or (instr.opcode = A_BSR)
  856. or (instr.opcode = A_JMP) or (instr.opcode = A_JSR)
  857. or ((instr.opcode >= A_FBEQ) and (instr.opcode <= A_FBNGLE))
  858. then
  859. Begin
  860. if instr.ops > 2 then
  861. Message(asmr_e_invalid_opcode_and_operand)
  862. else if instr.operands[1]^.opr.typ <> OPR_SYMBOL then
  863. Message(asmr_e_invalid_opcode_and_operand)
  864. else if (instr.operands[1]^.opr.typ = OPR_SYMBOL) and
  865. (instr.ops = 1) then
  866. if assigned(instr.operands[1]^.opr.symbol) and
  867. (instr.operands[1]^.opr.symofs=0) then
  868. p^.concat(new(pai_labeled,init_sym(instr.opcode,
  869. instr.operands[1]^.opr.symbol)))
  870. else
  871. Message(asmr_e_invalid_opcode_and_operand);
  872. end
  873. else
  874. if ((instr.opcode >= A_DBCC) and (instr.opcode <= A_DBF))
  875. or ((instr.opcode >= A_FDBEQ) and (instr.opcode <= A_FBDNGLE)) then
  876. begin
  877. if (instr.ops<>2) or
  878. (instr.operands[1]^.opr.typ <> OPR_REGISTER) or
  879. (instr.operands[2]^.opr.typ <> OPR_SYMBOL) or
  880. (instr.operands[2]^.opr.symofs <> 0) then
  881. Message(asmr_e_invalid_opcode_and_operand)
  882. else
  883. p^.concat(new(pai_labeled,init_reg_sym(instr.opcode,
  884. instr.operands[2]^.opr.symbol,instr.operands[1]^.opr.reg)));
  885. end
  886. else
  887. Message(asmr_e_invalid_opcode_and_operand);
  888. end;
  889. Function BuildExpression(allow_symbol : boolean; asmsym : pstring) : longint;
  890. {*********************************************************************}
  891. { FUNCTION BuildExpression: longint }
  892. { Description: This routine calculates a constant expression to }
  893. { a given value. The return value is the value calculated from }
  894. { the expression. }
  895. { The following tokens (not strings) are recognized: }
  896. { (,),SHL,SHR,/,*,NOT,OR,XOR,AND,MOD,+/-,numbers,ID to constants. }
  897. {*********************************************************************}
  898. { ENTRY: On entry the token should be any valid expression token. }
  899. { EXIT: On Exit the token points to either COMMA or SEPARATOR }
  900. { ERROR RECOVERY: Tries to find COMMA or SEPARATOR token by consuming }
  901. { invalid tokens. }
  902. {*********************************************************************}
  903. var expr: string;
  904. hs, tempstr: string;
  905. sym : psym;
  906. hl : pasmlabel;
  907. l : longint;
  908. errorflag: boolean;
  909. Begin
  910. errorflag := FALSE;
  911. expr := '';
  912. tempstr := '';
  913. if allow_symbol then
  914. asmsym^:='';
  915. Repeat
  916. Case actasmtoken of
  917. AS_LPAREN: Begin
  918. Consume(AS_LPAREN);
  919. expr := expr + '(';
  920. end;
  921. AS_RPAREN: Begin
  922. Consume(AS_RPAREN);
  923. expr := expr + ')';
  924. end;
  925. AS_SHL: Begin
  926. Consume(AS_SHL);
  927. expr := expr + '<';
  928. end;
  929. AS_SHR: Begin
  930. Consume(AS_SHR);
  931. expr := expr + '>';
  932. end;
  933. AS_SLASH: Begin
  934. Consume(AS_SLASH);
  935. expr := expr + '/';
  936. end;
  937. AS_MOD: Begin
  938. Consume(AS_MOD);
  939. expr := expr + '%';
  940. end;
  941. AS_STAR: Begin
  942. Consume(AS_STAR);
  943. expr := expr + '*';
  944. end;
  945. AS_PLUS: Begin
  946. Consume(AS_PLUS);
  947. expr := expr + '+';
  948. end;
  949. AS_MINUS: Begin
  950. Consume(AS_MINUS);
  951. expr := expr + '-';
  952. end;
  953. AS_AND: Begin
  954. Consume(AS_AND);
  955. expr := expr + '&';
  956. end;
  957. AS_NOT: Begin
  958. Consume(AS_NOT);
  959. expr := expr + '~';
  960. end;
  961. AS_XOR: Begin
  962. Consume(AS_XOR);
  963. expr := expr + '^';
  964. end;
  965. AS_OR: Begin
  966. Consume(AS_OR);
  967. expr := expr + '|';
  968. end;
  969. AS_ID: Begin
  970. if SearchIConstant(actasmpattern,l) then
  971. Begin
  972. str(l, tempstr);
  973. expr := expr + tempstr;
  974. Consume(AS_ID);
  975. End else
  976. if not allow_symbol then
  977. Begin
  978. Message(asmr_e_syn_constant);
  979. l := 0;
  980. End else
  981. Begin
  982. hs:='';
  983. if (expr[Length(expr)]='+') then
  984. Delete(expr,Length(expr),1)
  985. else if expr<>'' then
  986. Begin
  987. Message(asmr_e_invalid_constant_expression);
  988. break;
  989. End;
  990. tempstr:=actasmpattern;
  991. consume(AS_ID);
  992. if (length(tempstr)>1) and (tempstr[1]='@') then
  993. begin
  994. CreateLocalLabel(tempstr,hl,false);
  995. hs:=hl^.name
  996. end
  997. else if SearchLabel(tempstr,hl,false) then
  998. hs:=hl^.name
  999. else
  1000. begin
  1001. getsym(tempstr,false);
  1002. sym:=srsym;
  1003. if assigned(sym) then
  1004. begin
  1005. case srsym^.typ of
  1006. varsym :
  1007. begin
  1008. if sym^.owner^.symtabletype in [localsymtable,parasymtable] then
  1009. Message(asmr_e_no_local_or_para_allowed);
  1010. hs:=pvarsym(srsym)^.mangledname;
  1011. end;
  1012. typedconstsym :
  1013. hs:=ptypedconstsym(srsym)^.mangledname;
  1014. procsym :
  1015. hs:=pprocsym(srsym)^.mangledname;
  1016. else
  1017. Message(asmr_e_wrong_sym_type);
  1018. end;
  1019. end
  1020. else
  1021. Message1(sym_e_unknown_id,tempstr);
  1022. end;
  1023. { symbol found? }
  1024. if hs<>'' then
  1025. begin
  1026. if asmsym^='' then
  1027. asmsym^:=hs
  1028. else
  1029. Message(asmr_e_cant_have_multiple_relocatable_symbols);
  1030. end;
  1031. end;
  1032. end;
  1033. AS_INTNUM: Begin
  1034. expr := expr + actasmpattern;
  1035. Consume(AS_INTNUM);
  1036. end;
  1037. AS_BINNUM: Begin
  1038. tempstr := tostr(ValBinary(actasmpattern));
  1039. if tempstr = '' then
  1040. Message(asmr_e_error_converting_binary);
  1041. expr:=expr+tempstr;
  1042. Consume(AS_BINNUM);
  1043. end;
  1044. AS_HEXNUM: Begin
  1045. tempstr := tostr(ValHexadecimal(actasmpattern));
  1046. if tempstr = '' then
  1047. Message(asmr_e_error_converting_hexadecimal);
  1048. expr:=expr+tempstr;
  1049. Consume(AS_HEXNUM);
  1050. end;
  1051. AS_OCTALNUM: Begin
  1052. tempstr := tostr(ValOctal(actasmpattern));
  1053. if tempstr = '' then
  1054. Message(asmr_e_error_converting_octal);
  1055. expr:=expr+tempstr;
  1056. Consume(AS_OCTALNUM);
  1057. end;
  1058. { go to next term }
  1059. AS_COMMA: Begin
  1060. if not ErrorFlag then
  1061. BuildExpression := CalculateExpression(expr)
  1062. else
  1063. BuildExpression := 0;
  1064. Exit;
  1065. end;
  1066. { go to next symbol }
  1067. AS_SEPARATOR: Begin
  1068. if not ErrorFlag then
  1069. BuildExpression := CalculateExpression(expr)
  1070. else
  1071. BuildExpression := 0;
  1072. Exit;
  1073. end;
  1074. else
  1075. Begin
  1076. { only write error once. }
  1077. if not errorflag then
  1078. Message(asmr_e_invalid_constant_expression);
  1079. { consume tokens until we find COMMA or SEPARATOR }
  1080. Consume(actasmtoken);
  1081. errorflag := TRUE;
  1082. End;
  1083. end;
  1084. Until false;
  1085. end;
  1086. Procedure BuildRealConstant(typ : tfloattype);
  1087. {*********************************************************************}
  1088. { PROCEDURE BuilRealConst }
  1089. { Description: This routine calculates a constant expression to }
  1090. { a given value. The return value is the value calculated from }
  1091. { the expression. }
  1092. { The following tokens (not strings) are recognized: }
  1093. { +/-,numbers and real numbers }
  1094. {*********************************************************************}
  1095. { ENTRY: On entry the token should be any valid expression token. }
  1096. { EXIT: On Exit the token points to either COMMA or SEPARATOR }
  1097. { ERROR RECOVERY: Tries to find COMMA or SEPARATOR token by consuming }
  1098. { invalid tokens. }
  1099. {*********************************************************************}
  1100. var expr: string;
  1101. r : extended;
  1102. code : word;
  1103. negativ : boolean;
  1104. errorflag: boolean;
  1105. Begin
  1106. errorflag := FALSE;
  1107. Repeat
  1108. negativ:=false;
  1109. expr := '';
  1110. if actasmtoken=AS_PLUS then Consume(AS_PLUS)
  1111. else if actasmtoken=AS_MINUS then
  1112. begin
  1113. negativ:=true;
  1114. consume(AS_MINUS);
  1115. end;
  1116. Case actasmtoken of
  1117. AS_INTNUM: Begin
  1118. expr := actasmpattern;
  1119. Consume(AS_INTNUM);
  1120. end;
  1121. AS_REALNUM: Begin
  1122. expr := actasmpattern;
  1123. { in ATT syntax you have 0d in front of the real }
  1124. { should this be forced ? yes i think so, as to }
  1125. { conform to gas as much as possible. }
  1126. if (expr[1]='0') and (upper(expr[2])='D') then
  1127. expr:=copy(expr,3,255);
  1128. Consume(AS_REALNUM);
  1129. end;
  1130. AS_BINNUM: Begin
  1131. { checking for real constants with this should use }
  1132. { real DECODING otherwise the compiler will crash! }
  1133. Message(asmr_e_invalid_float_expr);
  1134. expr:='0.0';
  1135. Consume(AS_BINNUM);
  1136. end;
  1137. AS_HEXNUM: Begin
  1138. { checking for real constants with this should use }
  1139. { real DECODING otherwise the compiler will crash! }
  1140. Message(asmr_e_invalid_float_expr);
  1141. expr:='0.0';
  1142. Consume(AS_HEXNUM);
  1143. end;
  1144. AS_OCTALNUM: Begin
  1145. { checking for real constants with this should use }
  1146. { real DECODING otherwise the compiler will crash! }
  1147. { xxxToDec using reals could be a solution, but the }
  1148. { problem is that these will crash the m68k compiler }
  1149. { when compiling -- because of lack of good fpu }
  1150. { support. }
  1151. Message(asmr_e_invalid_float_expr);
  1152. expr:='0.0';
  1153. Consume(AS_OCTALNUM);
  1154. end;
  1155. else
  1156. Begin
  1157. { only write error once. }
  1158. if not errorflag then
  1159. Message(asmr_e_invalid_float_expr);
  1160. { consume tokens until we find COMMA or SEPARATOR }
  1161. Consume(actasmtoken);
  1162. errorflag := TRUE;
  1163. End;
  1164. end;
  1165. { go to next term }
  1166. if (actasmtoken=AS_COMMA) or (actasmtoken=AS_SEPARATOR) then
  1167. Begin
  1168. if negativ then expr:='-'+expr;
  1169. val(expr,r,code);
  1170. if code<>0 then
  1171. Begin
  1172. r:=0;
  1173. Message(asmr_e_invalid_float_expr);
  1174. ConcatRealConstant(p,r,typ);
  1175. End
  1176. else
  1177. Begin
  1178. ConcatRealConstant(p,r,typ);
  1179. End;
  1180. end
  1181. else
  1182. Message(asmr_e_invalid_float_expr);
  1183. Until actasmtoken=AS_SEPARATOR;
  1184. end;
  1185. Procedure BuildScaling(Var instr: TInstruction);
  1186. {*********************************************************************}
  1187. { Takes care of parsing expression starting from the scaling value }
  1188. { up to and including possible field specifiers. }
  1189. { EXIT CONDITION: On exit the routine should point to AS_SEPARATOR }
  1190. { or AS_COMMA. On entry should point to the AS_STAR token. }
  1191. {*********************************************************************}
  1192. var str:string;
  1193. l: longint;
  1194. code: integer;
  1195. Begin
  1196. Consume(AS_STAR);
  1197. if (instr.operands[operandnum]^.opr.ref.scalefactor <> 0)
  1198. and (instr.operands[operandnum]^.opr.ref.scalefactor <> 1) then
  1199. Message(asmr_e_wrong_base_index);
  1200. case actasmtoken of
  1201. AS_INTNUM: str := actasmpattern;
  1202. AS_HEXNUM: str := Tostr(ValHexadecimal(actasmpattern));
  1203. AS_BINNUM: str := Tostr(ValBinary(actasmpattern));
  1204. AS_OCTALNUM: str := Tostr(ValOctal(actasmpattern));
  1205. else
  1206. Message(asmr_e_syntax_error);
  1207. end;
  1208. val(str, l, code);
  1209. if code <> 0 then
  1210. Message(asmr_e_wrong_scale_factor);
  1211. if ((l = 2) or (l = 4) or (l = 8) or (l = 1)) and (code = 0) then
  1212. begin
  1213. instr.operands[operandnum]^.opr.ref.scalefactor := l;
  1214. end
  1215. else
  1216. Begin
  1217. Message(asmr_e_wrong_scale_factor);
  1218. instr.operands[operandnum]^.opr.ref.scalefactor := 0;
  1219. end;
  1220. if instr.operands[operandnum]^.opr.ref.index = R_NO then
  1221. Begin
  1222. Message(asmr_e_wrong_base_index);
  1223. instr.operands[operandnum]^.opr.ref.scalefactor := 0;
  1224. end;
  1225. { Consume the scaling number }
  1226. Consume(actasmtoken);
  1227. if actasmtoken = AS_RPAREN then
  1228. Consume(AS_RPAREN)
  1229. else
  1230. Message(asmr_e_wrong_scale_factor);
  1231. { // .Field.Field ... or separator/comma // }
  1232. if actasmtoken in [AS_COMMA,AS_SEPARATOR] then
  1233. Begin
  1234. end
  1235. else
  1236. Message(asmr_e_syntax_error);
  1237. end;
  1238. Function BuildRefExpression: longint;
  1239. {*********************************************************************}
  1240. { FUNCTION BuildExpression: longint }
  1241. { Description: This routine calculates a constant expression to }
  1242. { a given value. The return value is the value calculated from }
  1243. { the expression. }
  1244. { The following tokens (not strings) are recognized: }
  1245. { SHL,SHR,/,*,NOT,OR,XOR,AND,MOD,+/-,numbers,ID to constants. }
  1246. {*********************************************************************}
  1247. { ENTRY: On entry the token should be any valid expression token. }
  1248. { EXIT: On Exit the token points to the LPAREN token. }
  1249. { ERROR RECOVERY: Tries to find COMMA or SEPARATOR token by consuming }
  1250. { invalid tokens. }
  1251. {*********************************************************************}
  1252. var tempstr: string;
  1253. expr: string;
  1254. l : longint;
  1255. errorflag : boolean;
  1256. Begin
  1257. errorflag := FALSE;
  1258. tempstr := '';
  1259. expr := '';
  1260. Repeat
  1261. Case actasmtoken of
  1262. AS_RPAREN: Begin
  1263. Message(asmr_e_syntax_error);
  1264. Consume(AS_RPAREN);
  1265. end;
  1266. AS_SHL: Begin
  1267. Consume(AS_SHL);
  1268. expr := expr + '<';
  1269. end;
  1270. AS_SHR: Begin
  1271. Consume(AS_SHR);
  1272. expr := expr + '>';
  1273. end;
  1274. AS_SLASH: Begin
  1275. Consume(AS_SLASH);
  1276. expr := expr + '/';
  1277. end;
  1278. AS_MOD: Begin
  1279. Consume(AS_MOD);
  1280. expr := expr + '%';
  1281. end;
  1282. AS_STAR: Begin
  1283. Consume(AS_STAR);
  1284. expr := expr + '*';
  1285. end;
  1286. AS_PLUS: Begin
  1287. Consume(AS_PLUS);
  1288. expr := expr + '+';
  1289. end;
  1290. AS_MINUS: Begin
  1291. Consume(AS_MINUS);
  1292. expr := expr + '-';
  1293. end;
  1294. AS_AND: Begin
  1295. Consume(AS_AND);
  1296. expr := expr + '&';
  1297. end;
  1298. AS_NOT: Begin
  1299. Consume(AS_NOT);
  1300. expr := expr + '~';
  1301. end;
  1302. AS_XOR: Begin
  1303. Consume(AS_XOR);
  1304. expr := expr + '^';
  1305. end;
  1306. AS_OR: Begin
  1307. Consume(AS_OR);
  1308. expr := expr + '|';
  1309. end;
  1310. { End of reference }
  1311. AS_LPAREN: Begin
  1312. if not ErrorFlag then
  1313. BuildRefExpression := CalculateExpression(expr)
  1314. else
  1315. BuildRefExpression := 0;
  1316. { no longer in an expression }
  1317. exit;
  1318. end;
  1319. AS_ID:
  1320. Begin
  1321. if NOT SearchIConstant(actasmpattern,l) then
  1322. Begin
  1323. Message(asmr_e_syn_constant);
  1324. l := 0;
  1325. end;
  1326. str(l, tempstr);
  1327. expr := expr + tempstr;
  1328. Consume(AS_ID);
  1329. end;
  1330. AS_INTNUM: Begin
  1331. expr := expr + actasmpattern;
  1332. Consume(AS_INTNUM);
  1333. end;
  1334. AS_BINNUM: Begin
  1335. tempstr := Tostr(ValBinary(actasmpattern));
  1336. if tempstr = '' then
  1337. Message(asmr_e_error_converting_binary);
  1338. expr:=expr+tempstr;
  1339. Consume(AS_BINNUM);
  1340. end;
  1341. AS_HEXNUM: Begin
  1342. tempstr := Tostr(ValHexadecimal(actasmpattern));
  1343. if tempstr = '' then
  1344. Message(asmr_e_error_converting_hexadecimal);
  1345. expr:=expr+tempstr;
  1346. Consume(AS_HEXNUM);
  1347. end;
  1348. AS_OCTALNUM: Begin
  1349. tempstr := Tostr(ValOctal(actasmpattern));
  1350. if tempstr = '' then
  1351. Message(asmr_e_error_converting_octal);
  1352. expr:=expr+tempstr;
  1353. Consume(AS_OCTALNUM);
  1354. end;
  1355. else
  1356. Begin
  1357. { write error only once. }
  1358. if not errorflag then
  1359. Message(asmr_e_invalid_constant_expression);
  1360. BuildRefExpression := 0;
  1361. if actasmtoken in [AS_COMMA,AS_SEPARATOR] then exit;
  1362. { consume tokens until we find COMMA or SEPARATOR }
  1363. Consume(actasmtoken);
  1364. errorflag := TRUE;
  1365. end;
  1366. end;
  1367. Until false;
  1368. end;
  1369. Procedure BuildReference(var Instr: TInstruction);
  1370. {*********************************************************************}
  1371. { PROCEDURE BuildBracketExpression }
  1372. { Description: This routine builds up an expression after a LPAREN }
  1373. { token is encountered. }
  1374. { On entry actasmtoken should be equal to AS_LPAREN }
  1375. {*********************************************************************}
  1376. { EXIT CONDITION: On exit the routine should point to either the }
  1377. { AS_COMMA or AS_SEPARATOR token. }
  1378. {*********************************************************************}
  1379. var
  1380. l:longint;
  1381. code: integer;
  1382. str: string;
  1383. Begin
  1384. Consume(AS_LPAREN);
  1385. Case actasmtoken of
  1386. { // (reg ... // }
  1387. AS_REGISTER: Begin
  1388. instr.operands[operandnum]^.opr.ref.base :=
  1389. findregister(actasmpattern);
  1390. Consume(AS_REGISTER);
  1391. { can either be a register or a right parenthesis }
  1392. { // (reg) // }
  1393. { // (reg)+ // }
  1394. if actasmtoken=AS_RPAREN then
  1395. Begin
  1396. Consume(AS_RPAREN);
  1397. if actasmtoken = AS_PLUS then
  1398. Begin
  1399. if (instr.operands[operandnum]^.opr.ref.direction <> dir_none) then
  1400. Message(asmr_e_no_inc_and_dec_together)
  1401. else
  1402. instr.operands[operandnum]^.opr.ref.direction := dir_inc;
  1403. Consume(AS_PLUS);
  1404. end;
  1405. if not (actasmtoken in [AS_COMMA,AS_SEPARATOR]) then
  1406. Begin
  1407. Message(asmr_e_invalid_reference_syntax);
  1408. { error recovery ... }
  1409. while actasmtoken <> AS_SEPARATOR do
  1410. Consume(actasmtoken);
  1411. end;
  1412. exit;
  1413. end;
  1414. { // (reg,reg .. // }
  1415. Consume(AS_COMMA);
  1416. if actasmtoken = AS_REGISTER then
  1417. Begin
  1418. instr.operands[operandnum]^.opr.ref.index :=
  1419. findregister(actasmpattern);
  1420. Consume(AS_REGISTER);
  1421. { check for scaling ... }
  1422. case actasmtoken of
  1423. AS_RPAREN:
  1424. Begin
  1425. Consume(AS_RPAREN);
  1426. if not (actasmtoken in [AS_COMMA,AS_SEPARATOR]) then
  1427. Begin
  1428. { error recovery ... }
  1429. Message(asmr_e_invalid_reference_syntax);
  1430. while actasmtoken <> AS_SEPARATOR do
  1431. Consume(actasmtoken);
  1432. end;
  1433. exit;
  1434. end;
  1435. AS_STAR:
  1436. Begin
  1437. BuildScaling(instr);
  1438. end;
  1439. else
  1440. Begin
  1441. Message(asmr_e_invalid_reference_syntax);
  1442. while (actasmtoken <> AS_SEPARATOR) do
  1443. Consume(actasmtoken);
  1444. end;
  1445. end; { end case }
  1446. end
  1447. else
  1448. Begin
  1449. Message(asmr_e_invalid_reference_syntax);
  1450. while (actasmtoken <> AS_SEPARATOR) do
  1451. Consume(actasmtoken);
  1452. end;
  1453. end;
  1454. AS_HEXNUM,AS_OCTALNUM, { direct address }
  1455. AS_BINNUM,AS_INTNUM: Begin
  1456. case actasmtoken of
  1457. AS_INTNUM: str := actasmpattern;
  1458. AS_HEXNUM: str := Tostr(ValHexadecimal(actasmpattern));
  1459. AS_BINNUM: str := Tostr(ValBinary(actasmpattern));
  1460. AS_OCTALNUM: str := Tostr(ValOctal(actasmpattern));
  1461. else
  1462. Message(asmr_e_syntax_error);
  1463. end;
  1464. Consume(actasmtoken);
  1465. val(str, l, code);
  1466. if code <> 0 then
  1467. Message(asmr_e_invalid_reference_syntax)
  1468. else
  1469. instr.operands[operandnum]^.opr.ref.offset := l;
  1470. Consume(AS_RPAREN);
  1471. if not (actasmtoken in [AS_COMMA,AS_SEPARATOR]) then
  1472. Begin
  1473. { error recovery ... }
  1474. Message(asmr_e_invalid_reference_syntax);
  1475. while actasmtoken <> AS_SEPARATOR do
  1476. Consume(actasmtoken);
  1477. end;
  1478. exit;
  1479. end;
  1480. else
  1481. Begin
  1482. Message(asmr_e_invalid_reference_syntax);
  1483. while (actasmtoken <> AS_SEPARATOR) do
  1484. Consume(actasmtoken);
  1485. end;
  1486. end; { end case }
  1487. end;
  1488. Procedure BuildOperand(var instr: TInstruction);
  1489. {*********************************************************************}
  1490. { EXIT CONDITION: On exit the routine should point to either the }
  1491. { AS_COMMA or AS_SEPARATOR token. }
  1492. {*********************************************************************}
  1493. var
  1494. tempstr: string;
  1495. expr: string;
  1496. lab: Pasmlabel;
  1497. l : longint;
  1498. i: tregister;
  1499. hl: pasmlabel;
  1500. reg_one, reg_two: tregister;
  1501. reglist: set of tregister;
  1502. Begin
  1503. reglist := [];
  1504. tempstr := '';
  1505. expr := '';
  1506. case actasmtoken of
  1507. { // Memory reference // }
  1508. AS_LPAREN:
  1509. Begin
  1510. initAsmRef(instr);
  1511. BuildReference(instr);
  1512. end;
  1513. { // Constant expression // }
  1514. AS_APPT: Begin
  1515. Consume(AS_APPT);
  1516. if not (instr.operands[operandnum]^.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  1517. Message(asmr_e_invalid_operand_type);
  1518. { identifiers are handled by BuildExpression }
  1519. instr.operands[operandnum]^.opr.typ := OPR_CONSTANT;
  1520. instr.operands[operandnum]^.opr.val :=BuildExpression(true,@tempstr);
  1521. if tempstr<>'' then
  1522. begin
  1523. l:=instr.operands[operandnum]^.opr.val;
  1524. instr.operands[operandnum]^.opr.typ := OPR_SYMBOL;
  1525. instr.operands[operandnum]^.opr.symofs := l;
  1526. instr.operands[operandnum]^.opr.symbol := newasmsymbol(tempstr);
  1527. end;
  1528. end;
  1529. { // Constant memory offset . // }
  1530. { // This must absolutely be followed by ( // }
  1531. AS_HEXNUM,AS_INTNUM,
  1532. AS_BINNUM,AS_OCTALNUM,AS_PLUS:
  1533. Begin
  1534. InitAsmRef(instr);
  1535. instr.operands[operandnum]^.opr.ref.offset:=BuildRefExpression;
  1536. BuildReference(instr);
  1537. end;
  1538. { // A constant expression, or a Variable ref. // }
  1539. AS_ID: Begin
  1540. if actasmpattern[1] = '@' then
  1541. { // Label or Special symbol reference // }
  1542. Begin
  1543. if actasmpattern = '@RESULT' then
  1544. Begin
  1545. InitAsmRef(instr);
  1546. instr.operands[operandnum]^.SetUpResult;
  1547. end
  1548. else
  1549. if (actasmpattern = '@CODE') or (actasmpattern = '@DATA') then
  1550. Message(asmr_w_CODE_and_DATA_not_supported)
  1551. else
  1552. Begin
  1553. delete(actasmpattern,1,1);
  1554. if actasmpattern = '' then
  1555. Message(asmr_e_null_label_ref_not_allowed);
  1556. CreateLocalLabel(actasmpattern,lab,false);
  1557. instr.operands[operandnum]^.opr.typ := OPR_SYMBOL;
  1558. instr.operands[operandnum]^.opr.symbol := lab;
  1559. instr.operands[operandnum]^.opr.symofs := 0;
  1560. instr.labeled := TRUE;
  1561. end;
  1562. Consume(AS_ID);
  1563. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  1564. Message(asmr_e_syntax_error);
  1565. end
  1566. { probably a variable or normal expression }
  1567. { or a procedure (such as in CALL ID) }
  1568. else
  1569. Begin
  1570. { is it a constant ? }
  1571. if SearchIConstant(actasmpattern,l) then
  1572. Begin
  1573. InitAsmRef(instr);
  1574. instr.operands[operandnum]^.opr.ref.offset:=BuildRefExpression;
  1575. BuildReference(instr);
  1576. { if not (instr.operands[operandnum].opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  1577. Message(asmr_e_invalid_operand_type);
  1578. instr.operands[operandnum].opr.typ := OPR_CONSTANT;
  1579. instr.operands[operandnum].val :=BuildExpression;}
  1580. end
  1581. else { is it a label variable ? }
  1582. Begin
  1583. { // ID[ , ID.Field.Field or simple ID // }
  1584. { check if this is a label, if so then }
  1585. { emit it as a label. }
  1586. if SearchLabel(actasmpattern,hl,false) then
  1587. Begin
  1588. instr.operands[operandnum]^.opr.typ := OPR_SYMBOL;
  1589. instr.operands[operandnum]^.opr.symbol := hl;
  1590. instr.operands[operandnum]^.opr.symofs := 0;
  1591. instr.labeled := TRUE;
  1592. Consume(AS_ID);
  1593. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  1594. Message(asmr_e_syntax_error);
  1595. end
  1596. else
  1597. { is it a normal variable ? }
  1598. Begin
  1599. initAsmRef(instr);
  1600. if not instr.operands[operandnum]^.SetUpVar(actasmpattern,false) then
  1601. Begin
  1602. { not a variable.. }
  1603. { check special variables.. }
  1604. if actasmpattern = 'SELF' then
  1605. { special self variable }
  1606. Begin
  1607. if assigned(procinfo^._class) then
  1608. Begin
  1609. instr.operands[operandnum]^.opr.ref.offset := procinfo^.selfpointer_offset;
  1610. instr.operands[operandnum]^.opr.ref.base := procinfo^.framepointer;
  1611. end
  1612. else
  1613. Message(asmr_e_cannot_use_SELF_outside_a_method);
  1614. end
  1615. else
  1616. if (cs_compilesystem in aktmoduleswitches) then
  1617. Begin
  1618. if not assigned(instr.operands[operandnum]^.opr.ref.symbol) then
  1619. Begin
  1620. if getasmsymbol(actasmpattern) =nil then
  1621. Message1(asmr_w_id_supposed_external,actasmpattern);
  1622. instr.operands[operandnum]^.opr.ref.symbol:=newasmsymbol(actasmpattern);
  1623. end
  1624. else
  1625. Message(asmr_e_syntax_error);
  1626. end
  1627. else
  1628. Message1(asmr_e_unknown_label_identifier,actasmpattern);
  1629. end;
  1630. expr := actasmpattern;
  1631. Consume(AS_ID);
  1632. case actasmtoken of
  1633. AS_LPAREN: { indexing }
  1634. BuildReference(instr);
  1635. AS_SEPARATOR,AS_COMMA: ;
  1636. else
  1637. Message(asmr_e_syntax_error);
  1638. end;
  1639. end;
  1640. end;
  1641. end;
  1642. end;
  1643. { // Pre-decrement mode reference or constant mem offset. // }
  1644. AS_MINUS: Begin
  1645. Consume(AS_MINUS);
  1646. if actasmtoken = AS_LPAREN then
  1647. Begin
  1648. InitAsmRef(instr);
  1649. { indicate pre-decrement mode }
  1650. instr.operands[operandnum]^.opr.ref.direction := dir_dec;
  1651. BuildReference(instr);
  1652. end
  1653. else
  1654. if actasmtoken in [AS_OCTALNUM,AS_HEXNUM,AS_BINNUM,AS_INTNUM] then
  1655. Begin
  1656. InitAsmRef(instr);
  1657. instr.operands[operandnum]^.opr.ref.offset:=BuildRefExpression;
  1658. { negate because was preceded by a negative sign! }
  1659. instr.operands[operandnum]^.opr.ref.offset:=-instr.operands[operandnum]^.opr.ref.offset;
  1660. BuildReference(instr);
  1661. end
  1662. else
  1663. Begin
  1664. Message(asmr_e_syntax_error);
  1665. while not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) do
  1666. Consume(actasmtoken);
  1667. end;
  1668. end;
  1669. { // Register, a variable reference or a constant reference // }
  1670. AS_REGISTER: Begin
  1671. { save the type of register used. }
  1672. tempstr := actasmpattern;
  1673. Consume(AS_REGISTER);
  1674. { // Simple register // }
  1675. if (actasmtoken = AS_SEPARATOR) or (actasmtoken = AS_COMMA) then
  1676. Begin
  1677. if not (instr.operands[operandnum]^.opr.typ in [OPR_NONE,OPR_REGISTER]) then
  1678. Message(asmr_e_invalid_operand_type);
  1679. instr.operands[operandnum]^.opr.typ := OPR_REGISTER;
  1680. instr.operands[operandnum]^.opr.reg := findregister(tempstr);
  1681. end
  1682. else
  1683. { HERE WE MUST HANDLE THE SPECIAL CASE OF MOVEM AND FMOVEM }
  1684. { // Individual register listing // }
  1685. if (actasmtoken = AS_SLASH) then
  1686. Begin
  1687. reglist := [findregister(tempstr)];
  1688. Consume(AS_SLASH);
  1689. if actasmtoken = AS_REGISTER then
  1690. Begin
  1691. While not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) do
  1692. Begin
  1693. case actasmtoken of
  1694. AS_REGISTER: Begin
  1695. reglist := reglist + [findregister(actasmpattern)];
  1696. Consume(AS_REGISTER);
  1697. end;
  1698. AS_SLASH: Consume(AS_SLASH);
  1699. AS_SEPARATOR,AS_COMMA: break;
  1700. else
  1701. Begin
  1702. Message(asmr_e_invalid_reg_list_in_movem);
  1703. Consume(actasmtoken);
  1704. end;
  1705. end; { end case }
  1706. end; { end while }
  1707. instr.operands[operandnum]^.opr.typ:= OPR_REGLIST;
  1708. instr.operands[operandnum]^.opr.reglist := newreglist(reglist);
  1709. end
  1710. else
  1711. { error recovery ... }
  1712. Begin
  1713. Message(asmr_e_invalid_reg_list_in_movem);
  1714. while not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) do
  1715. Consume(actasmtoken);
  1716. end;
  1717. end
  1718. else
  1719. { // Range register listing // }
  1720. if (actasmtoken = AS_MINUS) then
  1721. Begin
  1722. Consume(AS_MINUS);
  1723. reg_one:=findregister(tempstr);
  1724. if actasmtoken <> AS_REGISTER then
  1725. Begin
  1726. Message(asmr_e_invalid_reg_list_in_movem);
  1727. while not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) do
  1728. Consume(actasmtoken);
  1729. end
  1730. else
  1731. Begin
  1732. { determine the register range ... }
  1733. reg_two:=findregister(actasmpattern);
  1734. if reg_one > reg_two then
  1735. begin
  1736. for i:=reg_two to reg_one do
  1737. reglist := reglist + [i];
  1738. end
  1739. else
  1740. Begin
  1741. for i:=reg_one to reg_two do
  1742. reglist := reglist + [i];
  1743. end;
  1744. Consume(AS_REGISTER);
  1745. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  1746. Begin
  1747. Message(asmr_e_invalid_reg_list_in_movem);
  1748. while not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) do
  1749. Consume(actasmtoken);
  1750. end;
  1751. { set up instruction }
  1752. instr.operands[operandnum]^.opr.typ:= OPR_REGLIST;
  1753. instr.operands[operandnum]^.opr.reglist := newreglist(reglist);
  1754. end;
  1755. end
  1756. else
  1757. { DIVSL/DIVS/MULS/MULU with long for MC68020 only }
  1758. if (actasmtoken = AS_COLON) then
  1759. Begin
  1760. if (aktoptprocessor = MC68020) or (cs_compilesystem in aktmoduleswitches) then
  1761. Begin
  1762. Consume(AS_COLON);
  1763. if (actasmtoken = AS_REGISTER) then
  1764. Begin
  1765. { set up old field, since register is valid }
  1766. instr.operands[operandnum]^.opr.typ := OPR_REGISTER;
  1767. instr.operands[operandnum]^.opr.reg := findregister(tempstr);
  1768. Inc(operandnum);
  1769. instr.operands[operandnum]^.opr.typ := OPR_REGISTER;
  1770. instr.operands[operandnum]^.opr.reg := findregister(actasmpattern);
  1771. Consume(AS_REGISTER);
  1772. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  1773. Begin
  1774. Message(asmr_e_invalid_reg_list_for_opcode);
  1775. while not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) do
  1776. Consume(actasmtoken);
  1777. end;
  1778. end;
  1779. end
  1780. else
  1781. Begin
  1782. Message(asmr_e_68020_mode_required);
  1783. if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  1784. Begin
  1785. Message(asmr_e_invalid_reg_list_for_opcode);
  1786. while not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) do
  1787. Consume(actasmtoken);
  1788. end;
  1789. end;
  1790. end
  1791. else
  1792. Message(asmr_e_invalid_register);
  1793. end;
  1794. AS_SEPARATOR, AS_COMMA: ;
  1795. else
  1796. Begin
  1797. Message(asmr_e_invalid_opcode_and_operand);
  1798. Consume(actasmtoken);
  1799. end;
  1800. end; { end case }
  1801. end;
  1802. Procedure BuildConstant(maxvalue: longint);
  1803. {*********************************************************************}
  1804. { PROCEDURE BuildConstant }
  1805. { Description: This routine takes care of parsing a DB,DD,or DW }
  1806. { line and adding those to the assembler node. Expressions, range- }
  1807. { checking are fullly taken care of. }
  1808. { maxvalue: $ff -> indicates that this is a DB node. }
  1809. { $ffff -> indicates that this is a DW node. }
  1810. { $ffffffff -> indicates that this is a DD node. }
  1811. {*********************************************************************}
  1812. { EXIT CONDITION: On exit the routine should point to AS_SEPARATOR. }
  1813. {*********************************************************************}
  1814. var
  1815. strlength: byte;
  1816. expr: string;
  1817. tempstr: string;
  1818. value : longint;
  1819. Begin
  1820. Repeat
  1821. Case actasmtoken of
  1822. AS_STRING: Begin
  1823. if maxvalue = $ff then
  1824. strlength := 1
  1825. else
  1826. Message(asmr_e_string_not_allowed_as_const);
  1827. expr := actasmpattern;
  1828. if length(expr) > 1 then
  1829. Message(asmr_e_string_not_allowed_as_const);
  1830. Consume(AS_STRING);
  1831. Case actasmtoken of
  1832. AS_COMMA: Consume(AS_COMMA);
  1833. AS_SEPARATOR: ;
  1834. else
  1835. Message(asmr_e_invalid_string_expression);
  1836. end; { end case }
  1837. ConcatString(p,expr);
  1838. end;
  1839. AS_INTNUM,AS_BINNUM,
  1840. AS_OCTALNUM,AS_HEXNUM:
  1841. Begin
  1842. value:=BuildExpression(false,nil);
  1843. ConcatConstant(p,value,maxvalue);
  1844. end;
  1845. AS_ID:
  1846. Begin
  1847. value:=BuildExpression(false,nil);
  1848. if value > maxvalue then
  1849. Begin
  1850. Message(asmr_e_constant_out_of_bounds);
  1851. { assuming a value of maxvalue }
  1852. value := maxvalue;
  1853. end;
  1854. ConcatConstant(p,value,maxvalue);
  1855. end;
  1856. { These terms can start an assembler expression }
  1857. AS_PLUS,AS_MINUS,AS_LPAREN,AS_NOT: Begin
  1858. value := BuildExpression(false,nil);
  1859. ConcatConstant(p,value,maxvalue);
  1860. end;
  1861. AS_COMMA: BEGIN
  1862. Consume(AS_COMMA);
  1863. END;
  1864. AS_SEPARATOR: ;
  1865. else
  1866. Begin
  1867. Message(asmr_e_syntax_error);
  1868. end;
  1869. end; { end case }
  1870. Until actasmtoken = AS_SEPARATOR;
  1871. end;
  1872. Procedure BuildStringConstant(asciiz: boolean);
  1873. {*********************************************************************}
  1874. { PROCEDURE BuildStringConstant }
  1875. { Description: Takes care of a ASCII, or ASCIIZ directive. }
  1876. { asciiz: boolean -> if true then string will be null terminated. }
  1877. {*********************************************************************}
  1878. { EXIT CONDITION: On exit the routine should point to AS_SEPARATOR. }
  1879. { On ENTRY: Token should point to AS_STRING }
  1880. {*********************************************************************}
  1881. var
  1882. expr: string;
  1883. errorflag : boolean;
  1884. Begin
  1885. errorflag := FALSE;
  1886. Repeat
  1887. Case actasmtoken of
  1888. AS_STRING: Begin
  1889. expr:=actasmpattern;
  1890. if asciiz then
  1891. expr:=expr+#0;
  1892. ConcatPasString(p,expr);
  1893. Consume(AS_STRING);
  1894. end;
  1895. AS_COMMA: BEGIN
  1896. Consume(AS_COMMA);
  1897. END;
  1898. AS_SEPARATOR: ;
  1899. else
  1900. Begin
  1901. Consume(actasmtoken);
  1902. if not errorflag then
  1903. Message(asmr_e_invalid_string_expression);
  1904. errorflag := TRUE;
  1905. end;
  1906. end; { end case }
  1907. Until actasmtoken = AS_SEPARATOR;
  1908. end;
  1909. Procedure BuildOpCode;
  1910. {*********************************************************************}
  1911. { PROCEDURE BuildOpcode; }
  1912. { Description: Parses the intel opcode and operands, and writes it }
  1913. { in the TInstruction object. }
  1914. {*********************************************************************}
  1915. { EXIT CONDITION: On exit the routine should point to AS_SEPARATOR. }
  1916. { On ENTRY: Token should point to AS_OPCODE }
  1917. {*********************************************************************}
  1918. var asmtok: tasmop;
  1919. op: tasmop;
  1920. expr: string;
  1921. segreg: tregister;
  1922. Begin
  1923. expr := '';
  1924. asmtok := A_NONE; { assmume no prefix }
  1925. segreg := R_NO; { assume no segment override }
  1926. { // opcode // }
  1927. { allow for newline as in gas styled syntax }
  1928. { under DOS you get two AS_SEPARATOR !! }
  1929. while actasmtoken=AS_SEPARATOR do
  1930. Consume(AS_SEPARATOR);
  1931. if (actasmtoken <> AS_OPCODE) then
  1932. Begin
  1933. Message(asmr_e_invalid_or_missing_opcode);
  1934. { error recovery }
  1935. While not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) do
  1936. Consume(actasmtoken);
  1937. exit;
  1938. end
  1939. else
  1940. Begin
  1941. op := findopcode(actasmpattern);
  1942. instr.opcode:=op;
  1943. Consume(AS_OPCODE);
  1944. { // Zero operand opcode ? // }
  1945. if actasmtoken = AS_SEPARATOR then
  1946. exit
  1947. else
  1948. operandnum := 1;
  1949. end;
  1950. While actasmtoken <> AS_SEPARATOR do
  1951. Begin
  1952. case actasmtoken of
  1953. { // Operand delimiter // }
  1954. AS_COMMA: Begin
  1955. if operandnum > MaxOperands then
  1956. Message(asmr_e_too_many_operands)
  1957. else
  1958. Inc(operandnum);
  1959. Consume(AS_COMMA);
  1960. end;
  1961. { // End of asm operands for this opcode // }
  1962. AS_SEPARATOR: ;
  1963. else
  1964. BuildOperand(instr);
  1965. end; { end case }
  1966. end; { end while }
  1967. end;
  1968. Function Assemble: Ptree;
  1969. {*********************************************************************}
  1970. { PROCEDURE Assemble; }
  1971. { Description: Parses the att assembler syntax, parsing is done }
  1972. { according to GAs rules. }
  1973. {*********************************************************************}
  1974. Var
  1975. hl: pasmlabel;
  1976. labelptr,nextlabel : pasmlabel;
  1977. commname : string;
  1978. store_p : paasmoutput;
  1979. Begin
  1980. Message(asmr_d_start_reading);
  1981. firsttoken := TRUE;
  1982. operandnum := 0;
  1983. { sets up all opcode and register tables in uppercase }
  1984. if not _asmsorted then
  1985. Begin
  1986. SetupTables;
  1987. _asmsorted := TRUE;
  1988. end;
  1989. p:=new(paasmoutput,init);
  1990. { save pointer code section }
  1991. store_p:=p;
  1992. { setup label linked list }
  1993. new(LocalLabelList,Init);
  1994. c:=current_scanner^.asmgetchar;
  1995. actasmtoken:=gettoken;
  1996. while actasmtoken<>AS_END do
  1997. Begin
  1998. case actasmtoken of
  1999. AS_LLABEL:
  2000. Begin
  2001. if CreateLocalLabel(actasmpattern,hl,true) then
  2002. ConcatLabel(p,hl);
  2003. Consume(AS_LLABEL);
  2004. end;
  2005. AS_LABEL: Begin
  2006. { when looking for Pascal labels, these must }
  2007. { be in uppercase. }
  2008. if SearchLabel(upper(actasmpattern),hl,true) then
  2009. ConcatLabel(p,hl)
  2010. else
  2011. Begin
  2012. Message1(asmr_e_unknown_label_identifier,actasmpattern);
  2013. end;
  2014. Consume(AS_LABEL);
  2015. end;
  2016. AS_DW: Begin
  2017. Consume(AS_DW);
  2018. BuildConstant($ffff);
  2019. end;
  2020. AS_DB: Begin
  2021. Consume(AS_DB);
  2022. BuildConstant($ff);
  2023. end;
  2024. AS_DD: Begin
  2025. Consume(AS_DD);
  2026. BuildConstant($ffffffff);
  2027. end;
  2028. AS_XDEF:
  2029. Begin
  2030. { normal units should not be able to declare }
  2031. { direct label names like this... anyhow }
  2032. { procedural calls in asm blocks are }
  2033. { supposedely replaced automatically }
  2034. if (cs_compilesystem in aktmoduleswitches) then
  2035. begin
  2036. Consume(AS_XDEF);
  2037. if actasmtoken <> AS_ID then
  2038. Message(asmr_e_invalid_global_def)
  2039. else
  2040. ConcatPublic(p,actasmpattern);
  2041. Consume(actasmtoken);
  2042. if actasmtoken <> AS_SEPARATOR then
  2043. Begin
  2044. Message(asmr_e_syntax_error);
  2045. while actasmtoken <> AS_SEPARATOR do
  2046. Consume(actasmtoken);
  2047. end;
  2048. end
  2049. else
  2050. begin
  2051. Message(asmr_w_xdef_not_supported);
  2052. while actasmtoken <> AS_SEPARATOR do
  2053. Consume(actasmtoken);
  2054. end;
  2055. end;
  2056. AS_ALIGN: Begin
  2057. Message(asmr_w_align_not_supported);
  2058. while actasmtoken <> AS_SEPARATOR do
  2059. Consume(actasmtoken);
  2060. end;
  2061. AS_OPCODE: Begin
  2062. instr.init;
  2063. BuildOpcode;
  2064. instr.ops := operandnum;
  2065. if instr.labeled then
  2066. ConcatLabeledInstr(instr)
  2067. else
  2068. ConcatOpCode(instr);
  2069. instr.done;
  2070. end;
  2071. AS_SEPARATOR:Begin
  2072. Consume(AS_SEPARATOR);
  2073. { let us go back to the first operand }
  2074. operandnum := 0;
  2075. end;
  2076. AS_END: ; { end assembly block }
  2077. else
  2078. Begin
  2079. Message(asmr_e_syntax_error);
  2080. { error recovery }
  2081. Consume(actasmtoken);
  2082. end;
  2083. end; { end case }
  2084. end; { end while }
  2085. { Check LocalLabelList }
  2086. LocalLabelList^.CheckEmitted;
  2087. dispose(LocalLabelList,Done);
  2088. assemble := genasmnode(p);
  2089. Message(asmr_d_finish_reading);
  2090. end;
  2091. procedure ra68kmot_exit;{$ifndef FPC}far;{$endif}
  2092. begin
  2093. if assigned(iasmops) then
  2094. dispose(iasmops);
  2095. exitproc:=old_exit;
  2096. end;
  2097. Begin
  2098. old_exit:=exitproc;
  2099. exitproc:=@ra68kmot_exit;
  2100. end.
  2101. {
  2102. $Log$
  2103. Revision 1.1 2002-08-06 15:15:42 carl
  2104. + more m68k fixes
  2105. Revision 1.1.2.7 2001/08/09 11:41:08 pierre
  2106. + add more errors
  2107. Revision 1.1.2.6 2001/08/08 12:21:49 pierre
  2108. * generate correct labeled instruction for DBRA
  2109. * improoved checking of operands
  2110. + support for OPR_SYMBOL in generic instructions like MOVE
  2111. + support for labels in constants like movel #datalabel + const,d0
  2112. Revision 1.1.2.5 2001/08/07 15:55:33 pierre
  2113. + new code for NetBSD, behaves like FreeBSD for now
  2114. Revision 1.1.2.4 2001/08/01 10:58:50 pierre
  2115. * avoid warning about supposed external in asm label is already known
  2116. Revision 1.1.2.3 2001/07/24 23:41:32 pierre
  2117. * firstreg and lastreg renamed firstasmreg and lastasmreg to aviod confusions
  2118. Revision 1.1.2.2 2001/04/24 11:58:37 carl
  2119. * correction of DBRA problems
  2120. Revision 1.1.2.1 2001/03/04 02:19:54 carl
  2121. - renamefest!
  2122. Revision 1.1.2.1 2001/02/25 01:32:56 carl
  2123. - imported from mian directory
  2124. Revision 1.1.2.2 2001/02/23 11:20:40 pierre
  2125. * fix an update problem
  2126. Revision 1.1.2.1 2001/02/23 10:05:19 pierre
  2127. * first bunch of m68k cpu updates
  2128. Revision 1.1 2000/07/13 06:29:56 michael
  2129. + Initial import
  2130. Revision 1.13 2000/02/09 13:23:02 peter
  2131. * log truncated
  2132. Revision 1.12 2000/01/07 01:14:37 peter
  2133. * updated copyright to 2000
  2134. Revision 1.11 1999/11/10 00:06:08 pierre
  2135. * adapted to procinfo as pointer
  2136. Revision 1.10 1999/11/09 23:06:46 peter
  2137. * esi_offset -> selfpointer_offset to be newcg compatible
  2138. * hcogegen -> cgbase fixes for newcg
  2139. Revision 1.9 1999/09/16 23:05:56 florian
  2140. * m68k compiler is again compilable (only gas writer, no assembler reader)
  2141. }