📄 picasm.c
字号:
static inthandle_opt(void){ if(token_type != TOK_IDENTIFIER) { error(1, "OPT syntax error"); return FAIL; } /* * Note: when listing is turned off, 'listing_on' is set to -1 * here and the listing routine sets it to zero after listing * the line containing the 'opt nol'. */ if(strcasecmp(token_string, "nol") == 0 || strcasecmp(token_string, "nolist") == 0) { listing_on = -1; } else if(strcasecmp(token_string, "l") == 0 || strcasecmp(token_string, "list") == 0) { listing_on = 1; } else { error(1, "OPT syntax error"); return FAIL; } get_token(); return OK;}/* * Define a macro */static voiddefine_macro(char *name){ struct symbol *sym; struct macro_line *ml; int t; if(token_type != TOK_NEWLINE && token_type != TOK_EOF) error(0, "Extraneous characters after a valid source line"); skip_eol(); write_listing_line(0); sym = add_symbol(name, SYMTAB_GLOBAL); sym->type = SYM_MACRO; sym->v.text = NULL; ml = NULL; for(;;) { get_token(); /* read first token on next line */ t = 0; if(token_type == TOK_IDENTIFIER) { t = 1; get_token(); if(token_type == TOK_COLON) get_token(); } if(token_type == TOK_EOF || token_type == KW_END) fatal_error("Macro definition not terminated"); if(token_type == KW_MACRO) fatal_error("Nested macro definitions not allowed"); if(token_type == KW_ENDM) /* end macro definition */ break;/* OPT must be handled inside macros at definition time */ if(token_type == KW_OPT) { get_token(); handle_opt(); } else { if(ml == NULL) { ml = mem_alloc(sizeof(struct macro_line) +strlen(line_buffer)); sym->v.text = ml; } else { ml->next = mem_alloc(sizeof(struct macro_line) +strlen(line_buffer)); ml = ml->next; } strcpy(ml->text, line_buffer); ml->next = NULL; } write_listing_line(0); line_buf_ptr = NULL; tok_char = ' '; } if(t) error(0, "Label not allowed with ENDM"); get_token();}/* * Skip subroutine used by the conditional assembly directives * return: -1=premature EOF, 0=ok, 1=label (not allowed) */static intif_else_skip(void){ int t, ccount; ccount = 0; ifskip_mode++; do { skip_eol(); get_token(); write_listing_line(1); t = 0; if(token_type == TOK_IDENTIFIER) { t = 1; get_token(); if(token_type == TOK_COLON) get_token(); } if(token_type == KW_IF) { ccount++; } else if(token_type == KW_ENDIF) { if(ccount <= 0) break; ccount--; } else if(token_type == KW_ELSE && ccount <= 0) { break; } } while(token_type != TOK_EOF && token_type != KW_END); ifskip_mode--; return (token_type == TOK_EOF || token_type == KW_END) ? -1 : t;}/* * Add a patch pointing to the current location */voidadd_patch(int tab, struct symbol *sym, patchtype_t type){ struct patch **patch_list_ptr, *ptch; patch_list_ptr = (tab == SYMTAB_GLOBAL ? &global_patch_list : local_patch_list_ptr); if(O_Mode == O_NONE) { O_Mode = O_PROGRAM; if(org_val < 0) { error(0, "ORG value not set"); prog_location = 0; return; } prog_location = org_val; } ptch = mem_alloc(sizeof(struct patch)); ptch->label = sym; ptch->type = type; ptch->location = prog_location; /* add a new patch to patch_list */ ptch->next = *patch_list_ptr; *patch_list_ptr = ptch;} /* * Apply the store patches and also free the patch list */static voidapply_patches(struct patch *patch_list){ struct patch *ptch, *p2; /* * fix forward jumps/calls */ for(ptch = patch_list; ptch != NULL; ptch = p2) { p2 = ptch->next; if(ptch->label->type == SYM_FORWARD) error(0, "Undefined label '%s%s'", (patch_list == global_patch_list ? "" : "="), ptch->label->name); else switch(ptch->type) { case PATCH8: if(pic_type->instr_set == PIC12BIT && (ptch->label->v.value & 0x100) != 0 && (prog_mem[ptch->location] & 0xff00) == 0x900) error(0, "CALL address in upper half of a page (label '%s%s')", (patch_list == global_patch_list ? "" : "="), ptch->label->name); prog_mem[ptch->location] = (prog_mem[ptch->location] & 0xff00) | (ptch->label->v.value & 0xff); break; case PATCH9: prog_mem[ptch->location] = (prog_mem[ptch->location] & 0xfe00) | (ptch->label->v.value & 0x1ff); break; case PATCH11: prog_mem[ptch->location] = (prog_mem[ptch->location] & 0xf800) | (ptch->label->v.value & 0x7ff); break; } mem_free(ptch); }}/* * Generate code for an instruction with 8-bit literal data * allows forward references */intgen_byte_c(int instr_code){ int t, symtype; long val; struct symbol *sym; t = 0; if(token_type == TOK_IDENTIFIER || token_type == TOK_LOCAL_ID) { symtype = (token_type == TOK_IDENTIFIER ? SYMTAB_GLOBAL : SYMTAB_LOCAL); if(symtype == SYMTAB_LOCAL && local_level == 0) { error(1, "Local symbol outside a LOCAL block"); return FAIL; } sym = lookup_symbol(token_string, symtype); if(sym == NULL || sym->type == SYM_FORWARD) { if(sym == NULL) { sym = add_symbol(token_string, symtype); sym->type = SYM_FORWARD; } add_patch(symtype, sym, PATCH8); get_token(); gen_code(instr_code); list_flags |= LIST_FORWARD; return OK; } } val = get_expression(); if(expr_error) return FAIL; if(val < -0x80 || val > 0xff) { error(0, "8-bit literal out of range"); return FAIL; } gen_code(instr_code | (val & 0xff)); return OK;}/* * check if the current token is a valid ORG mode specifier * and return the mode (or O_NONE if not valid mode specifier) */static intorg_mode(void){ if(token_type == KW_EDATA) return O_EDATA; if(token_type == TOK_IDENTIFIER) { if(strcasecmp(token_string, "code") == 0) return O_PROGRAM; if(strcasecmp(token_string, "reg") == 0) return O_REGFILE; } return O_NONE;}/* * The assembler itself */static voidassembler(char *fname){ static char symname[256]; struct symbol *sym; int op, t, symtype; long val; char *cp; struct pic_type *pic; if(pic_type != NULL) { sprintf(symname, "__%s", pic_type->name); sym = add_symbol(symname, SYMTAB_GLOBAL); sym->type = SYM_DEFINED; sym->v.value = 1; } begin_include(fname); get_token(); while(token_type != TOK_EOF) { sym = NULL; if(token_type == TOK_IDENTIFIER || token_type == TOK_LOCAL_ID) { symtype = (token_type == TOK_IDENTIFIER ? SYMTAB_GLOBAL : SYMTAB_LOCAL); if(symtype == SYMTAB_LOCAL && local_level == 0) { error(1, "Local symbol outside a LOCAL block"); continue; } t = (line_buf_off == 0); strcpy(symname, token_string); sym = lookup_symbol(symname, symtype); if(sym != NULL && sym->type == SYM_MACRO) { /* skip whitespace */ while(tok_char != '\n' && isspace(tok_char)) read_src_char(); if(line_buf_ptr != NULL && strncasecmp(line_buf_ptr-1, "macro", 5) == 0 && line_buf_ptr[4] != '.' && line_buf_ptr[4] != '_' && !isalnum((unsigned char)line_buf_ptr[4])) { error(1, "Multiple definition of macro '%s'", symname); continue; } expand_macro(sym); continue; } get_token(); switch(token_type) { case KW_MACRO: get_token(); if(sym != NULL) { error(1, "Multiply defined symbol '%s%s'", (symtype == SYMTAB_LOCAL ? "=" : ""), sym->name); continue; } define_macro(symname); goto line_end; case KW_EQU: if(sym != NULL) { if(sym->type != SYM_FORWARD) error(0, "Multiply defined symbol '%s%s'", (symtype == SYMTAB_LOCAL ? "=" : ""), sym->name); } else sym = add_symbol(symname, symtype); get_token(); sym->type = SYM_DEFINED; sym->v.value = get_expression(); if(expr_error) continue; /* error_lineskip() done in expr.c */ list_val = sym->v.value; list_flags = LIST_VAL; goto line_end; case KW_SET: if(sym != NULL && sym->type != SYM_SET) error(0, "Multiply defined symbol '%s%s'", (symtype == SYMTAB_LOCAL ? "=" : ""), sym->name); else if(sym == NULL) sym = add_symbol(symname, symtype); get_token(); sym->type = SYM_SET; sym->v.value = get_expression(); if(expr_error) continue; list_val = sym->v.value; list_flags = LIST_VAL; goto line_end; case TOK_COLON: get_token(); goto do_label; default: if(t == 0) warning("Label not in the beginning of a line");do_label: switch(O_Mode) { case O_PROGRAM: t = prog_location; break; case O_REGFILE: t = reg_location; break; case O_EDATA: t = edata_location; break; case O_NONE: t = org_val; break; } if(t < 0) { error(0, "ORG value not set"); } else { if(sym != NULL && sym->type != SYM_FORWARD) error(0, "Multiply defined symbol '%s%s'", (symtype == SYMTAB_LOCAL ? "=" : ""), sym->name); if(sym == NULL) sym = add_symbol(symname, symtype); sym->type = SYM_DEFINED; sym->v.value = t; list_loc = t; list_flags = LIST_LOC; } break; } } /* if this line has a label, 'sym' points to it */ if(token_type == TOK_NEWLINE) { write_listing_line(0); get_token(); continue; } if(token_type == TOK_IDENTIFIER && (sym = lookup_symbol(token_string, SYMTAB_GLOBAL)) != NULL && sym->type == SYM_MACRO) { expand_macro(sym); continue; } if(token_type == KW_END) break; if(token_type == KW_ERROR) { while(isspace((unsigned char)(*line_buf_ptr))) line_buf_ptr++; error(1, "%s", line_buf_ptr); continue; } op = token_type; get_token(); switch(op) { case KW_INCLUDE: if(token_type != TOK_STRCONST) { error(1, "Missing file name after INCLUDE"); continue; } strcpy(symname, token_string); get_token(); if(token_type != TOK_NEWLINE && token_type != TOK_EOF) error(0, "Extraneous characters after a valid source line"); begin_include(symname); write_listing_line(0); get_token(); continue; case KW_SET: case KW_EQU: if(sym == NULL) error(1, "SET/EQU without a label"); else error(1, "SET/EQU syntax error"); continue; case KW_MACRO: error(1, "MACRO without a macro name"); continue; case KW_ENDM: error(1, "ENDM not allowed outside a macro"); continue; case KW_EXITM: /* * EXITM works now (version 0.97). Strange that * nobody noticed that it wasn't implemented * at all in previous versions. */ if(current_file == NULL || current_file->type != INC_MACRO) { error(1, "EXITM not allowed outside a macro"); continue; } cond_nest_count = current_file->cond_nest_count; end_include(); break; case KW_OPT: if(handle_opt() != OK) { error_lineskip(); continue; } break; case KW_LOCAL:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -