#include #include #include #include #include "defs.h" #include "externs.h" #include "protos.h" int in_if; /* set when we are in an .if statement */ int if_expr; /* set when parsing an .if expression */ int if_level; /* level of nested .if's */ int if_state[256]; /* status when entering the .if */ int if_flag[256]; /* .if/.else status */ int skip_lines; /* set when lines must be skipped */ int continued_line; /* set when a line is the continuation of another line */ /* ---- * assemble() * ---- * translate source line to machine language */ void assemble(void) { struct t_line *ptr; char *buf; char c; int flag; int ip, i, j; /* prlnbuf pointer */ /* init variables */ lablptr = NULL; continued_line = 0; data_loccnt = -1; data_size = 3; data_level = 1; /* macro definition */ if (in_macro) { i = SFIELD; if (colsym(&i)) if (prlnbuf[i] == ':') i++; while (isspace((int)prlnbuf[i])) i++; if (pass == LAST_PASS) println(); if (oplook(&i) >= 0) { if (opflg == PSEUDO) { if (opval == P_MACRO) { error("Can not nest macro definitions!"); return; } if (opval == P_ENDM) { if (!check_eol(&i)) return; in_macro = 0; return; } } } if (pass == FIRST_PASS) { ptr = (void *)malloc(sizeof(struct t_line)); buf = (void *)malloc(strlen(&prlnbuf[SFIELD]) + 1); if ((ptr == NULL) || (buf == NULL)) { error("Out of memory!"); return; } strcpy(buf, &prlnbuf[SFIELD]); ptr->next = NULL; ptr->data = buf; if (mlptr) mlptr->next = ptr; else mptr->line = ptr; mlptr = ptr; } return; } /* IF/ELSE section; * check for a '.else' or '.endif' * to toggle state */ if (in_if) { i = SFIELD; while (isspace((int)prlnbuf[i])) i++; if (oplook(&i) >= 0) { if (opflg == PSEUDO) { switch (opval) { case P_IF: // .if case P_IFDEF: // .ifdef case P_IFNDEF: // .ifndef if (skip_lines) { if_level++; if_state[if_level] = 0; } break; case P_ELSE: // .else if (!check_eol(&i)) return; if (if_state[if_level]) { skip_lines = !if_flag[if_level]; if (pass == LAST_PASS) println(); } return; case P_ENDIF: // .endif if (!check_eol(&i)) return; if (if_state[if_level] && (pass == LAST_PASS)) println(); skip_lines = !if_state[if_level]; if_level--; if (if_level == 0) in_if = 0; return; } } } } if (skip_lines) return; /* comment line */ c = prlnbuf[SFIELD]; if (c == ';' || c == '*' || c == '\0') { // if (c == '\0') lastlabl = NULL; if (pass == LAST_PASS) println(); return; } /* search for a label */ i = SFIELD; j = 0; while (isspace((int)prlnbuf[i])) i++; for (;;) { c = prlnbuf[i + j]; if (isdigit(c) && (j == 0)) break; if (!isalnum(c) && (c != '_') && (c != '.')) break; j++; } if ((j == 0) || ((i != SFIELD) && (c != ':'))) i = SFIELD; else { if (colsym(&i) != 0) if ((lablptr = stlook(1)) == NULL) return; if ((lablptr) && (prlnbuf[i] == ':')) i++; } /* skip spaces */ while (isspace((int)prlnbuf[i])) i++; /* is it a macro? */ ip = i; mptr = macro_look(&ip); if (mptr) { /* define label */ labldef(loccnt, 1); /* output location counter */ if (pass == LAST_PASS) { if (!asm_opt[OPT_MACRO]) loadlc((page << 13) + loccnt, 0); } /* get macro args */ if (!macro_getargs(ip)) return; /* output line */ if (pass == LAST_PASS) println(); /* ok */ mcntmax++; mcounter = mcntmax; expand_macro = 1; mlptr = mptr->line; return; } /* an instruction then */ ip = i; flag = oplook(&ip); if (flag < 0) { labldef(loccnt, 1); if (flag == -1) error("Unknown instruction!"); if ((flag == -2) && (pass == LAST_PASS)) { if (lablptr) loadlc(loccnt, 0); println(); } lastlabl = NULL; return; } /* generate code */ if (opflg == PSEUDO) do_pseudo(&ip); else if (labldef(loccnt, 1) == -1) return; else { /* output infos */ data_loccnt = loccnt; /* check if we are in the CODE section */ if (section != S_CODE) fatal_error("Instructions not allowed in this section!"); /* generate code */ opproc(&ip); /* reset last label pointer */ lastlabl = NULL; } } /* ---- * oplook() * ---- * operation code table lookup * return symbol length if found * return -1 on syntax error * return -2 if no symbol */ int oplook(int *idx) { struct t_opcode *ptr; char name[16]; char c; int flag; int hash; int i; /* get instruction name */ i = 0; opext = 0; flag = 0; hash = 0; for (;;) { c = toupper(prlnbuf[*idx]); if (c == ' ' || c == '\t' || c == '\0' || c == ';') break; if (!isalnum(c) && c != '.' && c != '*' && c != '=') return (-1); if (i == 15) return (-1); /* handle instruction extension */ if (c == '.' && i) { if (flag) return (-1); flag = 1; (*idx)++; continue; } if (flag) { if (opext) return (-1); opext = c; (*idx)++; continue; } /* store char */ name[i++] = c; hash += c; hash = (hash << 3) + (hash >> 5) + c; (*idx)++; /* break if '=' directive */ if (c == '=') break; } /* check extension */ if (flag) { if ((opext != 'L') && (opext != 'H')) return (-1); } /* end name string */ name[i] = '\0'; /* return if no instruction */ if (i == 0) return (-2); /* search the instruction in the hash table */ ptr = inst_tbl[hash & 0xFF]; while (ptr) { if (!strcmp(name, ptr->name)) { opproc = ptr->proc; opflg = ptr->flag; opval = ptr->value; optype = ptr->type_idx; if (opext) { /* no extension for pseudos */ if (opflg == PSEUDO) return (-1); /* extension valid only for these addressing modes */ if (!(opflg & (IMM|ZP|ZP_X|ZP_IND_Y|ABS|ABS_X|ABS_Y))) return (-1); } return (i); } ptr = ptr->next; } /* didn't find this instruction */ return (-1); } /* ---- * addinst() * ---- * add a list of instructions to the instruction * hash table */ void addinst(struct t_opcode *optbl) { int hash; int len; int i; char *ptr; char c; if (optbl == NULL) return; /* parse list */ while (optbl->name) { /* calculate instruction hash value */ hash = 0; len = strlen(optbl->name); ptr = optbl->name; for (i = 0; i < len; i++) { c = *ptr++; hash += c; hash = (hash << 3) + (hash >> 5) + c; } hash &= 0xFF; /* insert the instruction in the hash table */ optbl->next = inst_tbl[hash]; inst_tbl[hash] = optbl; /* next instruction */ optbl++; } } /* ---- * check_eol() * ---- * check the end of line for garbage */ int check_eol(int *ip) { while (isspace((int)prlnbuf[*ip])) (*ip)++; if (prlnbuf[*ip] == ';' || prlnbuf[*ip] == '\0') return (1); else { error("Syntax error!"); return (0); } } /* .if pseudo */ void do_if(int *ip) { labldef(loccnt, 1); /* get expression */ if_expr = 1; if (!evaluate(ip, ';')) { if_expr = 0; return; } if_expr = 0; /* check for '.if' stack overflow */ if (if_level == 255) { fatal_error("Too many nested IF/ENDIF!"); return; } in_if = 1; if_level++; if_state[if_level] = !skip_lines; if (!skip_lines) skip_lines = if_flag[if_level] = value ? 0 : 1; if (pass == LAST_PASS) { loadlc(value, 1); println(); } } /* .else pseudo */ void do_else(int *ip) { if (!in_if) fatal_error("Unexpected ELSE!"); } /* .endif pseudo */ void do_endif(int *ip) { if (!in_if) fatal_error("Unexpected ENDIF!"); } /* .ifdef/.ifndef pseudo */ void do_ifdef(int *ip) { labldef(loccnt, 1); /* skip spaces */ while (isspace((int)prlnbuf[*ip])) (*ip)++; /* get symbol */ if (!colsym(ip)) { error("Syntax error!"); return; } if (!check_eol(ip)) return; lablptr = stlook(0); /* check for '.if' stack overflow */ if (if_level == 255) { fatal_error("Too many nested IF/ENDIF!"); return; } in_if = 1; if_level++; if_state[if_level] = !skip_lines; if (!skip_lines) { if (optype) { /* .ifdef */ skip_lines = if_flag[if_level] = (lablptr == NULL) ? 1 : 0; } else { /* .ifndef */ skip_lines = if_flag[if_level] = (lablptr == NULL) ? 0 : 1; } } if (pass == LAST_PASS) { loadlc(!skip_lines, 1); println(); } }