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