1 /* asmcro.c */
2
3 /*
4 * Copyright (C) 2010 Alan R. Baldwin
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 *
20 * Alan R. Baldwin
21 * 721 Berkeley St.
22 * Kent, Ohio 44240
23 */
24
25 #include "asxxxx.h"
26
27 /*)Module asmcro.c
28 *
29 * The module asmcro.c includes the macro processor.
30 *
31 * asmcro.c contains the following functions:
32 * char *fgetm() get a macro text line
33 * VOID getdarg() get a macro definition argument
34 * VOID getxarg() get a macro expansion argument
35 * VOID getxstr() get a macro expansion string
36 * int macro() run a macro
37 * VOID macroscn() scan macro text line for symbols
38 * int macrosub() substitute macro expansion arguments
39 * VOID mcrinit() initialize macro processing variables
40 * int mcrprc() macro processing control
41 * char *mstring() store a macro string
42 * char *mstruct() allocate macro space
43 * mcrdef *newdef() initialize a macro definition
44 * mcrdef *nlookup() lookup a macro
45 */
46
47 /*)Function int mcrprc(code))
48 *
49 * int code function code
50 *
51 * The function of mcrprc() is to evaluate the
52 * following assembler directives:
53 *
54 * .macro define a general macro
55 * .irp define an inline indefinite repeat macro by arguments
56 * .irpc define an inline indefinite repeat macro by characters
57 * .rept define an inline repeating macro
58 * .mexit exit to end of macro
59 * .endm end of macro
60 * .nchr assign number of characters in a string to a symbol
61 * .narg assign number of expansion arguments to a symbol
62 * .ntyp assign 0/1 if absolute/relocatable symbol
63 * .nval assign value of argument to an absolute symbol
64 * .mdelete delete a macro definition
65 *
66 * And to control the building and exiting of a macro
67 * by the use of the internal assembler directives:
68 *
69 * O_BUILD building a macro processing
70 * O_EXIT exit a macro processing
71 *
72 * local variables:
73 * int d character string delimiter
74 * expr e1 expression structure
75 * char id[] id string
76 * mne *mp pointer to an assembler mnemonic structure
77 * macrofp *nfp macro pseudo FILE Handle
78 * mcrdef *nq pointer to a macro definition structure
79 * mcrdef *np pointer to a macro definition structure
80 * int rptcnt repeat count evaluation
81 * sym *sp pointer to a symbol structure
82 * strlst *str string list structure
83 *
84 * global variables:
85 * asmf * asmc current asmf structure
86 * sym dot current program counter value structure
87 * a_uint laddr equate value
88 * int lmode assembler list mode
89 * mcrdef mcrlst pointer the macro definition linked list
90 * mcrdef mcrp pointer to macro definition being built
91 *
92 * functions called:
93 * a_uint absexpr() asexpr.c
94 * VOID clrexpr() asexpr.c
95 * int comma() aslex.c
96 * VOID getdarg() asmcro.c
97 * int getid() aslex.c
98 * int getdlm() aslex.c
99 * int getmap() aslex.c
100 * int getnb() aslex.c
101 * VOID getxarg() asmcro.c
102 * sym * lookup() assym.c
103 * VOID macro() asmcro.c
104 * mne * mlookup() assym.c
105 * int more() aslex.c
106 * char * mstring() asmcro.c
107 * VOID * mstruct() asmcro.c
108 * mcrdef *newdef() asmcro.c
109 * VOID qerr() assubr.c
110 * VOID unget() aslex.c
111 *
112 * side effects:
113 * Macro directives processed and
114 * macro structures created.
115 */
116 int
mcrprc(code)117 mcrprc(code)
118 int code;
119 {
120 struct mcrdef *np,*nq;
121 struct macrofp *nfp;
122 struct strlst *str;
123 struct mne *mp;
124 struct sym *sp;
125 struct expr e1;
126 char id[NCPS];
127 int d, rptcnt;
128
129 switch(code) {
130 case O_MACRO:
131 /*
132 * Valid .macro definition forms:
133 *
134 * .macro mne(,)
135 * .macro mne(,) arg1(,) arg2(,) ((,) arg3(,) ...(,) argn)
136 *
137 * where 'mne' is a string beginning with a
138 * LETTER followed by LETTERs or DIGITs.
139 *
140 * If the 'arg' is immediately preceeded by a '?'
141 * (ie ?arg) then the argument is a dummy argument.
142 * Dummy arguments left blank become local symbols
143 * when the macro is expanded.
144 */
145 /*
146 * Get macro mnemonic
147 */
148 if (more()) {
149 getid(id, getnb());
150 } else {
151 qerr();
152 }
153 np = newdef(code, id);
154 /*
155 * Get macro definition arguments
156 */
157 while (more()) {
158 getdarg(np);
159 }
160 break;
161
162 case O_IRP:
163 /*
164 * Valid .irp definition forms:
165 *
166 * .irp sym(,)
167 * .irp sym(,) arg1(,) arg2 ((,) arg3(,) ...(,) argn)
168 *
169 * where 'sym' is a string beginning with
170 * a LETTER followed by LETTERs or DIGITs.
171 *
172 * The complete .irp definition is processed once
173 * for each argument in the .irp definition.
174 */
175 /*
176 * An inline definition
177 */
178 np = newdef(code, NULL);
179 /*
180 * Get macro definition argument
181 */
182 getdarg(np);
183 /*
184 * Get expansion arguments
185 */
186 while (more()) {
187 getxarg(np);
188 }
189 np->rptcnt = np->xarg;
190 break;
191
192 case O_IRPC:
193 /*
194 * Valid .irpc definition forms:
195 *
196 * .irpc sym(,)
197 * .irpc sym(,) character_string
198 *
199 * where 'sym' is a string beginning with
200 * a LETTER followed by LETTERs or DIGITs.
201 *
202 * The complete .irpc definition is processed once
203 * for each character in the character_string.
204 *
205 * If the character_string contains white space
206 * or commas then the character string must be
207 * delimited as ^/character_string/ where the
208 * delimiting character ('/') must not be in
209 * the string.
210 */
211 /*
212 * An inline definition
213 */
214 np = newdef(code, NULL);
215 /*
216 * Get macro definition argument
217 */
218 getdarg(np);
219 /*
220 * Get expansion argument
221 */
222 getxarg(np);
223 np->rptcnt = (np->bgnxrg != NULL) ? strlen(np->bgnxrg->text) : 0;
224 break;
225
226 case O_REPT:
227 /*
228 * Valid .rept definition forms:
229 *
230 * .rept sym
231 *
232 * where 'sym' is a symbol or expression which
233 * is evalauated to an absolute value.
234 *
235 * The complete .rept definition is processed
236 * value times.
237 */
238 /*
239 * An inline definition
240 */
241 np = newdef(code, NULL);
242 /*
243 * Get repeat count
244 */
245 if (more()) {
246 unget(getnb());
247 rptcnt = (int) absexpr();
248 if (rptcnt < 0) {
249 rptcnt = 0;
250 }
251 } else {
252 err('o');
253 rptcnt = 0;
254 }
255 np->rptcnt = rptcnt;
256 break;
257
258 case O_ENDM:
259 if (asmc->objtyp != T_MACRO) {
260 err('n');
261 } else {
262 lmode = NLIST;
263 }
264 break;
265
266 case O_MEXIT:
267 if (asmc->objtyp == T_MACRO) {
268 nfp = (struct macrofp *) asmc->fp;
269 nfp->npexit = 1;
270 nfp->lstptr = nfp->np->endlst;
271 } else {
272 err('n');
273 }
274 break;
275
276 case O_NCHR:
277 getid(id, -1);
278 sp = lookup(id);
279 if (sp == &dot) {
280 err('.');
281 break;
282 }
283 sp->s_flag |= S_ASG;
284 sp->s_type = S_USER;
285 comma(0);
286 d = getdlm();
287 rptcnt = 0;
288 while (getmap(d) >= 0) {
289 rptcnt += 1;
290 }
291 lmode = ELIST;
292 laddr = sp->s_addr = rptcnt;
293 break;
294
295 case O_NARG:
296 nfp = (struct macrofp *) asmc->fp;
297 np = nfp->np;
298 if (asmc->objtyp != T_MACRO) {
299 err('n');
300 break;
301 } else
302 if (np->type != O_MACRO) {
303 err('n');
304 break;
305 }
306 getid(id, -1);
307 sp = lookup(id);
308 if (sp == &dot) {
309 err('.');
310 break;
311 }
312 sp->s_flag |= S_ASG;
313 sp->s_type = S_USER;
314 lmode = ELIST;
315 laddr = sp->s_addr = np->xarg;
316 break;
317
318 case O_NTYP:
319 getid(id, -1);
320 sp = lookup(id);
321 sp->s_flag |= S_ASG;
322 sp->s_type = S_USER;
323 sp->s_area = NULL;
324 comma(0);
325 clrexpr(&e1);
326 expr(&e1, 0);
327 lmode = ELIST;
328 laddr = sp->s_addr = (e1.e_flag || e1.e_base.e_ap) ? 1 : 0;
329 break;
330
331 case O_NVAL:
332 getid(id, -1);
333 sp = lookup(id);
334 if (sp == &dot) {
335 err('.');
336 break;
337 }
338 sp->s_flag |= S_ASG;
339 sp->s_type = S_USER;
340 sp->s_area = NULL;
341 comma(0);
342 clrexpr(&e1);
343 expr(&e1, 0);
344 lmode = ELIST;
345 laddr = sp->s_addr = e1.e_addr;
346 break;
347
348 case O_MDEL:
349 while (more()) {
350 getid(id, getnb());
351 np = nlookup(id);
352 if (np != NULL) {
353 if (np == mcrlst) {
354 mcrlst = np->next;
355 } else {
356 nq = mcrlst;
357 while (nq != NULL) {
358 if (np == nq->next) {
359 nq->next = np->next;
360 break;
361 }
362 nq = nq->next;
363 }
364 }
365 }
366 if (more() && comma(0) && !more()) {
367 qerr();
368 }
369 }
370 break;
371
372 case O_CHECK:
373 if (mcrp == NULL) {
374 if (asmc->objtyp == T_MACRO) {
375 nfp = (struct macrofp *) asmc->fp;
376 if (nfp->npexit) {
377 lmode = NLIST;
378 return(1);
379 }
380 }
381 return(0);
382 }
383 while (more()) {
384 getid(id, getnb());
385 if (((mp = mlookup(id)) != NULL) &&
386 (mp->m_type == S_MACRO)) {
387 switch (mp->m_valu) {
388 case O_MACRO:
389 case O_IRP:
390 case O_IRPC:
391 case O_REPT:
392 mcrp->nest += 1;
393 break;
394 case O_ENDM:
395 mcrp->nest -= 1;
396 break;
397 default:
398 break;
399 }
400 break;
401 }
402 }
403 /*
404 * Append to MACRO Definition
405 */
406 str = (struct strlst *) mstruct (sizeof (struct strlst));
407 str->next = NULL;
408 str->text = mstring(ib);
409 if (mcrp->bgnlst == NULL) {
410 mcrp->bgnlst = str;
411 } else {
412 mcrp->endlst->next = str;
413 }
414 mcrp->endlst = str;
415 /*
416 * Check for .ENDM
417 */
418 if (mcrp->nest == 0) {
419 switch (mcrp->type) {
420 case O_MACRO:
421 mcrp->next = mcrlst;
422 mcrlst = mcrp;
423 break;
424 case O_IRP:
425 case O_IRPC:
426 case O_REPT:
427 if (mcrp->rptcnt != 0) {
428 macro(mcrp);
429 }
430 break;
431 default:
432 break;
433 }
434 mcrp = NULL;
435 }
436 if ((lnlist & LIST_MD) == 0) {
437 lmode = NLIST;
438 }
439 return(1);
440
441 default:
442 break;
443 }
444 return(0);
445 }
446
447 /*)Function VOID getdarg(np)
448 *
449 * struct mcrdef *np pointer to macro definition structure
450 *
451 * The function getdarg() gets the next macro definition
452 * argument from the assembler input text. The definiton
453 * may be any valid label or symbol (excluding temporary
454 * symbols).
455 *
456 * local variables:
457 * strlst *str text line structure
458 * char id[] text string
459 * int c character
460 *
461 * global variables:
462 * char ctype[] charcter type array
463 * mcrdef mcrp link to macro definition being built
464 *
465 * functions called:
466 * int comma() aslex.c
467 * int getid() aslex.c
468 * int getnb() aslex.c
469 * char * mstring() asmcro.c
470 * VOID * mstruct() asmcro.c
471 * VOID qerr() assubr.c
472 *
473 * side effects:
474 * Macro definition argument is added to macro definition
475 * structure and the number of arguments is incremented.
476 * Failure to allocate space for the argument string will
477 * terminate the assembler.
478 */
479
480 VOID
getdarg(np)481 getdarg(np)
482 struct mcrdef * np;
483 {
484 struct strlst *str;
485 char id[NCPS];
486 int c;
487
488 /*
489 * Skip leading ','
490 */
491 comma(0);
492 if (more()) {
493 if (((c=getnb()) == '?') && (ctype[c=get()] & LETTER)) {
494 unget(c);
495 c = '?';
496 } else
497 if (ctype[c] & LETTER) {
498 ;
499 } else {
500 qerr();
501 }
502 getid(id, c);
503 } else {
504 qerr();
505 }
506 str = (struct strlst *) mstruct (sizeof (struct strlst));
507 str->next = NULL;
508 str->text = mstring(id);
509 if (np->bgnarg == NULL) {
510 np->bgnarg = str;
511 } else {
512 np->endarg->next = str;
513 }
514 np->endarg = str;
515 np->narg += 1;
516 }
517
518 /*)Function VOID getxarg(np)
519 *
520 * struct mcrdef *np pointer to macro definition structure
521 *
522 * The function getxarg() gets the next macro expansion
523 * argument from the assembler input text. The expansion
524 * may contain any ASCII character including the space and
525 * tab characters. If the argument contains a comma then
526 * the argument string must be delimited using the form
527 *
528 * ^/ ... / where the character '/' may be any
529 * printing character not in the delimited string.
530 *
531 * If the undelimited string is of the form \arg then
532 * the argument is evaluated and represented by an
533 * unsigned integer in the current radix.
534 *
535 * local variables:
536 * char id[] text string
537 * char * frmt format string pointer
538 * char * sip save ip pointer
539 * strlst *str text line structure
540 *
541 * global variables:
542 * char * ip source text line pointer
543 *
544 * functions called:
545 * a_uint absexpr() asexpr.c
546 * VOID getxstr() asmcro.c
547 * char * mstring() asmcro.c
548 * VOID * mstruct() asmcro.c
549 * int sprintf() c_library
550 *
551 * side effects:
552 * Macro expansion argument is added to macro definition
553 * structure and the number of arguments is incremented.
554 * Failure to allocate space for the argument string will
555 * terminate the assembler.
556 */
557
558 VOID
getxarg(np)559 getxarg(np)
560 struct mcrdef * np;
561 {
562 struct strlst *str;
563 char id[NCPS];
564 char *frmt;
565 char *sip;
566
567 /*
568 * Get the argument string
569 */
570 getxstr(id);
571
572 str = (struct strlst *) mstruct (sizeof (struct strlst));
573 str->next = NULL;
574 if (*id == '\\') {
575 sip = ip;
576 ip = id + 1;
577 #ifdef LONGINT
578 switch (radix) {
579 default:
580 case 10: frmt = "%lu"; break;
581 case 8: frmt = "%lo"; break;
582 case 16: frmt = "%lX"; break;
583 }
584 #else
585 switch (radix) {
586 default:
587 case 10: frmt = "%u"; break;
588 case 8: frmt = "%o"; break;
589 case 16: frmt = "%X"; break;
590 }
591 #endif
592 sprintf(id, frmt, absexpr());
593 ip = sip;
594 }
595 str->text = mstring(id);
596 if (np->bgnxrg == NULL) {
597 np->bgnxrg = str;
598 } else {
599 np->endxrg->next = str;
600 }
601 np->endxrg = str;
602 np->xarg += 1;
603 }
604
605 /*)Function VOID getxstr(id)
606 *
607 * char * id pointer to string
608 *
609 * The function getxstr() processes the next macro expansion
610 * argument from the assembler input text. The expansion
611 * may contain any ASCII character including the space and
612 * tab characters. If the argument contains a comma then
613 * the argument string must be delimited using the form
614 *
615 * ^/ ... / where the character '/' may be any
616 * printing character not in the delimited string.
617 *
618 * local variables:
619 * int c character
620 * int dc delimiting character
621 * char * p character string pointer
622 *
623 * global variables:
624 * char ctype[] charcter type array
625 *
626 * functions called:
627 * int comma() aslex.c
628 * int get() aslex.c
629 * int getnb() aslex.c
630 * VOID qerr() assubr.c
631 * VOID unget() assym.c
632 *
633 * side effects:
634 * Macro expansion argument is returned in id[].
635 */
636
637 VOID
getxstr(id)638 getxstr(id)
639 char *id;
640 {
641 char *p;
642 int c, dc;
643
644 /*
645 * The argument delimiters are SPACE, TAB, and ','.
646 * If the argument contains a SPACE, TAB, or ',' then
647 * the argument must be enclosed within a delimiter of
648 * the form ^/ ... / where the character '/' may
649 * be any character not in the delimited string.
650 */
651 p = id;
652 /*
653 * Skip leading ','
654 */
655 comma(0);
656 switch (c=getnb()) {
657 case '^': dc = get(); break;
658 default: dc = ','; break;
659 }
660 switch (c) {
661 case '^':
662 while ((c=get()) != '\0') {
663 if (c == dc) {
664 break;
665 }
666 *p++ = c;
667 }
668 if (ctype[c] & ILL) {
669 qerr();
670 }
671 break;
672 default:
673 unget(c);
674 while ((c=get()) != '\0') {
675 if ((c == dc) ||
676 (c == ' ') ||
677 (c == '\t') ||
678 (c == ';')) {
679 unget(c);
680 break;
681 }
682 *p++ = c;
683 }
684 break;
685 }
686 *p = '\0';
687 }
688
689 /*)Function VOID macro(np)
690 *
691 * mcrdef *np macro definition structure
692 *
693 * macro() prepares the macro described by
694 * np for insertion into the code stream.
695 *
696 * local variables:
697 * macrofp *nfp pseudo FILE Handle
698 * strlst *str missing argument expansion string
699 * strlst *arg macro definition argument string
700 * strlst *xrg macro expansion argument string
701 * char xrgstr[] dumby argument evaluation string
702 *
703 * global variables:
704 * asmf asmq queued macro structure
705 * int srcline current assembler line number
706 * int flevel current IF-ELSE-ENDIF level
707 * int tlevel current IF-ELSE-ENDIF level index
708 * int maxmcr maximum macro nesting level encountered
709 * int mcrfil macro nesting counter
710 * int lnlist current LIST-NLIST flags
711 *
712 * functions called:
713 * VOID getxarg() asmcro.c
714 * char * mstring() asmcro.c
715 * VOID * mstruct() asmcro.c
716 * char * strcpy() c_library
717 * int sprintf() c_library
718 * int strlen() c_library
719 * VOID qerr() assubr.c
720 *
721 * side effects:
722 * Macro is inserted into assembler stream
723 */
724
725 VOID
macro(np)726 macro(np)
727 struct mcrdef * np;
728 {
729 struct macrofp *nfp;
730 struct strlst *str;
731 struct strlst *arg;
732 struct strlst *xrg;
733 char xrgstr[NINPUT];
734
735 if (++mcrfil > MAXMCR) {
736 --mcrfil;
737 err('m');
738 return;
739 }
740 if (mcrfil > maxmcr) {
741 maxmcr = mcrfil;
742 }
743 /*
744 * Create an asmf structure for nxtline()
745 */
746 asmq = (struct asmf *) mstruct (sizeof (struct asmf));
747 asmq->next = asmc;
748 asmq->objtyp = T_MACRO;
749 asmq->line = srcline;
750 if (ftflevel != 0) {
751 asmq->flevel = ftflevel - 1;
752 ftflevel = 0;
753 } else {
754 asmq->flevel = flevel;
755 }
756 asmq->tlevel = tlevel;
757 asmq->lnlist = lnlist;
758 asmq->afp = 0;
759 strcpy(asmq->afn,np->name);
760 /*
761 * Create a macrofp structure for fgetm()
762 */
763 nfp = (struct macrofp *) mstruct (sizeof (struct macrofp));
764 nfp->np = np;
765 nfp->lstptr = np->bgnlst;
766 nfp->rptcnt = np->rptcnt;
767 nfp->rptidx = 0;
768 nfp->flevel = asmq->flevel;
769 nfp->tlevel = asmq->tlevel;
770 nfp->lnlist = asmq->lnlist;
771 nfp->npexit = nfp->rptcnt ? 0 : 1;
772 /*
773 * Check if arguments are required
774 */
775 if (np->type == O_MACRO) {
776 np->xarg = 0;
777 np->bgnxrg = NULL;
778 np->endxrg = NULL;
779 while (more()) {
780 getxarg(np);
781 }
782 if (np->xarg > np->narg) {
783 qerr();
784 }
785 /*
786 * Fill in missing arguments and
787 * check for dummy arguments.
788 */
789 arg = np->bgnarg;
790 xrg = np->bgnxrg;
791 while (arg != NULL) {
792 if (xrg == NULL) {
793 str = (struct strlst *) mstruct (sizeof (struct strlst));
794 str->next = NULL;
795 str->text = mstring("");
796 if (np->bgnxrg == NULL) {
797 np->bgnxrg = str;
798 } else {
799 np->endxrg->next = str;
800 }
801 np->endxrg = str;
802 xrg = str;
803 }
804 if ((*arg->text == '?') && (strlen(xrg->text) == 0)) {
805 #ifdef LONGINT
806 sprintf(xrgstr, "%lu$", mls.s_addr++);
807 #else
808 sprintf(xrgstr, "%u$", mls.s_addr++);
809 #endif
810 xrg->text = mstring(xrgstr);
811 }
812 arg = arg->next;
813 xrg = xrg->next;
814 }
815 }
816 /*
817 * Cast nfp as a FILE HANDLE
818 */
819 asmq->fp = (FILE *) nfp;
820
821 return;
822 }
823
824 /*)Function mcrdef *newdef(code, id)
825 *
826 * int code macro type code
827 * char * id macro name string
828 *
829 * The function mcrdef() creates a new macro
830 * definition structure and initializes it.
831 *
832 * local variables:
833 * mne * mp pointer to a mnemonic structure
834 *
835 * global variables:
836 * mcrdef *mcrp pointer to the new macro definition structure
837 *
838 * functions called:
839 * mne * mlookup() assym.c
840 * char * mstring() asmcro.c
841 * VOID * mstruct() asmcro.c
842 * mne * nlookup() asmcro.c
843 *
844 * side effects:
845 * Macro definiton structure created
846 * and initialized.
847 */
848
849 struct mcrdef *
newdef(code,id)850 newdef(code, id)
851 int code;
852 char *id;
853 {
854 struct mne *mp;
855
856 /*
857 * New MACRO Definition
858 */
859 mcrp = (struct mcrdef *) mstruct (sizeof (struct mcrdef));
860 mcrp->next = NULL;
861 /*
862 * Check for Assembler Directive Conflicts
863 */
864 if (id != NULL) {
865 if (nlookup(id) != NULL) {
866 err('m');
867 }
868 mcrp->name = mstring(id);
869 mp = mlookup(id);
870 if (mp != NULL) {
871 if (mp->m_type < S_DIREOL) {
872 err('m');
873 }
874 }
875 } else {
876 mcrp->name = mstring("");
877 }
878 mcrp->bgnlst = NULL;
879 mcrp->endlst = NULL;
880 mcrp->type = code;
881 mcrp->rptcnt = 1;
882 mcrp->nest = 1;
883 mcrp->narg = 0;
884 mcrp->bgnarg = NULL;
885 mcrp->endarg = NULL;
886 mcrp->xarg = 0;
887 mcrp->bgnxrg = NULL;
888 mcrp->endxrg = NULL;
889 return (mcrp);
890 }
891
892 /*)Function mcrdef *nlookup(id)
893 *
894 * char * id macro name string
895 *
896 * The function nlookup() searches the macro list
897 * for a match returning a pointer to the macro
898 * definition structure else it returns a NULL.
899 *
900 * local variables:
901 * mcrdef *np pointer to macro structure
902 *
903 * global variables:
904 * none
905 *
906 * functions called:
907 * symeq() assym.c
908 *
909 * side effects:
910 * none
911 */
912
913 struct mcrdef *
nlookup(id)914 nlookup(id)
915 char *id;
916 {
917 struct mcrdef * np;
918
919 np = mcrlst;
920 while (np != NULL) {
921 if (symeq(id, np->name, 1)) {
922 return (np);
923 }
924 np = np->next;
925 }
926 return (NULL);
927 }
928
929 /*)Function char *fgetm(ptr, len, fp)
930 *
931 * char * ptr pointer string address
932 * int len maximum number of characters to return
933 * FILE * fp pseudo FILE Handle
934 *
935 * The function fgetm() reads characters from the pseudo
936 * stream fp into the string pointed to by ptr. The integer
937 * argument len indicates the maximum number of characters
938 * that the buffer ptr can store. Reading stops when an end
939 * of string or len-1 characters were read. The string read
940 * is terminated with a 0.
941 *
942 * Macro types O_MACRO, O_IRP, and O_IRPC will have
943 * the macro definition strings replaced by their
944 * respective macro expression strings.
945 *
946 * When no more macro lines are available then
947 * the macro terminates by restoring the assembler
948 * conditional and listing state at the time the
949 * macro was invoked and a NULL is returned.
950 *
951 * local variables:
952 * macrofp *nfp pointer to the pseudo FILE Handle
953 * mcrdef *np pointer to macro structure
954 *
955 * global variables:
956 * char * ib string buffer containing
957 * assembler-source text line for processing
958 * char * ip pointer into the assembler-source
959 * text line in ib
960 * int flevel current IF-ELSE-ENDIF level
961 * int tlevel current IF-ELSE-ENDIF level index
962 * int lnlist current LIST-NLIST flags
963 * int mcrline current macro line number
964 *
965 * functions called:
966 * asexit() asmain.c
967 * fprintf() c_library
968 * macroscn() asmcro.c
969 * strncpy() c_library
970 *
971 * side effects:
972 * mcrline, the current macro line number
973 * is updated.
974 */
975
976 char *
fgetm(ptr,len,fp)977 fgetm(ptr, len, fp)
978 char *ptr;
979 int len;
980 FILE *fp;
981 {
982 struct macrofp *nfp;
983 struct mcrdef *np;
984
985 /*
986 * macroscn() and macrosub()
987 * require that ptr == ib !!!
988 */
989 if (ptr != ib) {
990 fprintf(stderr, "?ASxxxx-Internal-fgetm(ptr)-Error.\n\n");
991 asexit(ER_FATAL);
992 }
993 ip = ptr;
994
995 if (fp == NULL) {
996 fprintf(stderr, "?ASxxxx-Internal-fgetm(fp)-Error srcline %d.\n\n", srcline);
997 asexit(ER_FATAL);
998 }
999
1000 nfp = (struct macrofp *) fp;
1001 np = nfp->np;
1002
1003 if (nfp->lstptr == NULL) {
1004 if (nfp->npexit == 0) {
1005 if ((flevel != nfp->flevel) ||
1006 (tlevel != nfp->tlevel)) {
1007 err('i');
1008 }
1009 }
1010 /*
1011 * Repeat macro until repeat count is zero or an
1012 * .mexit has been processed then exit with NULL
1013 */
1014 if ((--nfp->rptcnt <= 0) || (nfp->npexit != 0)) {
1015 return(NULL);
1016 } else {
1017 nfp->lstptr = np->bgnlst;
1018 nfp->rptidx += 1;
1019 mcrline = 0;
1020 }
1021 /*
1022 * Reset IF-ELSE-ENDIF and LIST-NLIST levels
1023 */
1024 flevel = nfp->flevel;
1025 tlevel = nfp->tlevel;
1026 lnlist = nfp->lnlist;
1027 }
1028 strncpy(ptr, nfp->lstptr->text, len);
1029 ptr[len-1] = '\0';
1030 nfp->lstptr = nfp->lstptr->next;
1031 /*
1032 * Macro String Processing
1033 */
1034 switch (np->type) {
1035 case O_MACRO:
1036 case O_IRP:
1037 case O_IRPC:
1038 macroscn(nfp);
1039 break;
1040
1041 case O_REPT:
1042 default:
1043 break;
1044 }
1045
1046 /*
1047 * Return Macro String
1048 */
1049 return(ptr);
1050 }
1051
1052 /*)Function VOID macroscn(nfp)
1053 *
1054 * struct macrofp * nfp a Macro 'FILE Handle'
1055 *
1056 * The function mcroscn() scans the macro text line
1057 * for a valid substitutable string. The only valid targets
1058 * for substitution strings are strings beginning with a
1059 * LETTER and containing any combination of DIGITS and LETTERS.
1060 * If a valid target is found then the function macrosub() is
1061 * called to search the macro definition argument list.
1062 *
1063 * local variables:
1064 * int c temporary character value
1065 * char id[] a string of maximum length NINPUT
1066 *
1067 * global variables:
1068 * char ctype[] a character array which defines the
1069 * type of character being processed.
1070 * The index is the character
1071 * being processed.
1072 *
1073 * called functions:
1074 * int endline() aslex.c
1075 * int getid() aslex.c
1076 * int macrosub() asmcro.c
1077 * int unget() aslex.c
1078 *
1079 * side effects:
1080 * The assembler-source text line may be updated
1081 * and a substitution made for the string id[].
1082 */
1083
1084 VOID
macroscn(nfp)1085 macroscn(nfp)
1086 struct macrofp *nfp;
1087 {
1088 int c;
1089 char id[NINPUT];
1090
1091 while ((c = endline()) != 0) {
1092 if (ctype[c] & DIGIT) {
1093 while (ctype[c] & (LETTER|DIGIT)) c = get();
1094 unget(c);
1095 } else
1096 if (ctype[c] & LETTER) {
1097 getid(id, c);
1098 if (macrosub(id, nfp)) {
1099 return;
1100 }
1101 }
1102 }
1103 return;
1104 }
1105
1106
1107 /*)Function int macrosub(id, nfp)
1108 *
1109 * char * id a pointer to the search string
1110 * of maximum length NINPUT
1111 * macrofp *nfp a Macro 'FILE Handle'
1112 *
1113 * The function macrosub() scans the current macro's argument
1114 * definition list for a match to the string id[]. If a match
1115 * is found then a substitution is made with the corresponding
1116 * expansion argument.
1117 *
1118 * local variables:
1119 * int arglen definition argument string length
1120 * int indx repeat argument index
1121 * char * p pointer to definition argument string
1122 * struct strlst *arg pointer to macro definition arguments
1123 * struct strlst *xrg pointer to macro expansion arguments
1124 * int xrglen length of xarg
1125 * char xrgstr[] temporary argument string
1126 *
1127 * global variables:
1128 * char ib[] source text line
1129 * char * ip pointer into the source text line
1130 * int zflag case sensitivity flag
1131 *
1132 * called functions:
1133 * char * strcat() c_library
1134 * char * strcpy() c_library
1135 * int strlen() c_library
1136 * int symeq() assym.c
1137 *
1138 * side effects:
1139 * The source text line may be updated with
1140 * a substitution made for the string id[].
1141 * If there is insufficient space to make
1142 * the substitution then macrosub returns
1143 * a 1, else 0.
1144 */
1145
1146 int
macrosub(id,nfp)1147 macrosub(id, nfp)
1148 char *id;
1149 struct macrofp *nfp;
1150 {
1151 char *p;
1152 char xrgstr[NINPUT*2];
1153 int indx;
1154 struct strlst *arg;
1155 int arglen;
1156 struct strlst *xrg;
1157 int xrglen;
1158
1159 /*
1160 * Check for a macro substitution
1161 */
1162 arg = nfp->np->bgnarg;
1163 xrg = nfp->np->bgnxrg;
1164 while (arg != NULL) {
1165 *xrgstr = '\0';
1166 p = arg->text;
1167 if (nfp->np->type == O_MACRO) {
1168 if (*p == '?') { ++p; }
1169 }
1170 if (symeq(id, p, zflag)) {
1171 indx = nfp->rptidx;
1172 /*
1173 * Substitution string
1174 */
1175 switch (nfp->np->type) {
1176 case O_IRP:
1177 while ((--indx >= 0) && (xrg != NULL)) {
1178 xrg = xrg->next;
1179 }
1180 /* Continue into O_MACRO */
1181 case O_MACRO:
1182 if (xrg != NULL) {
1183 strcpy(xrgstr, xrg->text);
1184 }
1185 break;
1186 case O_IRPC:
1187 if (xrg != NULL) {
1188 xrgstr[0] = xrg->text[indx];
1189 xrgstr[1] = '\0';
1190 }
1191 break;
1192 default:
1193 break;
1194 }
1195 /*
1196 * Lengths
1197 */
1198 arglen = strlen(id);
1199 xrglen = strlen(xrgstr);
1200 /*
1201 * Verify string space is available
1202 */
1203 if ((strlen(ib) - arglen + xrglen) > (NINPUT*2 - 1)) {
1204 return(1);
1205 }
1206 /*
1207 * Beginning of Substitutable string
1208 */
1209 p = ip - arglen;
1210 /*
1211 * Remove a leading '.
1212 */
1213 if (p != ib) {
1214 p -= *(p - 1) == '\'' ? 1 : 0;
1215 }
1216 *p = 0;
1217 /*
1218 * Remove a trailing '.
1219 */
1220 ip += *ip == '\'' ? 1 : 0;
1221 /*
1222 * Append the tail of the original
1223 * string to the new argument string
1224 * and then replace the dummy argument
1225 * and tail with this string.
1226 */
1227 strcat(xrgstr, ip);
1228 strcat(ib, xrgstr);
1229 /*
1230 * Set pointer to first character
1231 * after argument replacement.
1232 */
1233 ip = p + xrglen;
1234 return(0);
1235 }
1236 arg = arg->next;
1237 xrg = xrg->next;
1238 }
1239 return(0);
1240 }
1241
1242 /*)Function VOID * mhunk()
1243 *
1244 * Allocate space.
1245 * Return a pointer to the allocated space.
1246 *
1247 * This function based on code by
1248 * John L. Hartman
1249 * jhartman at compuserve dot com
1250 *
1251 * local variables:
1252 * memlnk *lnk memory link pointer
1253 *
1254 * static variables:
1255 * int bytes bytes remaining in buffer area
1256 * char * pnext next location in buffer area
1257 *
1258 * global variables:
1259 * memlnk mcrmem pointer to 1K Byte block being allocated
1260 * int mcrblk 1K Byte block allocations
1261 * memlnk pmcrmem pointer to first 1K Byte block allocated
1262 *
1263 * functions called:
1264 * VOID * new() assym.c
1265 *
1266 * side effects:
1267 * Space allocated for object.
1268 * Out of Space terminates assembler.
1269 */
1270
1271 /*
1272 * To avoid wasting memory headers on small allocations
1273 * allocate a big chunk and parcel it out as required.
1274 *
1275 * Hunks are linked to allow reuse during each pass
1276 * of the assembler.
1277 */
1278
1279 #define MCR_SPC 1024
1280
1281 /*
1282 * MCR_MSK = 1 for a 2 byte boundary
1283 * MCR_MSK = 3 for a 4 byte boundary
1284 * MCR_MSK = 7 for a 8 byte boundary
1285 */
1286
1287 #define MCR_MSK 3
1288
1289 static char * pnext;
1290 static int bytes;
1291
1292 VOID *
mhunk()1293 mhunk()
1294 {
1295 struct memlnk *lnk;
1296
1297 /*
1298 * 1st Call Initializes Linked Hunks
1299 */
1300 if (pmcrmem == NULL) {
1301 lnk = (struct memlnk *) new (sizeof(struct memlnk));
1302 lnk->ptr = (VOID *) new (MCR_SPC);
1303 lnk->next = NULL;
1304 pmcrmem = mcrmem = lnk;
1305 mcrblk = 1;
1306 } else
1307 /*
1308 * Start Reuse of Linked Hunks
1309 */
1310 if (mcrmem == NULL) {
1311 mcrmem = pmcrmem;
1312 } else
1313 /*
1314 * Allocate a New Hunk
1315 */
1316 if (mcrmem->next == NULL) {
1317 lnk = (struct memlnk *) new (sizeof(struct memlnk));
1318 lnk->ptr = (VOID *) new (MCR_SPC);
1319 lnk->next = NULL;
1320 mcrmem->next = lnk;
1321 mcrmem = lnk;
1322 mcrblk += 1;
1323 } else {
1324 /*
1325 * Reuse Next Hunk
1326 */
1327 mcrmem = mcrmem->next;
1328 }
1329 pnext = (char *) mcrmem->ptr;
1330 bytes = MCR_SPC;
1331
1332 return(pnext);
1333 }
1334
1335 /*)Function char * mstring(str)
1336 *
1337 * char * str pointer to string to save
1338 *
1339 * Allocate space for "str", copy str into new space.
1340 * Return a pointer to the allocated string.
1341 *
1342 * This function based on code by
1343 * John L. Hartman
1344 * jhartman at compuserve dot com
1345 *
1346 * local variables:
1347 * int len string length + 1
1348 * int bytes bytes remaining in buffer area
1349 *
1350 * static variables:
1351 * char * p pointer to head of copied string
1352 * char * pnext next location in buffer area
1353 *
1354 * global variables:
1355 * none
1356 *
1357 * functions called:
1358 * VOID * mhunk() asmcro.c
1359 * char * strcpy() c_library
1360 * int strlen() c_library
1361 *
1362 * side effects:
1363 * Space allocated for string, string copied
1364 * to space. Out of Space terminates assembler.
1365 */
1366
1367 char *
mstring(str)1368 mstring(str)
1369 char *str;
1370 {
1371 int len;
1372 char *p;
1373
1374 /*
1375 * What we need, including a null.
1376 */
1377 len = strlen(str) + 1;
1378
1379 if (len > bytes) {
1380 p = mhunk();
1381 } else {
1382 p = pnext;
1383 }
1384 pnext += len;
1385 bytes -= len;
1386
1387 /*
1388 * Copy the name and terminating null.
1389 */
1390 strcpy(p, str);
1391
1392 return(p);
1393 }
1394
1395 /*)Function char * mstruct(n)
1396 *
1397 * int n size required
1398 *
1399 * Allocate n bytes of space.
1400 * Return a pointer to the allocated space.
1401 * Structure boundary is defined by MCR_MSK.
1402 *
1403 * local variables:
1404 * int bofst calculated boundary offset
1405 * int bytes bytes remaining in buffer area
1406 *
1407 * static variables:
1408 * char * p pointer to head of copied string
1409 * char * pnext next location in buffer area
1410 *
1411 * global variables:
1412 * none
1413 *
1414 * functions called:
1415 * VOID * mhunk() asmcro.c
1416 *
1417 * side effects:
1418 * Space allocated.
1419 * Out of Space terminates assembler.
1420 */
1421
1422 char *
mstruct(n)1423 mstruct(n)
1424 int n;
1425 {
1426 int bofst;
1427 char *p;
1428
1429 /*
1430 * Memory Boundary Fixup
1431 */
1432 bofst = bytes & MCR_MSK;
1433
1434 pnext += bofst;
1435 bytes -= bofst;
1436
1437 if (n > bytes) {
1438 p = mhunk();
1439 } else {
1440 p = pnext;
1441 }
1442 pnext += n;
1443 bytes -= n;
1444
1445 return(p);
1446 }
1447
1448 /*)Function VOID mcrinit()
1449 *
1450 * Initialize Macro Processor Variables
1451 *
1452 * static variables:
1453 * int bytes bytes remaining in buffer area
1454 * char * pnext next location in buffer area
1455 *
1456 * global variables:
1457 * struct sym mls Macro local symbol
1458 * int mcrfil macro nesting counter
1459 * int maxmcr maximum macro nesting emcountered
1460 * int mcrline current macro line number
1461 *
1462 * struct mcrdef *mcrlst link to list of defined macros
1463 * struct mcrdef *mcrp macro being defined
1464 * struct memlnk *mcrmem Macro Memory Allocation Structure
1465 *
1466 * functions called:
1467 * none
1468 *
1469 * side effects:
1470 * Prepares values for next assembler pass.
1471 */
1472
1473 VOID
mcrinit()1474 mcrinit()
1475 {
1476 mls.s_addr = 10000;
1477
1478 mcrfil = 0;
1479 maxmcr = 0;
1480 mcrline = 0;
1481
1482 mcrlst = NULL;
1483 mcrp = NULL;
1484 mcrmem = NULL;
1485
1486 pnext = NULL;
1487 bytes = 0;
1488 }
1489