static int rd_expr_shift (const char **p, int *valid, int level, int *check, int print_errors) { int result; if (verbose >= 6) fprintf (stderr, "%5d (0x%04x): Starting to read shift expression " "(string=%s).\n", stack[sp].line, addr, *p); result = rd_term (p, valid, level, check, print_errors); *p = delspc (*p); while ((**p == '<' || **p == '>') && (*p)[1] == **p) { *check = 0; if (**p == '<') { (*p) += 2; result <<= rd_term (p, valid, level, check, print_errors); } else if (**p == '>') { (*p) += 2; result >>= rd_term (p, valid, level, check, print_errors); } *p = delspc (*p); }
static int rd_term (const char **p, int *valid, int level, int *check, int print_errors) { /* read a term of an expression */ int result; if (verbose >= 6) fprintf (stderr, "%5d (0x%04x): Starting to read term (string=%s).\n", stack[sp].line, addr, *p); result = rd_factor (p, valid, level, check, print_errors); *p = delspc (*p); while (**p == '+' || **p == '-') { *check = 0; if (**p == '+') { (*p)++; result += rd_factor (p, valid, level, check, print_errors); } else if (**p == '-') { (*p)++; result -= rd_factor (p, valid, level, check, print_errors); } *p = delspc (*p); } if (verbose >= 7) fprintf (stderr, "%5d (0x%04x): rd_term returned %d (%04x).\n", stack[sp].line, addr, result, result); return result; }
static int rd_number (const char **p, const char **endp, int base) { int result = 0, i; char *c, num[] = "0123456789abcdefghijklmnopqrstuvwxyz"; if (verbose >= 6) fprintf (stderr, "%5d (0x%04x): Starting to read number of base %d" "(string=%s).\n", stack[sp].line, addr, base, *p); num[base] = '\0'; *p = delspc (*p); while (**p && (c = strchr (num, tolower (**p)))) { i = c - num; if (verbose >= 7) fprintf (stderr, "%5d (0x%04x): Digit found:%1x.\n", stack[sp].line, addr, i); result = result * base + i; (*p)++; } if (endp) *endp = *p; *p = delspc (*p); if (verbose >= 7) fprintf (stderr, "%5d (0x%04x): rd_number returned %d (%04x).\n", stack[sp].line, addr, result, result); return result; }
/* read away a comma, error if there is none */ static void rd_comma (const char **p) { *p = delspc (*p); if (**p != ',') { eprintf ("`,' expected. Remainder of line: %s\n", *p); return; } *p = delspc ((*p) + 1); }
/* find any of the list[] entries as the start of ptr and return index */ static int indx (const char **ptr, const char **list, int error, const char **expr) { int i; *ptr = delspc (*ptr); if (!**ptr) { if (error) { eprintf ("unexpected end of line\n"); return 0; } else return 0; } if (comma > 1) rd_comma (ptr); for (i = 0; list[i]; i++) { const char *input = *ptr; const char *check = list[i]; int had_expr = 0; if (!list[i][0]) continue; while (*check) { if (*check == ' ') { input = delspc (input); } else if (*check == '*') { *expr = input; mem_delimiter = check[1]; rd_expr (&input, mem_delimiter, NULL, sp, 0); had_expr = 1; } else if (*check == '+') { if (*input == '+' || *input == '-') { *expr = input; mem_delimiter = check[1]; rd_expr (&input, mem_delimiter, NULL, sp, 0); } } else if (*check == *input || (*check >= 'a' && *check <= 'z' && *check - 'a' + 'A' == *input)) ++input; else break; ++check; } if (*check || (isalnum ((const unsigned char)check[-1]) && isalnum ((const unsigned char)input[0]))) continue; if (had_expr) { input = delspc (input); if (*input && *input != ',') continue; } *ptr = input; comma++; return i + 1; } //if (error) eprintf ("parse error. Remainder of line=%s\n", *ptr); return 0; }
/* read a number from 0 to 7, for bit, set or res */ static int rd_0_7 (const char **p) { *p = delspc (*p); if (**p == 0) return 0; bitsetres = *p; skipword (p, ','); return 1; }
/* read a word from input and store it in readword. return 1 on success */ static int rd_word (const char **p, char delimiter) { *p = delspc (*p); if (**p == 0) return 0; readword = *p; mem_delimiter = delimiter; skipword (p, delimiter); return 1; }
static int check_label (struct label *labels, const char **p, struct label **ret, struct label **previous, int force_skip) { struct label *l; const char *c; unsigned s2; *p = delspc (*p); for (c = *p; isalnum (*c) || *c == '_' || *c == '.'; ++c) { } s2 = c - *p; for (l = labels; l; l = l->next) { unsigned s1, s; int cmp; s1 = strlen (l->name); s = s1 < s2 ? s1 : s2; cmp = strncmp (l->name, *p, s); if (cmp > 0 || (cmp == 0 && s1 > s)) { if (force_skip) *p = c; return 0; } if (cmp < 0 || s2 > s) { if (previous) *previous = l; continue; } *p = c; /* if label is not valid, compute it */ if (l->ref) { compute_ref (l->ref, 1); if (!l->ref->done) { /* label was not valid, and isn't computable. tell the * caller that it doesn't exist, so it will try again later. * Set ret to show actual existence. */ if (verbose >= 6) fprintf (stderr, "%5d (0x%04x): returning invalid label %s.\n", stack[sp].line, addr, l->name); *ret = l; return 0; } } *ret = l; return 1; } if (force_skip) *p = c; return 0; }
/* read a byte from input and store it in readbyte. return 1 on success */ static int rd_byte (const char **p, char delimiter) { *p = delspc (*p); if (**p == 0) return 0; readbyte = *p; writebyte = 1; mem_delimiter = delimiter; skipword (p, delimiter); return 1; }
/* do the actual work */ static int assemble (const char *str, unsigned char *_obuf) { int ifcount = 0, noifcount = 0; const char *ptr; char *bufptr; int r, s; /* registers */ obuflen = 0; obuf = _obuf; /* continue assembling until the last input file is done */ //for (file = 0; file < infilecount; ++file) do { int cmd, cont = 1; // XXX: must free z80buffer = strdup (str); if (!cont) break; /* break to next source file */ // if (havelist) // fprintf (listfile, "%04x", addr); for (bufptr = z80buffer; (bufptr = strchr (bufptr, '\n'));) *bufptr = ' '; for (bufptr = z80buffer; (bufptr = strchr (bufptr, '\r'));) *bufptr = ' '; ptr = z80buffer; //lastlabel = NULL; baseaddr = addr; ++stack[sp].line; ptr = delspc (ptr); if (!*ptr) continue; if (!noifcount && !define_macro) readlabel (&ptr, 1); else readlabel (&ptr, 0); ptr = delspc (ptr); if (!*ptr) continue; comma = 0; indexed = 0; indexjmp = 0; writebyte = 0; readbyte = 0; readword = 0; cmd = readcommand (&ptr) - 1; int i, have_quote; switch (cmd) { case Z80_ADC: if (!(r = rd_a_hl (&ptr))) break; if (r == HL) { if (!(r = rd_rr_ (&ptr))) break; wrtb (0xED); wrtb (0x4A + 0x10 * --r); break; } if (!(r = rd_r (&ptr))) break; wrtb (0x88 + --r); break; case Z80_ADD: if (!(r = rd_r_add (&ptr))) break; if (r == addHL) { if (!(r = rd_rrxx (&ptr))) break; wrtb (0x09 + 0x10 * --r); /* ADD HL/IX/IY, qq */ break; } if (has_argument (&ptr)) { if (r != A) { eprintf ("parse error before: %s\n", ptr); break; } if (!(r = rd_r (&ptr))) break; wrtb (0x80 + --r); /* ADD A,r */ break; } wrtb (0x80 + --r); /* ADD r */ break; case Z80_AND: if (!(r = rd_r (&ptr))) break; wrtb (0xA0 + --r); break; case Z80_BIT: if (!rd_0_7 (&ptr)) break; rd_comma (&ptr); if (!(r = rd_r_ (&ptr))) break; wrtb (0xCB); wrtb (0x40 + (r - 1)); break; case Z80_CALL: if ((r = rd_cc (&ptr))) { wrtb (0xC4 + 8 * --r); rd_comma (&ptr); } else wrtb (0xCD); break; case Z80_CCF: wrtb (0x3F); break; case Z80_CP: if (!(r = rd_r (&ptr))) break; wrtb (0xB8 + --r); break; case Z80_CPD: wrtb (0xED); wrtb (0xA9); break; case Z80_CPDR: wrtb (0xED); wrtb (0xB9); break; case Z80_CPI: wrtb (0xED); wrtb (0xA1); break; case Z80_CPIR: wrtb (0xED); wrtb (0xB1); break; case Z80_CPL: wrtb (0x2F); break; case Z80_DAA: wrtb (0x27); break; case Z80_DEC: if (!(r = rd_r_rr (&ptr))) break; if (r < 0) { wrtb (0x05 - 8 * ++r); break; } wrtb (0x0B + 0x10 * --r); break; case Z80_DI: wrtb (0xF3); break; case Z80_DJNZ: wrtb (0x10); //rd_wrt_jr (&ptr, '\0'); break; case Z80_EI: wrtb (0xFB); break; case Z80_EX: if (!(r = rd_ex1 (&ptr))) break; switch (r) { case DE: if (!rd_hl (&ptr)) break; wrtb (0xEB); break; case AF: if (!rd_af_ (&ptr)) break; wrtb (0x08); break; default: if (!rd_hlx (&ptr)) break; wrtb (0xE3); } break; case Z80_EXX: wrtb (0xD9); break; case Z80_HALT: wrtb (0x76); break; case Z80_IM: if (!(r = rd_0_2 (&ptr))) break; wrtb (0xED); wrtb (0x46 + 8 * --r); break; case Z80_IN: if (!(r = rd_in (&ptr))) break; if (r == A) { if (!(r = rd_nnc (&ptr))) break; if (r == C) { wrtb (0xED); wrtb (0x40 + 8 * (A - 1)); break; } wrtb (0xDB); break; } if (!rd_c (&ptr)) break; wrtb (0xED); wrtb (0x40 + 8 * --r); break; case Z80_INC: if (!(r = rd_r_rr (&ptr))) break; if (r < 0) { wrtb (0x04 - 8 * ++r); break; } wrtb (0x03 + 0x10 * --r); break; case Z80_IND: wrtb (0xED); wrtb (0xAA); break; case Z80_INDR: wrtb (0xED); wrtb (0xBA); break; case Z80_INI: wrtb (0xED); wrtb (0xA2); break; case Z80_INIR: wrtb (0xED); wrtb (0xB2); break; case Z80_JP: r = rd_jp (&ptr); if (r < 0) { wrtb (0xE9); break; } if (r) { wrtb (0xC2 + 8 * --r); rd_comma (&ptr); } else wrtb (0xC3); break; case Z80_JR: r = rd_jr (&ptr); if (r) rd_comma (&ptr); wrtb (0x18 + 8 * r); break; case Z80_LD: if (!(r = rd_ld (&ptr))) break; switch (r) { case ld_BC: case ld_DE: if (!rd_a (&ptr)) break; wrtb (0x02 + 0x10 * (r == ld_DE)); break; case ld_HL: r = rd_ld_hl (&ptr); wrtb (0x70 + --r); break; case ld_NN: if (!(r = rd_ld_nn (&ptr))) break; if (r == ld_nnA || r == ld_nnHL) { wrtb (0x22 + 0x10 * (r == ld_nnA)); break; } wrtb (0xED); wrtb (0x43 + 0x10 * --r); break; case ldA: if (!(r = rd_lda (&ptr))) break; if (r == A_NN) { wrtb (0x3A); break; } if (r == A_I || r == A_R) { wrtb (0xED); wrtb (0x57 + 8 * (r == A_R)); break; } if (r < 0) { wrtb (0x0A - 0x10 * ++r); break; } wrtb (0x78 + --r); break; case ldB: case ldC: case ldD: case ldE: case ldH: case ldL: if (!(s = rd_ldbcdehla (&ptr))) break; wrtb (0x40 + 0x08 * (r - 7) + (s - 1)); break; case ldBC: case ldDE: s = rd_nn_nn (&ptr); if (s == _NN) { wrtb (0xED); wrtb (0x4B + 0x10 * (r == ldDE)); break; } wrtb (0x01 + (r == ldDE) * 0x10); break; case ldHL: r = rd_nn_nn (&ptr); wrtb (0x21 + (r == _NN) * 9); break; case ldI: case ldR: if (!rd_a (&ptr)) break; wrtb (0xED); wrtb (0x47 + 0x08 * (r == ldR)); break; case ldSP: r = rd_sp (&ptr); if (r == SPHL) { wrtb (0xF9); break; } if (r == SPNN) { wrtb (0x31); break; } wrtb (0xED); wrtb (0x7B); break; } break; case Z80_LDD: wrtb (0xED); wrtb (0xA8); break; case Z80_LDDR: wrtb (0xED); wrtb (0xB8); break; case Z80_LDI: wrtb (0xED); wrtb (0xA0); break; case Z80_LDIR: wrtb (0xED); wrtb (0xB0); break; case Z80_NEG: wrtb (0xED); wrtb (0x44); break; case Z80_NOP: wrtb (0x00); break; case Z80_OR: if (!(r = rd_r (&ptr))) break; wrtb (0xB0 + --r); break; case Z80_OTDR: wrtb (0xED); wrtb (0xBB); break; case Z80_OTIR: wrtb (0xED); wrtb (0xB3); break; case Z80_OUT: if (!(r = rd_nnc (&ptr))) break; if (r == C) { if (!(r = rd_out (&ptr))) break; wrtb (0xED); wrtb (0x41 + 8 * --r); break; } if (!rd_a (&ptr)) break; wrtb (0xD3); break; case Z80_OUTD: wrtb (0xED); wrtb (0xAB); break; case Z80_OUTI: wrtb (0xED); wrtb (0xA3); break; case Z80_POP: if (!(r = rd_stack (&ptr))) break; wrtb (0xC1 + 0x10 * --r); break; case Z80_PUSH: if (!(r = rd_stack (&ptr))) break; wrtb (0xC5 + 0x10 * --r); break; case Z80_RES: if (!rd_0_7 (&ptr)) break; rd_comma (&ptr); if (!(r = rd_r_ (&ptr))) break; wrtb (0xCB); wrtb (0x80 + --r); break; case Z80_RET: if (!(r = rd_cc (&ptr))) { wrtb (0xC9); break; } wrtb (0xC0 + 8 * --r); break; case Z80_RETI: wrtb (0xED); wrtb (0x4D); break; case Z80_RETN: wrtb (0xED); wrtb (0x45); break; case Z80_RL: if (!(r = rd_r_ (&ptr))) break; wrtb (0xCB); wrtb (0x10 + --r); break; case Z80_RLA: wrtb (0x17); break; case Z80_RLC: if (!(r = rd_r_ (&ptr))) break; wrtb (0xCB); wrtb (0x00 + --r); break; case Z80_RLCA: wrtb (0x07); break; case Z80_RLD: wrtb (0xED); wrtb (0x6F); break; case Z80_RR: if (!(r = rd_r_ (&ptr))) break; wrtb (0xCB); wrtb (0x18 + --r); break; case Z80_RRA: wrtb (0x1F); break; case Z80_RRC: if (!(r = rd_r_ (&ptr))) break; wrtb (0xCB); wrtb (0x08 + --r); break; case Z80_RRCA: wrtb (0x0F); break; case Z80_RRD: wrtb (0xED); wrtb (0x67); break; case Z80_RST: ptr = ""; break; case Z80_SBC: if (!(r = rd_a_hl (&ptr))) break; if (r == HL) { if (!(r = rd_rr_ (&ptr))) break; wrtb (0xED); wrtb (0x42 + 0x10 * --r); break; } if (!(r = rd_r (&ptr))) break; wrtb (0x98 + --r); break; case Z80_SCF: wrtb (0x37); break; case Z80_SET: if (!rd_0_7 (&ptr)) break; rd_comma (&ptr); if (!(r = rd_r_ (&ptr))) break; wrtb (0xCB); wrtb (0xC0 + --r); break; case Z80_SLA: if (!(r = rd_r_ (&ptr))) break; wrtb (0xCB); wrtb (0x20 + --r); break; case Z80_SLI: if (!(r = rd_r_ (&ptr))) break; wrtb (0xCB); wrtb (0x30 + --r); break; case Z80_SRA: if (!(r = rd_r_ (&ptr))) break; wrtb (0xCB); wrtb (0x28 + --r); break; case Z80_SRL: if (!(r = rd_r_ (&ptr))) break; wrtb (0xCB); wrtb (0x38 + --r); break; case Z80_SUB: if (!(r = rd_r (&ptr))) break; if (has_argument (&ptr)) {/* SUB A,r ? */ if (r != A) { eprintf ("parse error before: %s\n", ptr); break; } if (!(r = rd_r (&ptr))) break; } wrtb (0x90 + --r); break; case Z80_XOR: if (!(r = rd_r (&ptr))) break; wrtb (0xA8 + --r); break; case Z80_DEFB: case Z80_DB: case Z80_DEFM: case Z80_DM: ptr = delspc (ptr); while (1) { have_quote = (*ptr == '"' || *ptr == '\''); if (have_quote) { /* Read string. */ int quote = *ptr; ++ptr; while (*ptr != quote) { write_one_byte (rd_character (&ptr, NULL, 1), 0); if (*ptr == 0) { eprintf ("end of line in quoted string\n"); break; } } ++ptr; } else { /* Read expression. */ skipword (&ptr, ','); } ptr = delspc (ptr); if (*ptr == ',') { ++ptr; continue; } if (*ptr != 0) eprintf ("junk in byte definition: %s\n", ptr); break; } break; case Z80_DEFW: case Z80_DW: if (!(r = rd_word (&ptr, ','))) { eprintf ("No data for word definition\n"); break; } while (1) { ptr = delspc (ptr); if (*ptr != ',') break; ++ptr; if (!(r = rd_word (&ptr, ','))) eprintf ("Missing expression in defw\n"); } break; case Z80_DEFS: case Z80_DS: r = rd_expr (&ptr, ',', NULL, sp, 1); if (r < 0) { eprintf ("ds should have its first argument >=0" " (not -0x%x)\n", -r); break; } ptr = delspc (ptr); if (*ptr) { rd_comma (&ptr); readbyte = 0; rd_byte (&ptr, '\0'); writebyte = 0; break; } for (i = 0; i < r; i++) { write_one_byte (0, 0); } break; case Z80_END: break; case Z80_ORG: addr = rd_expr (&ptr, '\0', NULL, sp, 1) & 0xffff; break; case Z80_IF: if (rd_expr (&ptr, '\0', NULL, sp, 1)) ifcount++; else noifcount++; break; case Z80_ELSE: if (ifcount == 0) { eprintf ("else without if\n"); break; } noifcount = 1; ifcount--; break; case Z80_ENDIF: if (noifcount == 0 && ifcount == 0) { eprintf ("endif without if\n"); break; } if (noifcount) noifcount--; else ifcount--; break; case Z80_ENDM: if (stack[sp].file) eprintf ("endm outside macro definition\n"); break; case Z80_SEEK: eprintf ("seek error\n"); break; default: //eprintf ("command or comment expected (was %s)\n", ptr); return 0; } } while (0); //free (infile); return obuflen; }
/* look ahead for a comma, no error if not found */ static int has_argument (const char **p) { const char *q = delspc (*p); return (*q == ','); }
static int rd_value (const char **p, int *valid, int level, int *check, int print_errors) { int sign = 1, not = 0, base, v; const char *p0, *p1, *p2; if (verbose >= 6) fprintf (stderr, "%5d (0x%04x): Starting to read value (string=%s).\n", stack[sp].line, addr, *p); *p = delspc (*p); while (**p && strchr ("+-~", **p)) { if (**p == '-') sign = -sign; else if (**p == '~') not = ~not; (*p)++; *p = delspc (*p); } base = 10; /* Default base for suffixless numbers */ /* Check for parenthesis around full expression: not if no parenthesis */ if (**p != '(') *check = 0; switch (**p) { int exist, retval; char quote; int dummy_check; case '(': (*p)++; dummy_check = 0; retval = not ^ (sign * do_rd_expr (p, ')', valid, level, &dummy_check, print_errors)); ++*p; return retval; case '0': if ((*p)[1] == 'x') { (*p) += 2; return not ^ (sign * rd_number (p, NULL, 0x10)); } base = 8; /* If first digit it 0, assume octal unless suffix */ /* fall through */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': p0 = *p; rd_number (p, &p1, 36); /* Advance to end of numeric string */ p1--; /* Last character in numeric string */ switch (*p1) { case 'h': case 'H': base = 16; break; case 'b': case 'B': base = 2; break; case 'o': case 'O': case 'q': case 'Q': base = 8; break; case 'd': case 'D': base = 10; break; default: /* No suffix */ p1++; break; } v = rd_number (&p0, &p2, base); if (p1 != p2) { if (valid) *valid = 0; else if (print_errors) printerr (1, "invalid character in number: \'%c\'\n", *p2); } return not ^ (sign * v); case '$': ++*p; *p = delspc (*p); p0 = *p; v = rd_number (&p0, &p2, 0x10); if (p2 == *p) { v = baseaddr; } else *p = p2; return not ^ (sign * v); case '%': (*p)++; return not ^ (sign * rd_number (p, NULL, 2)); case '\'': case '"': quote = **p; ++*p; retval = not ^ (sign * rd_character (p, valid, print_errors)); if (**p != quote) { if (valid) *valid = 0; else if (print_errors) printerr (1, "missing closing quote (%c)\n", quote); return 0; } ++*p; return retval; case '@': return not ^ (sign * rd_otherbasenumber (p, valid, print_errors)); case '?': rd_label (p, &exist, NULL, level, 0); return not ^ (sign * exist); case '&': { ++*p; switch (**p) { case 'h': case 'H': base = 0x10; break; case 'o': case 'O': base = 010; break; case 'b': case 'B': base = 2; break; default: if (valid) *valid = 0; else if (print_errors) printerr (1, "invalid literal starting with &%c\n", **p); return 0; } ++*p; return not ^ (sign * rd_number (p, NULL, base)); } default: { int value; exist = 1; value = rd_label (p, valid ? &exist : NULL, NULL, level, print_errors); if (!exist) *valid = 0; return not ^ (sign * value); } } }