home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 190_01 / as68.c < prev    next >
Text File  |  1985-11-14  |  24KB  |  891 lines

  1. /******************************************************************
  2.     as68.c, the source of a 68000 assembler....
  3. */
  4.  
  5. /*        (C) Copyright 1982 Steve Passe        */
  6. /*        All Rights Reserved                    */
  7.  
  8. /*  ver. 1.00 */
  9. /* created 10/7/82 */
  10.  
  11. /* version 1.01
  12.  
  13.     8/30/83    ver. 1.01 modified for Aztec ver. 1.05g    smp
  14.     12/23/83    fixed 24 bit address bug in flush_rcrd smp
  15.     12/24/83    fixed lowercase a-f in S-records smp
  16.  
  17. */
  18.  
  19. /* begincode */
  20.  
  21. /* includes */
  22.  
  23. #define AZTECZII 1
  24.  
  25. #ifndef AZTECZII
  26. #include <stdio.h>
  27. #else
  28. #include "stdio.h"                                /* with aztecII compiler */
  29. #endif
  30. #include "b:as68.h"
  31.  
  32. /* externals */
  33.  
  34. struct _symbol *symtbl;
  35. struct _symbol *syms_head;                    /* head of sym table free space */
  36. char *syms_tail;                            /* tail of sym table free space */
  37. int symspace = SYMTSIZE;                    /* bytes in symbol table */
  38. int symbols = 0;                            /* number of symbols in table */
  39.  
  40. FLAG fatal = NO;
  41. char pass = 1;                                /* present pass number, 1 or 2 */
  42. unsigned line_count = 0;                    /* line number of source file */
  43. unsigned list_count = 0;                    /* line # of list file */
  44. long loc_counter = 0;                        /* address to assemble obj code */
  45. int loc_plus = 0;                            /* increment to loc counter */
  46. char lcksm;                        /* bytes + addr. + count + lcksm == 0xff */
  47. FLAG abs_long = YES;                        /* default to absolute long add.*/
  48. FLAG rorg = NO;                                /* prog. counter relative flag */
  49. FLAG do_label = YES;                        /* process label if set */
  50. char statement[STMNT_SIZE];                    /* statement line buffer */
  51. char label[32];                                /* bufr for label from preparse */
  52. char instr[32];                                /* bufr for mnem, psdo or macro */
  53. char *opfld_ptr;                            /* pointer to operand field */
  54. char *stmnt_ptr;                            /* ptr to statement field */
  55. char stmnt_typ;                                /* statement type, instr, pseudo */
  56. int wrap = 80;                                /* wrap column for list output */
  57. FLAG trunc = NO;                            /* truncate lines in listing */
  58. char source_name[FNAME_SIZE];                /* source file name */
  59. int src_level = 0;                            /* source file level */
  60. FILE *_src[SRCLEVELS];                        /* source file descripters */
  61. FLAG objchnl = 's';                            /* Motorola S ('s') or nil ('x') */
  62. FLAG obj_open = NO;                            /* object channel open flag */
  63. char of_disk = NULL;                        /* default object file drive */
  64. char object_name[FNAME_SIZE];                /* object file name */
  65. FILE *obj_f;                                /* object file descripter */
  66. FLAG lstchnl = NO;                            /* list channel(s) open */
  67. FLAG nolist = NO;                            /* flag for list/nolist pseudos */
  68. FLAG lcon = NO;                                /* list to console flag */
  69. FLAG llst = NO;                                /* list to list device flag */
  70. FLAG lfile = NO;                            /* list to file flag */
  71. FLAG lfile_open = NO;                        /* list file open flag */
  72. char lf_disk = NULL;                        /* default list file drive */
  73. char list_name[FNAME_SIZE];                    /* listing file name */
  74. FILE *lst_f, *lst_d;                        /* listing file & dev descripter */
  75. FLAG errchnl = YES;                            /* error channel(s) open */
  76. FLAG econ = YES;                            /* errors to console flag */
  77. FLAG elst = NO;                                /* errors to list device flag */
  78. FLAG elfile = NO;                            /* errors to listing file */
  79. FLAG efile = NO;                            /* errors to error file */
  80. FLAG efile_open = NO;                        /* error file open flag */
  81. char ef_disk = NULL;                        /* default error file drive */
  82. char error_name[FNAME_SIZE];                /* error file name */
  83. FILE *err_f;                                /* error file descripter */
  84.  
  85. struct _oprnd op1, op2;                    /* structs to hold operand val */
  86.  
  87. char code[12];                    /* 12 minimum for overflow */
  88. char buf[85];
  89.  
  90. long lex_val;
  91. char *p;
  92.  
  93. extern struct _mtable mtable[];
  94.  
  95. /* beginmain */
  96.  
  97. main(argc, argv)
  98. int argc;
  99. char *argv[];
  100. {
  101.  
  102.     register int x, y;
  103.     char *c_ptr;                    /* scratch pointer to char */
  104.     char _ext[5];                    /* scratch ext buffer */
  105.     struct _ptable *pt;                /* function ptr returned by psdosearch */
  106.     struct _mtable *mt;                /* function ptr returned by mnemsearch */
  107.     long _dtol();
  108.  
  109.     puts("\nas68, ver 1.01, 68000 assembler, (C) Copyright 1982 Steve Passe\n");
  110.  
  111. /** parse the command line, setting variables as needed */
  112.  
  113.     if (argc < 2) {
  114.         puts("\n...source file?");
  115.         exit(0);
  116.     }
  117. /** set flag variables according to command line args */
  118.  
  119.     for (x = 2; x < argc; ++x) {
  120.         switch (tolower(argv[x][0])) {
  121.         case 'e':                                        /* error file opt */
  122.             econ = NO;
  123.             for (y = 1; argv[x][y]; ++y) {
  124.                 switch (tolower(argv[x][y])) {
  125.                 case 'c':    econ = YES;        continue;
  126.                 case 'l':    elst = YES;        continue;
  127.                 case 'f':    elfile = YES;    continue;
  128.                 case 'e':    efile = YES;
  129.                     if (argv[x][y+1] && argv[x][y+2] == ':') {
  130.                         ef_disk = argv[x][++y];
  131.                         ++y;
  132.                     }
  133.                     continue;
  134.                 default:    errchnl = NO;
  135.                 }
  136.             }
  137.             continue;
  138.         case 'l':                                        /* list file opt */
  139.             lstchnl = YES;
  140.             for (y = 1; argv[x][y]; ++y) {
  141.                 switch (tolower(argv[x][y])) {
  142.                 case 'c':    lcon = YES;        continue;
  143.                 case 'l':    llst = YES;        continue;
  144.                 case 'f':    lfile = YES;
  145.                     if (argv[x][y+1] && argv[x][y+2] == ':') {
  146.                         lf_disk = argv[x][++y];
  147.                         ++y;
  148.                     }
  149.                     continue;
  150.                 default:    lstchnl = NO;
  151.                 }
  152.             }
  153.             continue;
  154.         case 'o':                                        /* object file opt */
  155.             for (y = 1; argv[x][y]; ++y) {
  156.                 switch (tolower(argv[x][y])) {
  157.                 case 's':    objchnl = 's';
  158.                     if (argv[x][y+1] && argv[x][y+2] == ':') {
  159.                         of_disk = argv[x][++y];
  160.                         ++y;
  161.                     }
  162.                     continue;
  163.                 default:    objchnl = 'x';
  164.                 }
  165.             }
  166.             continue;
  167.         case 's':
  168.             opfld_ptr = &argv[x][1];
  169.             symspace = (int) _dtol();
  170.             continue;
  171.         case 'w':
  172.             wrap = atoi(&argv[x][1]);
  173.             if (wrap < 60) wrap = 60;
  174.             continue;
  175.         case 't':
  176.             trunc = YES;
  177.             continue;
  178.         default:    puts("\nhuh?");    exit(0);
  179.         }
  180.     }
  181.  
  182.     if (!(symtbl = alloc(symspace))) {    /* allocate space for symbol table */
  183.         printf("\n...symbol table too large (%d)", symspace);
  184.         exit(0);
  185.     }
  186.     syms_head = symtbl + 1;                            /* init free space head */
  187.     syms_tail = symtbl;    syms_tail += symspace;        /* init free space tail */
  188.  
  189.     symtbl[0]._sym = "";                            /* dummy entry */
  190.     symtbl[0]._val = NULL;
  191.     symtbl[0]._atr = NULL;
  192.  
  193. /* initialize sourcename, errname, listname, and objname */
  194.  
  195.     if (too_long(argv[1], 14)) {
  196.         exit(0);
  197.     }
  198.     if (argv[1][1] == ':') {                    /* a disk identifier exists */
  199.         strcpy(source_name, argv[1]);                /* get source file name */
  200.     }
  201.     else {                                        /* default to logged in disk */
  202.         if (too_long(argv[1], 12)) {
  203.             exit(0);
  204.         }
  205.         source_name[0] = bdos(CURR_DISK, 0) + 'A';        /* read default disk */
  206.         source_name[1] = ':';                            /* separator */
  207.         source_name[2] = '\0';                            /* make a string */
  208.         strcat(source_name, argv[1]);                    /* add the name */
  209.     }
  210.     if (c_ptr = cisat('.', source_name)) {        /* if extension */
  211.         word_copy(_ext, 4, c_ptr);                    /* save ext */
  212.         *c_ptr = '\0';                                /* erase it */
  213.     }
  214.     else strcpy(_ext, ".sa");                    /* default extension */
  215.     if (too_long(source_name, 10)) {
  216.         exit(0);
  217.     }
  218.     strcpy(object_name, source_name);            /* make object file name */
  219.     switch (objchnl) {
  220.     case 'x':    break;                                /* none wanted */
  221.     case 's':    strcat(object_name, ".mx");        /* for Motorola S FILE */
  222.                 break;
  223.     default:    printf("\n...bad object file type ('%c')", objchnl);
  224.     }
  225.     if (of_disk) object_name[0] = of_disk;        /* pick up option */
  226.     strcpy(list_name, source_name);
  227.     strcat(list_name, ".ls");                    /* make list file name */
  228.     if (lf_disk) list_name[0] = lf_disk;        /* option */
  229.     strcpy(error_name, source_name);
  230.     strcat(error_name, ".err");                    /* make error file name */
  231.     if (ef_disk) error_name[0] = ef_disk;        /* option */
  232.     strcat(source_name, _ext);                    /* add ext. */
  233.  
  234.     /* open appropriate source, list, error, and object files */
  235.  
  236.     if (!(_src[0] = fopen(source_name, "r"))) {
  237.         printf("\n...can't open source (\"%s\")", source_name);
  238.         exit(0);
  239.     }
  240.                                     /* open list, err, and obj as needed */
  241.     if (objchnl != 'x') {
  242.         if (!(obj_f = fopen(object_name, "w"))) {
  243.             printf("\n...can't open object (\"%s\")", object_name);
  244.             exit(0);
  245.         }
  246.         obj_open = TRUE;
  247.         obj_out(OPEN, 0, 0);
  248.     }
  249.     if (lfile) {
  250.         if (!(lst_f = fopen(list_name, "w"))) {
  251.             printf("\n...can't open list (\"%s\")", list_name);
  252.             exit(0);
  253.         }
  254.         lfile_open = TRUE;
  255.     }
  256.     if (efile) {
  257.         if (!(err_f = fopen(error_name, "w"))) {
  258.             printf("\n...can't open error (\"%s\")", error_name);
  259.             exit(0);
  260.         }
  261.         efile_open = TRUE;
  262.     }
  263.     if (llst || elst) {
  264.         if (!(lst_d = fopen("lst:", "w"))) {
  265.             puts("\n...can't access list device.");
  266.             exit(0);
  267.         }
  268.     }
  269.  
  270. /******************************************** start pass loop... */
  271.  
  272.     while (nextline()) {
  273.  
  274. /* parse line for label, instruction and operand field pointer */
  275.  
  276.         if (preparse() == COMMENT) {
  277.             if (pass == 2) dump_code(MSG, code, 0);        /* dump the line */
  278.             continue;
  279.         }
  280.         if (instr[0]) {        /*  mnemonic/pseudo-op/macro field is present) */
  281.             if (instr[31] && (pass == 2)) err_out(BAD_INSTR);
  282.                                                     /* check for mnemonic */
  283.             if (mt = mnemsearch(instr)) {
  284.                 stmnt_typ = MNEMONIC;
  285.                 pass == 1 ? p1_mnem(mt) : p2_mnem(mt);
  286.             }
  287.                                                     /* or pseudo-op */
  288.             else if (pt = psdosearch(instr)) {
  289.                 stmnt_typ = PSEUDO;                /* record the fact */
  290.                 switch (pass) {
  291.                 case 1:
  292.                     (*pt->_p1)(pt->_psdo, pt->_arg);
  293.                     if (pass == 2) continue;
  294.                     break;
  295.                 case 2:
  296.                     (*pt->_p2)(pt->_psdo, pt->_arg);
  297.                     if (pass == 3) goto finis;
  298.                 }
  299.             }
  300.                                                 /** or macro use */
  301.             else if (FALSE /** macros not used yet **/) {
  302.                         /** MACROS NOT IMPLIMENTED in version 1.xx */
  303.                         stmnt_typ = MACRO;
  304.             }
  305.             else {
  306.                 stmnt_typ = NULL;
  307.                 err_out(UNREC_INSTR);
  308.                 dump_code (CODE, code, 0);
  309.             }
  310.         }
  311.         else {
  312.             if (pass == 2) {
  313.                 dump_code (CODE, code, 0);                /* label only line ? */
  314.             }
  315.         }
  316.  
  317.         if (label[0] && do_label) {
  318.             label_do();
  319.         }
  320.         do_label = YES;                        /* reset for next line */
  321.         loc_counter += loc_plus;            /* update loc_counter */
  322.         loc_plus = NULL;                    /* clear for next instruction */
  323.         if (fatal) {                        /* fatal system ERROR */
  324.             puts("\007\nFATAL SYSTEM ERROR!\007");
  325.             break;
  326.         }
  327.     }                                        /* end of pass loop */
  328.  
  329. /** close shop... */
  330.  
  331. finis:
  332.     if (obj_open) {
  333.         fclose(obj_f);
  334.     }
  335.     if (efile_open) {
  336.         fclose(err_f);
  337.     }
  338.     if (lstchnl) {                                    /* display symbol table */
  339.         sprintf(buf,"\n\n\n%-32s%-14s%-12s%s\n\n",
  340.                     "symbol -", "hex value -", "decimal -", "atrb. -");
  341.         list_dump(buf);
  342.         for (x = 0; x++ < symbols; ) {
  343.             sprintf(buf, " %-32s%9lx%12ld      0x%02x\n",
  344.                 symtbl[x]._sym, symtbl[x]._val,symtbl[x]._val, symtbl[x]._atr);
  345.             list_dump(buf);
  346.         }
  347.         if (lfile_open) {
  348.             /** finish listing file */
  349.             fclose(lst_f);
  350.         }
  351.     }
  352.     exit(0);
  353. }
  354.  
  355.  
  356. /* endmain */
  357.  
  358. label_do()
  359. {
  360.     int x;
  361.  
  362.     do_label = NO;
  363.     if (pass == 1) {
  364.         /** add as permanent (and/or relative) */
  365.         if (symenter(label, loc_counter, (rorg) ? 'r' : 'a')
  366.             == ERROR) {
  367.             fatal = YES;
  368.             puts("\007\nsymbol table FULL!\007");
  369.             return ERROR;
  370.         }
  371.     }
  372.     else {                                        /* pass == 2 */
  373.         if (x = symsearch(label)) {
  374.             if (symtbl[x]._atr & 4) {                /* redefined */
  375.                 err_out(REDEF);
  376.                 err_out(NULL);    /* cause the dumping of this error */
  377.             }
  378.         }
  379.         else {
  380.             err_out(UNDEF_SYMBOL);    /* label never defined */
  381.             err_out(NULL);        /* cause the dumping of this error */
  382.         }
  383.     }
  384.     return OK;
  385. }
  386.  
  387. /* parse statement for label and instruction, find operand field */
  388.  
  389. /* state types */
  390. #define START 1
  391. #define LBL 2
  392. #define LIM 3
  393. #define STOP 4
  394.  
  395. /* character types */
  396. #define LIM_C 1
  397. #define LM_C 2
  398. #define LBLTRM_C 3
  399. #define WS_C 4
  400. #define STMEND_C 5
  401. #define CMNT_C 6
  402. #define ILGL_C 7
  403.  
  404. preparse()
  405. {
  406.     char *sbuf_ptr = statement;            /* pointer to statement buffer */
  407.     char *field_ptr = NULL;                /* pointer to present field */
  408.     char field_len = 0;                    /* length of present scanned field */
  409.     FLAG state = START;                    /* present state */
  410.     FLAG bad_field = NO;
  411.  
  412.     label[0] = label[31] = instr[0] = instr[31] = NULL;
  413.     opfld_ptr = NULL;
  414.     stmnt_ptr = statement;                /* init for get_source() */
  415.  
  416. /* LIM_C:        'A'-'Z','a'-'z','.'        */
  417. /* LM_C:        '0'-'9','_',?'-'?,'$'    */
  418. /* LBLTRM_C:    ':'                        */
  419. /* WS_C:        ' ','\t'                */
  420. /* STMEND_C:    '\n'                    */
  421. /* CMNT_C:        '*'                        */
  422. /* ILGL_C:        <anything else>            */
  423.  
  424. /* START state */
  425.  
  426.     switch (nextc(&sbuf_ptr)) {
  427.     case CMNT_C:
  428.     case STMEND_C:
  429.         opfld_ptr = statement;            /* operands or comment */
  430.         return COMMENT;                    /* nothing here... */
  431.     case ILGL_C:                        /* illegal character */
  432.     case LM_C:                            /* LM_C's can't start label */
  433.         label[31] = YES;                /* bad label char in label field */
  434.     case LIM_C:
  435.         field_ptr = sbuf_ptr - 1;        /* nextc already inc. sbuf_ptr */
  436.         ++field_len;                    /* got 1 so far */
  437.         state = LBL;                    /* enter LBL state */
  438.         break;
  439.     case WS_C:
  440.         field_ptr = nextfield(&sbuf_ptr);        /* skip the white space */
  441.         if (*field_ptr == '*' || *field_ptr == '\n') {
  442.             opfld_ptr = statement;                /* operands or comment */
  443.             return COMMENT;
  444.         }
  445.         state = LIM;
  446.         break;                                    /* try again */
  447.     }
  448.  
  449. /* LBL state */
  450.  
  451.     while (state == LBL) {
  452.         switch(nextc(&sbuf_ptr)) {
  453.         case ILGL_C:
  454.             label[31] = YES;                /* got a bad char */
  455.         case LIM_C:
  456.         case LM_C:
  457.             ++field_len;                    /* one more label char */
  458.             continue;                        /* still in LBL state */
  459.         case STMEND_C:
  460.             state = STOP;
  461.         case LBLTRM_C:                            /* label ended... */
  462.         case WS_C:
  463.             savefield(field_ptr, field_len, label);    /* save the label */
  464.             if (state != STOP) {
  465.                 field_len = NULL;                    /* starting fresh */
  466.                 field_ptr = nextfield(&sbuf_ptr);    /* get a new field */
  467. /**f3*/            state = (*field_ptr == '*') ? STOP : LIM;
  468.             }
  469.         }
  470.     }
  471.  
  472. /* LIM state */
  473.  
  474.     while (state == LIM) {
  475.         switch(nextc(&sbuf_ptr)) {
  476.         case LM_C:
  477.         case LIM_C:
  478.                 ++field_len;
  479.                 continue;                                /* try another */
  480.         case STMEND_C:
  481.         case WS_C:
  482.                 state = STOP;
  483.                 savefield(field_ptr, field_len, instr);    /* save legal instr */
  484.                 instr[31] = bad_field;
  485.                 break;
  486.         case LBLTRM_C:
  487.                 savefield(field_ptr, field_len, label);    /* save label */
  488.                 label[31] = bad_field;
  489.                 bad_field = field_len = NULL;            /* going for instr */
  490.                 field_ptr = nextfield(&sbuf_ptr);        /* look for it */
  491.                 continue;                                /* still LIM state */
  492.         case ILGL_C:
  493.                 bad_field = YES;                        /* bad char */
  494.                 ++field_len;
  495.                 continue;                                /* try another */
  496.         }
  497.     }
  498.  
  499.  
  500. /* STOP state */
  501.  
  502.     nextfield(&sbuf_ptr);                            /* get to next field */
  503.     opfld_ptr =  sbuf_ptr;                            /* operands or comment */
  504.     return OK;
  505. }
  506.  
  507. /* return type of char pointed to, bump pointer */
  508.  
  509. nextc(ptr)
  510. char **ptr;
  511. {
  512.     register char c;
  513.  
  514.     c = *(*ptr)++;    /* get the buf ptr, post inc., get char it points to */
  515.     if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || (c == '.'))
  516.         return LIM_C;
  517.     if (((c >= '0') && (c <= '9')) || (c == '_') || (c == '$'))
  518.         return LM_C;                /** || (c == '-') ??? **/
  519.     switch (c) {
  520.     case '\n':    return STMEND_C;
  521.     case ' ':
  522.     case '\t':    return WS_C;
  523.     case ':':    return LBLTRM_C;
  524.     case '*':    return CMNT_C;
  525.     default:    return ILGL_C;
  526.     }
  527. }
  528.  
  529. /* align pointer on next char other than ' ' or '\t' */
  530.  
  531. nextfield(ptr)
  532. char **ptr;
  533. {
  534.     if (!**ptr)    return --(*ptr);
  535.     while ((**ptr == ' ') || (**ptr == '\t'))    ++(*ptr);    /* bump buf ptr */
  536.     return *ptr;                                            /* value of ptr */
  537. }
  538.  
  539. /***
  540.     get a line of text into statement.  Allows nesting of source files and
  541.     input from stdin.
  542. ***/
  543.  
  544. char *
  545. nextline()
  546. {                                                /* get a line into buffer */
  547.     while (!fgets(statement, STMNT_SIZE, _src[src_level])) {
  548.         if (src_level) {                    /* in an included file */
  549.             fclose(_src[src_level--]);        /* close file, pop stack */
  550.             continue;                        /* try level above */
  551.         }    
  552.         if (++pass > 2) return NULL;        /* end second pass main file */
  553.         loc_counter = loc_plus = 0;            /* set counter to default */
  554.         line_count = 0;                        /* rewind for second pass */
  555.         for ( ; src_level; fclose(_src[src_level--]));/* close include files */
  556.         fseek(_src[0], 0L, 0);                /* rewind the source file */
  557.         continue;                            /* start second pass */
  558.     }
  559.     ++line_count;                            /* count the line */
  560.     return statement;                        /* anything but NULL would work */
  561. }
  562.  
  563. /* save the field pointed to by ptr, max field length is 30 + NULL */
  564.  
  565. savefield(ptr, len, dest)
  566. char *ptr;
  567. int len;
  568. char *dest;
  569. {
  570.     char x;
  571.     for (x = 30; x && len; --x, --len)            /* dec. x and len each time */
  572.         *dest++ = *ptr++;            /* move ptr char to dest char, inc. both */
  573.     *dest = '\0';                    /* terminate string */
  574. }
  575.  
  576. /*** aztec can't...
  577. #undef START
  578. #undef LBL
  579. #undef LIM
  580. #undef STOP
  581.  
  582. #undef LIM_C
  583. #undef LM_C
  584. #undef LBLTRM_C
  585. #undef WS_C
  586. #undef STMEND_C
  587. #undef CMNT_C
  588. #undef ILGL_C
  589. ***/                                                    /* end of preparse() */
  590.  
  591. /***
  592.     send data for present line here, dump when appropriate
  593.  
  594. line format:
  595.  
  596.          1         2         3         4         5         6         7
  597. 1234567890123456789012345678901234567890123456789012345678901234567890123456789
  598. |  | |    | |  | |       | |       |     |     | |             | |            |
  599. line locval opcd 1st  word 2nd  word     instrct operand field.. .comment field
  600.  
  601. 1234 123456 1234 1234 1234 1234 1234    123456789223456789323456789423456789...
  602.            [---- ---- ---- ---- ----]   [-----------------------------------..]
  603.  
  604. ***/
  605.  
  606. /*
  607.     raw code is sent here as it is produced by the system. this
  608.     function will send it to appropriate places, in the correct form.
  609. */
  610.  
  611. dump_code(typ, cdp, cdl)
  612. int typ;
  613. char *cdp;
  614. int cdl;
  615. {
  616.     register int x, y;
  617.     char buf[85];
  618.     char acode[20];
  619.  
  620.     switch (typ) {
  621.     case CODE:                    /* dump all fields, including error stack */
  622.     case DATA:                    /* dump line, loc, code, pseudo, op/comments */
  623.     case MSG:
  624.         obj_out(typ, cdp, cdl);
  625.         if (!lstchnl) {
  626.             if (typ == CODE  || typ == MSG)            /* dump remaining op/com */
  627.                 if (errchnl) err_out(NULL);            /* dump errors */
  628.             break;
  629.         }
  630.         sprintf(buf, " %04d %06lx ", line_count, loc_counter); /* bytes 0-12 */
  631.         x = 13;
  632.         if (cdl) {
  633.             hex_byt(acode, cdp, cdl);        /* convert raw code to ascii hex */
  634.             for (y = 0; y < (cdl * 2); ) {    /* for each byt in acode */
  635.                 buf[x++] = acode[y++];            /* ...move to buf... */
  636.                 if (!(y%4)) buf[x++] = ' ';        /* ...if 4th byte add space */
  637.             }
  638.         }
  639.         while (x < 40) buf[x++] = ' ';        /* pad rest with spaces */
  640.         buf[x] = '\0';
  641.         list_dump(buf);                        /* send it */
  642.         if (get_source(buf)) {                /* dump the source */
  643.             list_dump(buf);
  644.         }
  645.         if (typ == DATA) break;                /* let data sender flush */
  646.         goto flush;                            /* dump source */
  647.     case MDATA:                                /* dump loc, code, op/comments */
  648.         obj_out(typ, cdp, cdl);
  649.         if (!lstchnl) break;
  650.         hex_byt(acode, cdp, cdl);            /* convert raw code to ascii hex */
  651.         for (x = 0; x < 13; ) buf[x++] = ' ';                /* pad it */
  652.         for (y = 0; y < (cdl * 2); ) {        /* for each byte in acode... */
  653.             buf[x++] = acode[y++];            /* ...move to buf... */
  654.             if (!(y%4)) buf[x++] = ' ';        /* ...if 4th byte add space */
  655.         }
  656.         while (x < 40) buf[x++] = ' ';
  657.         buf[x] = '\0';
  658.         list_dump(buf);
  659.         if (get_source(buf)) {                    /* dump the source */
  660.             list_dump(buf);
  661.         }
  662.         else list_dump("\n");                /* terminate the data line */
  663.         break;
  664.     case FLUSH:    /* dump remaining comment field, error stack */
  665. flush:
  666.         while (get_source(buf)) {
  667. /**            if (buf[0] == '\n') break;    */
  668.             list_dump("\t\t\t\t\t");            /* 5 tabs equals 40 spaces */
  669.             list_dump(buf);
  670.         }
  671.         if (errchnl) err_out(NULL);                            /* dump errors */
  672.         break;
  673.     }
  674. }
  675.  
  676. /* send buffer to all open list channels */
  677.  
  678. list_dump(buf)
  679. char *buf;
  680. {
  681.     if (nolist) return;
  682.     if (lcon) puts(buf);
  683.     if (llst) fputs(buf, lst_d);
  684.     if (lfile) fputs(buf, lst_f);
  685. }
  686.  
  687. /* report the error to all open error channels */
  688.  
  689. err_out(err_num)
  690. int err_num;
  691. {
  692.     register int x;
  693.     char buf[85];
  694.     static int err_stk[10];
  695.     static int err_sp = 10;
  696.  
  697.     switch (err_num) {
  698.     case NULL:
  699.         for (x = 10; --x >= err_sp; ) {
  700.             sprintf(buf, "?> error # %d\n", -(err_stk[x]) - 100);
  701.             if (econ) {
  702.                 puts(buf);
  703.             }
  704.             if (elst) {
  705.                 fputs(buf, lst_d);
  706.             }
  707.             if (elfile) {
  708.                 fputs(buf, lst_f);
  709.             }
  710.             if (efile) {
  711.                 fprintf(err_f, ">> level: %d, line: %d\n",
  712.                             src_level + 1, line_count);
  713.                 fputs(buf, err_f);
  714.             }
  715.         }
  716.     case FLUSH:
  717.         err_sp = 10;                                    /* reset */
  718.         break;
  719.     default:
  720.         if (err_sp) {
  721.             err_stk[--err_sp] = err_num;
  722.         }
  723.     }
  724.     return err_num;
  725. }
  726.  
  727. obj_out(action, cdp, size)
  728. int action;
  729. char *cdp;
  730. int size;
  731. {
  732.     register int y;
  733.     static long lc = 0L;
  734.     static char s_buf[48] = "S";    /* init first char, room to spare */
  735.     static char cnt;                /* bytes in current buffer */
  736.     static int x;                    /* index into s_buf */
  737.  
  738.     if (!obj_open) return NULL;                    /* put into obj file */
  739.     switch (action) {
  740.     case CODE:
  741.     case DATA:
  742.         lc = 0L;
  743.     case MDATA:
  744. top:
  745.         for (y = 0; size && (cnt < 16); --size, ++cnt) {
  746. /**f4*/        lcksm += cdp[y++];                            /* line checksum */
  747.         }
  748.         hex_byt(s_buf + x, cdp, y);                        /* get them in buf */
  749.         x += y * 2;                                        /* bump x */
  750.         lc += y;
  751.         if (cnt == 16) {                                /* time to flush */
  752.             flush_rcrd(s_buf, cnt, x);
  753.             new_rcrd(s_buf, lc, &x);
  754.             cnt = 0;
  755.             if (size) {                                    /* more to buffer */
  756.                 cdp += y;                                /* skip already done */
  757.                 goto top;
  758.             }
  759.         }
  760.         break;
  761.     case SYNC:
  762. /**f4*/    flush_rcrd(s_buf, cnt, x);                /* flush s_buf */
  763.         new_rcrd(s_buf, 0L, &x);
  764.         cnt = 0;
  765.         break;
  766.     case OPEN:
  767.         fputs("S0030000FC\n", obj_f);                    /* header record */
  768. /**f4*/ new_rcrd(s_buf, 0L, &x);
  769.         cnt = 0;
  770.         break;
  771.     case CLOSE:
  772.         flush_rcrd(s_buf, cnt, x);                /* flush s_buf */
  773. /**f4*/    fputs("S9020000\n", obj_f);
  774. /**        fprintf(obj_f, "S9030000%02x\n", fcksm);*/
  775.         break;
  776.     case MSG:    break;
  777.     default:    return ERROR;
  778.     }
  779.     return NULL;
  780. }
  781.  
  782. new_rcrd(s_buf, lc, x)
  783. char *s_buf;
  784. long lc;
  785. int *x;
  786. {
  787. /**f4*/
  788.     long temp;
  789.  
  790.     temp = loc_counter + lc;
  791.     if (temp & ~0xffffL) {
  792.         sprintf(s_buf + 1, "200%06lx", temp);
  793. /**f4?*/
  794.         lcksm = (temp >> 16) + (temp >> 8) + temp;
  795.         *x = 10;
  796.     }
  797.     else {
  798.         sprintf(s_buf + 1, "100%04lx", temp);
  799.         lcksm = (temp >> 8) + temp;
  800.         *x = 8;
  801.     }
  802. }
  803.  
  804. flush_rcrd(s_buf, cnt, x)
  805. char *s_buf;
  806. char cnt;
  807. char x;
  808. {
  809.     register char *c;
  810.  
  811.     if (!cnt) return NULL;                        /* empty record */
  812. /** fixed 12/20/83 tnx m hitch */
  813.     cnt += 1 + ((s_buf[1] == '2') ? 3 : 2);        /* add byte count */
  814.     hex_byt(s_buf + 2, &cnt, 1);                /* place in s_buf */
  815.     lcksm = 0xff - (lcksm + cnt);                /* add checksum */
  816.     hex_byt(&s_buf[x], &lcksm, 1);                /* place it in s_buf */
  817.     strcpy(&s_buf[x+2], "\n");                    /* terminate record */
  818. /** lc fix */
  819.     for (c = s_buf; *c; ++c)    /* some printf()'s make a-f lowercase  */
  820.         if (*c >= 'a' && *c <= 'f') *c -= ('a' - 'A');                    
  821.     fputs(s_buf, obj_f);
  822.     return TRUE;
  823. }
  824.  
  825. /**
  826.     given a pointer to an array of bytes, convert each to a 2 byte
  827.     ascii rep, and place into char array pointed at by ap, for len
  828.     bytes
  829. **/
  830.  
  831. hex_byt(ap, bp, len)
  832. char *ap;
  833. char *bp;
  834. int len;
  835. {
  836.     for ( ; len; --len, ++bp, ap += 2) {
  837.         ap[0] = *bp >> 4;
  838.         ap[0] += (ap[0] > 9) ? 55 : 48;    /* ':' + ('A' - ':') : '0' */
  839.         ap[1] = *bp & 0x0f;
  840.         ap[1] += (ap[1] > 9) ? 55 : 48;
  841.     }
  842. }
  843.  
  844. /***
  845.     gets up to wrap - 40 chars from statement, places into buf.
  846. ***/
  847.  
  848. get_source(buf)
  849. char *buf;
  850. {
  851.     register int size, cnt = 1;
  852.     int x;
  853.  
  854.     if ((stmnt_ptr != statement) && trunc) return (int)(buf[0] = '\0');
  855.     for (size = wrap - (40 + 1); --size; ++cnt) {
  856.         switch (*stmnt_ptr) {
  857.         case NULL:    return (int)(buf[0] = '\0');
  858.         case '\n':
  859.             break;
  860.         case '\t':
  861.             size -= (x = 7 - (cnt % 8));    /* 7 'cause loop subs 1 */
  862.             if (size < 1) {                    /* tab would overflow.. */
  863.                 size = 1;                    /* ..so cause exit without */
  864.                 continue;                    /* placing tab into buffer */
  865.             }
  866.             cnt += x;                        /* fall thru to default */
  867.         default:
  868.             *buf++ = *stmnt_ptr++;
  869.             continue;
  870.         }
  871.     }
  872. /**    while ((buf-1) != ' ' && (buf-1) != '\t') {
  873.         --buf;
  874.         --stmnt_ptr;
  875.     }
  876. **/
  877.     *buf++ = '\n';
  878.     *buf = '\0';
  879.     if (*stmnt_ptr == '\n') ++stmnt_ptr;    /* make NULL for next call */
  880.     return TRUE;
  881. }
  882.  
  883. /* endcode */
  884. 5 : 48;    /* ':' + ('A' - ':') : '0' */
  885.         ap[1] = *bp & 0x0f;
  886.         ap[1] += (ap[1] > 9) ? 55 : 48;
  887.     }
  888. }
  889.  
  890. /***
  891.     gets up