📄 tc-tahoe.c
字号:
int reg = -1; /* major register, -1 means absent */ int imreg = -1; /* Major register in immediate mode */ int ndx = -1; /* index register number, -1 means absent */ char dec_inc = ' '; /* Is the SP auto-incremented '+' or auto-decremented '-' or neither ' '. */ int immediate = 0; /* 1 if '$' immediate mode */ int call_width = 0; /* If the caller casts the displacement */ int abs_width = 0; /* The width of the absolute displacment */ int com_width = 0; /* Displacement width required by branch */ int deferred = 0; /* 1 if '*' deferral is used */ byte disp_size = 0; /* How big is this operand. 0 == don't know */ char *op_bad = ""; /* Bad operand error */ char *tp, *temp, c; /* Temporary holders */ char access = topP->top_access; /* Save on a deref. */ char width = topP->top_width; int really_none = 0; /* Empty expressions evaluate to 0 but I need to know if it's there or not */ expressionS *expP; /* -> expression values for this operand */ /* Does this command restrict the displacement size. */ if (access == 'b') com_width = (width == 'b' ? 1 : (width == 'w' ? 2 : (width == 'l' ? 4 : 0))); *optex = '\0'; /* This is kind of a back stop for all the searches to fail on if needed.*/ if (*point == '*') { /* A dereference? */ deferred = 1; point++; } /* Force words into a certain mode */ /* Bitch, Bitch, Bitch! */ /* * Using the ^ operator is ambigous. If I have an absolute label * called 'w' set to, say 2, and I have the expression 'w^1', do I get * 1, forced to be in word displacement mode, or do I get the value of * 'w' or'ed with 1 (3 in this case). * The default is 'w' as an offset, so that's what I use. * Stick with `, it does the same, and isn't ambig. */ if (*point != '\0' && ((point[1] == '^') || (point[1] == '`'))) switch (*point) { case 'b': case 'B': case 'w': case 'W': case 'l': case 'L': if (com_width) as_warn (_("Casting a branch displacement is bad form, and is ignored.")); else { c = (isupper (*point) ? tolower (*point) : *point); call_width = ((c == 'b') ? 1 : ((c == 'w') ? 2 : 4)); } point += 2; break; } /* Setting immediate mode */ if (*point == '$') { immediate = 1; point++; } /* * I've pulled off all the easy stuff off the front, move to the end and * yank. */ for (end = point; *end != '\0'; end++) /* Move to the end. */ ; if (end != point) /* Null string? */ end--; if (end > point && *end == ' ' && end[-1] != '\'') end--; /* Hop white space */ /* Is this an index reg. */ if ((*end == ']') && (end[-1] != '\'')) { temp = end; /* Find opening brace. */ for (--end; (*end != '[' && end != point); end--) ; /* If I found the opening brace, get the index register number. */ if (*end == '[') { tp = end + 1; /* tp should point to the start of a reg. */ ndx = tahoe_reg_parse (&tp); if (tp != temp) { /* Reg. parse error. */ ndx = -1; } else { end--; /* Found it, move past brace. */ } if (ndx == -1) { op_bad = _("Couldn't parse the [index] in this operand."); end = point; /* Force all the rest of the tests to fail. */ } } else { op_bad = _("Couldn't find the opening '[' for the index of this operand."); end = point; /* Force all the rest of the tests to fail. */ } } /* Post increment? */ if (*end == '+') { dec_inc = '+'; /* was: *end--; */ end--; } /* register in parens? */ if ((*end == ')') && (end[-1] != '\'')) { temp = end; /* Find opening paren. */ for (--end; (*end != '(' && end != point); end--) ; /* If I found the opening paren, get the register number. */ if (*end == '(') { tp = end + 1; reg = tahoe_reg_parse (&tp); if (tp != temp) { /* Not a register, but could be part of the expression. */ reg = -1; end = temp; /* Rest the pointer back */ } else { end--; /* Found the reg. move before opening paren. */ } } else { op_bad = _("Couldn't find the opening '(' for the deref of this operand."); end = point; /* Force all the rest of the tests to fail. */ } } /* Pre decrement? */ if (*end == '-') { if (dec_inc != ' ') { op_bad = _("Operand can't be both pre-inc and post-dec."); end = point; } else { dec_inc = '-'; /* was: *end--; */ end--; } } /* * Everything between point and end is the 'expression', unless it's * a register name. */ c = end[1]; end[1] = '\0'; tp = point; imreg = tahoe_reg_parse (&point); /* Get the immediate register if it is there.*/ if (*point != '\0') { /* If there is junk after point, then the it's not immediate reg. */ point = tp; imreg = -1; } if (imreg != -1 && reg != -1) op_bad = _("I parsed 2 registers in this operand."); /* * Evaluate whats left of the expression to see if it's valid. * Note again: This assumes that the calling expression has saved * input_line_pointer. (Nag, nag, nag!) */ if (*op_bad == '\0') { /* Statement has no syntax goofs yet: let's sniff the expression. */ input_line_pointer = point; expP = &(topP->exp_of_operand); topP->seg_of_operand = expression (expP); switch (expP->X_op) { case O_absent: /* No expression. For BSD4.2 compatibility, missing expression is absolute 0 */ expP->X_op = O_constant; expP->X_add_number = 0; really_none = 1; case O_constant: /* for SEG_ABSOLUTE, we shouldnt need to set X_op_symbol, X_add_symbol to any particular value. */ /* But, we will program defensively. Since this situation occurs rarely so it costs us little to do so. */ expP->X_add_symbol = NULL; expP->X_op_symbol = NULL; /* How many bytes are needed to express this abs value? */ abs_width = ((((expP->X_add_number & 0xFFFFFF80) == 0) || ((expP->X_add_number & 0xFFFFFF80) == 0xFFFFFF80)) ? 1 : (((expP->X_add_number & 0xFFFF8000) == 0) || ((expP->X_add_number & 0xFFFF8000) == 0xFFFF8000)) ? 2 : 4); case O_symbol: break; default: /* * Major bug. We can't handle the case of a operator * expression in a synthetic opcode variable-length * instruction. We don't have a frag type that is smart * enough to relax a operator, and so we just force all * operators to behave like SEG_PASS1s. Clearly, if there is * a demand we can invent a new or modified frag type and * then coding up a frag for this case will be easy. */ need_pass_2 = 1; op_bad = _("Can't relocate expression error."); break; case O_big: /* This is an error. Tahoe doesn't allow any expressions bigger that a 32 bit long word. Any bigger has to be referenced by address. */ op_bad = _("Expression is too large for a 32 bits."); break; } if (*input_line_pointer != '\0') { op_bad = _("Junk at end of expression."); } } end[1] = c; /* I'm done, so restore optex */ *optex = segfault; /* * At this point in the game, we (in theory) have all the components of * the operand at least parsed. Now it's time to check for syntax/semantic * errors, and build the mode. * This is what I have: * deferred = 1 if '*' * call_width = 0,1,2,4 * abs_width = 0,1,2,4 * com_width = 0,1,2,4 * immediate = 1 if '$' * ndx = -1 or reg num * dec_inc = '-' or '+' or ' ' * reg = -1 or reg num * imreg = -1 or reg num * topP->exp_of_operand * really_none */ /* Is there a displacement size? */ disp_size = (call_width ? call_width : (com_width ? com_width : abs_width ? abs_width : 0)); if (*op_bad == '\0') { if (imreg != -1) { /* Rn */ mode = TAHOE_DIRECT_REG; if (deferred || immediate || (dec_inc != ' ') || (reg != -1) || !really_none) op_bad = _("Syntax error in direct register mode."); else if (ndx != -1) op_bad = _("You can't index a register in direct register mode."); else if (imreg == SP_REG && access == 'r') op_bad = _("SP can't be the source operand with direct register addressing."); else if (access == 'a') op_bad = _("Can't take the address of a register."); else if (access == 'b') op_bad = _("Direct Register can't be used in a branch."); else if (width == 'q' && ((imreg % 2) || (imreg > 13))) op_bad = _("For quad access, the register must be even and < 14."); else if (call_width) op_bad = _("You can't cast a direct register."); if (*op_bad == '\0') { /* No errors, check for warnings */ if (width == 'q' && imreg == 12) as_warn (_("Using reg 14 for quadwords can tromp the FP register.")); reg = imreg; } /* We know: imm = -1 */ } else if (dec_inc == '-') { /* -(SP) */ mode = TAHOE_AUTO_DEC; if (deferred || immediate || !really_none) op_bad = _("Syntax error in auto-dec mode."); else if (ndx != -1) op_bad = _("You can't have an index auto dec mode."); else if (access == 'r') op_bad = _("Auto dec mode cant be used for reading."); else if (reg != SP_REG) op_bad = _("Auto dec only works of the SP register."); else if (access == 'b') op_bad = _("Auto dec can't be used in a branch."); else if (width == 'q') op_bad = _("Auto dec won't work with quadwords."); /* We know: imm = -1, dec_inc != '-' */ } else if (dec_inc == '+') { if (immediate || !really_none) op_bad = _("Syntax error in one of the auto-inc modes."); else if (deferred) { /* *(SP)+ */ mode = TAHOE_AUTO_INC_DEFERRED; if (reg != SP_REG) op_bad = _("Auto inc deferred only works of the SP register."); else if (ndx != -1) op_bad = _("You can't have an index auto inc deferred mode."); else if (access == 'b') op_bad = _("Auto inc can't be used in a branch."); } else { /* (SP)+ */ mode = TAHOE_AUTO_INC; if (access == 'm' || access == 'w') op_bad = _("You can't write to an auto inc register."); else if (reg != SP_REG) op_bad = _("Auto inc only works of the SP register."); else if (access == 'b') op_bad = _("Auto inc can't be used in a branch."); else if (width == 'q') op_bad = _("Auto inc won't work with quadwords."); else if (ndx != -1) op_bad = _("You can't have an index in auto inc mode."); } /* We know: imm = -1, dec_inc == ' ' */ } else if (reg != -1) { if ((ndx != -1) && (reg == SP_REG)) op_bad = _("You can't index the sp register."); if (deferred) { /* *<disp>(Rn) */ mode = TAHOE_REG_DISP_DEFERRED; if (immediate) op_bad = _("Syntax error in register displaced mode."); } else if (really_none) { /* (Rn) */ mode = TAHOE_REG_DEFERRED; /* if reg = SP then cant be indexed */ } else { /* <disp>(Rn) */ mode = TAHOE_REG_DISP; } /* We know: imm = -1, dec_inc == ' ', Reg = -1 */ } else { if (really_none) op_bad = _("An offest is needed for this operand."); if (deferred && immediate) { /* *$<ADDR> */ mode = TAHOE_ABSOLUTE_ADDR; disp_size = 4; } else if (immediate) { /* $<disp> */ mode = TAHOE_IMMEDIATE; if (ndx != -1) op_bad = _("You can't index a register in immediate mode."); if (access == 'a') op_bad = _("Immediate access can't be used as an address."); /* ponder the wisdom of a cast because it doesn't do any good. */ } else if (deferred) { /* *<disp> */ mode = TAHOE_DISP_REL_DEFERRED; } else { /* <disp> */ mode = TAHOE_DISPLACED_RELATIVE; } } } /* * At this point, all the errors we can do have be checked for. * We can build the 'top'. */ topP->top_ndx = ndx; topP->top_reg = reg; topP->top_mode = mode; topP->top_error = op_bad; topP->top_dispsize = disp_size;} /* tip_op *//* * t i p ( ) * * This converts a string into a tahoe instruction. * The string must be a bare single instruction in tahoe (with BSD4 frobs) * format. * It provides at most one fatal error message (which stops the scan) * some warning messages as it finds them. * The tahoe instruction is returned in exploded form. * * The exploded instruction is returned to a struct tit of your choice. * #include "tahoe-inst.h" to know what a struct tit is. * */static voidtip (titP, instring) struct tit *titP; /* We build an exploded instruction here. */ char *instring; /* Text of a vax instruction: we modify. */{ register struct tot_wot *twP = NULL; /* How to bit-encode this opcode. */ register char *p; /* 1/skip whitespace.2/scan vot_how */ register char *q; /* */ register unsigned char count; /* counts number of operands seen */ register struct top *operandp;/* scan operands in struct tit */ register char *alloperr = ""; /* error over all operands */ register char c; /* Remember char, (we clobber it with '\0' temporarily). */ char *save_input_line_pointer; if (*instring == ' ') ++instring; /* Skip leading whitespace. */ for (p = instring; *p && *p != ' '; p++) ; /* MUST end in end-of-string or exactly 1 space. */ /* Scanned up to end of operation-code. */ /* Operation-code is ended with whitespace. */ if (p == instring) { titP->tit_error = _("No operator"); count = 0; titP->tit_opcode = 0; } else { c = *p; *p = '\0'; /* * Here with instring pointing to what better be an op-name, and p * pointing to character just past that. * We trust instring points to an op-name, with no whitespace. */ twP = (struct tot_wot *) hash_find (op_hash, instring); *p = c; /* Restore char after op-code. */ if (twP == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -