home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / BDSC / BDSC-1 / CASM.C < prev    next >
Text File  |  2000-06-30  |  19KB  |  736 lines

  1. /*
  2.     CASM.C    -- written by Leor Zolman, 2/82
  3.  
  4.     CP/M ASM preprocessor: renders MAC.COM and CMAC.LIB unnecessary.
  5.  
  6.     See CASM.DOC for info.
  7.  
  8.     Compile and link with:
  9.  
  10.         cc casm.c -o -e4800
  11.  
  12.         l2 casm usercode
  13.     (or)    clink casm -f usercode
  14.  
  15.     (you can skip linking in 'usercode' if you don't care about being
  16.      able to specify user areas in filenames for the INCLUDE op, but in
  17.      that case be sure to comment out the USERAREAS define.)
  18. */
  19.  
  20. #include <bdscio.h>
  21.  
  22. #define USERAREAS 1        /* comment this out if you don't care about */
  23.                 /* default user areas for included files    */
  24.  
  25. #define TPALOC    0x100        /* base of TPA in your system     */
  26. #define    EQUMAX    500        /* maximum number of EQU ops    */
  27. #define FUNCMAX    100        /* maximum number of functions  */
  28. #define NFMAX    100        /* maximum number of external
  29.                    functions in one function     */
  30. #define LABMAX    150        /* max number of local labels in one func */
  31. #define TXTBUFSIZE 2000        /* max # of chars for labels and needed
  32.                    function names for a single function    */
  33. #define DEFUSER    "2/"        /* default user area for include files    */
  34. #define DEFDISK "C:"        /* default disk for include files    */
  35. #define CASMEXT    ".CSM"        /* extension on input files     */
  36. #define ASMEXT    ".ASM"        /* extension on output files    */
  37. #define DIRSIZE    512        /* max # of byte in CRL directory     */
  38.  
  39.         /* Global data used throughout processing
  40.            of the intput file:            */
  41.  
  42. char    fbuf[BUFSIZ];        /* I/O buffer for main input file    */
  43. char    incbuf[BUFSIZ];        /* I/O buffer for included file     */
  44. char    obuf[BUFSIZ];        /* I/O buffer for output file        */
  45.  
  46. char    *cbufp;            /* pointer to currently active input buf */
  47. char    *cfilnam;        /* pointer to name of current input file */
  48. char    nambuf[30],        /* filenames for current intput */
  49.     nambuf2[30],        /* and output files.        */
  50.     onambuf[30];
  51.  
  52. char    *equtab[EQUMAX];    /* table of absolute symbols    */
  53. int    equcount;        /* # of entries in equtab    */
  54.  
  55. char    *fnames[FUNCMAX];    /* list of functions in the source file */
  56. int    fcount;            /* # of entries in fnames        */
  57.  
  58. int    lino,savlino;        /* line number values used for error     */
  59.                 /* reporting.                */
  60.  
  61. char    doingfunc;        /* true if currently processing a function */
  62.  
  63. char    errf;            /* true if an error has been detected    */
  64.  
  65.         /* Global data used during the processing of a
  66.            single function in the source file:        */
  67.  
  68. char    *nflist[NFMAX];        /* list of needed functions for a function */
  69. int    nfcount;        /* number of entries in nflist    */
  70.  
  71. struct {
  72.     char *labnam;        /* name of function label */
  73.     char defined;        /* whether it has been defined yet */
  74. } lablist[LABMAX];
  75.  
  76. int    labcount;        /* number of local labels in a function */
  77.  
  78. char    txtbuf[TXTBUFSIZE],    /* where text of needed function names    */
  79.     *txtbufp;        /* and function labels go        */
  80.  
  81. char     linbuf[150],        /* text line buffers    */
  82.     linsav[150],
  83.     workbuf[150],
  84.     pbuf[150], *pbufp;
  85.  
  86. char    *cfunam;        /* pointer to name of current function */
  87. int    relblc;            /* relocation object count for a function */
  88.  
  89. char    pastnfs;        /* true if we've passed all needed function */
  90.                 /* declarations ("external" pseudo ops)        */
  91.  
  92. int    argcnt;            /* values set by the "parse_line" function */
  93. char    *label,
  94.     *op,
  95.     *argsp,
  96.     *args[40];
  97.  
  98. char     *gpcptr;        /* general-purpose text pointer    */
  99.  
  100. /*
  101.  * Open main input file, open output file, initialize needed globals
  102.  * and process the file:
  103.  */
  104.  
  105. main(aarghc,aarghv)
  106. char **aarghv;
  107. {
  108.     int i,j,k;
  109.     char c;
  110.  
  111.     puts("BD Software CRL-format ASM Preprocessor v1.46\n");
  112.  
  113.     initequ();        /* initialize EQU table with reserved words */
  114.     fcount = 0;        /* haven't seen any functions yet */
  115.     doingfunc = 0;        /* not currently processing a function */
  116.     errf = 0;        /* no errors yet */
  117.  
  118.     if (aarghc != 2)
  119.         exit(puts("Usage:\ncasm <filename>\n"));
  120.  
  121.                 /* set up filenames with proper extensions: */
  122.  
  123.     for (i = 0; (c = aarghv[1][i]) && c != '.'; i++)
  124.         nambuf[i] = c;
  125.     nambuf[i] = '\0';
  126.     strcpy(onambuf,nambuf);
  127.     strcat(nambuf,CASMEXT);        /* input filename */
  128.     cbufp = fbuf;            /* buffer pointer */
  129.     cfilnam = nambuf;        /* current filename pointer */
  130.     if (fopen(cfilnam,cbufp) == ERROR)
  131.         exit(printf("Can't open %s\n",cfilnam));
  132.  
  133.     strcat(onambuf,ASMEXT);        /* output filename */
  134.     if (fcreat(onambuf,obuf) == ERROR)
  135.         exit(printf("Can't open %s\n",onambuf));
  136.  
  137.                     /* begin writing output file */
  138.     fprintf(obuf,"\nTPALOC\t\tEQU\t%04xH\n",TPALOC);
  139.  
  140.     lino = 1;            /* initialize line count */
  141.  
  142.     while (get_line()) {        /* main loop */
  143.         process_line();        /* process lines till EOF */
  144.         lino++;
  145.     }
  146.  
  147.     if (doingfunc)            /* if ends inside a function, error */
  148.         abort("File ends, but last function is unterminated\n");
  149.  
  150.     fputs("\nEND$CRL\t\tEQU\t$-TPALOC\n",obuf);    /* end of functions */
  151.     fputs("SECTORS$ EQU ($-TPALOC)/256+1 ;USE FOR \"SAVE\" !.\n",obuf);
  152.     putdir();            /* now spit out CRL directory */
  153.     fputs("\t\tEND\n",obuf);    /* end of file */
  154.     putc(CPMEOF,obuf);        /* CP/M EOF character */
  155.     fclose(cbufp);            /* close input file */
  156.     fflush(obuf);            /* flush and close output file */
  157.     fclose(obuf);
  158.     if (errf)
  159.         printf("Fix those errors and try again...\n");
  160.     else
  161.         printf("\n%s is ready to be assembled.\n",onambuf);
  162. }
  163.  
  164. /*
  165.  * Get a line of text from input stream, and process
  166.  * "include" ops on the fly:
  167.  */
  168.  
  169. int get_line()
  170. {
  171.     int i;
  172.  
  173.     if (!fgets(linbuf,cbufp)) {        /* on EOF: */
  174.         if (cbufp == incbuf) {        /* in an "include" file? */
  175.             fabort(cbufp->_fd);        /* close the file */
  176.             cbufp = fbuf;        /* go back to mainline file */
  177.             cfilnam = nambuf;
  178.             lino = savlino + 1;
  179.             return get_line();
  180.         }
  181.         else return NULL;
  182.     }
  183.  
  184.     parse_line();                /* not EOF. Parse line */
  185.     if (streq(op,"INCLUDE")  ||        /* check for file inclusion */
  186.         streq(op,"MACLIB")) {
  187.         if (cbufp == incbuf)        /* if already in an include, */
  188.          abort("Only one level of inclusion is supported"); /* error */
  189.         if (!argsp)
  190.          abort("No filename specified");
  191.         cbufp = incbuf;            /* set up for inclusion */
  192.         savlino = lino;
  193.         lino = 1;
  194.  
  195.         for (i = 0; !isspace(argsp[i]); i++)    /* put null after */
  196.             ;                /* filename      */
  197.         argsp[i] = '\0';
  198.  
  199.         *nambuf2 = '\0';
  200.  
  201.         if (*argsp == '<') {        /* look for magic delimiters */
  202. #ifdef USERAREAS
  203.             strcpy(nambuf2,DEFUSER);
  204. #endif
  205.             if (argsp[2] != ':')    /* if no explicit disk given */
  206.                 strcat(nambuf2,DEFDISK); /* then use default */
  207.             strcat(nambuf2,argsp+1);
  208.             if (nambuf2[i = strlen(nambuf2) - 1] == '>')
  209.                 nambuf2[i] = '\0';
  210.         } else if (*argsp == '"') {
  211.             strcpy(nambuf2,argsp+1);
  212.             if (nambuf2[i = strlen(nambuf2) - 1] == '"')
  213.                 nambuf2[i] = '\0';
  214.         } else
  215.             strcpy(nambuf2,argsp);
  216.  
  217.         if (fopen(nambuf2,cbufp) == ERROR) {
  218.             if (nambuf2[strlen(nambuf2) - 1] != '.') {
  219.                 strcat(nambuf2,".LIB");
  220.                 if (fopen(nambuf2,cbufp) != ERROR)
  221.                     goto ok;
  222.             }                
  223.             printf("Can't open %s\n",nambuf2);
  224.             abort("Missing include file");
  225.         }
  226.  
  227.     ok:    cfilnam = nambuf2;
  228.         return get_line();
  229.     }
  230.     return 1;
  231. }
  232.  
  233. parse_line()
  234. {
  235.     int i;
  236.     char c;
  237.  
  238.     label = op = argsp = NULL;
  239.     argcnt = 0;
  240.  
  241.     strcpy2(pbuf,linbuf);
  242.     strcpy2(linsav,linbuf);
  243.     pbufp = pbuf;
  244.  
  245.     if (!isspace(c = *pbufp)) {
  246.         if (c == ';')
  247.             return;        /* totally ignore comment lines */
  248.         label = pbufp;        /* set pointer to label    */
  249.         while (isidchr(*pbufp))    /* pass over the label identifier */
  250.             pbufp++;
  251.         *pbufp++ = '\0';    /* place null after the identifier */
  252.     }
  253.  
  254.     skip_wsp(&pbufp);
  255.     if (!*pbufp || *pbufp == ';')
  256.         return;
  257.     op = pbufp;            /* set pointer to operation mnemonic */
  258.     while (isalpha(*pbufp))
  259.         pbufp++;          /* skip over the op         */
  260.     if (*pbufp) *pbufp++ = '\0';    /* place null after the op    */
  261.  
  262.  
  263.                     /* now process arguments    */
  264.     skip_wsp(&pbufp);
  265.     if (!*pbufp || *pbufp == ';')
  266.         return;
  267.     argsp = linsav + (pbufp - pbuf);    /* set pointer to arg list */
  268.  
  269.                     /* create vector of ptrs to all args
  270.                        that are possibly relocatable */
  271.     for (argcnt = 0; argcnt < 40;) {
  272.         while (!isidstrt(c = *pbufp))
  273.             if (!c || c == ';')
  274.                 return;
  275.             else
  276.                 pbufp++;
  277.  
  278.         if (isidchr(*(pbufp - 1))) {
  279.             pbufp++;
  280.             continue;
  281.         }
  282.  
  283.         args[argcnt++] = pbufp;            
  284.         while (isidchr(*pbufp)) pbufp++;
  285.         if (*pbufp) *pbufp++ = '\0';
  286.     }
  287.     error("Too many operands in this instruction for me to handle\n");
  288. }
  289.  
  290. process_line()
  291. {
  292.     char *cptr, c;
  293.     int i,j;
  294.  
  295.     if (op) {
  296.             /* check for definitions of global data that will be
  297.                exempt from relocation when encountered in the
  298.                argument field of assembly instructions:        */
  299.  
  300.        if (streq(op,"EQU") || streq(op,"SET") ||
  301.         (!doingfunc &&
  302.             (streq(op,"DS") || streq(op,"DB") || streq(op,"DW"))))
  303.        {
  304.         fputs(linbuf,obuf);
  305.         cptr = sbrk2(strlen(label) + 1);
  306.         strcpy(cptr,label);
  307.         equtab[equcount++] = cptr;
  308.         if (equcount >= EQUMAX)
  309.             abort(
  310.           "Too many EQU lines...increase 'EQUMAX' and recompile CASM");
  311.         return;
  312.        }
  313.  
  314.        if (streq(op,"EXTERNAL")) {
  315.         if (!doingfunc) abort(
  316.          "'External's for a function must appear inside the function");
  317.         if (pastnfs) error(
  318.          "Externals must all be together at start of function\n");
  319.         for (i = 0; i < argcnt; i++) {
  320.             nflist[nfcount++] = txtbufp;
  321.             strcpy(txtbufp,args[i]);
  322.             bumptxtp(args[i]);
  323.         }
  324.         if (nfcount >= NFMAX) {
  325.           printf("Too many external functions in function \"%s\"\n",
  326.                     cfunam);
  327.           abort("Change the NFMAX constant and recompile CASM");
  328.         }
  329.         return;
  330.        }
  331.  
  332.        if (streq(op,"FUNCTION")) {
  333.         if (!fcount) {
  334.             fputs("\n; dummy external data information:\n",obuf);
  335.             fputs("\t\tORG\tTPALOC+200H\n",obuf);
  336.             fputs("\t\tDB\t0,0,0,0,0\n",obuf);
  337.         }
  338.  
  339.         if (doingfunc) {
  340.             printf("'Function' op encountered in a function.\n");
  341.             abort("Did you forget an 'endfunc' op?");
  342.         }
  343.         if (!argcnt)
  344.             abort("A name is required for the 'function' op");
  345.  
  346.         cfunam = sbrk2(strlen(args[0]) + 1);
  347.         fnames[fcount++] = cfunam;
  348.         strcpy(cfunam,args[0]);
  349.  
  350.         printf("Processing the %s function...          \r",cfunam);
  351.  
  352.         doingfunc = 1;
  353.         txtbufp = txtbuf;
  354.         labcount = 0;
  355.         nfcount = 0;
  356.         pastnfs = 0;
  357.         fprintf(obuf,"\n\n; The \"%s\" function:\n",cfunam);
  358.         fprintf(obuf,"%s$BEG\tEQU\t$-TPALOC\n",cfunam);
  359.         return;
  360.        }
  361.  
  362.        if (streq(op,"ENDFUNC") || streq(op,"ENDFUNCTION")) {
  363.         if (!doingfunc)
  364.           abort("'Endfunc' op encountered while not in a function");
  365.  
  366.         if (!pastnfs) flushnfs();    /* flush needed function list */
  367.         fprintf(obuf,"%s$END\tEQU\t$\n",cfunam);
  368.         doreloc();             /* flush relocation parameters */
  369.  
  370.         for (i = 0; i < labcount; i++)    /* detect undefined labels */
  371.           if (!lablist[i].defined) {
  372.             printf("The label %s in function %s is undefined\n",
  373.                     lablist[i].labnam,cfunam);
  374.             errf = 1;
  375.           }
  376.         doingfunc = 0;
  377.         return;
  378.        }
  379.     }
  380.  
  381.     if (streq(op,"RELOC") || streq(op,"DWREL") || streq(op,"DIRECT") ||
  382.         streq(op,"ENDDIR") || streq(op,"EXREL") || streq(op,"EXDWREL") ||
  383.         streq(op,"PRELUDE") || streq(op,"POSTLUDE") || streq(op,"DEFINE"))
  384.         error("Old macro leftover from \"CMAC.LIB\" days...\n");
  385.  
  386.                 /* No special pseudo ops, so now process
  387.                    the line as a line of assemby code:     */
  388.  
  389.     if (streq(op,"END")) return;        /* don't allow "end" yet     */
  390.  
  391.     if (!doingfunc || (!label && !op))    /* if nothing interesting on */
  392.         return fputs(linbuf,obuf);    /* line, ignore it    */
  393.  
  394.     if (!pastnfs)                /* if haven't flushed needed */
  395.         flushnfs();            /* function list yet, do it  */
  396.  
  397.                         /* check for possible label  */
  398.     if (label) {
  399.         fprintf(obuf,"%s$L$%s\t\tEQU\t$-%s$STRT\n",
  400.             cfunam, label, cfunam);
  401.         for (i=0; linbuf[i]; i++)
  402.             if (isspace(linbuf[i]) || linbuf[i] == ':')
  403.                 break;
  404.             else
  405.                 linbuf[i] = ' ';
  406.         if (linbuf[i] == ':') linbuf[i] = ' ';
  407.         for (i = 0; i < labcount; i++)      /* check if in label table */
  408.           if (streq(label,lablist[i].labnam)) {            /* if found, */
  409.             if (lablist[i].defined) {  /* check for redefinition */
  410.                 error("Re-defined label:");
  411.                 printf("%s, in function %s\n",
  412.                         lablist[i].labnam,cfunam);
  413.             }
  414.              else
  415.                 lablist[i].defined = 1;
  416.             goto out;
  417.           }
  418.         lablist[i].labnam = txtbufp;    /* add new entry to */
  419.         lablist[i].defined = 1;        /* label list         */
  420.         strcpy(txtbufp,label);
  421.         bumptxtp(label);
  422.         labcount++;
  423.     }
  424. out:
  425.     if (!op) return fputs(linbuf,obuf);    /* if label only, all done   */
  426.  
  427.                         /* if a non-relocatable op,  */
  428.     if (norelop(op)) return fputs(linbuf,obuf);    /* then we're done   */
  429.  
  430.     if (argcnt && doingfunc)
  431.       for (i = 0; i < argcnt; i++) {
  432.         if (norel(args[i])) continue;
  433.         if (gpcptr = isef(args[i]))
  434.            sprintf(workbuf,"%s$EF$%s-%s$STRT",
  435.                 cfunam,gpcptr,cfunam);
  436.         else {
  437.             sprintf(workbuf,"%s$L$%s",cfunam,args[i]);
  438.             for (j = 0; j < labcount; j++)
  439.                 if (streq(args[i],lablist[j].labnam))
  440.                     goto out2;
  441.             lablist[j].labnam = txtbufp;    /* add new entry to */
  442.             lablist[j].defined = 0;        /* label list         */
  443.             strcpy(txtbufp,args[i]);
  444.             bumptxtp(txtbufp);
  445.             labcount++;
  446.         }           
  447.  
  448.     out2:
  449.         replstr(linbuf, workbuf, args[i] - pbuf, strlen(args[i]));
  450.  
  451.         if (streq(op,"DW")) {
  452.             fprintf(obuf,"%s$R%03d\tEQU\t$-%s$STRT\n",
  453.                 cfunam, relblc++, cfunam);
  454.             if (argcnt > 1)
  455.               error("Only one relocatable value allowed per DW\n");
  456.         }
  457.         else
  458.             fprintf(obuf,"%s$R%03d\tEQU\t$+1-%s$STRT\n",
  459.                 cfunam, relblc++, cfunam);
  460.         break;
  461.       }
  462.     fputs(linbuf,obuf);
  463. }
  464.  
  465.  
  466. /*
  467.     Test for ops in which there is guanranteed to be no need
  468.     for generation of relocation parameters. Note that the list
  469.     of non-relocatable ops doesn't necessarily have to be complete,
  470.     because for any op that doesn't match, an argument must still
  471.     pass other tests before it is deemed relocatable. This only
  472.     speeds things up by telling the program not to bother checking
  473.     the arguments.
  474. */
  475.  
  476. norelop(op)
  477. char *op;
  478. {
  479.     if (streq(op,"MOV")) return 1;
  480.     if (streq(op,"INR")) return 1;
  481.     if (streq(op,"DCR")) return 1;
  482.     if (streq(op,"INX")) return 1;
  483.     if (streq(op,"DCX")) return 1;
  484.     if (streq(op,"DAD")) return 1;
  485.     if (streq(op,"MVI")) return 1;
  486.     if (streq(op,"DB")) return 1;
  487.     if (streq(op,"DS")) return 1;
  488.     if (op[2] == 'I') {
  489.         if (streq(op,"CPI")) return 1;
  490.         if (streq(op,"ORI")) return 1;
  491.         if (streq(op,"ANI")) return 1;
  492.         if (streq(op,"ADI")) return 1;
  493.         if (streq(op,"SUI")) return 1;
  494.         if (streq(op,"SBI")) return 1;
  495.         if (streq(op,"XRI")) return 1;
  496.         if (streq(op,"ACI")) return 1;
  497.     }
  498.     if (streq(op,"ORG")) return 1;
  499.     if (streq(op,"TITLE")) return 1;
  500.     if (streq(op,"PAGE")) return 1;
  501.     if (streq(op,"IF")) return 1;
  502.     if (streq(op,"EJECT")) return 1;
  503.     if (streq(op,"MACRO")) return 1;
  504.     return 0;
  505. }
  506.  
  507.  
  508. flushnfs()
  509. {
  510.     int i,j, length;
  511.  
  512.     pastnfs = 1;
  513.     relblc = 0;
  514.  
  515.     fputs("\n\n; List of needed functions:\n",obuf);
  516.     for (i=0; i < nfcount; i++) {
  517.         strcpy(workbuf,"\t\tDB\t'");
  518.         length = strlen(nflist[i]);
  519.         length = length < 8 ? length : 8;
  520.         for (j = 0; j < length - 1; j++)
  521.             workbuf[6+j] = nflist[i][j];
  522.         workbuf[6+j] = '\0';
  523.         fprintf(obuf,"%s','%c'+80H\n",workbuf,nflist[i][j]);
  524.     }
  525.  
  526.     fputs("\t\tDB\t0\n",obuf);
  527.     fputs("\n; Length of body:\n",obuf);
  528.     fprintf(obuf,"\t\tDW\t%s$END-$-2\n",cfunam);
  529.     fputs("\n; Body:\n",obuf);
  530.     fprintf(obuf,"%s$STRT\tEQU\t$\n",cfunam);
  531.     if (nfcount) {
  532.         fprintf(obuf,"%s$R%03d\tEQU\t$+1-%s$STRT\n",
  533.             cfunam,relblc++,cfunam);
  534.         fprintf(obuf,"\t\tJMP\t%s$STRTC-%s$STRT\n",cfunam,cfunam);
  535.     }
  536.     fprintf(obuf,"%s$EF$%s\tEQU\t%s$STRT\n",cfunam,cfunam,cfunam);
  537.     for (i=0; i < nfcount; i++)
  538.         fprintf(obuf,"%s$EF$%s\tJMP\t0\n",cfunam,nflist[i]);
  539.     fprintf(obuf,"\n%s$STRTC\tEQU\t$\n",cfunam);
  540. }
  541.  
  542.  
  543. doreloc()
  544. {
  545.     int i;
  546.     fputs("\n; Relocation parameters:\n",obuf);
  547.     fprintf(obuf,"\t\tDW\t%d\n",relblc);
  548.     for(i = 0; i < relblc; i++)
  549.         fprintf(obuf,"\t\tDW\t%s$R%03d\n",cfunam,i);
  550.     fputs("\n",obuf);
  551. }
  552.  
  553.  
  554. putdir()
  555. {
  556.     int i,j, length;
  557.     int bytecount;
  558.  
  559.     bytecount = 0;
  560.  
  561.     fputs("\n\t\tORG\tTPALOC\n\n; Directory:\n",obuf);
  562.     for (i = 0; i < fcount; i++) {
  563.         strcpy(workbuf,"\t\tDB\t'");
  564.         length = strlen(fnames[i]);
  565.         length = length < 8 ? length : 8;
  566.         for (j = 0; j < length - 1; j++)
  567.             workbuf[6+j] = fnames[i][j];
  568.         workbuf[6+j] = '\0';
  569.         fprintf(obuf,"%s','%c'+80H\n",workbuf,fnames[i][j]);
  570.         fprintf(obuf,"\t\tDW\t%s$BEG\n",fnames[i]);
  571.         bytecount += (length + 2);
  572.     }
  573.     fputs("\t\tDB\t80H\n\t\tDW\tEND$CRL\n",obuf);
  574.  
  575.     bytecount += 3;
  576.     if (bytecount > DIRSIZE) {
  577.         printf("CRL Directory size will exceed 512 bytes;\n");
  578.         printf("Break the file up into smaller chunks, please!\n");
  579.         exit(-1);
  580.     }
  581. }
  582.  
  583.  
  584. initequ()
  585. {
  586.     equtab[0] = "A";
  587.     equtab[1] = "B";
  588.     equtab[2] = "C";
  589.     equtab[3] = "D";
  590.     equtab[4] = "E";
  591.     equtab[5] = "H";
  592.     equtab[6] = "L";
  593.     equtab[7] = "M";
  594.     equtab[8] = "SP";
  595.     equtab[9] = "PSW";
  596.     equtab[10]= "AND";
  597.     equtab[11]= "OR";
  598.     equtab[12]= "MOD";
  599.     equtab[13]= "NOT";
  600.     equtab[14]= "XOR";
  601.     equtab[15]= "SHL";
  602.     equtab[16]= "SHR";
  603.     equcount = 14;
  604. }
  605.  
  606.  
  607. int isidchr(c)    /* return true if c is legal character in identifier */
  608. char c;
  609. {    
  610.     return isalpha(c) || c == '$' || isdigit(c) || c == '.';
  611. }
  612.  
  613.  
  614. int isidstrt(c)    /* return true if c is legal as first char of idenfitier */
  615. char c;
  616. {
  617.     return isalpha(c);
  618. }
  619.  
  620.  
  621. int streq(s1, s2)    /* return true if the two strings are equal */
  622. char *s1, *s2;
  623. {
  624.     if (*s1 != *s2) return 0;    /* special case for speed */
  625.     while (*s1) if (*s1++ != *s2++) return 0;
  626.     return (*s2) ? 0 : 1;
  627. }
  628.  
  629.  
  630. skip_wsp(strptr)    /* skip white space at *strptr and modify the ptr */
  631. char **strptr;
  632. {
  633.     while (isspace(**strptr)) (*strptr)++;
  634. }
  635.  
  636.  
  637. strcpy2(s1,s2)    /* copy s2 to s1, converting to upper case as we go */
  638. char *s1, *s2;
  639. {
  640.     while (*s2)
  641.          *s1++ = toupper(*s2++);
  642.     *s1 = '\0';
  643. }
  644.  
  645.  
  646. /*
  647.     General-purpose string-replacement function:
  648.         'string'    is pointer to entire string,
  649.         'insstr'    is pointer to string to be inserted,
  650.         'pos'        is the position in 'string' where 'insstr'
  651.                 is to be inserted
  652.         'lenold'    is the length of the substring in 'string'
  653.                 that is being replaced.
  654. */
  655.  
  656. replstr(string, insstr, pos, lenold)
  657. char *string, *insstr;
  658. {
  659.     int length, i, j, k, x;
  660.  
  661.     length = strlen(string);
  662.     x = strlen(insstr);
  663.     k = x - lenold;
  664.     i = string + pos + lenold;
  665.     if (k) movmem(i, i+k, length - (pos + lenold) + 1);
  666.     for (i = 0, j = pos; i < x; i++, j++)
  667.         string[j] = insstr[i];
  668. }
  669.  
  670.  
  671. error(msg)
  672. char *msg;
  673. {
  674.     printf("\n\7%s: %d: %s ",cfilnam,lino,msg);
  675.     errf = 1;
  676. }
  677.  
  678.  
  679. abort(msg)
  680. char *msg;
  681. {
  682.     error(msg);
  683.     putchar('\n');
  684.     if (cbufp == incbuf) fclose(incbuf);
  685.     fclose(fbuf);
  686.     exit(-1);
  687. }
  688.  
  689.  
  690. sbrk2(n)    /* allocate storage and check for out of space condition */
  691. {
  692.     int i;
  693.     if ((i = sbrk(n)) == ERROR)
  694.         abort("Out of storage allocation space\n");
  695.     return i;
  696. }
  697.  
  698. bumptxtp(str)    /* bump txtbufp by size of given string + 1 */
  699. char *str;
  700. {
  701.     txtbufp += strlen(str) + 1;
  702.     if (txtbufp >= txtbuf + (TXTBUFSIZE - 8))
  703.      abort("Out of text space. Increase TXTBUFSIZE and recompile CASM");
  704. }
  705.  
  706.  
  707. int norel(id)    /* return true if identifier is exempt from relocatetion */
  708. char *id;
  709. {
  710.     if (isequ(id)) return 1;
  711.     return 0;
  712. }
  713.  
  714.  
  715. int isequ(str)    /* return true if given string is in the EQU table */
  716. char *str;
  717. {
  718.     int i;
  719.     for (i = 0; i < equcount; i++)
  720.         if (streq(str,equtab[i]))
  721.             return 1;
  722.     return 0;
  723. }
  724.  
  725.  
  726. char *isef(str)    /* return nflist entry if given string is an external */
  727. char *str;    /* function name */
  728. {
  729.     int i;
  730.     for (i = 0; i < nfcount; i++)
  731.         if (streq(str,nflist[i]))
  732.             return nflist[i];
  733.     return 0;
  734. }
  735.  
  736.