Windows NT 4.0 source code leak
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.

2403 lines
57 KiB

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