ra68kmot.pas 84 KB

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