home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 348_01 / z80a.c < prev    next >
Text File  |  1991-05-02  |  23KB  |  961 lines

  1. /*
  2.  
  3. This file contains the main program and line assembly routines for the
  4. assembler.  The main program parses the command line, feeds the source lines
  5. to the line assembly routine, and sends the results to the listing and object
  6. file output routines.  It also coordinates the activities of everything.  The
  7. line assembly routine uses the expression analyzer and the lexical analyzer to
  8. parse the source line convert it into the object bytes that it represents.
  9. */
  10.  
  11. #define YES 1
  12. #define NO  0
  13.  
  14. /*  Get global goodies:  */
  15.  
  16. #include "z80a.h"
  17.  
  18. /*  Define global mailboxes for all modules:                */
  19.  
  20. char errcode, line[MAXLINE + 1], title[MAXLINE], sub_tit[MAXLINE];
  21. int pass = 0;
  22. int code = TRUE;
  23. int listok = TRUE;
  24. int eject, filesp, forwd, listhex;
  25. unsigned address, bytes, errors, listleft, obj[MAXLINE], pc;
  26. unsigned pagelen = 60;
  27. FILE *filestk[FILES], *source;
  28. TOKEN token;
  29.  
  30. /*  Mainline routine.  This routine parses the command line, sets up    */
  31. /*  the assembler at the beginning of each pass, feeds the source text    */
  32. /*  to the line assembler, feeds the result to the listing and hex file    */
  33. /*  drivers, and cleans everything up at the end of the run.        */
  34.  
  35. static int done, ifsp, off;
  36.  
  37. main(argc,argv)
  38. int argc;
  39. char **argv;
  40. {
  41.     SCRATCH unsigned *o;
  42.     int newline();
  43.     void asm_line();
  44.     void lclose(), lopen(), lputs();
  45.     void hclose(), hopen(), hputc();
  46.     void error_s(), fatal_error(), warning();
  47.  
  48.     printf("Z80 Cross-Assembler (Portable Z80ASM version) Ver 0.0\n");
  49.     printf("Copyright (c) 1988 Michael G. Panas\n\n");
  50.  
  51.     while (--argc) {
  52.     if (**++argv == '-') {
  53.         switch (toupper(*++*argv)) {
  54.         case 'L':   if (!*++*argv) {
  55.                 if (!--argc) { warning(NOLST);  break; }
  56.                 else ++argv;
  57.                 }
  58.                 lopen(*argv);
  59.                 break;
  60.  
  61.         case 'O':   if (!*++*argv) {
  62.                 if (!--argc) { warning(NOHEX);  break; }
  63.                 else ++argv;
  64.                 }
  65.                 hopen(*argv);
  66.                 break;
  67.  
  68.         default:    warning(BADOPT);
  69.         }
  70.     }
  71.     else if (filestk[0]) warning(TWOASM);
  72.     else if (!(filestk[0] = fopen(*argv,"r"))) fatal_error(ASMOPEN);
  73.     }
  74.     if (!filestk[0]) fatal_error(NOASM);
  75.  
  76.     while (++pass < 3) {
  77.     fseek(source = filestk[0],0L,0);  done = off = FALSE;
  78.     errors = filesp = ifsp = pc = 0;  title[0] = '\0';
  79.     while (!done) {
  80.         errcode = ' ';
  81.         if (newline()) {
  82.         error_s('*');
  83.         strcpy(line,"\tEND\n");
  84.         done = eject = TRUE;  listhex = FALSE;
  85.         bytes = 0;
  86.         }
  87.         else asm_line();
  88.         pc = word(pc + bytes);
  89.         if (pass == 2) {
  90.         lputs();
  91.         for (o = obj; bytes--; hputc(*o++));
  92.         }
  93.     }
  94.     }
  95.  
  96.     fclose(filestk[0]);  lclose();  hclose();
  97.  
  98.     if (errors) printf("%d Error(s)\n",errors);
  99.     else printf("No Errors\n");
  100.  
  101.     exit(errors);
  102. }
  103.  
  104. /*  Line assembly routine.  This routine gets expressions and tokens    */
  105. /*  from the source file using the expression evaluator and lexical    */
  106. /*  analyzer, respectively.  It fills a buffer with the machine code    */
  107. /*  bytes and returns nothing.                        */
  108.  
  109. static char label[MAXLINE];
  110. static int ifstack[IFDEPTH] = { ON };
  111.  
  112. static OPCODE *opcod;
  113.  
  114. void asm_line()
  115. {
  116.     SCRATCH int i;
  117.     int isalph(), popc();
  118.     OPCODE *find_code(), *find_operator();
  119.     void do_label(), flush(), normal_op(), pseudo_op();
  120.     void error_s(), pops(), pushc(), trash(), trash_lex();
  121. #ifdef MICROSOFT_C
  122.     void put_len(unsigned);
  123. #else
  124.     void put_len();
  125. #endif
  126.  
  127.     address = pc;  bytes = 0;  eject = forwd = listhex = FALSE;
  128.     for (i = 0; i < BIGINST; obj[i++] = NOP);
  129.  
  130.     label[0] = '\0';
  131.  
  132.     if ((i = popc()) != ' ' && i != '\n') {
  133.     if (isalph(i)) {
  134.         pushc(i);  pops(label);
  135.         if (find_operator(label)) { label[0] = '\0';  error_s('L'); }
  136.     }
  137.     else {
  138.         error_s('L');
  139.         while ((i = popc()) != ' ' && i != '\n');
  140.     }
  141.     }
  142.  
  143.     trash(); opcod = NULL;
  144.     if ((i = popc()) != '\n') {
  145.     if (!isalph(i)) error_s('S');
  146.     else {
  147.         pushc(i);  pops(token.sval);
  148.         if (!(opcod = find_code(token.sval))) error_s('O');
  149.     }
  150.     if (!opcod) { listhex = TRUE;  bytes = BIGINST; }
  151.     }
  152.  
  153.     if (opcod && opcod -> attr & ISIF) { if (label[0]) error_s('L'); }
  154.     else if (off) { listhex = FALSE;  flush();  return; }
  155.  
  156.     if (!opcod) { do_label();  flush(); }
  157.     else {
  158.     listhex = TRUE;
  159.     trash_lex();        /* space allowed here - don't eat '*' */
  160.     if (opcod -> attr & PSEUDO) {
  161.         pseudo_op();
  162.         if (bytes) put_len(bytes);
  163.     } else {
  164.         normal_op();
  165.         put_len(0);
  166.     }
  167.     flush(); /* throw rest of line away */
  168.     }
  169.     source = filestk[filesp];
  170.     return;
  171. }
  172.  
  173. static void flush()
  174. {
  175.     while (popc() != '\n');
  176. }
  177.  
  178. static void do_label()
  179. {
  180.     SCRATCH SYMBOL *l;
  181.     unsigned pin, st;
  182.     SYMBOL *find_symbol(), *new_symbol();
  183.     void error_s();
  184.  
  185.     if (label[0]) {
  186.     listhex = TRUE;
  187.     if (label[0] == '@') {
  188.         pin = PIN;
  189.         st = 1;
  190.     } else {
  191.         pin = st = 0;
  192.     }
  193.     if (pass == 1) {
  194.         if (!((l = new_symbol(&label[st])) -> attr)) {
  195.         l -> attr = FORWD + VAL + pin;
  196.         l -> valu = pc;
  197.         l -> len = 2; /* preset length */
  198.         }
  199.     }
  200.     else {
  201.         if (l = find_symbol(&label[st])) {
  202.         l -> attr = VAL + pin;
  203.         if (l -> valu != pc) error_s('M');
  204.         }
  205.         else error_s('P');
  206.     }
  207.     }
  208. }
  209.  
  210. static void put_len(length)
  211. unsigned length;
  212. {
  213.     unsigned st = 0;
  214.     SCRATCH SYMBOL *l;
  215.     SYMBOL *find_symbol();
  216.     
  217.     if (label[0]) {
  218.     if (label[0] == '@')    st = 1;
  219.     if (l = find_symbol(&label[st])) {
  220.         l -> len = length;
  221.     }
  222.     }
  223. }
  224. static void put_attr(attrv)
  225. unsigned attrv;
  226. {
  227.     unsigned st = 0;
  228.     SCRATCH SYMBOL *l;
  229.     SYMBOL *find_symbol();
  230.     
  231.     if (label[0]) {
  232.     if (label[0] == '@')    st = 1;
  233.     if (l = find_symbol(&label[st])) {
  234.         l -> attr |= attrv;
  235.     }
  236.     }
  237. }
  238.  
  239. unsigned get_len(sym)
  240. char *sym;
  241. {
  242.     SCRATCH SYMBOL *l;
  243.     SYMBOL *find_symbol();
  244.     
  245.     if (pass == 1) return 1;
  246.     if (l = find_symbol(sym)) {
  247.         if (l -> len == 0) return 2;
  248.         return l -> len;
  249.     }
  250.     return 0;
  251. }
  252.  
  253. static void normal_op()
  254. {
  255.     SCRATCH unsigned t, opcode, op, left, index, long_op;
  256.     int grab_comma();
  257.     unsigned expr(), grab_index();
  258.     TOKEN *lex(), *lex_op();
  259.     void do_label(), error_s(), s_error(), unlex();
  260.  
  261.     opcode = opcod -> valu;
  262.     do_label();
  263.     left = ((opcod -> attr & SHIFT) >> 8);
  264.     long_op = NO;
  265.     
  266.     switch (opcod -> attr & OPTYPE) {
  267.     case NO_ARG:
  268.             bytes = 1;
  269.             break;
  270.  
  271.     case NO_ARG_L:    long_op = YES;
  272.             bytes = 2;
  273.             break;
  274.  
  275.     case ONE_ARG:    /* all 8 bit IMM mode instuctions */
  276.             if (left) { /* LDI case */
  277.                 op = (lex() -> valu);
  278.                 switch (token.attr & TYPE) {
  279.                     case MIX:
  280.                     case REG: break;
  281.                     default:  goto error;
  282.                 }
  283.                 if (token.attr & INDEX) { /* IX or IY */
  284.                     opcode += ((op << 8)+0x30); /* set prefix */
  285.                     if (grab_comma()) goto error;
  286.                     op = grab_index();
  287.                 /* SEP eaten by grab_index() */
  288.                     op += (expr() & 0xff) << 8;
  289.                     long_op = YES;
  290.                     bytes = 4;
  291.                     break;
  292.                 }
  293.                 if (grab_sep()) goto error; /* no semicolon */
  294.                 opcode += (op << left);
  295.             }
  296.             op = expr();
  297.             bytes = 2;
  298.             break;
  299.  
  300.     case ONE_ARG_L: /* opcode is one or two bytes with arg */
  301.             /* JUMPI and LDSP only */
  302.             op = lex() -> valu;
  303.             if ((token.attr & TYPE) != REG) {
  304.                 goto error;
  305.             }
  306.             if (token.attr & INDEX) { /* IX or IY */
  307.                 opcode += (op << 8); /* set prefix */
  308.                 long_op = YES;
  309.                 bytes = 2;
  310.                 break;
  311.             }
  312.             if (op != HL) goto error; /* only HL allowed */
  313.             bytes = 1;
  314.             break;
  315.     
  316.     case ONE_ARG_L2: /* opcode is two bytes with arg type 2 */
  317.             /* ADCHL, ADDIY, ADDIX, SBCHL only */
  318.             op = lex() -> valu;
  319.             if ((token.attr & TYPE) != REG) {
  320.                 goto error;
  321.             }
  322.             switch (op) {
  323.                 case BC: op = 0; break;
  324.                 case DE: op = 1; break;
  325.                 case X: op = 2;
  326.                     if (opcode != 0xdd09) goto error;
  327.                     break;
  328.                 case Y: op = 2;
  329.                     if (opcode != 0xfd09) goto error;
  330.                     break;
  331.                 case HL: op = 2;
  332.                     if (opcode == 0xdd09 || opcode == 0xfd09)
  333.                         goto error;
  334.                     break;
  335.                 case SP: op = 3; break;
  336.                 default: goto error;
  337.             }
  338.             opcode += (op << 4);
  339.             long_op = YES;
  340.             bytes = 2;
  341.             break;            
  342.  
  343.     case CALL:
  344.     case JUMP:    op = lex() -> valu;
  345.             if ((t = token.attr & TYPE) == CON || (t == MIX)) {
  346.                 switch (op) {
  347.                     case C:     op = 0x03;
  348.                          break;
  349.                     case M:  op = 0x07;
  350.                          break;
  351.                     default: op -= 0x10;
  352.                 }
  353.                 if (grab_sep()) goto error;
  354.                 if (opcode == 0xcd) {
  355.                     opcode = 0xc4;
  356.                 } else {
  357.                     opcode--;
  358.                 }
  359.                 opcode += (op << 3);
  360.                 op = expr();
  361.                 bytes = 3;
  362.                 break;
  363.             }
  364.             unlex();
  365.             op = expr();
  366.             bytes = 3;
  367.             break;
  368.  
  369.     case RETURN:    op = lex_op() -> valu;
  370.             if ((t = token.attr & TYPE) == CON || (t == MIX)) {
  371.                 switch (op) {
  372.                     case C:     op = 0x03;
  373.                          break;
  374.                     case M:  op = 0x07;
  375.                          break;
  376.                     default: op -= 0x10;
  377.                 }
  378.                 opcode = 0xc0;
  379.                 opcode += (op << 3);
  380.             }
  381.             unlex();
  382.             bytes = 1;
  383.             break;
  384.     
  385.     case JREL:    op = lex() -> valu;
  386.             if ((t = token.attr & TYPE) == CON || (t == MIX)) {
  387.                 switch (op) {
  388.                     case C:     opcode = 0x38;
  389.                          break;
  390.                     case NC: opcode = 0x30;
  391.                          break;
  392.                     case Z:  opcode = 0x28;
  393.                          break;
  394.                     case NZ: opcode = 0x20;
  395.                          break;
  396.                     default: goto error;
  397.                 }
  398.                 if (grab_sep()) goto error;
  399.                 goto jrel;
  400.             }
  401.             unlex();
  402. jrel:
  403.             op = expr();
  404.             op -= pc + 2;
  405.             if ((clamp(op) > 0x007f) && (op < 0xff80))
  406.                 error_s('R');
  407.             bytes = 2;
  408.             break;
  409.  
  410.     case L_ARG:    /* LDI16 - only BC, DE, HL, IX, IY and SP allowed as operands */
  411.             op = lex() -> valu;
  412.             switch (token.attr & TYPE) {
  413.                 case MIX:
  414.                 case REG: break;
  415.                 default:  goto error;
  416.             }
  417.             if (token.attr & INDEX) { /* IX or IY */
  418.                 opcode = ((op << 8)+0x21); /* set prefix */
  419.                 if (grab_sep()) goto error;
  420.                 op = expr();
  421.                 long_op = YES;
  422.                 bytes = 4;
  423.                 break;
  424.             }
  425.             switch (op) {
  426.                 case BC: op = 0; break;
  427.                 case DE: op = 1; break;
  428.                 case HL: op = 2; break;
  429.                 case SP: op = 3; break;
  430.                 default: goto error;
  431.             }
  432.             opcode += (op << 4);
  433.             if (grab_sep()) goto error;
  434. l_arg2:
  435.     case L_ARG2:
  436.             op = expr();
  437. l_arg:
  438.             bytes = 3;
  439.             break;            
  440.  
  441.     case L_ARG_L:    /* LD16 only         */
  442.             op = lex() -> valu;
  443.             if ((token.attr & TYPE) != REG) {
  444.                 goto error;
  445.             }
  446.             if (token.attr & INDEX) { /* IX or IY */
  447.                 opcode += (op << 8); /* set prefix */
  448.                 if (grab_sep()) goto error;
  449.                 op = expr();
  450.                 long_op = YES;
  451.                 bytes = 4;
  452.                 break;
  453.             }
  454.             switch (op) {
  455.                 case BC: op = 0; break;
  456.                 case DE: op = 1; break;
  457.                 case HL: if (grab_sep()) goto error; 
  458.                      goto l_arg2;
  459.                 case SP: op = 3; break;
  460.                 default: goto error;
  461.             }
  462.             opcode = ((op << 4) + 0xed4b);
  463.             if (grab_sep()) goto error;
  464.             op = expr();
  465.             long_op = YES;
  466.             bytes = 4;
  467.             break;            
  468.             
  469.     case L_ARG_L2:    /* ST16 only         */
  470.             op = expr();
  471.             /* expr() eats SEP */
  472.             t = lex() -> valu;
  473.             if ((token.attr & TYPE) != REG) {
  474.                 goto error;
  475.             }
  476.             if (token.attr & INDEX) { /* IX or IY */
  477.                 opcode += (t << 8); /* set prefix */
  478.                 long_op = YES;
  479.                 bytes = 4;
  480.                 break;
  481.             }
  482.             switch (t) {
  483.                 case BC: t = 0; break;
  484.                 case DE: t = 1; break;
  485.                 case HL: goto l_arg;
  486.                 case SP: t = 3; break;
  487.                 default: goto error;
  488.             }
  489.             opcode = ((t << 4) + 0xed43);
  490.             long_op = YES;
  491.             bytes = 4;
  492.             break;            
  493.             
  494.     case L_OP:    /* ADDHL, DEC16, INC16, PUSH and POP */
  495.             op = lex() -> valu;
  496.             switch (token.attr & TYPE) {
  497.                 case MIX:
  498.                 case REG: break;
  499.                 default:  goto error;
  500.             }
  501.             if (token.attr & INDEX) { /* IX or IY */
  502.                 opcode += ((op << 8)+0x20); /* set prefix */
  503.                 long_op = YES;
  504.                 bytes = 2;
  505.                 break;
  506.             }
  507.             if ((opcode == 0xC1 || opcode == 0xC5) && op == SP) {
  508. error:                s_error(); break;
  509.             }
  510.             if (op == AF) {
  511.                 switch (opcode) {
  512.                     case 0x09:
  513.                     case 0x0B:
  514.                     case 0x03: goto error;
  515.                 }
  516.             }
  517.             switch (op) {
  518.                 case BC: op = 0; break;
  519.                 case DE: op = 1; break;
  520.                 case HL: op = 2; break;
  521.                 case AF:
  522.                 case SP: op = 3; break;
  523.                 default: goto error;
  524.             }
  525.             opcode += (op << 4);
  526.             bytes = 1;
  527.             break;            
  528.  
  529.     case MOV:    /* LD - no value checking */
  530.             op = (lex() -> valu);
  531.             switch (token.attr & TYPE) {
  532.                 case MIX:
  533.                 case REG: break;
  534.                 default:  goto error;
  535.             }
  536.             if (token.attr & INDEX) { /* first operand IX or IY */
  537.                 opcode += ((op << 8)+0x30); /* set prefix */
  538.                 if (grab_comma()) goto error;
  539.                 index = grab_index();
  540.                 /* SEP eaten by grab_index() */
  541.                 /* get second operand */
  542.                 op = (lex() -> valu);
  543.                 switch (token.attr & TYPE) {
  544.                     case MIX:
  545.                     case REG: break;
  546.                     default:  goto error;
  547.                 }
  548.                 if (token.attr & INDEX) { /* second operand IX or IY */
  549.                     goto error;
  550.                 }
  551.                 opcode += op;
  552.                 op = low(index);
  553.                 long_op = YES;
  554.                 bytes = 3;
  555.                 break;
  556.             }
  557.             if (grab_sep()) goto error; /* no comma */
  558.             opcode += (op << 3);
  559.             /* get second operand ( first was not IX or IY) */
  560.             op = (lex() -> valu);
  561.             switch (token.attr & TYPE) {
  562.                 case MIX:
  563.                 case REG: break;
  564.                 default:  goto error;
  565.             }
  566.             if (token.attr & INDEX) { /* second operand IX or IY */
  567.                 opcode += ((op << 8)+0x06); /* set prefix */
  568.                 if (grab_comma()) goto error;
  569.                 op = low(grab_index());
  570.                 long_op = YES;
  571.                 bytes = 3;
  572.                 break;
  573.             }
  574.             opcode += op;
  575.             bytes = 1;
  576.             break;            
  577.     case RESTART:
  578.             op = expr();
  579.             op >>= 3;
  580.             if (op > 7) goto error;
  581.             opcode += (op << 3);
  582.             bytes = 1;
  583.             break;
  584.     
  585.     case S_OP:    
  586.             op = (lex() -> valu);
  587.             switch (token.attr & TYPE) {
  588.                 case MIX:
  589.                 case REG: break;
  590.                 default:  goto error;
  591.             }
  592.             if (token.attr & INDEX) { /* operand IX or IY */
  593.                 opcode += ((op << 8)+(0x06 << left)); /* set prefix */
  594.                 if (grab_comma()) goto error;
  595.                 op = grab_index();
  596.                 long_op = YES;
  597.                 bytes = 3;
  598.                 break;
  599.             }
  600.             opcode += (op << left);
  601.             bytes = 1;
  602.             break;
  603.  
  604.     case ROTATE:
  605.             op = (lex() -> valu);
  606.             switch (token.attr & TYPE) {
  607.                 case MIX:
  608.                 case REG: break;
  609.                 default:  goto error;
  610.             }
  611.             if (token.attr & INDEX) { /* operand IX or IY */
  612.                 op <<= 8; op += high(opcode);
  613.                 index = opcode; /* temp only */
  614.                 opcode = op;
  615.                 if (grab_comma()) goto error;
  616.                 op = (low(index) + 0x06) << 8;
  617.                 op += grab_index();
  618.                 long_op = YES;
  619.                 bytes = 4;
  620.                 break;
  621.             }
  622.             opcode += op;
  623.             long_op = YES;
  624.             bytes = 2;
  625.             break;            
  626.  
  627.     case XIO:
  628.             op = (lex() -> valu);
  629.             switch (token.attr & TYPE) {
  630.                 case MIX:
  631.                 case REG: break;
  632.                 default:  goto error;
  633.             }
  634.             switch (op) {
  635.                 case X:
  636.                 case Y:
  637.                 case M:
  638.                 case AF:
  639.                 case BC:
  640.                 case DE:
  641.                 case HL:
  642.                 case SP: goto error;
  643.             }
  644.             opcode += (op << 3);
  645.             long_op = YES;
  646.             bytes = 2;
  647.             break;
  648.     case BIT:
  649.             op = expr();
  650.             if (op > 7 || op < 0) goto error;
  651.             opcode += (op << 3);
  652.             /* if (grab_sep()) goto error; */
  653.             op = (lex() -> valu);
  654.             switch (token.attr & TYPE) {
  655.                 case MIX:
  656.                 case REG: break;
  657.                 default:  goto error;
  658.             }
  659.             if (token.attr & INDEX) { /* operand IX or IY */
  660.                 op <<= 8; op += high(opcode);
  661.                 index = opcode; /* temp only */
  662.                 opcode = op;
  663.                 op = (low(index) + 0x06) << 8;
  664.                 if (grab_comma()) goto error;
  665.                 op += grab_index();
  666.                 long_op = YES;
  667.                 bytes = 4;
  668.                 break;
  669.             }
  670.             opcode += op;
  671.             long_op = YES;
  672.             bytes = 2;
  673.             break;            
  674.  
  675.  
  676.     }
  677.     if (long_op) {
  678.         obj[3] = high(op); obj[2] = low(op);
  679.         obj[1] = low(opcode); obj[0] = high(opcode);
  680.         return;
  681.     } else {
  682.         obj[2] = high(op);  obj[1] = low(op);
  683.         obj[0] = low(opcode);
  684.        return;
  685.     }
  686. }
  687.  
  688. static int grab_sep()
  689. {
  690.     TOKEN *lex();
  691.  
  692.     return (lex() -> attr & TYPE) != SEP;
  693. }
  694.  
  695. static int grab_comma()
  696. {
  697.     TOKEN *lex();
  698.  
  699.     return (lex() -> attr & TYPE) != SIZE;
  700. }
  701.  
  702. static unsigned grab_index()
  703. {
  704.     SCRATCH unsigned index;
  705.     unsigned expr();
  706.     
  707.     if ((index = expr()) > 0x7f && index < 0xff80) error_s('V');
  708.     return low(index);
  709. }
  710.     
  711. static void s_error()
  712. {
  713.     void error_s();
  714.  
  715.     bytes = 2;  error_s('S');
  716. }
  717.  
  718. static void pseudo_op()
  719. {
  720.     SCRATCH char *s;
  721.     SCRATCH unsigned *o, u, t, c, cnt;
  722.     SCRATCH SYMBOL *l;
  723.     int popc(), ishex(), isnum();
  724.     unsigned expr();
  725.     SYMBOL *find_symbol(), *new_symbol();
  726.     TOKEN *lex();
  727.     void do_label(), error_s(), fatal_error();
  728.     void hseek(), pushc(), trash(), unlex();
  729. #ifdef MICROSOFT_C
  730.     void put_attr(unsigned), put_len(unsigned);
  731. #else
  732.     void put_attr(), put_len();
  733. #endif
  734.  
  735.     for (o = obj; o != obj+MAXLINE; *o++ = 0); /* zero array */
  736.     o = obj;
  737.     switch (opcod -> valu) {
  738.     case DB:    do_label();
  739.             do {
  740.             /*if ((lex() -> attr & TYPE) == SEP) u = 0;*/
  741. more_db:
  742.             pushc(t = popc());
  743.                 /*if (token.attr == STR) { */
  744.                 if (t == '"' || t == '\'') {
  745.                 lex();
  746.                 pushc(u = popc());
  747.                 if (u == ';' || u == '\n' || u == ' ') {
  748.                         for (s = token.sval; *s; *o++ = *s++)
  749.                         ++bytes;
  750.                         if ((token.attr & TYPE) == SEP) goto more_db;
  751.                         /*lex();*/  continue;
  752.                 }
  753.                 }
  754.                 /* unlex();*/
  755.                 u = popc();
  756.                 if (u == '$') {
  757.                     cnt = 0;
  758.                     while (pushc(u = popc()), ishex(u) && u != '\n') {
  759.                         for (c = t = 0; c != 2; c++) {
  760.                             if (ishex(u = popc())) {
  761.                                   t = (t*16)+(toupper(u)
  762.                                 - (isnum(u) ? '0' : 'A'-10));
  763.                             } else { pushc(u); break; }
  764.                         }
  765.                         *o++ = low(t); bytes++; cnt++;
  766.                     }
  767.                     if ( u == ',') {
  768.                         grab_comma();
  769.                         t = expr();
  770.                         if (t > MAXLINE) t = MAXLINE;
  771.                         if ((u = t - cnt) < 0) {
  772.                             u = 0; error_s('d');
  773.                         }
  774.                         bytes += u;
  775.                     if ((token.attr & TYPE) == SEP) goto more_db;
  776.                     }
  777.                 } else {
  778.                     pushc(u);
  779.                     u = expr();
  780.                     if ((token.attr & TYPE) == SIZE) t = expr();
  781.                     else t = 1;
  782.                     if (t > MAXLINE) {
  783.                         t = MAXLINE;
  784.                         error_s('r');
  785.                     }
  786.                 if (t > 1) {
  787.                     *o++ = low(u); *o++ = high(u); bytes += t;
  788.                    } else {
  789.                     *o++ = low(u);  ++bytes;
  790.                 }
  791.                 if ((token.attr & TYPE) == SEP) goto more_db;
  792.                 }
  793.             /*} while ((token.attr & TYPE) == SEP);*/
  794.             } while (pushc(t = popc()), t == ';');
  795.             put_attr(PIN_VAL);
  796.             break;
  797.  
  798.     case DS:    do_label();  u = word(pc + (t = expr()));
  799.             if (forwd) error_s('P');
  800.             else {
  801.             pc = u;
  802.             if (pass == 2) hseek(pc);
  803.             }
  804.             put_len(t);
  805.             put_attr(PIN_VAL);
  806.             break;
  807.  
  808.     case DW:    do_label();
  809.             do {
  810.             if ((lex() -> attr & TYPE) == SEP) u = 0;
  811.             else { unlex();  u = expr(); }
  812.             *o++ = high(u);  *o++ = low(u);
  813.             bytes += 2;
  814.             } while ((token.attr & TYPE) == SEP);
  815.             put_attr(PIN_VAL);
  816.             break;
  817.  
  818.     case ELSE:  listhex = FALSE;
  819.             if (ifsp) off = (ifstack[ifsp] = -ifstack[ifsp]) != ON;
  820.             else error_s('I');
  821.             break;
  822.  
  823.     case END:   do_label();
  824.             if (filesp) { listhex = FALSE;  error_s('*'); }
  825.             else {
  826.             done = eject = TRUE;
  827.             if (pass == 2 && (lex() -> attr & TYPE) != EOL) {
  828.                 unlex();  hseek(address = expr());
  829.             }
  830.             if (ifsp) error_s('I');
  831.             }
  832.             break;
  833.  
  834.     case ENDIF: listhex = FALSE;
  835.             if (ifsp) off = ifstack[--ifsp] != ON;
  836.             else error_s('I');
  837.             break;
  838.  
  839.     case EQU:   if (label[0]) {
  840.             if (pass == 1) {
  841.                 if (!((l = new_symbol(label)) -> attr)) {
  842.                 l -> attr = FORWD + VAL;  address = expr();
  843.                 if (!forwd) l -> valu = address;
  844.                     if ((token.attr & TYPE) == SIZE) {
  845.                         l -> len = expr();
  846.                         if (forwd) l -> len = 2;
  847.                     } else l -> len = 2; /* preset length */
  848.                 }
  849.             }
  850.             else {
  851.                 if (l = find_symbol(label)) {
  852.                 l -> attr = VAL;  address = expr();
  853.                 if (forwd) error_s('P');
  854.                 if (l -> valu != address) error_s('M');
  855.                 }
  856.                 else error_s('P');
  857.             }
  858.             }
  859.             else error_s('L');
  860.             break;
  861.  
  862.     case IF:    if (++ifsp == IFDEPTH) fatal_error(IFOFLOW);
  863.             address = expr();
  864.             if (forwd) { error_s('P');  address = TRUE; }
  865.             if (off) { listhex = FALSE;  ifstack[ifsp] = NULL; }
  866.             else {
  867.             ifstack[ifsp] = address ? ON : OFF;
  868.             if (!address) off = TRUE;
  869.             }
  870.             break;
  871.  
  872.     case INCL:  listhex = FALSE;  do_label();
  873.             if ((lex() -> attr & TYPE) == STR) {
  874.             if (++filesp == FILES) fatal_error(FLOFLOW);
  875.             if (!(filestk[filesp] = fopen(token.sval,"r"))) {
  876.                 --filesp;  error_s('V');
  877.             }
  878.             }
  879.             else error_s('S');
  880.             break;
  881.  
  882.     case RLC:
  883.     case ORG:   u = expr();
  884.             if (forwd) error_s('P');
  885.             else {
  886.             pc = address = u;
  887.             if (pass == 2) hseek(pc);
  888.             }
  889.     case CSECT: do_label();
  890.             break;
  891.  
  892.     case PAGT:  listhex = FALSE;  do_label();
  893.             if ((lex() -> attr & TYPE) == EOL) sub_tit[0] = '\0';
  894.             else if ((token.attr & TYPE) != STR) error_s('S');
  895.             else strcpy(sub_tit,token.sval);
  896.             eject = TRUE;
  897.             break;
  898.  
  899.     case PAGE:  listhex = FALSE;  do_label();
  900.             if ((lex() -> attr & TYPE) != EOL) {
  901.             unlex();  pagelen = expr();
  902.             if (pagelen > 0 && pagelen < 3) {
  903.                 pagelen = 0;  error_s('V');
  904.             }
  905.             break; /* no eject on value */
  906.             }
  907.             eject = TRUE;
  908.             break;
  909.  
  910.     case SET:   if (label[0]) {
  911.             if (pass == 1) {
  912.                 if (!((l = new_symbol(label)) -> attr)
  913.                 || (l -> attr & SOFT)) {
  914.                 l -> attr = FORWD + SOFT + VAL;
  915.                 address = expr();
  916.                 if (!forwd) l -> valu = address;
  917.                     if ((token.attr & TYPE) == SIZE) {
  918.                         l -> len = expr();
  919.                         if (forwd) l -> len = 2;
  920.                     } else l -> len = 2; /* preset length */
  921.                 }
  922.             }
  923.             else {
  924.                 if (l = find_symbol(label)) {
  925.                 address = expr();
  926.                 if (forwd) error_s('P');
  927.                 else if (l -> attr & SOFT) {
  928.                     l -> attr = SOFT + VAL;
  929.                     l -> valu = address;
  930.                 }
  931.                 else error_s('M');
  932.                 }
  933.                 else error_s('P');
  934.             }
  935.             }
  936.             else error_s('L');
  937.             break;
  938.  
  939.     case LIST:
  940.     case ULIST: break;
  941.     case SKP:   listok = FALSE;
  942.             break;
  943.     case TYP:   listok = TRUE;
  944.             break;
  945.     case URLC:  break;
  946.  
  947.     case CODE:  code = TRUE;
  948.             break;
  949.     case NCODE: code = FALSE;
  950.             break;
  951.  
  952.     case TITL:  listhex = FALSE;  do_label();
  953.             if ((lex() -> attr & TYPE) == EOL) title[0] = '\0';
  954.             else if ((token.attr & TYPE) != STR) error_s('S');
  955.             else strcpy(title,token.sval);
  956.             break;
  957.  
  958.     }
  959.     return;
  960. }
  961.