struct / union in initializer, RFE #901.
[sdcc.git] / sdcc / sdas / asxxsrc / asmcro.c
blob38eb22788e02ba5245e746611573fae99e77c6e4
1 /* asmcro.c */
3 /*
4 * Copyright (C) 2010-2021 Alan R. Baldwin
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.
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.
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/>.
20 * Alan R. Baldwin
21 * 721 Berkeley St.
22 * Kent, Ohio 44240
25 #include "asxxxx.h"
27 /*)Module asmcro.c
29 * The module asmcro.c includes the macro processor.
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
47 /*)Function int mcrprc(code))
49 * int code function code
51 * The function of mcrprc() is to evaluate the
52 * following assembler directives:
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
66 * And to control the building and exiting of a macro
67 * by the use of the internal assembler directives:
69 * O_BUILD building a macro processing
70 * O_EXIT exit a macro processing
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
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
92 * functions called:
93 * a_uint absexpr() asexpr.c
94 * VOID clrexpr() asexpr.c
95 * int comma() aslex.c
96 * VOID err() assubr.c
97 * VOID getdarg() asmcro.c
98 * int getid() aslex.c
99 * int getdlm() aslex.c
100 * int getmap() aslex.c
101 * int getnb() aslex.c
102 * VOID getxarg() asmcro.c
103 * sym * lookup() assym.c
104 * VOID macro() asmcro.c
105 * mne * mlookup() assym.c
106 * int more() aslex.c
107 * char * mstring() asmcro.c
108 * VOID * mstruct() asmcro.c
109 * mcrdef *newdef() asmcro.c
110 * VOID qerr() assubr.c
111 * VOID unget() aslex.c
112 * VOID xerr() assubr.c
114 * side effects:
115 * Macro directives processed and
116 * macro structures created.
119 mcrprc(code)
120 int code;
122 struct mcrdef *np,*nq;
123 struct macrofp *nfp;
124 struct strlst *str;
125 struct mne *mp;
126 struct sym *sp;
127 struct expr e1;
128 char id[NCPS];
129 int d, rptcnt;
131 switch(code) {
132 case O_MACRO:
134 * Valid .macro definition forms:
136 * .macro mne(,)
137 * .macro mne(,) arg1(,) arg2(,) ((,) arg3(,) ...(,) argn)
139 * where 'mne' is a string beginning with a
140 * LETTER followed by LETTERs or DIGITs.
142 * If the 'arg' is immediately preceeded by a '?'
143 * (ie ?arg) then the argument is a dummy argument.
144 * Dummy arguments left blank become local symbols
145 * when the macro is expanded.
148 * Get macro mnemonic
150 if (more()) {
151 getid(id, getnb());
152 } else {
153 xerr('q', ".macro requires at least one argument.");
155 np = newdef(code, id);
157 * Get macro definition arguments
159 while (more()) {
160 getdarg(np);
162 break;
164 case O_IRP:
166 * Valid .irp definition forms:
168 * .irp sym(,)
169 * .irp sym(,) arg1(,) arg2 ((,) arg3(,) ...(,) argn)
171 * where 'sym' is a string beginning with
172 * a LETTER followed by LETTERs or DIGITs.
174 * The complete .irp definition is processed once
175 * for each argument in the .irp definition.
178 * An inline definition
180 np = newdef(code, NULL);
182 * Get macro definition argument
184 getdarg(np);
186 * Get expansion arguments
188 while (more()) {
189 getxarg(np);
191 np->rptcnt = np->xarg;
192 break;
194 case O_IRPC:
196 * Valid .irpc definition forms:
198 * .irpc sym(,)
199 * .irpc sym(,) character_string
201 * where 'sym' is a string beginning with
202 * a LETTER followed by LETTERs or DIGITs.
204 * The complete .irpc definition is processed once
205 * for each character in the character_string.
207 * If the character_string contains white space
208 * or commas then the character string must be
209 * delimited as ^/character_string/ where the
210 * delimiting character ('/') must not be in
211 * the string.
214 * An inline definition
216 np = newdef(code, NULL);
218 * Get macro definition argument
220 getdarg(np);
222 * Get expansion argument
224 getxarg(np);
225 np->rptcnt = (np->bgnxrg != NULL) ? strlen(np->bgnxrg->text) : 0;
226 break;
228 case O_REPT:
230 * Valid .rept definition forms:
232 * .rept sym
234 * where 'sym' is a symbol or expression which
235 * is evalauated to an absolute value.
237 * The complete .rept definition is processed
238 * value times.
241 * An inline definition
243 np = newdef(code, NULL);
245 * Get repeat count
247 if (more()) {
248 unget(getnb());
249 rptcnt = (int) absexpr();
250 if (rptcnt < 0) {
251 rptcnt = 0;
253 } else {
254 xerr('o', ".rept requires a repeat count.");
255 rptcnt = 0;
257 np->rptcnt = rptcnt;
258 break;
260 case O_ENDM:
261 if (asmc->objtyp != T_MACRO) {
262 xerr('n', ".endm found without matching .macro.");
263 } else {
264 lmode = NLIST;
266 break;
268 case O_MEXIT:
269 if (asmc->objtyp == T_MACRO) {
270 nfp = (struct macrofp *) asmc->fp;
271 nfp->npexit = 1;
272 nfp->lstptr = nfp->np->endlst;
273 } else {
274 xerr('n', ".mexit found outside of a macro.");
276 break;
278 case O_NCHR:
279 getid(id, -1);
280 sp = lookup(id);
281 if (sp == &dot) {
282 err('.');
283 break;
285 sp->s_flag |= S_ASG;
286 sp->s_type = S_USER;
287 comma(0);
288 d = getdlm();
289 rptcnt = 0;
290 while (getmap(d) >= 0) {
291 rptcnt += 1;
293 lmode = ELIST;
294 laddr = sp->s_addr = rptcnt;
295 break;
297 case O_NARG:
298 nfp = (struct macrofp *) asmc->fp;
299 np = nfp->np;
300 if (asmc->objtyp != T_MACRO) {
301 xerr('n', ".narg found outside of a macro.");
302 break;
303 } else
304 if (np->type != O_MACRO) {
305 err('n');
306 break;
308 getid(id, -1);
309 sp = lookup(id);
310 if (sp == &dot) {
311 err('.');
312 break;
314 sp->s_flag |= S_ASG;
315 sp->s_type = S_USER;
316 lmode = ELIST;
317 laddr = sp->s_addr = np->xarg;
318 break;
320 case O_NTYP:
321 getid(id, -1);
322 sp = lookup(id);
323 sp->s_flag |= S_ASG;
324 sp->s_type = S_USER;
325 sp->s_area = NULL;
326 comma(0);
327 clrexpr(&e1);
328 expr(&e1, 0);
329 lmode = ELIST;
330 laddr = sp->s_addr = (e1.e_flag || e1.e_base.e_ap) ? 1 : 0;
331 break;
333 case O_NVAL:
334 getid(id, -1);
335 sp = lookup(id);
336 if (sp == &dot) {
337 err('.');
338 break;
340 sp->s_flag |= S_ASG;
341 sp->s_type = S_USER;
342 sp->s_area = NULL;
343 comma(0);
344 clrexpr(&e1);
345 expr(&e1, 0);
346 lmode = ELIST;
347 laddr = sp->s_addr = e1.e_addr;
348 break;
350 case O_MDEL:
351 while (more()) {
352 getid(id, getnb());
353 np = nlookup(id);
354 if (np != NULL) {
355 if (np == mcrlst) {
356 mcrlst = np->next;
357 } else {
358 nq = mcrlst;
359 while (nq != NULL) {
360 if (np == nq->next) {
361 nq->next = np->next;
362 break;
364 nq = nq->next;
368 if (more() && comma(0) && !more()) {
369 xerr('q', "Expecting argument after ','.");
372 break;
374 case O_CHECK:
375 if (mcrp == NULL) {
376 if (asmc->objtyp == T_MACRO) {
377 nfp = (struct macrofp *) asmc->fp;
378 if (nfp->npexit) {
379 lmode = NLIST;
380 return(1);
383 return(0);
385 while (more()) {
386 getid(id, getnb());
387 if (((mp = mlookup(id)) != NULL) &&
388 (mp->m_type == S_MACRO)) {
389 switch (mp->m_valu) {
390 case O_MACRO:
391 case O_IRP:
392 case O_IRPC:
393 case O_REPT:
394 mcrp->nest += 1;
395 break;
396 case O_ENDM:
397 mcrp->nest -= 1;
398 break;
399 default:
400 break;
402 break;
406 * Append to MACRO Definition
408 str = (struct strlst *) mstruct (sizeof (struct strlst));
409 str->next = NULL;
410 str->text = mstring(ib);
411 if (mcrp->bgnlst == NULL) {
412 mcrp->bgnlst = str;
413 } else {
414 mcrp->endlst->next = str;
416 mcrp->endlst = str;
418 * Check for .ENDM
420 if (mcrp->nest == 0) {
421 switch (mcrp->type) {
422 case O_MACRO:
423 mcrp->next = mcrlst;
424 mcrlst = mcrp;
425 break;
426 case O_IRP:
427 case O_IRPC:
428 case O_REPT:
429 if (mcrp->rptcnt != 0) {
430 macro(mcrp);
432 break;
433 default:
434 break;
436 mcrp = NULL;
438 if ((lnlist & LIST_MD) == 0) {
439 lmode = NLIST;
441 return(1);
443 default:
444 break;
446 return(0);
449 /*)Function VOID getdarg(np)
451 * struct mcrdef *np pointer to macro definition structure
453 * The function getdarg() gets the next macro definition
454 * argument from the assembler input text. The definiton
455 * may be any valid label or symbol (excluding temporary
456 * symbols).
458 * local variables:
459 * strlst *str text line structure
460 * char id[] text string
461 * int c character
463 * global variables:
464 * char ctype[] charcter type array
465 * mcrdef mcrp link to macro definition being built
467 * functions called:
468 * int comma() aslex.c
469 * int getid() aslex.c
470 * int getnb() aslex.c
471 * char * mstring() asmcro.c
472 * VOID * mstruct() asmcro.c
473 * VOID qerr() assubr.c
475 * side effects:
476 * Macro definition argument is added to macro definition
477 * structure and the number of arguments is incremented.
478 * Failure to allocate space for the argument string will
479 * terminate the assembler.
482 VOID
483 getdarg(struct mcrdef *np)
485 struct strlst *str;
486 char id[NCPS];
487 int c;
490 * Skip leading ','
492 comma(0);
493 if (more()) {
494 if (((c=getnb()) == '?') && (ctype[c=get()] & LETTER)) {
495 unget(c);
496 c = '?';
497 } else
498 if (ctype[c] & LETTER) {
500 } else {
501 qerr();
503 getid(id, c);
504 } else {
505 qerr();
507 str = (struct strlst *) mstruct (sizeof (struct strlst));
508 str->next = NULL;
509 str->text = mstring(id);
510 if (np->bgnarg == NULL) {
511 np->bgnarg = str;
512 } else {
513 np->endarg->next = str;
515 np->endarg = str;
516 np->narg += 1;
519 /*)Function VOID getxarg(np)
521 * struct mcrdef *np pointer to macro definition structure
523 * The function getxarg() gets the next macro expansion
524 * argument from the assembler input text. The expansion
525 * may contain any ASCII character including the space and
526 * tab characters. If the argument contains a comma then
527 * the argument string must be delimited using the form
529 * ^/ ... / where the character '/' may be any
530 * printing character not in the delimited string.
532 * If the undelimited string is of the form \arg then
533 * the argument is evaluated and represented by an
534 * unsigned integer in the current radix.
536 * local variables:
537 * char id[] text string
538 * char * frmt format string pointer
539 * char * sip save ip pointer
540 * strlst *str text line structure
542 * global variables:
543 * char * ip source text line pointer
545 * functions called:
546 * a_uint absexpr() asexpr.c
547 * VOID getxstr() asmcro.c
548 * char * mstring() asmcro.c
549 * VOID * mstruct() asmcro.c
550 * int sprintf() c_library
552 * side effects:
553 * Macro expansion argument is added to macro definition
554 * structure and the number of arguments is incremented.
555 * Failure to allocate space for the argument string will
556 * terminate the assembler.
559 VOID
560 getxarg(struct mcrdef *np)
562 struct strlst *str;
563 char id[NCPS];
564 char *frmt;
565 char *sip;
568 * Get the argument string
570 getxstr(id);
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;
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;
591 #endif
592 sprintf(id, frmt, absexpr());
593 ip = sip;
595 str->text = mstring(id);
596 if (np->bgnxrg == NULL) {
597 np->bgnxrg = str;
598 } else {
599 np->endxrg->next = str;
601 np->endxrg = str;
602 np->xarg += 1;
605 /*)Function VOID getxstr(id)
607 * char * id pointer to string
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
615 * ^/ ... / where the character '/' may be any
616 * printing character not in the delimited string.
618 * local variables:
619 * int c character
620 * int dc delimiting character
621 * char * p character string pointer
623 * global variables:
624 * char ctype[] charcter type array
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
633 * side effects:
634 * Macro expansion argument is returned in id[].
637 VOID
638 getxstr(char *id)
640 char *p;
641 int c, dc;
644 * The argument delimiters are SPACE, TAB, and ','.
645 * If the argument contains a SPACE, TAB, or ',' then
646 * the argument must be enclosed within a delimiter of
647 * the form ^/ ... / where the character '/' may
648 * be any character not in the delimited string.
650 p = id;
652 * Skip leading ','
654 comma(0);
655 switch (c=getnb()) {
656 case '^': dc = get(); break;
657 default: dc = ','; break;
659 switch (c) {
660 case '^':
661 while ((c=get()) != '\0') {
662 if (c == dc) {
663 break;
665 *p++ = c;
667 if (ctype[c] & ILL) {
668 qerr();
670 break;
671 default:
672 unget(c);
673 while ((c=get()) != '\0') {
674 if ((c == dc) ||
675 (c == ' ') ||
676 (c == '\t') ||
677 (c == ';')) {
678 unget(c);
679 break;
681 *p++ = c;
683 break;
685 *p = '\0';
688 /*)Function VOID macro(np)
690 * mcrdef *np macro definition structure
692 * macro() prepares the macro described by
693 * np for insertion into the code stream.
695 * local variables:
696 * macrofp *nfp pseudo FILE Handle
697 * strlst *str missing argument expansion string
698 * strlst *arg macro definition argument string
699 * strlst *xrg macro expansion argument string
700 * char xrgstr[] dumby argument evaluation string
702 * global variables:
703 * asmf asmq queued macro structure
704 * int srcline current assembler line number
705 * int flevel current IF-ELSE-ENDIF level
706 * int tlevel current IF-ELSE-ENDIF level index
707 * int maxmcr maximum macro nesting level encountered
708 * int mcrfil macro nesting counter
709 * int lnlist current LIST-NLIST flags
711 * functions called:
712 * VOID getxarg() asmcro.c
713 * char * mstring() asmcro.c
714 * VOID * mstruct() asmcro.c
715 * char * strcpy() c_library
716 * int sprintf() c_library
717 * int strlen() c_library
718 * VOID qerr() assubr.c
720 * side effects:
721 * Macro is inserted into assembler stream
724 VOID
725 macro(np)
726 struct mcrdef * np;
728 struct macrofp *nfp;
729 struct strlst *str;
730 struct strlst *arg;
731 struct strlst *xrg;
732 char xrgstr[NINPUT];
734 if (++mcrfil > MAXMCR) {
735 --mcrfil;
736 err('m');
737 return;
739 if (mcrfil > maxmcr) {
740 maxmcr = mcrfil;
743 * Create an asmf structure for nxtline()
745 asmq = (struct asmf *) mstruct (sizeof (struct asmf));
746 asmq->next = asmc;
747 asmq->objtyp = T_MACRO;
748 asmq->line = srcline;
749 if (ftflevel != 0) {
750 asmq->flevel = ftflevel - 1;
751 ftflevel = 0;
752 } else {
753 asmq->flevel = flevel;
755 asmq->tlevel = tlevel;
756 asmq->lnlist = lnlist;
757 asmq->afp = 0;
758 strcpy(asmq->afn,np->name);
760 * Create a macrofp structure for fgetm()
762 nfp = (struct macrofp *) mstruct (sizeof (struct macrofp));
763 nfp->np = np;
764 nfp->lstptr = np->bgnlst;
765 nfp->rptcnt = np->rptcnt;
766 nfp->rptidx = 0;
767 nfp->flevel = asmq->flevel;
768 nfp->tlevel = asmq->tlevel;
769 nfp->lnlist = asmq->lnlist;
770 nfp->npexit = nfp->rptcnt ? 0 : 1;
772 * Check if arguments are required
774 if (np->type == O_MACRO) {
775 np->xarg = 0;
776 np->bgnxrg = NULL;
777 np->endxrg = NULL;
778 while (more()) {
779 getxarg(np);
781 if (np->xarg > np->narg) {
782 qerr();
785 * Fill in missing arguments and
786 * check for dummy arguments.
788 arg = np->bgnarg;
789 xrg = np->bgnxrg;
790 while (arg != NULL) {
791 if (xrg == NULL) {
792 str = (struct strlst *) mstruct (sizeof (struct strlst));
793 str->next = NULL;
794 str->text = mstring("");
795 if (np->bgnxrg == NULL) {
796 np->bgnxrg = str;
797 } else {
798 np->endxrg->next = str;
800 np->endxrg = str;
801 xrg = str;
803 if ((*arg->text == '?') && (strlen(xrg->text) == 0)) {
804 #ifdef LONGINT
805 sprintf(xrgstr, "%lu$", mls.s_addr++);
806 #else
807 sprintf(xrgstr, "%u$", mls.s_addr++);
808 #endif
809 xrg->text = mstring(xrgstr);
811 arg = arg->next;
812 xrg = xrg->next;
816 * Cast nfp as a FILE HANDLE
818 asmq->fp = (FILE *) nfp;
820 return;
823 /*)Function mcrdef *newdef(code, id)
825 * int code macro type code
826 * char * id macro name string
828 * The function mcrdef() creates a new macro
829 * definition structure and initializes it.
831 * local variables:
832 * mne * mp pointer to a mnemonic structure
834 * global variables:
835 * mcrdef *mcrp pointer to the new macro definition structure
837 * functions called:
838 * mne * mlookup() assym.c
839 * char * mstring() asmcro.c
840 * VOID * mstruct() asmcro.c
841 * mne * nlookup() asmcro.c
843 * side effects:
844 * Macro definiton structure created
845 * and initialized.
848 struct mcrdef *
849 newdef(code, id)
850 int code;
851 char *id;
853 struct mne *mp;
856 * New MACRO Definition
858 mcrp = (struct mcrdef *) mstruct (sizeof (struct mcrdef));
859 mcrp->next = NULL;
861 * Check for Assembler Directive Conflicts
863 if (id != NULL) {
864 if (nlookup(id) != NULL) {
865 err('m');
867 mcrp->name = mstring(id);
868 mp = mlookup(id);
869 if (mp != NULL) {
870 if (mp->m_type < S_DIREOL) {
871 err('m');
874 } else {
875 mcrp->name = mstring("");
877 mcrp->bgnlst = NULL;
878 mcrp->endlst = NULL;
879 mcrp->type = code;
880 mcrp->rptcnt = 1;
881 mcrp->nest = 1;
882 mcrp->narg = 0;
883 mcrp->bgnarg = NULL;
884 mcrp->endarg = NULL;
885 mcrp->xarg = 0;
886 mcrp->bgnxrg = NULL;
887 mcrp->endxrg = NULL;
888 return (mcrp);
891 /*)Function mcrdef *nlookup(id)
893 * char * id macro name string
895 * The function nlookup() searches the macro list
896 * for a match returning a pointer to the macro
897 * definition structure else it returns a NULL.
899 * local variables:
900 * mcrdef *np pointer to macro structure
902 * global variables:
903 * none
905 * functions called:
906 * symeq() assym.c
908 * side effects:
909 * none
912 struct mcrdef *
913 nlookup(id)
914 char *id;
916 struct mcrdef * np;
918 np = mcrlst;
919 while (np != NULL) {
920 if (symeq(id, np->name, 1)) {
921 return (np);
923 np = np->next;
925 return (NULL);
928 /*)Function char *fgetm(ptr, len, fp)
930 * char * ptr pointer string address
931 * int len maximum number of characters to return
932 * FILE * fp pseudo FILE Handle
934 * The function fgetm() reads characters from the pseudo
935 * stream fp into the string pointed to by ptr. The integer
936 * argument len indicates the maximum number of characters
937 * that the buffer ptr can store. Reading stops when an end
938 * of string or len-1 characters were read. The string read
939 * is terminated with a 0.
941 * Macro types O_MACRO, O_IRP, and O_IRPC will have
942 * the macro definition strings replaced by their
943 * respective macro expression strings.
945 * When no more macro lines are available then
946 * the macro terminates by restoring the assembler
947 * conditional and listing state at the time the
948 * macro was invoked and a NULL is returned.
950 * local variables:
951 * macrofp *nfp pointer to the pseudo FILE Handle
952 * mcrdef *np pointer to macro structure
954 * global variables:
955 * char ib[] string buffer containing
956 * assembler-source text line for processing
957 * char * ip pointer into the assembler-source
958 * text line in ib[]
959 * int flevel current IF-ELSE-ENDIF level
960 * int tlevel current IF-ELSE-ENDIF level index
961 * int lnlist current LIST-NLIST flags
962 * int mcrline current macro line number
964 * functions called:
965 * asexit() asmain.c
966 * fprintf() c_library
967 * macroscn() asmcro.c
968 * strncpy() c_library
970 * side effects:
971 * mcrline, the current macro line number
972 * is updated.
975 char *
976 fgetm(char *ptr, int len, FILE *fp)
978 struct macrofp *nfp;
979 struct mcrdef *np;
982 * macroscn() and macrosub()
983 * require that ptr == ib !!!
985 if (ptr != ib) {
986 fprintf(stderr, "?ASxxxx-Internal-fgetm(ptr)-Error.\n\n");
987 asexit(ER_FATAL);
989 ip = ptr;
991 if (fp == NULL) {
992 fprintf(stderr, "?ASxxxx-Internal-fgetm(fp)-Error srcline %d.\n\n", srcline);
993 asexit(ER_FATAL);
996 nfp = (struct macrofp *) fp;
997 np = nfp->np;
999 if (nfp->lstptr == NULL) {
1000 if (nfp->npexit == 0) {
1001 if ((flevel != nfp->flevel) ||
1002 (tlevel != nfp->tlevel)) {
1003 err('i');
1007 * Repeat macro until repeat count is zero or an
1008 * .mexit has been processed then exit with NULL
1010 if ((--nfp->rptcnt <= 0) || (nfp->npexit != 0)) {
1011 return(NULL);
1012 } else {
1013 nfp->lstptr = np->bgnlst;
1014 nfp->rptidx += 1;
1015 mcrline = 0;
1018 * Reset IF-ELSE-ENDIF and LIST-NLIST levels
1020 flevel = nfp->flevel;
1021 tlevel = nfp->tlevel;
1022 lnlist = nfp->lnlist;
1024 strncpy(ptr, nfp->lstptr->text, len);
1025 ptr[len-1] = '\0';
1026 nfp->lstptr = nfp->lstptr->next;
1028 * Macro String Processing
1030 switch (np->type) {
1031 case O_MACRO:
1032 case O_IRP:
1033 case O_IRPC:
1034 macroscn(nfp);
1035 break;
1037 case O_REPT:
1038 default:
1039 break;
1043 * Return Macro String
1045 return(ptr);
1048 /*)Function VOID macroscn(nfp)
1050 * struct macrofp * nfp a Macro 'FILE Handle'
1052 * The function mcroscn() scans the macro text line
1053 * for a valid substitutable string. The only valid targets
1054 * for substitution strings are strings beginning with a
1055 * LETTER and containing any combination of DIGITS and LETTERS.
1056 * If a valid target is found then the function macrosub() is
1057 * called to search the macro definition argument list.
1059 * local variables:
1060 * int c temporary character value
1061 * char id[] a string of maximum length NINPUT
1063 * global variables:
1064 * char ctype[] a character array which defines the
1065 * type of character being processed.
1066 * The index is the character
1067 * being processed.
1069 * called functions:
1070 * int endline() aslex.c
1071 * int getid() aslex.c
1072 * int macrosub() asmcro.c
1073 * int unget() aslex.c
1075 * side effects:
1076 * The assembler-source text line may be updated
1077 * and a substitution made for the string id[].
1080 VOID
1081 macroscn(nfp)
1082 struct macrofp *nfp;
1084 int c;
1085 char id[NINPUT];
1087 while ((c = endline()) != 0) {
1088 if (ctype[c] & DIGIT) {
1089 while (ctype[c] & (LETTER|DIGIT)) c = get();
1090 unget(c);
1091 } else
1092 if (ctype[c] & LETTER) {
1093 getid(id, c);
1094 if (macrosub(id, nfp)) {
1095 return;
1099 return;
1103 /*)Function int macrosub(id, nfp)
1105 * char * id a pointer to the search string
1106 * of maximum length NINPUT
1107 * macrofp *nfp a Macro 'FILE Handle'
1109 * The function macrosub() scans the current macro's argument
1110 * definition list for a match to the string id[]. If a match
1111 * is found then a substitution is made with the corresponding
1112 * expansion argument.
1114 * local variables:
1115 * int arglen definition argument string length
1116 * int indx repeat argument index
1117 * char * p pointer to definition argument string
1118 * struct strlst *arg pointer to macro definition arguments
1119 * struct strlst *xrg pointer to macro expansion arguments
1120 * int xrglen length of xarg
1121 * char xrgstr[] temporary argument string
1123 * global variables:
1124 * char ib[] source text line
1125 * char * ip pointer into the source text line
1126 * int zflag case sensitivity flag
1128 * called functions:
1129 * char * strcat() c_library
1130 * char * strcpy() c_library
1131 * int strlen() c_library
1132 * int symeq() assym.c
1134 * side effects:
1135 * The source text line may be updated with
1136 * a substitution made for the string id[].
1137 * If there is insufficient space to make
1138 * the substitution then macrosub returns
1139 * a 1, else 0.
1143 macrosub(id, nfp)
1144 char *id;
1145 struct macrofp *nfp;
1147 char *p;
1148 char xrgstr[NINPUT*2];
1149 int indx;
1150 struct strlst *arg;
1151 int arglen;
1152 struct strlst *xrg;
1153 int xrglen;
1156 * Check for a macro substitution
1158 arg = nfp->np->bgnarg;
1159 xrg = nfp->np->bgnxrg;
1160 while (arg != NULL) {
1161 *xrgstr = '\0';
1162 p = arg->text;
1163 if (nfp->np->type == O_MACRO) {
1164 if (*p == '?') { ++p; }
1166 if (symeq(id, p, zflag)) {
1167 indx = nfp->rptidx;
1169 * Substitution string
1171 switch (nfp->np->type) {
1172 case O_IRP:
1173 while ((--indx >= 0) && (xrg != NULL)) {
1174 xrg = xrg->next;
1176 /* Continue into O_MACRO */
1177 case O_MACRO:
1178 if (xrg != NULL) {
1179 strcpy(xrgstr, xrg->text);
1181 break;
1182 case O_IRPC:
1183 if (xrg != NULL) {
1184 xrgstr[0] = xrg->text[indx];
1185 xrgstr[1] = '\0';
1187 break;
1188 default:
1189 break;
1192 * Lengths
1194 arglen = strlen(id);
1195 xrglen = strlen(xrgstr);
1197 * Verify string space is available
1199 if ((strlen(ib) - arglen + xrglen) > (NINPUT*2 - 1)) {
1200 return(1);
1203 * Beginning of Substitutable string
1205 p = ip - arglen;
1207 * Remove a leading '.
1209 if (p != ib) {
1210 p -= *(p - 1) == '\'' ? 1 : 0;
1212 *p = 0;
1214 * Remove a trailing '.
1216 ip += *ip == '\'' ? 1 : 0;
1218 * Append the tail of the original
1219 * string to the new argument string
1220 * and then replace the dummy argument
1221 * and tail with this string.
1223 strcat(xrgstr, ip);
1224 strcat(ib, xrgstr);
1226 * Set pointer to first character
1227 * after argument replacement.
1229 ip = p + xrglen;
1230 return(0);
1232 arg = arg->next;
1233 xrg = xrg->next;
1235 return(0);
1238 /*)Function VOID * mhunk()
1240 * Allocate space.
1241 * Return a pointer to the allocated space.
1243 * This function based on code by
1244 * John L. Hartman
1245 * jhartman at compuserve dot com
1247 * local variables:
1248 * memlnk *lnk memory link pointer
1250 * static variables:
1251 * int bytes bytes remaining in buffer area
1252 * char * pnext next location in buffer area
1254 * global variables:
1255 * memlnk mcrmem pointer to 1K Byte block being allocated
1256 * int mcrblk 1K Byte block allocations
1257 * memlnk pmcrmem pointer to first 1K Byte block allocated
1259 * functions called:
1260 * VOID * new() assym.c
1262 * side effects:
1263 * Space allocated for object.
1264 * Out of Space terminates assembler.
1268 * To avoid wasting memory headers on small allocations
1269 * allocate a big chunk and parcel it out as required.
1271 * Hunks are linked to allow reuse during each pass
1272 * of the assembler.
1275 #define MCR_SPC 1024
1278 * MCR_MSK = 1 for a 2 byte boundary
1279 * MCR_MSK = 3 for a 4 byte boundary
1280 * MCR_MSK = 7 for a 8 byte boundary
1283 #define MCR_MSK 3
1285 static char * pnext;
1286 static int bytes;
1288 VOID *
1289 mhunk()
1291 struct memlnk *lnk;
1294 * 1st Call Initializes Linked Hunks
1296 if (pmcrmem == NULL) {
1297 lnk = (struct memlnk *) new (sizeof(struct memlnk));
1298 lnk->ptr = (VOID *) new (MCR_SPC);
1299 lnk->next = NULL;
1300 pmcrmem = mcrmem = lnk;
1301 mcrblk = 1;
1302 } else
1304 * Start Reuse of Linked Hunks
1306 if (mcrmem == NULL) {
1307 mcrmem = pmcrmem;
1308 } else
1310 * Allocate a New Hunk
1312 if (mcrmem->next == NULL) {
1313 lnk = (struct memlnk *) new (sizeof(struct memlnk));
1314 lnk->ptr = (VOID *) new (MCR_SPC);
1315 lnk->next = NULL;
1316 mcrmem->next = lnk;
1317 mcrmem = lnk;
1318 mcrblk += 1;
1319 } else {
1321 * Reuse Next Hunk
1323 mcrmem = mcrmem->next;
1325 pnext = (char *) mcrmem->ptr;
1326 bytes = MCR_SPC;
1328 return(pnext);
1331 /*)Function char * mstring(str)
1333 * char * str pointer to string to save
1335 * Allocate space for "str", copy str into new space.
1336 * Return a pointer to the allocated string.
1338 * This function based on code by
1339 * John L. Hartman
1340 * jhartman at compuserve dot com
1342 * local variables:
1343 * int len string length + 1
1344 * int bytes bytes remaining in buffer area
1346 * static variables:
1347 * char * p pointer to head of copied string
1348 * char * pnext next location in buffer area
1350 * global variables:
1351 * none
1353 * functions called:
1354 * VOID * mhunk() asmcro.c
1355 * char * strcpy() c_library
1356 * int strlen() c_library
1358 * side effects:
1359 * Space allocated for string, string copied
1360 * to space. Out of Space terminates assembler.
1363 char *
1364 mstring(str)
1365 char *str;
1367 int len;
1368 char *p;
1371 * What we need, including a null.
1373 len = strlen(str) + 1;
1375 if (len > bytes) {
1376 p = mhunk();
1377 } else {
1378 p = pnext;
1380 pnext += len;
1381 bytes -= len;
1384 * Copy the name and terminating null.
1386 strcpy(p, str);
1388 return(p);
1391 /*)Function char * mstruct(n)
1393 * int n size required
1395 * Allocate n bytes of space.
1396 * Return a pointer to the allocated space.
1397 * Structure boundary is defined by MCR_MSK.
1399 * local variables:
1400 * int bofst calculated boundary offset
1401 * int bytes bytes remaining in buffer area
1403 * static variables:
1404 * char * p pointer to head of copied string
1405 * char * pnext next location in buffer area
1407 * global variables:
1408 * none
1410 * functions called:
1411 * VOID * mhunk() asmcro.c
1413 * side effects:
1414 * Space allocated.
1415 * Out of Space terminates assembler.
1418 char *
1419 mstruct(n)
1420 int n;
1422 int bofst;
1423 char *p;
1426 * Memory Boundary Fixup
1428 bofst = bytes & MCR_MSK;
1430 pnext += bofst;
1431 bytes -= bofst;
1433 if (n > bytes) {
1434 p = mhunk();
1435 } else {
1436 p = pnext;
1438 pnext += n;
1439 bytes -= n;
1441 return(p);
1444 /*)Function VOID mcrinit()
1446 * Initialize Macro Processor Variables
1448 * static variables:
1449 * int bytes bytes remaining in buffer area
1450 * char * pnext next location in buffer area
1452 * global variables:
1453 * struct sym mls Macro local symbol
1454 * int mcrfil macro nesting counter
1455 * int maxmcr maximum macro nesting emcountered
1456 * int mcrline current macro line number
1458 * struct mcrdef *mcrlst link to list of defined macros
1459 * struct mcrdef *mcrp macro being defined
1460 * struct memlnk *mcrmem Macro Memory Allocation Structure
1462 * functions called:
1463 * none
1465 * side effects:
1466 * Prepares values for next assembler pass.
1469 VOID
1470 mcrinit()
1472 mls.s_addr = 10000;
1474 mcrfil = 0;
1475 maxmcr = 0;
1476 mcrline = 0;
1478 mcrlst = NULL;
1479 mcrp = NULL;
1480 mcrmem = NULL;
1482 pnext = NULL;
1483 bytes = 0;