Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2483 lines
52 KiB

  1. /* asmdir.c -- microsoft 80x86 assembler
  2. **
  3. ** microsoft (r) macro assembler
  4. ** copyright (c) microsoft corp 1986. all rights reserved
  5. **
  6. ** randy nevin
  7. **
  8. ** 10/90 - Quick conversion to 32 bit by Jeff Spencer
  9. */
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include "asm86.h"
  13. #include "asmfcn.h"
  14. #include <fcntl.h>
  15. #include <errno.h>
  16. #include <string.h>
  17. #ifndef XENIX286
  18. #include <share.h>
  19. #include <io.h>
  20. #endif
  21. #include "asmctype.h"
  22. #include "asmindex.h"
  23. #include "asmmsg.h"
  24. extern PFPOSTRUCT pFpoHead;
  25. extern PFPOSTRUCT pFpoTail;
  26. extern unsigned long numFpoRecords;
  27. SHORT CODESIZE fetLang(void);
  28. int PASCAL CODESIZE trypathname PARMS((char *));
  29. int PASCAL CODESIZE openincfile PARMS(( void ));
  30. VOID PASCAL CODESIZE creatPubName (void);
  31. extern char *siznm[];
  32. /*** setsymbol - set attribute in symbol
  33. *
  34. * setsymbol (bit);
  35. *
  36. * Entry
  37. * Exit
  38. * Returns
  39. * Calls
  40. */
  41. VOID
  42. PASCAL
  43. CODESIZE
  44. setsymbol (
  45. UCHAR bit
  46. )
  47. {
  48. /* Scan symbol name */
  49. if (getatom ()) {
  50. if (!symsrch ())
  51. errorn (E_SND);
  52. symptr->attr |= bit;
  53. }
  54. }
  55. /*** publicitem - scan symbol and make PUBLIC
  56. *
  57. * publicitem ();
  58. *
  59. * Entry naim = symbol name
  60. * Exit Global attribute set in symbol entry
  61. * Returns none
  62. * Calls error, scanatom, symsearch
  63. */
  64. VOID
  65. PASCAL
  66. CODESIZE
  67. publicitem()
  68. {
  69. static char newAttr;
  70. if (getatom ()) {
  71. newAttr = NULL;
  72. if (fetLang() == CLANG)
  73. newAttr = M_CDECL;
  74. if (!symsrch ()) {
  75. /* define forward refernced name, so global attribute
  76. * is available on the end of pass 1 */
  77. symcreate ( (UCHAR)(M_GLOBAL | newAttr), (UCHAR)PROC);
  78. } else {
  79. symptr->attr |= newAttr;
  80. /* public is legal for an alias if target ok */
  81. if (symptr->symkind == EQU &&
  82. symptr->symu.equ.equtyp == ALIAS)
  83. if (! (symptr = chasealias (symptr))) {
  84. errorc(E_TUL);
  85. return;
  86. }
  87. if (pass2) { /* catch forward reference symbol errors */
  88. if (! (symptr->attr & M_GLOBAL))
  89. errorn (E_IFR);
  90. else if ((symptr->attr&~M_CDECL) == M_GLOBAL ||
  91. !(symptr->attr & M_DEFINED))
  92. errorn (E_SND);
  93. }
  94. switch (symptr->symkind) {
  95. case PROC:
  96. case DVAR:
  97. case CLABEL:
  98. if (M_XTERN & symptr->attr)
  99. errorc (E_SAE);
  100. break;
  101. case EQU:
  102. if (symptr->symu.equ.equtyp != EXPR)
  103. errorc (E_TUL);
  104. break;
  105. default:
  106. errorc (E_TUL);
  107. }
  108. }
  109. creatPubName();
  110. }
  111. }
  112. VOID
  113. PASCAL
  114. CODESIZE
  115. creatPubName ()
  116. {
  117. symptr->attr |= M_GLOBAL;
  118. if (caseflag == CASEX && symptr->lcnamp == NULL)
  119. symptr->lcnamp =
  120. #ifdef M8086
  121. creatlname (naim.pszLowerCase);
  122. #else
  123. createname (naim.pszLowerCase);
  124. #endif
  125. }
  126. /*** xcrefitem - scan symbol and xcref it
  127. *
  128. * xcrefitem ();
  129. *
  130. * Entry
  131. * Exit
  132. * Returns
  133. * Calls
  134. */
  135. VOID
  136. PASCAL
  137. CODESIZE
  138. xcrefitem ()
  139. {
  140. if (pass2 && !loption) {
  141. setsymbol (M_NOCREF);
  142. creftype = CREFEND;
  143. } else
  144. getatom ();
  145. }
  146. /*** externflag -
  147. *
  148. * routine ();
  149. *
  150. * Entry
  151. * Exit
  152. * Returns
  153. * Calls
  154. */
  155. VOID
  156. PASCAL
  157. CODESIZE
  158. externflag (
  159. register UCHAR kind,
  160. register UCHAR new
  161. )
  162. {
  163. switchname ();
  164. /* Make name be extern name */
  165. if (!new) {
  166. /* Create symbol */
  167. symcreate (M_XTERN | M_DEFINED,
  168. (UCHAR)((kind == CLABEL)? DVAR: kind));
  169. symptr->symkind = kind;
  170. if (caseflag == CASEX)
  171. symptr->lcnamp =
  172. #ifdef M8086
  173. creatlname (naim.pszLowerCase);
  174. #else
  175. createname (naim.pszLowerCase);
  176. #endif /* M8086 */
  177. symptr->symtype = varsize;
  178. symptr->length = 1;
  179. if (kind == EQU)
  180. /* expr type EQU is constant */
  181. symptr->symu.equ.equtyp = EXPR;
  182. else
  183. symptr->symsegptr = pcsegment;
  184. if (pass2)
  185. emitextern (symptr);
  186. }
  187. checkRes();
  188. crefdef ();
  189. if (! (M_XTERN & symptr->attr))
  190. errorc (E_ALD);
  191. else {
  192. if (kind != symptr->symkind || symptr->symtype != varsize ||
  193. (symptr->length != 1 && kind != EQU) &&
  194. (symptr->symsegptr != pcsegment &&
  195. !(fSimpleSeg && varsize == CSFAR)))
  196. errorn (E_SDK);
  197. else {
  198. symptr->attr |= M_XTERN | M_BACKREF;
  199. if (fSimpleSeg && varsize == CSFAR) {
  200. symptr->symsegptr = NULL;
  201. } else if (varsize == CSNEAR ||
  202. (varsize == CSFAR && pcsegment))
  203. symptr->symu.clabel.csassume = regsegment[CSSEG];
  204. }
  205. }
  206. }
  207. /*** externitem -
  208. *
  209. * externitem ();
  210. *
  211. * Entry
  212. * Exit
  213. * Returns
  214. * Calls
  215. */
  216. VOID
  217. PASCAL
  218. CODESIZE
  219. externitem ()
  220. {
  221. register char new;
  222. char newAttr;
  223. /* Get name of external */
  224. if (getatom ()) {
  225. newAttr = NULL;
  226. if (fetLang() == CLANG)
  227. newAttr = M_CDECL;
  228. new = symFetNoXref ();
  229. switchname (); /* Save name of external */
  230. if (NEXTC () != ':')
  231. errorc (E_SYN);
  232. else {
  233. /* Scan name of extern type */
  234. getatom ();
  235. if (tokenIS("abs")) {
  236. equsel = EXPR;
  237. varsize = 0;
  238. externflag (EQU, new);
  239. } else if (!fnsize ())
  240. errorc (E_UST);
  241. else {
  242. if (varsize >= CSFAR) {
  243. /* NEAR | FAR */
  244. externflag (CLABEL, new);
  245. }
  246. else /* data reference */
  247. externflag (DVAR, new);
  248. }
  249. symptr->attr |= newAttr;
  250. }
  251. }
  252. }
  253. /*** segcreate - create and initialize segment
  254. *
  255. * segcreate (makeseg);
  256. *
  257. * Entry makeseg = TRUE if segement is to be make
  258. * Exit
  259. * Returns
  260. * Calls
  261. */
  262. VOID
  263. PASCAL
  264. CODESIZE
  265. segcreate (
  266. register UCHAR makeseg
  267. )
  268. {
  269. if (pass2) /* Segment must be defined */
  270. errorn (E_PS1);
  271. if (makeseg)
  272. symcreate (0, SEGMENT);
  273. else
  274. symptr->symkind = SEGMENT;
  275. /* Initialize segment data */
  276. symptr->symu.segmnt.align = -1;
  277. symptr->symu.segmnt.use32 = -1;
  278. symptr->symu.segmnt.combine = 7;
  279. }
  280. /*** addglist - add segment to group list
  281. *
  282. * addglist ();
  283. *
  284. * Entry
  285. * Exit
  286. * Returns
  287. * Calls
  288. */
  289. VOID
  290. PASCAL
  291. CODESIZE
  292. addglist ()
  293. {
  294. register SYMBOL FARSYM *p, FARSYM *pSY;
  295. p = symptr;
  296. if (pass2)
  297. if (!(M_DEFINED & p->attr))
  298. errorn (E_PS1);
  299. /* Can get segment in 2 group lists unless check
  300. * symptr->grouptr == curgroup */
  301. if (p->symu.segmnt.grouptr) {
  302. if (p->symu.segmnt.grouptr != curgroup)
  303. /* Trying to put in 2 groups */
  304. errorc (E_SPC);
  305. return;
  306. }
  307. p->symu.segmnt.grouptr = curgroup;
  308. pSY = curgroup->symu.grupe.segptr;
  309. if (!pSY)
  310. curgroup->symu.grupe.segptr = p;
  311. else {
  312. /* scan the list of segments on the group */
  313. do {
  314. if (pSY == p) /* already on list */
  315. return;
  316. } while (pSY->symu.segmnt.nxtseg &&
  317. (pSY = pSY->symu.segmnt.nxtseg));
  318. /* Link into list */
  319. pSY->symu.segmnt.nxtseg = p;
  320. }
  321. }
  322. /*** groupitem -
  323. *
  324. * routine ();
  325. *
  326. * Entry
  327. * Exit
  328. * Returns
  329. * Calls
  330. */
  331. VOID
  332. PASCAL
  333. CODESIZE
  334. groupitem ()
  335. {
  336. if (!getatom ())
  337. error (E_EXP,"segment name");
  338. else if (!fnoper ()) {
  339. /* Have a segment name */
  340. if (!symFet())
  341. /* Forward segment, make it */
  342. segcreate (TRUE);
  343. /* If not segment, could be class so make undef */
  344. if (symptr->symkind != SEGMENT)
  345. /* If a class, consider undef instead of wrong kind */
  346. errorn ((USHORT)((symptr->symkind == CLASS) && !pass2 ?
  347. E_IFR : E_SDK));
  348. else if (symptr->attr & M_DEFINED || !pass2) {
  349. if (curgroup)
  350. addglist ();
  351. } else
  352. errorn (E_PS1);
  353. } else { /* Have error or SEG <sym> */
  354. if (opertype != OPSEG)
  355. /* Symbol can't be reserved */
  356. errorn (E_RES);
  357. else {
  358. /* Have SEG <var> | <label> */
  359. getatom ();
  360. if (*naim.pszName == 0)
  361. error (E_EXP,"variable or label");
  362. else if (!symFet())
  363. /* Forward reference bad */
  364. errorc (E_IFR);
  365. else if (1 << symptr->symkind &
  366. (M_DVAR | M_CLABEL | M_PROC)) {
  367. /* Segment of variable */
  368. symptr = symptr->symsegptr;
  369. if (!symptr)
  370. /* Must have segment */
  371. errorc (E_OSG);
  372. else
  373. addglist ();
  374. } else
  375. /* Wrong type */
  376. errorc (E_TUL);
  377. }
  378. }
  379. }
  380. /*** groupdefine - define segments that form a group
  381. *
  382. * routine ();
  383. *
  384. * Entry
  385. * Exit
  386. * Returns
  387. * Calls
  388. */
  389. VOID
  390. PASCAL
  391. CODESIZE
  392. groupdefine ()
  393. {
  394. if (symFet()) { /* Symbol exists */
  395. checkRes();
  396. if (symptr->symkind != GROUP)
  397. /* Should have been group */
  398. errorc (E_NGR);
  399. symptr->attr |= M_BACKREF;
  400. } else if (pass2)
  401. /* Must be seen 1st on pass 1 */
  402. errorn (E_PS1);
  403. else {
  404. /* Create group name */
  405. symcreate (M_DEFINED, GROUP);
  406. }
  407. /* CURgroup is used by GROUPitem to know which group segment
  408. name should be added to. If it is NIL, means that either
  409. it is pass 2 so list already made or there was an error in
  410. GROUP name */
  411. curgroup = NULL;
  412. if (! pass2) { /* Don't make list if pass 2 */
  413. symptr->attr |= M_BACKREF | M_DEFINED;
  414. if (symptr->symkind == GROUP)
  415. curgroup = symptr;
  416. }
  417. /* Handle segment list */
  418. BACKC ();
  419. do {
  420. SKIPC ();
  421. groupitem ();
  422. } while (PEEKC () == ',');
  423. }
  424. /*** setsegment -
  425. *
  426. * routine ();
  427. *
  428. * Entry
  429. * Exit
  430. * Returns
  431. * Calls
  432. */
  433. VOID
  434. PASCAL
  435. CODESIZE
  436. setsegment ()
  437. {
  438. if (pass2 && !(M_DEFINED & symptr->attr))
  439. /* undef */
  440. errorn (E_SND);
  441. else
  442. regsegment[lastsegptr->offset] = symptr;
  443. }
  444. /*** assumeitem -
  445. *
  446. * routine ();
  447. *
  448. * Entry
  449. * Exit
  450. * Returns
  451. * Calls
  452. * Note Form of ASSUME item is:
  453. * <segreg> : <group> | <segment> | SEG <var> | NOTHING
  454. * Will set XXsegment to segment or group pointer. NOTHING
  455. * will set to NIL
  456. */
  457. VOID
  458. PASCAL
  459. CODESIZE
  460. assumeitem ()
  461. {
  462. register SYMBOL FARSYM *p;
  463. register short j;
  464. // int segIndex;
  465. /* Scan segment name */
  466. getatom ();
  467. if (PEEKC() != ':') {
  468. /* NOTHING or error */
  469. if (fnoper ())
  470. if (opertype == OPNOTHING) { /* No segments assumed*/
  471. memset(regsegment, 0, sizeof(regsegment));
  472. } else
  473. /* Must have colon */
  474. error (E_EXP,"colon");
  475. else
  476. /* Must have colon */
  477. error (E_EXP,"colon");
  478. } else if (!symsearch ()) /* get seg register - Must be defined */
  479. errorn (E_SND);
  480. else {
  481. lastsegptr = p = symptr; /* At least have defined */
  482. if (p->symkind != REGISTER ||
  483. p->symu.regsym.regtype != SEGREG)
  484. errorn (E_MBR);
  485. else { /* Have segment reg so go on */
  486. /* Save ptr to segment */
  487. SKIPC ();
  488. getatom ();
  489. if (*naim.pszName == 0)
  490. error (E_EXP,"segment, group, or NOTHING");
  491. else
  492. if (!fnoper ()) {
  493. /* Must be segment or group */
  494. if (!symFet ())
  495. segcreate (TRUE); /* Make if not found */
  496. p = symptr;
  497. if (p->symkind == SEGMENT ||
  498. p->symkind == GROUP) {
  499. setsegment ();
  500. #ifndef FEATURE
  501. if (tokenIS("flat") && (cputype&P386)) {
  502. pFlatGroup = symptr;
  503. pFlatGroup->symkind = GROUP;
  504. pFlatGroup->attr |= M_DEFINED | M_BACKREF;
  505. pFlatGroup->symu.grupe.segptr = NULL;
  506. }
  507. #endif
  508. } else
  509. errorc (E_MSG);
  510. } else {
  511. /* Have NOTHING or SEG */
  512. if (opertype == OPNOTHING) {
  513. regsegment[lastsegptr->offset] = NULL;
  514. } else if (opertype == OPSEG) {
  515. getatom ();
  516. if (!symFet ())
  517. /* Must be defined on pass 1 */
  518. errorn (E_PS1);
  519. else {
  520. p = symptr;
  521. if (!(M_DEFINED & p->attr))
  522. errorn (E_PS1);
  523. else if (1 << p->symkind &
  524. (M_CLABEL | M_PROC | M_DVAR)) {
  525. if (!(M_XTERN & p->attr))
  526. symptr = symptr->symsegptr;
  527. p = symptr;
  528. setsegment ();
  529. } else
  530. errorc (E_TUL);
  531. }
  532. } else
  533. errorn (E_RES);
  534. }
  535. }
  536. }
  537. }
  538. /*** evendir - process <even> directive
  539. *
  540. * routine ();
  541. *
  542. * Entry
  543. * Exit
  544. * Returns
  545. * Calls
  546. */
  547. VOID
  548. PASCAL
  549. CODESIZE
  550. evendir (
  551. SHORT arg
  552. )
  553. {
  554. register SHORT size;
  555. if (arg)
  556. size = arg;
  557. else
  558. size = (SHORT)exprconst ();
  559. if ((size & (size - 1)) != 0 || !size)
  560. errorc(E_AP2);
  561. else if (!pcsegment)
  562. /* Not in segment */
  563. errorc (E_MSB);
  564. else if (pcsegment->symu.segmnt.align == 1)
  565. /* Byte aligned */
  566. errorc (E_NEB);
  567. else {
  568. if (!((USHORT) pcoffset % size))
  569. return;
  570. size = size - (USHORT) pcoffset % size;
  571. while (size--)
  572. if (!pcsegment->symu.segmnt.hascode)
  573. emitopcode(0);
  574. else
  575. if (size > 0) {
  576. size--;
  577. emitopcode(0x87); /* two byte form is faster */
  578. emitopcode(0xDB);
  579. } else
  580. emitopcode(0x90);
  581. }
  582. }
  583. /*** namedir - process <name> directive
  584. *
  585. * routine ();
  586. *
  587. * Entry
  588. * Exit
  589. * Returns
  590. * Calls
  591. */
  592. VOID
  593. PASCAL
  594. CODESIZE
  595. namedir ()
  596. {
  597. getatom ();
  598. if (*naim.pszName == 0)
  599. error (E_EXP,"module name");
  600. else if (modulename)
  601. /* Already have one */
  602. errorc (E_RSY);
  603. else
  604. modulename = createname (naim.pszName);
  605. }
  606. /*** includeLib - process include lib directive
  607. *
  608. * Format : includeLib token
  609. */
  610. VOID
  611. PASCAL
  612. CODESIZE
  613. includeLib()
  614. {
  615. char *pFirst;
  616. TEXTSTR FAR *bodyline, FAR *ptr;
  617. register USHORT siz;
  618. pFirst = lbufp;
  619. while (!ISTERM (PEEKC()) && !ISBLANK (PEEKC()))
  620. SKIPC();
  621. siz = (USHORT)(lbufp - pFirst);
  622. if (siz == 0 || siz > 126)
  623. errorc(E_IIS);
  624. if (pass2)
  625. return;
  626. bodyline = (TEXTSTR FAR *)talloc ((USHORT)(sizeof (TEXTSTR) + siz));
  627. bodyline->strnext = (TEXTSTR FAR *)NULL;
  628. bodyline->text[siz] = NULL;
  629. fMemcpy (bodyline->text, pFirst, siz);
  630. if (!(ptr = pLib))
  631. pLib = bodyline;
  632. else {
  633. while (ptr->strnext)
  634. ptr = ptr->strnext;
  635. ptr->strnext = bodyline;
  636. }
  637. }
  638. /*** orgdir - process <org> directive
  639. *
  640. * routine ();
  641. *
  642. * Entry
  643. * Exit
  644. * Returns
  645. * Calls
  646. */
  647. VOID
  648. PASCAL
  649. CODESIZE
  650. orgdir ()
  651. {
  652. register DSCREC *dsc;
  653. dsc = expreval (&nilseg);
  654. if (dsc->dsckind.opnd.dflag == FORREF)
  655. /* Must be known */
  656. errorc (E_PS1);
  657. /* Can get <code> set and segment NIL, fix */
  658. else if (dsc->dsckind.opnd.dsegment) {/* code var */
  659. if (!isdirect(&(dsc->dsckind.opnd)) &&
  660. dsc->dsckind.opnd.mode != 4)
  661. /* Not direct */
  662. errorc (E_IOT);
  663. if (pcsegment != dsc->dsckind.opnd.dsegment)
  664. /* Different segment */
  665. errorc (E_NIP);
  666. } else { /* Should be const */
  667. /* Must be constant */
  668. forceimmed (dsc);
  669. if (dsc->dsckind.opnd.dsign)
  670. /* And plus */
  671. errorc (E_VOR);
  672. }
  673. if (dsc->dsckind.opnd.doffset < pcoffset)
  674. if (pcmax < pcoffset)
  675. /* If moving down, save */
  676. pcmax = pcoffset;
  677. /* Set new PC */
  678. pcoffset = dsc->dsckind.opnd.doffset;
  679. /* Display new PC */
  680. pcdisplay ();
  681. dfree ((char *)dsc );
  682. }
  683. /*** purgemacro - process <purge> directive
  684. *
  685. * purgemacro ();
  686. *
  687. * Entry
  688. * Exit
  689. * Returns
  690. * Calls
  691. */
  692. VOID
  693. PASCAL
  694. CODESIZE
  695. purgemacro ()
  696. {
  697. getatom ();
  698. if (!symFet ())
  699. errorn (E_SND);
  700. else if (symptr->symkind != MACRO)
  701. symptr->attr &= ~(M_BACKREF);
  702. else {
  703. if (symptr->symu.rsmsym.rsmtype.rsmmac.active)
  704. symptr->symu.rsmsym.rsmtype.rsmmac.delete = TRUE;
  705. else
  706. deletemacro (symptr);
  707. }
  708. }
  709. /*** deletemacro - delete macro body
  710. *
  711. * deletemacro (p);
  712. *
  713. * Entry p = pointer to macro symbol entry
  714. * Exit macro body deleted
  715. * Returns none
  716. * Calls
  717. */
  718. VOID
  719. PASCAL
  720. CODESIZE
  721. deletemacro (
  722. SYMBOL FARSYM *p
  723. )
  724. {
  725. listfree (p->symu.rsmsym.rsmtype.rsmmac.macrotext);
  726. p->symu.rsmsym.rsmtype.rsmmac.macrotext = NULL;
  727. p->symu.rsmsym.rsmtype.rsmmac.active = 0;
  728. p->symu.rsmsym.rsmtype.rsmmac.delete = FALSE;
  729. }
  730. /*** radixdir - process <radix> directive
  731. *
  732. * radixdir ();
  733. *
  734. * Entry
  735. * Exit
  736. * Returns
  737. * Calls
  738. */
  739. VOID
  740. PASCAL
  741. CODESIZE
  742. radixdir ()
  743. {
  744. register USHORT rdx;
  745. /* Force decimal radix */
  746. radixescape = TRUE;
  747. /* Get wanted radix */
  748. rdx = (USHORT)exprconst ();
  749. if (2 <= rdx && rdx <= 16)
  750. radix = (char)rdx;
  751. else
  752. errorc (E_VOR);
  753. radixescape = FALSE;
  754. /* Convert radix to ascii and display */
  755. offsetAscii ((OFFSET) radix);
  756. copyascii ();
  757. }
  758. /*** checkline - check line for delimiter
  759. *
  760. * flag = checkline (cc);
  761. *
  762. * Entry cc = chearacter to check line for
  763. * Exit none
  764. * Returns TRUE if cc matched in line
  765. * FALSE if cc not matched in line
  766. * Calls none
  767. */
  768. UCHAR
  769. PASCAL
  770. CODESIZE
  771. checkline (
  772. register UCHAR cc
  773. )
  774. {
  775. register UCHAR nc;
  776. while (nc = NEXTC())
  777. if (nc == cc)
  778. return (TRUE);
  779. BACKC ();
  780. return (FALSE);
  781. }
  782. /*** comment - copy characters to end of comment
  783. *
  784. * commentbuild ();
  785. *
  786. * Entry
  787. * Exit
  788. * Returns
  789. * Calls
  790. */
  791. VOID
  792. PASCAL
  793. CODESIZE
  794. commentbuild ()
  795. {
  796. if (checkline ((char)delim)) {
  797. handler = HPARSE;
  798. swaphandler = TRUE;
  799. }
  800. if (!lsting) {
  801. linebuffer[0] = '\0';
  802. linelength = 0;
  803. lbufp = linebuffer;
  804. }
  805. listline ();
  806. }
  807. /*** comdir - process <comment> directive
  808. *
  809. * comdir ();
  810. *
  811. * Entry
  812. * Exit
  813. * Returns
  814. * Calls
  815. */
  816. VOID
  817. PASCAL
  818. CODESIZE
  819. comdir ()
  820. {
  821. if (!PEEKC ())
  822. error (E_EXP,"comment delimiter");
  823. else {
  824. /* Save delim char */
  825. if (!checkline ((char)(delim = NEXTC ()))) {
  826. /* Delim is not on same line */
  827. swaphandler = TRUE;
  828. handler = HCOMMENT;
  829. }
  830. }
  831. if (!lsting) {
  832. linebuffer[0] = '\0';
  833. linelength = 0;
  834. lbufp = linebuffer;
  835. }
  836. }
  837. /*** outdir - display remainder of line to console
  838. *
  839. * outdir ();
  840. *
  841. * Entry
  842. * Exit
  843. * Returns
  844. * Calls
  845. */
  846. VOID
  847. PASCAL
  848. CODESIZE
  849. outdir ()
  850. {
  851. if (!listquiet)
  852. fprintf (stdout, "%s\n", lbufp);
  853. lbufp = lbuf + strlen (lbuf);
  854. }
  855. /*** enddir - process <end> directive
  856. *
  857. * enddir ();
  858. *
  859. * Entry
  860. * Exit
  861. * Returns
  862. * Calls
  863. */
  864. VOID
  865. PASCAL
  866. CODESIZE
  867. enddir ()
  868. {
  869. if (!ISTERM (PEEKC ())) {
  870. /* Have a start addr */
  871. startaddr = expreval (&nilseg);
  872. if (!(M_CODE & startaddr->dsckind.opnd.dtype))
  873. errorc (E_ASC);
  874. }
  875. #ifdef BCBOPT
  876. if (fNotStored)
  877. storeline();
  878. #endif
  879. if (fSimpleSeg && pcsegment)
  880. endCurSeg();
  881. listline();
  882. longjmp(forceContext, 1);
  883. }
  884. /*** exitmdir - process <exitm> directive
  885. *
  886. * exitmdir ();
  887. *
  888. * Entry
  889. * Exit
  890. * Returns
  891. * Calls
  892. */
  893. VOID
  894. PASCAL
  895. CODESIZE
  896. exitmdir ()
  897. {
  898. if (macrolevel == 0)
  899. /* Must be in macro */
  900. errorc (E_NMC);
  901. else
  902. /* set ExitBody since need to see conditionals */
  903. exitbody = TRUE;
  904. }
  905. /*** trypathname - try to open a file in a directory
  906. *
  907. * trypathname (szPath);
  908. *
  909. * Entry lbufp = pointer to include file name
  910. * szPath = directory to search in
  911. * Exit Include file opened if found.
  912. * Fully qualified name in "save"
  913. * Returns file handle of file, or -1 if not opened
  914. * special handle of -2 means FCB has been allocated
  915. * Note If include file name does not begin with path separator
  916. * character, the path separator is appended to include path.
  917. */
  918. int
  919. PASCAL
  920. CODESIZE
  921. trypathname (
  922. char * szPath
  923. )
  924. {
  925. char cc;
  926. int fh;
  927. char *p = save;
  928. char *pe = save + LINEMAX - 2;
  929. char *ic;
  930. register FCB * pFCBT;
  931. ic = szPath;
  932. if (*ic) {
  933. while (*ic && p < pe)
  934. *p++ = *ic++;
  935. if ((*(p-1) != PSEP) && (*(p-1) != ':'))
  936. /* include path separator if not in file name */
  937. *p++ = PSEP;
  938. }
  939. for (ic = lbufp; !ISTERM (cc = *ic++) && !ISBLANK (cc) && p < pe ; )
  940. if (cc == ALTPSEP)
  941. *p++ = PSEP;
  942. else
  943. *p++ = cc;
  944. #ifdef MSDOS
  945. if (*(p-1) == ':') /* kill 'con:' */
  946. p--;
  947. #endif
  948. *p = NULL;
  949. /* look for an existing include file on pass 2 with a fully qualified
  950. * name */
  951. #ifdef BCBOPT
  952. if (pass2) {
  953. for (pFCBT = pFCBInc->pFCBNext; pFCBT; pFCBT = pFCBT->pFCBNext) {
  954. if (!memcmp (save, pFCBT->fname, strlen(pFCBT->fname)+1)) {
  955. pFCBT->pbufCur = NULL;
  956. if (pFCBT->pBCBCur = pFCBT->pBCBFirst) {
  957. pFCBT->pBCBCur->fInUse = 1;
  958. if (! (pFCBT->pbufCur = pFCBT->pBCBCur->pbuf))
  959. pFCBT->fh = tryOneFile( save );
  960. } else
  961. pFCBT->fh = tryOneFile( save );
  962. pFCBCur = pFCBT;
  963. return(-2);
  964. }
  965. }
  966. }
  967. #endif
  968. return(tryOneFile( save ));
  969. }
  970. int
  971. PASCAL
  972. CODESIZE
  973. tryOneFile(
  974. UCHAR *fname
  975. )
  976. {
  977. int iRet;
  978. int fTryAgain;
  979. do {
  980. fTryAgain = FALSE;
  981. #ifdef XENIX286
  982. iRet = open (fname, TEXTREAD);
  983. #else
  984. iRet = _sopen (fname, O_RDONLY | O_BINARY, SH_DENYWR);
  985. #endif
  986. if ( iRet == -1 && errno == EMFILE ) { /* If out of file handles */
  987. if ( freeAFileHandle() ) {
  988. fTryAgain = TRUE; /* Keep trying until out of files to close */
  989. }
  990. }
  991. }while ( fTryAgain );
  992. return( iRet ); /* Return file handle or error */
  993. }
  994. /*** openincfile - try to find and open include file
  995. *
  996. * openincfile ()
  997. *
  998. * Entry lbufp = pointer to include file name
  999. * inclcnt = count of -I paths from command line and INCLUDE e.v.
  1000. * inclpath[i] = pointer to path to prepend to include file name
  1001. * Exit include file opened if found on any path or current directory
  1002. * Aborts with code EX_UINC if file not found
  1003. * Returns none
  1004. * Note If include file name does not begin with path separator
  1005. * character, the path separator is appended to include path.
  1006. * For every attempt to find a file in a path, the alternate
  1007. * path separator character is used. This will improve program
  1008. * portability between DOS and XENIX.
  1009. */
  1010. int
  1011. PASCAL
  1012. CODESIZE
  1013. openincfile ()
  1014. {
  1015. register char cc;
  1016. int fh;
  1017. SHORT i;
  1018. #ifdef MSDOS
  1019. if ((cc = *lbufp) != PSEP && cc != ALTPSEP && cc != '.' &&
  1020. lbufp[1] != ':') {
  1021. #else
  1022. if ((cc = *lbufp) != PSEP && cc != ALTPSEP && cc != '.') {
  1023. #endif /* MSDOS */
  1024. for (i = inclFirst; i < inclcnt; i++) {
  1025. if ((fh = trypathname (inclpath[i])) != -1) {
  1026. return (fh);
  1027. }
  1028. }
  1029. } else
  1030. if ((fh = trypathname ("")) != -1) {
  1031. return (fh);
  1032. }
  1033. error(E_INC, lbufp);
  1034. errordisplay ();
  1035. closeOpenFiles();
  1036. exit (EX_UINC);
  1037. return 0;
  1038. }
  1039. /*** includedir - process <include> directive
  1040. *
  1041. * includedir ();
  1042. *
  1043. * Entry lbufp = pointer to include file name
  1044. * Exit Opens include file on pass1. Gets correct buffers on pass 2
  1045. * Returns none
  1046. * Notes Notice the GOTO when correct FCB found in pass2
  1047. */
  1048. VOID
  1049. PASCAL
  1050. CODESIZE
  1051. includedir ()
  1052. {
  1053. char lastreadT;
  1054. register FCB * pFCBT;
  1055. unsigned long filelen;
  1056. FCB * svInc;
  1057. int fh;
  1058. #ifdef BCBOPT
  1059. if (fNotStored)
  1060. storelinepb ();
  1061. #endif
  1062. listline();
  1063. /* Get here on pass 1 OR when file names didn't match */
  1064. #ifdef BCBOPT
  1065. if ((fh = openincfile()) == -2) {
  1066. pFCBT = pFCBInc = pFCBCur;
  1067. goto gotinclude;
  1068. }
  1069. #else
  1070. fh = openincfile();
  1071. #endif
  1072. pFCBT = (FCB *)
  1073. nalloc((USHORT)(sizeof(FCB) + strlen(save) + sizeof(char)),"includedir");
  1074. pFCBT->fh = fh;
  1075. strcpy (pFCBT->fname, save); // Save the file name
  1076. pFCBT->pFCBParent = pFCBCur; /* Add bidirectional linked list entry */
  1077. pFCBCur->pFCBChild = pFCBT;
  1078. #ifdef BCBOPT
  1079. if (!pass2) {
  1080. pFCBT->pFCBNext = NULL;
  1081. pFCBInc->pFCBNext = pFCBT;
  1082. pFCBInc = pFCBT;
  1083. } else
  1084. pFCBT->pbufCur = NULL;
  1085. #endif
  1086. if ((filelen = _lseek(pFCBT->fh, 0L, 2 )) == -1L)
  1087. TERMINATE1(ER_ULI, EX_UINP, save);
  1088. /* go back to beginning */
  1089. _lseek(pFCBT->fh, 0L, 0 );
  1090. if (filelen > DEF_INCBUFSIZ << 10)
  1091. pFCBT->cbbuf = DEF_INCBUFSIZ << 10;
  1092. else
  1093. pFCBT->cbbuf = (USHORT) filelen + 1;
  1094. pFCBCur = pFCBT;
  1095. /* get a buffer */
  1096. #ifdef BCBOPT
  1097. if (fBuffering && !pass2)
  1098. pFCBT->pBCBFirst = pBCBalloc(pFCBT->cbbuf);
  1099. else
  1100. pFCBT->pBCBFirst = NULL;
  1101. pFCBT->pBCBCur = pFCBT->pBCBFirst;
  1102. #endif
  1103. #ifdef BCBOPT
  1104. gotinclude:
  1105. #endif
  1106. pFCBT->line = 0;
  1107. pFCBT->ctmpbuf = 0;
  1108. #ifdef XENIX286
  1109. pFCBT->ptmpbuf = pFCBT->buf = nalloc(pFCBT->cbbuf, "incdir");
  1110. #else
  1111. pFCBT->ptmpbuf = pFCBT->buf = falloc(pFCBT->cbbuf, "incdir");
  1112. #endif
  1113. if (crefing && pass2)
  1114. fprintf( crf.fil, "\t%s", save );
  1115. lastreadT = lastreader;
  1116. lineprocess(RREADSOURCE, NULL );
  1117. lastreader = lastreadT;
  1118. swaphandler++; /* sync local handler with global state */
  1119. fSkipList++;
  1120. }
  1121. /*** segdefine - process <segment> directive
  1122. *
  1123. * routine ();
  1124. *
  1125. * Entry
  1126. * Exit
  1127. * Returns
  1128. * Calls
  1129. * Note Format is:
  1130. * <name> SEGMENT [align] | [combine] | ['class']
  1131. * align: PARA | BYTE | WORD | PAGE | INPAGE
  1132. * combine:PUBLIC | COMMON | STACK | MEMORY | AT <expr>
  1133. */
  1134. VOID
  1135. PASCAL
  1136. CODESIZE
  1137. segdefine ()
  1138. {
  1139. register char cc;
  1140. register SYMBOL FARSYM *p;
  1141. register SYMBOL FARSYM *pT;
  1142. if (!symFetNoXref ())
  1143. /* Create if new segment */
  1144. segcreate (TRUE);
  1145. else {
  1146. if (symptr->symkind != SEGMENT)
  1147. if (symptr->symkind == CLASS)
  1148. segcreate (FALSE);
  1149. else
  1150. /* Wasn't segment */
  1151. errorn (E_SDK);
  1152. }
  1153. strcpy(&segName[8], naim.pszName);
  1154. p = symptr;
  1155. /* Output CREF info */
  1156. crefdef ();
  1157. if (p->symkind == SEGMENT) {
  1158. if (!(pass2 || (M_BACKREF & p->attr)))
  1159. addseglist (p);
  1160. p->attr |= M_BACKREF | M_DEFINED;
  1161. if (pcsegment) {
  1162. /* Save previous segment info */
  1163. /* Save current segment PC */
  1164. pcsegment->offset = pcoffset;
  1165. pcsegment->symu.segmnt.seglen =
  1166. (pcmax > pcoffset) ? pcmax : pcoffset;
  1167. }
  1168. /* check for nested segment opens */
  1169. for (pT = pcsegment; pT;) {
  1170. if (pT == p) {
  1171. errorc(E_BNE);
  1172. goto badNest;
  1173. }
  1174. pT = pT->symu.segmnt.lastseg;
  1175. }
  1176. /* Save previous segment */
  1177. p->symu.segmnt.lastseg = pcsegment;
  1178. badNest:
  1179. /* Set new current segment */
  1180. pcsegment = p;
  1181. pcoffset = p->offset;
  1182. /* Set segment maximum offset */
  1183. pcmax = p->symu.segmnt.seglen;
  1184. /* Display where in segment */
  1185. pcdisplay ();
  1186. while (!ISTERM (cc = PEEKC ())) {
  1187. if (cc == '\'')
  1188. segclass (p);
  1189. else if (LEGAL1ST (cc))
  1190. segalign (p);
  1191. else {
  1192. error(E_EXP,"align, combine, or 'class'");
  1193. break;
  1194. }
  1195. }
  1196. #ifdef V386
  1197. if (p->symu.segmnt.use32 == (char)-1)
  1198. p->symu.segmnt.use32 = wordszdefault;
  1199. wordsize = p->symu.segmnt.use32;
  1200. defwordsize();
  1201. if (wordsize == 4 && !(cputype & P386))
  1202. errorc(E_CPU);
  1203. #endif
  1204. }
  1205. definesym(segName);
  1206. symptr->attr |= M_NOCREF; /* don't cref @curSeg */
  1207. }
  1208. /*** addseglist - add segment to list
  1209. *
  1210. * addseglist (pseg);
  1211. *
  1212. * Entry pseg = segment symbol entry
  1213. * Exit
  1214. * Returns
  1215. * Calls
  1216. */
  1217. VOID
  1218. PASCAL
  1219. CODESIZE
  1220. addseglist (
  1221. register SYMBOL FARSYM *pseg
  1222. )
  1223. {
  1224. register SYMBOL FARSYM *tseg;
  1225. register SYMBOL FARSYM * FARSYM *lseg;
  1226. /* Add segment to list */
  1227. if (!firstsegment) {
  1228. firstsegment = pseg;
  1229. pseg->symu.segmnt.segordered = NULL;
  1230. return;
  1231. }
  1232. tseg = firstsegment;
  1233. lseg = &firstsegment;
  1234. for (; tseg; lseg = &(tseg->symu.segmnt.segordered),
  1235. tseg = tseg->symu.segmnt.segordered) {
  1236. if (segalpha) {
  1237. if (STRFFCMP (pseg->nampnt->id, tseg->nampnt->id) < 0) {
  1238. pseg->symu.segmnt.segordered = tseg;
  1239. *lseg = pseg;
  1240. return;
  1241. }
  1242. }
  1243. }
  1244. *lseg = pseg;
  1245. pseg->symu.segmnt.segordered = NULL;
  1246. }
  1247. /*** segclass - process <segment> 'class' subdirective
  1248. *
  1249. * segclass (pseg);
  1250. *
  1251. * Entry pseg = segment symbol entry
  1252. * *lbufp = leading ' of class name
  1253. * Exit
  1254. * Returns
  1255. * Calls scanatom, skipblanks
  1256. * Note Format is:
  1257. * <name> SEGMENT [align] | [combine] | ['class']
  1258. * align: PARA | BYTE | WORD | PAGE | INPAGE
  1259. * combine:PUBLIC | COMMON | STACK | MEMORY | AT <expr>
  1260. */
  1261. VOID
  1262. PASCAL
  1263. CODESIZE
  1264. segclass (
  1265. register SYMBOL FARSYM *pseg
  1266. )
  1267. {
  1268. SKIPC ();
  1269. getatom ();
  1270. if (NEXTC () != '\'')
  1271. /* Don't have right delim */
  1272. error (E_EXP,"'");
  1273. skipblanks ();
  1274. if (symptr->symu.segmnt.classptr) {
  1275. /* Make sure 'class' matches */
  1276. if (!symFet ())
  1277. /* Not same class */
  1278. errorc (E_SPC);
  1279. else if (symptr->symkind != CLASS &&
  1280. symptr->symkind != SEGMENT &&
  1281. symptr->symkind != GROUP)
  1282. errorn(E_SDK);
  1283. else if (symptr != pseg->symu.segmnt.classptr)
  1284. errorc (E_SPC);
  1285. } else if (*naim.pszName == 0)
  1286. errorc (E_EMS);
  1287. else if (!symFet ()) {
  1288. symcreate (M_DEFINED, SEGMENT);
  1289. symptr->symkind = CLASS;
  1290. }
  1291. checkRes();
  1292. pseg->symu.segmnt.classptr = symptr;
  1293. }
  1294. /*** segalign - process <segment> align and combine subdirectives
  1295. *
  1296. * segalign ();
  1297. *
  1298. * Entry
  1299. * Exit
  1300. * Returns
  1301. * Calls
  1302. * Note Format is:
  1303. * <name> SEGMENT [align] | [combine] | [16/32] | ['class']
  1304. * align: PARA | BYTE | WORD | PAGE | INPAGE
  1305. * combine:PUBLIC | COMMON | STACK | MEMORY | AT <expr>
  1306. * 16/32: USE16 | USE32
  1307. */
  1308. VOID
  1309. PASCAL
  1310. CODESIZE
  1311. segalign (
  1312. register SYMBOL FARSYM *pseg
  1313. )
  1314. {
  1315. /* Scan align or combine type */
  1316. getatom ();
  1317. if (fnspar ())
  1318. switch (segidx) {
  1319. case IS_BYTE:
  1320. case IS_WORD:
  1321. #ifdef V386
  1322. case IS_DWORD:
  1323. #endif
  1324. case IS_PAGE:
  1325. case IS_PARA:
  1326. /* Some align field */
  1327. if (pseg->symu.segmnt.align == (char)-1)
  1328. pseg->symu.segmnt.align = segtyp;
  1329. else if (pseg->symu.segmnt.align != segtyp &&
  1330. (pseg->symu.segmnt.align != pseg->symu.segmnt.combine ||
  1331. pseg->symu.segmnt.align))
  1332. errorc (E_SPC);
  1333. break;
  1334. case IS_MEMORY:
  1335. case IS_PUBLIC:
  1336. case IS_STACK:
  1337. case IS_COMMON:
  1338. if (pseg->symu.segmnt.combine == 7)
  1339. pseg->symu.segmnt.combine = segtyp;
  1340. else if (pseg->symu.segmnt.combine != segtyp)
  1341. errorc (E_SPC);
  1342. break;
  1343. #ifdef V386
  1344. case IS_USE16:
  1345. if (pseg->symu.segmnt.use32 != (char)-1 &&
  1346. pseg->symu.segmnt.use32 != 2)
  1347. errorc (E_SPC);
  1348. if ((cputype&P386)==0)
  1349. errorc (E_NPA);
  1350. pseg->symu.segmnt.use32 = 2;
  1351. break;
  1352. case IS_USE32:
  1353. if (pseg->symu.segmnt.use32 != (char)-1 &&
  1354. pseg->symu.segmnt.use32 != 4)
  1355. errorc (E_SPC);
  1356. if ((cputype&P386)==0)
  1357. errorc (E_NPA);
  1358. pseg->symu.segmnt.use32 = 4;
  1359. break;
  1360. #endif
  1361. default:
  1362. /* Have AT <expr> */
  1363. pseg->symu.segmnt.locate = exprconst ();
  1364. pseg->symu.segmnt.align = 0;
  1365. pseg->symu.segmnt.combine = 0;
  1366. } else {
  1367. /* Not good align or define */
  1368. errorc (E_NPA);
  1369. }
  1370. }
  1371. /*** procdefine - start procedure block
  1372. *
  1373. * procdefine ();
  1374. *
  1375. * Parse the proc statement with optional distance parameters
  1376. */
  1377. SYMBOL FARSYM *pArgFirst; /* pointer to first argument */
  1378. SYMBOL FARSYM *pArgCur; /* pointer to currect argment */
  1379. OFFSET offsetCur; /* current stack offset */
  1380. char bp16 [] =" PTR [BP]?"; /* template for text macro creation */
  1381. char bp32 [] =" PTR [EBP]?";
  1382. char *bp;
  1383. VOID
  1384. PASCAL
  1385. CODESIZE
  1386. procdefine ()
  1387. {
  1388. /* create PROC name with default size*/
  1389. varsize = dirsize[I_PROC];
  1390. switchname();
  1391. if (getatom ()) {
  1392. if (fnsize ()) { /* process optional near|far */
  1393. if (varsize < CSFAR)
  1394. errorc (E_TIL);
  1395. if (langType)
  1396. getatom();
  1397. } else if (!langType)
  1398. errorc (E_MSY);
  1399. }
  1400. switchname();
  1401. labelcreate (varsize, PROC);
  1402. if (symptr->symkind != PROC)
  1403. return;
  1404. /* Set previous PROC, make sure no loop possible */
  1405. if (iProcStack < PROCMAX && pcproc != symptr)
  1406. procStack[++iProcStack] = symptr;
  1407. pcproc = symptr; /* Set ptr to new PROC */
  1408. symptr->length = 1;
  1409. symptr->symu.clabel.type = typeFet(varsize);
  1410. pcproc->symu.plabel.pArgs = NULL;
  1411. if (langType)
  1412. creatPubName();
  1413. else
  1414. return;
  1415. if (iProcStack > 1) /* nested procs not allowed */
  1416. errorc(E_BNE);
  1417. iProcCur = ++iProc;
  1418. emitline();
  1419. if (! pass2) {
  1420. /* keep a chain of procedures in sorted order so we can output
  1421. * proc's in the correct order for CV */
  1422. if (pProcCur)
  1423. pProcCur->alpha = symptr;
  1424. else
  1425. pProcFirst = symptr;
  1426. }
  1427. pProcCur = symptr;
  1428. /* check and process any "uses reg1 reg2 ... " */
  1429. iRegSave = -1;
  1430. fProcArgs = ARGS_NONE;
  1431. cbProcLocals = 0;
  1432. switchname();
  1433. if (fetLang() == CLANG)
  1434. pProcCur->attr |= M_CDECL;
  1435. #ifndef FEATURE
  1436. if (tokenIS("private")) {
  1437. symptr->attr &= ~M_GLOBAL;
  1438. getatom();
  1439. }
  1440. #endif
  1441. if (tokenIS("uses")) {
  1442. char count = 0;
  1443. while (iRegSave < 8 && getatom()) {
  1444. count++;
  1445. #ifndef FEATURE
  1446. if (symsrch() && symptr->symkind == EQU
  1447. && symptr->symu.equ.equtyp == TEXTMACRO) {
  1448. expandTM (symptr->symu.equ.equrec.txtmacro.equtext);
  1449. getatom ();
  1450. }
  1451. if (*naim.pszName)
  1452. #endif
  1453. strcpy(regSave[++iRegSave], naim.pszName);
  1454. }
  1455. if (!count)
  1456. errorc(E_OPN);
  1457. else
  1458. fProcArgs = ARGS_REG;
  1459. }
  1460. pTextEnd = (char *) -1;
  1461. bp = (wordsize == 2)? bp16: bp32;
  1462. offsetCur = wordsize*2; /* room for [e]bp and offset of ret addr */
  1463. if (pcproc->symtype == CSFAR)
  1464. offsetCur += wordsize; /* room for [ ]cs (16 or 32 bits) */
  1465. cbProcParms = cbProcParms - offsetCur;
  1466. scanArgs();
  1467. cbProcParms += offsetCur;
  1468. if (cbProcParms)
  1469. fProcArgs = ARGS_PARMS;
  1470. pcproc->symu.plabel.pArgs = pArgFirst;
  1471. offsetCur = 0;
  1472. }
  1473. /*** defineLocals
  1474. *
  1475. * Parse the local statment for stack based variables
  1476. */
  1477. VOID
  1478. PASCAL
  1479. CODESIZE
  1480. defineLocals ()
  1481. {
  1482. /* check for valid active proc */
  1483. if (!pcproc || fProcArgs < 0)
  1484. return;
  1485. fProcArgs = ARGS_LOCALS;
  1486. getatom();
  1487. scanArgs();
  1488. /* tack on the the end the parm list any locals */
  1489. addLocal(pArgFirst);
  1490. cbProcLocals = offsetCur;
  1491. }
  1492. /*** addLocal - concatenate a null-terminated list of locals onto a proc
  1493. *
  1494. */
  1495. VOID
  1496. PASCAL
  1497. CODESIZE
  1498. addLocal (
  1499. SYMBOL FARSYM *pSY
  1500. )
  1501. {
  1502. if (pcproc) {
  1503. if (!(pArgCur = pcproc->symu.plabel.pArgs))
  1504. pcproc->symu.plabel.pArgs = pSY;
  1505. else {
  1506. for (; pArgCur->alpha; pArgCur = pArgCur->alpha);
  1507. pArgCur->alpha = pSY;
  1508. }
  1509. }
  1510. }
  1511. char *
  1512. PASCAL
  1513. CODESIZE
  1514. xxradixconvert (
  1515. OFFSET valu,
  1516. register char *p
  1517. )
  1518. {
  1519. if (valu / radix) {
  1520. p = xxradixconvert (valu / radix, p);
  1521. valu = valu % radix;
  1522. } else /* leading digit */
  1523. if (valu > 9) /* do leading '0' for hex */
  1524. *p++ = '0';
  1525. *p++ = (char)(valu + ((valu > 9)? 'A' - 10 : '0'));
  1526. return (p);
  1527. }
  1528. SHORT mpTypeAlign[] = { 4, 1, 2, 4};
  1529. /*** scanArgs - process an argument list into text macros
  1530. *
  1531. *
  1532. */
  1533. SHORT
  1534. PASCAL
  1535. CODESIZE
  1536. scanArgs ()
  1537. {
  1538. struct eqar eqarT;
  1539. USHORT defKind;
  1540. USHORT defType;
  1541. USHORT defCV;
  1542. USHORT defPtrSize;
  1543. SHORT fIsPtr;
  1544. char *pLeftBrack;
  1545. char *p;
  1546. pArgFirst = pArgCur = NULL;
  1547. if (*naim.pszName)
  1548. goto First;
  1549. do {
  1550. if (PEEKC() == ',')
  1551. SKIPC();
  1552. if (!getatom())
  1553. break;
  1554. First:
  1555. switchname();
  1556. if (!createequ (TEXTMACRO))
  1557. break;
  1558. /* chain in the text macro to this procedure. You must either
  1559. do a FIFO or LIFO quque depending on calling order */
  1560. if (pProcCur->attr & M_CDECL) {
  1561. if (pArgCur)
  1562. pArgCur->alpha = symptr;
  1563. else
  1564. pArgFirst = symptr;
  1565. symptr->alpha = NULL;
  1566. } else {
  1567. pArgFirst = symptr;
  1568. symptr->alpha = pArgCur;
  1569. }
  1570. pArgCur = symptr;
  1571. if (PEEKC() == '[' && fProcArgs == ARGS_LOCALS) { /* array element given */
  1572. SKIPC();
  1573. for (pLeftBrack = lbufp; PEEKC() && PEEKC() != ']'; SKIPC());
  1574. *lbufp = ','; /* to stop expression evaluation */
  1575. lbufp = pLeftBrack;
  1576. pArgCur->length = (USHORT)exprconst ();
  1577. *lbufp++ = ']'; /* restore bracket */
  1578. }
  1579. fIsPtr = FALSE;
  1580. defType = varsize = wordsize;
  1581. if (PEEKC() == ':') { /* parse optional type information */
  1582. SKIPC();
  1583. getatom();
  1584. if (fnsize()) {
  1585. if (varsize >= CSFAR) { /* near | far given */
  1586. if (varsize == CSFAR)
  1587. defType += 2;
  1588. varsize = wordsize;
  1589. getatom();
  1590. if (! tokenIS("ptr"))
  1591. error(E_EXP, "PTR");
  1592. getatom();
  1593. } else {
  1594. defType = varsize;
  1595. goto notPtr;
  1596. }
  1597. }
  1598. else if (tokenIS("ptr")) {
  1599. if (farData[10] > '0')
  1600. defType += 2;
  1601. getatom();
  1602. } else
  1603. errorc(E_UST);
  1604. defCV = fnPtr(defType);
  1605. } else
  1606. notPtr:
  1607. defCV = typeFet(defType);
  1608. pArgCur->symu.equ.iProc = iProcCur;
  1609. pArgCur->symtype = defType;
  1610. pArgCur->symu.equ.equrec.txtmacro.type = defCV;
  1611. } while (PEEKC() == ',');
  1612. /* Now that all the parmeters have been scanned, go back through
  1613. the list and assign offsets and create the text macro string */
  1614. bp[strlen(bp)-1] = (fProcArgs == ARGS_LOCALS)? '-': '+';
  1615. for (pArgCur = pArgFirst; pArgCur; pArgCur = pArgCur->alpha) {
  1616. if (fProcArgs == ARGS_LOCALS) {
  1617. offsetCur += (offsetCur % mpTypeAlign[pArgCur->symtype % 4]) +
  1618. (pArgCur->symtype * pArgCur->length);
  1619. pArgCur->offset = -(long)offsetCur;
  1620. }
  1621. p = xxradixconvert (offsetCur, &save[100]);
  1622. if (radix == 16)
  1623. *p++ = 'h';
  1624. *p++ = ')';
  1625. *p = NULL;
  1626. strcat( strcat( strcpy (&save[1], siznm[pArgCur->symtype]),
  1627. bp), &save[100]);
  1628. *save = '(';
  1629. if (fProcArgs != ARGS_LOCALS) {
  1630. pArgCur->offset = offsetCur;
  1631. offsetCur += pArgCur->symtype + wordsize - 1;
  1632. offsetCur -= offsetCur % wordsize;
  1633. }
  1634. if (!pass2)
  1635. pArgCur->symu.equ.equrec.txtmacro.equtext = _strdup(save);
  1636. }
  1637. return 0;
  1638. }
  1639. /*** procbuild - check for end of PROC block
  1640. *
  1641. * procbuild ();
  1642. *
  1643. * Entry *pcproc = current PROC
  1644. * Exit *pcproc = current or previous PROC
  1645. * Returns none
  1646. * Calls endblk, parse
  1647. * Note if not end of PROC, parse line as normal. Otherwise,
  1648. * terminate block.
  1649. */
  1650. SHORT
  1651. PASCAL
  1652. CODESIZE
  1653. procend ()
  1654. {
  1655. USHORT size;
  1656. if (!pcproc)
  1657. errorc( E_BNE );
  1658. else if (pcproc->symkind == PROC) {
  1659. if (!symFet() || symptr != pcproc)
  1660. errorc (E_BNE);
  1661. /* Length of PROC */
  1662. size = (USHORT)(pcoffset - pcproc->offset);
  1663. if (pass2 && size != pcproc->symu.plabel.proclen)
  1664. errorc (E_PHE);
  1665. fProcArgs = 0;
  1666. iProcCur = 0;
  1667. pcproc->symu.plabel.proclen = size;
  1668. /* Point to prev PROC */
  1669. pcproc = procStack[--iProcStack];
  1670. pcdisplay ();
  1671. }
  1672. return(0);
  1673. }
  1674. /* bit flags for segment table */
  1675. #define SG_OVERIDE 1 /* name can be overriden */
  1676. #define SG_GROUP 2 /* segment belongs to dgroup */
  1677. char models[] = "SMALL\0 COMPACT\0MEDIUM\0 LARGE\0 HUGE";
  1678. char langs[] = "C\0 PASCAL\0 FORTRAN\0BASIC";
  1679. char textN[] = "_TEXT";
  1680. char farTextName[14+5];
  1681. SHORT modelWordSize;
  1682. char farCode[] = "@CodeSize=0"; /* text macros for model stuff */
  1683. char farData[] = "@DataSize=0";
  1684. char modelT[] = ".model";
  1685. /* table of segment names and attributes for the model */
  1686. struct sSeg {
  1687. char *sName; /* segment name */
  1688. UCHAR align; /* alignment */
  1689. UCHAR combine; /* combine */
  1690. char *cName; /* class name */
  1691. UCHAR flags; /* internal state flags */
  1692. } rgSeg[] = {
  1693. textN, 2, 2, "'CODE'", SG_OVERIDE,
  1694. "_DATA", 2, 2, "'DATA'", SG_GROUP,
  1695. "_BSS", 2, 2, "'BSS'", SG_GROUP,
  1696. "CONST", 2, 2, "'CONST'", SG_GROUP,
  1697. "STACK", 3, 5, "'STACK'", SG_GROUP,
  1698. "FAR_DATA", 3, 0, "'FAR_DATA'", SG_OVERIDE,
  1699. "FAR_BSS", 3, 0, "'FAR_BSS'", SG_OVERIDE
  1700. };
  1701. /*** model - process the model directive
  1702. *
  1703. *
  1704. * Note Format is:
  1705. * .MODEL SMALL|MEDIUM|COMPACT|LARGE|HUGE {,C|BASIC|FORTRAN|PASCAL}
  1706. */
  1707. VOID
  1708. PASCAL
  1709. CODESIZE
  1710. model ()
  1711. {
  1712. register SHORT iModel;
  1713. char buffT[80];
  1714. /* get the model and classify */
  1715. getatom ();
  1716. for (iModel = 0; iModel <= 32; iModel += 8)
  1717. if (tokenIS(&models[iModel]))
  1718. goto goodModel;
  1719. errorc(E_OPN);
  1720. iModel = 0;
  1721. goodModel:
  1722. iModel /= 8; /* offset into index */
  1723. if (fSimpleSeg && iModel+1 != fSimpleSeg)
  1724. error(E_SMD, modelT);
  1725. fSimpleSeg = iModel + 1;
  1726. if (iModel > 1) { /* far code */
  1727. farCode[10]++;
  1728. rgSeg[0].sName = strcat(strcpy(farTextName, &baseName[10]), textN);
  1729. dirsize[I_PROC] = CSFAR;
  1730. } else
  1731. rgSeg[0].flags &= ~SG_OVERIDE;
  1732. if (iModel != 0 && iModel != 2 ) { /* far data */
  1733. farData[10]++;
  1734. if (iModel == 4) /* huge get a '2' */
  1735. farData[10]++;
  1736. }
  1737. #ifdef V386
  1738. if (cputype & P386)
  1739. rgSeg[0].align =
  1740. rgSeg[1].align =
  1741. rgSeg[2].align =
  1742. rgSeg[3].align =
  1743. rgSeg[5].align =
  1744. rgSeg[6].align = 5; /* make data dword aligned */
  1745. #endif
  1746. if (PEEKC() == ',') { /* language option present */
  1747. SKIPC();
  1748. getatom();
  1749. if (! (langType = fetLang()))
  1750. error(E_EXP, "C|BASIC|FORTRAN|PASCAL");
  1751. }
  1752. if (! pass2) {
  1753. modelWordSize = wordsize;
  1754. /* define the text macros, the _data segment so dgroup may
  1755. defined, dgroup and the assume */
  1756. definesym(farCode);
  1757. definesym(farData);
  1758. definesym(strcat(strcpy(buffT, "@code="), rgSeg[0].sName));
  1759. definesym("@data=DGROUP"); symptr->attr |= M_NOCREF;
  1760. definesym("@fardata=FAR_DATA"); symptr->attr |= M_NOCREF;
  1761. definesym("@fardata?=FAR_BSS"); symptr->attr |= M_NOCREF;
  1762. doLine(".code");
  1763. doLine(".data");
  1764. endCurSeg();
  1765. }
  1766. xcreflag--;
  1767. doLine("assume cs:@code,ds:@data,ss:@data");
  1768. xcreflag++;
  1769. }
  1770. SHORT
  1771. CODESIZE
  1772. fetLang()
  1773. {
  1774. SHORT iModel;
  1775. for (iModel = 0; iModel <= 24; iModel += 8)
  1776. if (tokenIS(&langs[iModel])) {
  1777. getatom();
  1778. return(iModel/8 + 1);
  1779. }
  1780. return(langType);
  1781. }
  1782. /*** openSeg - open a segment in the simplified segment
  1783. *
  1784. *
  1785. */
  1786. VOID
  1787. PASCAL
  1788. CODESIZE
  1789. openSeg ()
  1790. {
  1791. register struct sSeg *pSEG;
  1792. char *pSegName;
  1793. char buffT[80];
  1794. if (!fSimpleSeg)
  1795. error(E_EXP, modelT);
  1796. pSEG = &rgSeg[opkind];
  1797. getatom ();
  1798. if (*naim.pszName) {
  1799. if (! (pSEG->flags & SG_OVERIDE))
  1800. errorc(E_OCI);
  1801. pSegName = naim.pszName;
  1802. } else
  1803. pSegName = pSEG->sName;
  1804. strcat( strcat( strcpy(buffT,
  1805. pSegName),
  1806. " segment "),
  1807. pSEG->cName);
  1808. if (pcsegment && opkind != 4)
  1809. endCurSeg();
  1810. doLine(buffT);
  1811. pcsegment->symu.segmnt.combine = pSEG->combine;
  1812. pcsegment->symu.segmnt.align = pSEG->align;
  1813. if (pSEG == &rgSeg[0])
  1814. regsegment[CSSEG] = pcsegment;
  1815. #ifdef V386
  1816. pcsegment->symu.segmnt.use32 = (char)modelWordSize;
  1817. wordsize = modelWordSize;
  1818. defwordsize();
  1819. #endif
  1820. if (pSEG->flags & SG_GROUP) {
  1821. doLine("DGROUP group @CurSeg");
  1822. pSEG->flags &= ~SG_GROUP;
  1823. }
  1824. }
  1825. /*** stack - create a stack segment
  1826. *
  1827. *
  1828. */
  1829. VOID
  1830. PASCAL
  1831. CODESIZE
  1832. createStack ()
  1833. {
  1834. SHORT size;
  1835. if ((size = (SHORT)exprconst()) == 0)
  1836. size = 1024;
  1837. opkind = 4; /* index into seg table */
  1838. openSeg();
  1839. pcoffset = size;
  1840. endCurSeg();
  1841. }
  1842. VOID
  1843. PASCAL
  1844. CODESIZE
  1845. endCurSeg ()
  1846. {
  1847. xcreflag--;
  1848. doLine("@CurSeg ends");
  1849. xcreflag++;
  1850. }
  1851. /*** freeAFileHandle
  1852. *
  1853. * Free's a file handle if possible
  1854. *
  1855. * When working with deeply nested include files it is possible
  1856. * to run out of file handles. If this happens this function is
  1857. * called to temporarily close one of the include files. This is
  1858. * done by saving the current file position, closing the file and
  1859. * replacing the file handle with FH_CLOSED. Notice that the data
  1860. * buffer assosciated with the file is not destroyed. Hence readline
  1861. * can continue to read data from it until more data is needed from
  1862. * disk. There are two files that won't be closed, the main file and
  1863. * the current file.
  1864. * Associated functions:
  1865. * readmore - if neccessary, will reopen and seek to the original
  1866. * position the file.
  1867. * closefile - closes the file if it hasn't been already.
  1868. *
  1869. * return: TRUE = Was able to close a file, FALSE = Couldn't
  1870. */
  1871. int
  1872. PASCAL
  1873. CODESIZE
  1874. freeAFileHandle ()
  1875. {
  1876. register FCB *pFCBTmp;
  1877. if ( !(pFCBTmp = pFCBMain->pFCBChild) ) {
  1878. return( FALSE ); /* The only file open is the main source */
  1879. }
  1880. /* Loop down linked list of nested include files */
  1881. while ( pFCBTmp ) {
  1882. if ( (pFCBTmp->fh != FH_CLOSED) && (pFCBTmp != pFCBCur) ) {
  1883. pFCBTmp->savefilepos = _tell( pFCBTmp->fh );
  1884. _close( pFCBTmp->fh );
  1885. pFCBTmp->fh = FH_CLOSED;
  1886. return( TRUE );
  1887. }
  1888. pFCBTmp = pFCBTmp->pFCBChild;
  1889. }
  1890. return( FALSE ); /* Couldn't find a file to close */
  1891. }
  1892. int
  1893. PASCAL
  1894. CODESIZE
  1895. fpoRecord ()
  1896. {
  1897. unsigned long dwValue[6];
  1898. char peekChar;
  1899. int i;
  1900. PFPOSTRUCT pFpo = pFpoTail;
  1901. PFPO_DATA pFpoData = 0;
  1902. if (PEEKC() != '(') {
  1903. errorc(E_PAR);
  1904. return FALSE;
  1905. }
  1906. SKIPC();
  1907. for (i=0; i<6; i++) {
  1908. dwValue[i] = exprconst();
  1909. peekChar = PEEKC();
  1910. SKIPC();
  1911. if (peekChar != ',') {
  1912. if (i < 5) {
  1913. errorc(E_FPO1);
  1914. return FALSE;
  1915. }
  1916. if (peekChar != ')') {
  1917. errorc(E_PAR);
  1918. return FALSE;
  1919. } else {
  1920. break;
  1921. }
  1922. }
  1923. }
  1924. if (!pcproc) {
  1925. errorc(E_FPO2);
  1926. return FALSE;
  1927. }
  1928. if (pass2) {
  1929. return TRUE;
  1930. }
  1931. if (!pFpoHead) {
  1932. pFpoTail = pFpoHead = (PFPOSTRUCT)malloc(sizeof(FPOSTRUCT));
  1933. if (!pFpoHead) {
  1934. errorc(E_RRF);
  1935. return FALSE;
  1936. }
  1937. pFpo = pFpoTail;
  1938. } else {
  1939. pFpoTail->next = (PFPOSTRUCT)malloc(sizeof(FPOSTRUCT));
  1940. if (!pFpoTail->next) {
  1941. errorc(E_RRF);
  1942. return FALSE;
  1943. }
  1944. pFpo = pFpoTail->next;
  1945. pFpoTail = pFpo;
  1946. }
  1947. numFpoRecords++;
  1948. memset((void*)pFpo,0,sizeof(FPOSTRUCT));
  1949. pFpoData = &pFpo->fpoData;
  1950. if (pcproc->offset != pcoffset) {
  1951. sprintf(naim.pszName, "%s_fpo%d", pcproc->nampnt->id, numFpoRecords);
  1952. strcpy(naim.pszLowerCase, naim.pszName);
  1953. _strlwr(naim.pszLowerCase);
  1954. naim.ucCount = (unsigned char) strlen(naim.pszName);
  1955. naim.usHash = 0;
  1956. labelcreate(CSNEAR, CLABEL);
  1957. pFpo->pSymAlt = symptr;
  1958. } else {
  1959. pFpo->pSymAlt = 0;
  1960. }
  1961. pFpo->pSym = pcproc;
  1962. pFpoData->ulOffStart = pcoffset;
  1963. pFpoData->cbProcSize = 0;
  1964. pFpoData->cdwLocals = dwValue[0];
  1965. pFpoData->cdwParams = (USHORT)dwValue[1];
  1966. pFpoData->cbProlog = (USHORT)dwValue[2];
  1967. pFpoData->cbRegs = (USHORT)dwValue[3];
  1968. pFpoData->fUseBP = (USHORT)dwValue[4];
  1969. pFpoData->cbFrame = (USHORT)dwValue[5];
  1970. pFpoData->fHasSEH = 0;
  1971. return TRUE;
  1972. }