📄 tc-vax.c
字号:
* You MUST have called vip_begin() once before using this function. */static voidvip (vitP, instring) struct vit *vitP; /* We build an exploded instruction here. */ char *instring; /* Text of a vax instruction: we modify. */{ /* How to bit-encode this opcode. */ struct vot_wot *vwP; /* 1/skip whitespace.2/scan vot_how */ char *p; char *q; /* counts number of operands seen */ unsigned char count; /* scan operands in struct vit */ struct vop *operandp; /* error over all operands */ const char *alloperr; /* Remember char, (we clobber it with '\0' temporarily). */ char c; /* Op-code of this instruction. */ vax_opcodeT oc; 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 == 0) { vitP->vit_error = _("No operator"); count = 0; memset (vitP->vit_opcode, '\0', sizeof (vitP->vit_opcode)); } 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. */ vwP = (struct vot_wot *) hash_find (op_hash, instring); *p = c; /* Restore char after op-code. */ if (vwP == 0) { vitP->vit_error = _("Unknown operator"); count = 0; memset (vitP->vit_opcode, '\0', sizeof (vitP->vit_opcode)); } else { /* * We found a match! So let's pick up as many operands as the * instruction wants, and even gripe if there are too many. * We expect comma to seperate each operand. * We let instring track the text, while p tracks a part of the * struct vot. */ const char *howp; /* * The lines below know about 2-byte opcodes starting FD,FE or FF. * They also understand synthetic opcodes. Note: * we return 32 bits of opcode, including bucky bits, BUT * an opcode length is either 8 or 16 bits for vit_opcode_nbytes. */ oc = vwP->vot_code; /* The op-code. */ vitP->vit_opcode_nbytes = (oc & 0xFF) >= 0xFD ? 2 : 1; md_number_to_chars (vitP->vit_opcode, oc, 4); count = 0; /* no operands seen yet */ instring = p; /* point just past operation code */ alloperr = ""; for (howp = vwP->vot_how, operandp = vitP->vit_operand; !(alloperr && *alloperr) && *howp; operandp++, howp += 2) { /* * Here to parse one operand. Leave instring pointing just * past any one ',' that marks the end of this operand. */ if (!howp[1]) as_fatal (_("odd number of bytes in operand description")); else if (*instring) { for (q = instring; (c = *q) && c != ','; q++) ; /* * Q points to ',' or '\0' that ends argument. C is that * character. */ *q = 0; operandp->vop_width = howp[1]; operandp->vop_nbytes = vax_operand_width_size[(unsigned) howp[1]]; operandp->vop_access = howp[0]; vip_op (instring, operandp); *q = c; /* Restore input text. */ if (operandp->vop_error) alloperr = _("Bad operand"); instring = q + (c ? 1 : 0); /* next operand (if any) */ count++; /* won another argument, may have an operr */ } else alloperr = _("Not enough operands"); } if (!*alloperr) { if (*instring == ' ') instring++; /* Skip whitespace. */ if (*instring) alloperr = _("Too many operands"); } vitP->vit_error = alloperr; } } vitP->vit_operands = count;}#ifdef test/* * Test program for above. */struct vit myvit; /* build an exploded vax instruction here */char answer[100]; /* human types a line of vax assembler here */char *mybug; /* "" or an internal logic diagnostic */int mycount; /* number of operands */struct vop *myvop; /* scan operands from myvit */int mysynth; /* 1 means want synthetic opcodes. */char my_immediate[200];char my_indirect[200];char my_displen[200];main (){ char *p; printf ("0 means no synthetic instructions. "); printf ("Value for vip_begin? "); gets (answer); sscanf (answer, "%d", &mysynth); printf ("Synthetic opcodes %s be included.\n", mysynth ? "will" : "will not"); printf ("enter immediate symbols eg enter # "); gets (my_immediate); printf ("enter indirect symbols eg enter @ "); gets (my_indirect); printf ("enter displen symbols eg enter ^ "); gets (my_displen); if (p = vip_begin (mysynth, my_immediate, my_indirect, my_displen)) { error ("vip_begin=%s", p); } printf ("An empty input line will quit you from the vax instruction parser\n"); for (;;) { printf ("vax instruction: "); fflush (stdout); gets (answer); if (!*answer) { break; /* out of for each input text loop */ } vip (&myvit, answer); if (*myvit.vit_error) { printf ("ERR:\"%s\"\n", myvit.vit_error); } printf ("opcode="); for (mycount = myvit.vit_opcode_nbytes, p = myvit.vit_opcode; mycount; mycount--, p++ ) { printf ("%02x ", *p & 0xFF); } printf (" operand count=%d.\n", mycount = myvit.vit_operands); for (myvop = myvit.vit_operand; mycount; mycount--, myvop++) { printf ("mode=%xx reg=%xx ndx=%xx len='%c'=%c%c%d. expr=\"", myvop->vop_mode, myvop->vop_reg, myvop->vop_ndx, myvop->vop_short, myvop->vop_access, myvop->vop_width, myvop->vop_nbytes); for (p = myvop->vop_expr_begin; p <= myvop->vop_expr_end; p++) { putchar (*p); } printf ("\"\n"); if (myvop->vop_error) { printf (" err:\"%s\"\n", myvop->vop_error); } if (myvop->vop_warn) { printf (" wrn:\"%s\"\n", myvop->vop_warn); } } } vip_end (); exit (EXIT_SUCCESS);}#endif /* #ifdef test *//* end of vax_ins_parse.c *//* vax_reg_parse.c - convert a VAX register name to a number *//* Copyright (C) 1987 Free Software Foundation, Inc. A part of GNU. *//* * v a x _ r e g _ p a r s e ( ) * * Take 3 char.s, the last of which may be `\0` (non-existent) * and return the VAX register number that they represent. * * Return -1 if they don't form a register name. Good names return * a number from 0:15 inclusive. * * Case is not important in a name. * * Register names understood are: * * R0 * R1 * R2 * R3 * R4 * R5 * R6 * R7 * R8 * R9 * R10 * R11 * R12 AP * R13 FP * R14 SP * R15 PC * */#include <ctype.h>#define AP (12)#define FP (13)#define SP (14)#define PC (15)int /* return -1 or 0:15 */vax_reg_parse (c1, c2, c3) /* 3 chars of register name */ char c1, c2, c3; /* c3 == 0 if 2-character reg name */{ int retval; /* return -1:15 */ retval = -1; if (isupper (c1)) c1 = tolower (c1); if (isupper (c2)) c2 = tolower (c2); if (isdigit (c2) && c1 == 'r') { retval = c2 - '0'; if (isdigit (c3)) { retval = retval * 10 + c3 - '0'; retval = (retval > 15) ? -1 : retval; /* clamp the register value to 1 hex digit */ } else if (c3) retval = -1; /* c3 must be '\0' or a digit */ } else if (c3) /* There are no three letter regs */ retval = -1; else if (c2 == 'p') { switch (c1) { case 's': retval = SP; break; case 'f': retval = FP; break; case 'a': retval = AP; break; default: retval = -1; } } else if (c1 == 'p' && c2 == 'c') retval = PC; else retval = -1; return (retval);}/* * v i p _ o p ( ) * * Parse a vax operand in DEC assembler notation. * For speed, expect a string of whitespace to be reduced to a single ' '. * This is the case for GNU AS, and is easy for other DEC-compatible * assemblers. * * Knowledge about DEC VAX assembler operand notation lives here. * This doesn't even know what a register name is, except it believes * all register names are 2 or 3 characters, and lets vax_reg_parse() say * what number each name represents. * It does, however, know that PC, SP etc are special registers so it can * detect addressing modes that are silly for those registers. * * Where possible, it delivers 1 fatal or 1 warning message if the operand * is suspect. Exactly what we test for is still evolving. *//* * B u g s * * Arg block. * * There were a number of 'mismatched argument type' bugs to vip_op. * The most general solution is to typedef each (of many) arguments. * We used instead a typedef'd argument block. This is less modular * than using seperate return pointers for each result, but runs faster * on most engines, and seems to keep programmers happy. It will have * to be done properly if we ever want to use vip_op as a general-purpose * module (it was designed to be). * * G^ * * Doesn't support DEC "G^" format operands. These always take 5 bytes * to express, and code as modes 8F or 9F. Reason: "G^" deprives you of * optimising to (say) a "B^" if you are lucky in the way you link. * When someone builds a linker smart enough to convert "G^" to "B^", "W^" * whenever possible, then we should implement it. * If there is some other use for "G^", feel free to code it in! * * * speed * * If I nested if()s more, I could avoid testing (*err) which would save * time, space and page faults. I didn't nest all those if()s for clarity * and because I think the mode testing can be re-arranged 1st to test the * commoner constructs 1st. Does anybody have statistics on this? * * * * error messages * * In future, we should be able to 'compose' error messages in a scratch area * and give the user MUCH more informative error messages. Although this takes * a little more code at run-time, it will make this module much more self- * documenting. As an example of what sucks now: most error messages have * hardwired into them the DEC VAX metacharacters "#^@" which are nothing like * the Un*x characters "$`*", that most users will expect from this AS. *//* * The input is a string, ending with '\0'. * * We also require a 'hint' of what kind of operand is expected: so * we can remind caller not to write into literals for instance. * * The output is a skeletal instruction. * * The algorithm has two parts. * 1. extract the syntactic features (parse off all the @^#-()+[] mode crud); * 2. express the @^#-()+[] as some parameters suited to further analysis. * * 2nd step is where we detect the googles of possible invalid combinations * a human (or compiler) might write. Note that if we do a half-way * decent assembler, we don't know how long to make (eg) displacement * fields when we first meet them (because they may not have defined values). * So we must wait until we know how many bits are needed for each address, * then we can know both length and opcodes of instructions. * For reason(s) above, we will pass to our caller a 'broken' instruction * of these major components, from which our caller can generate instructions: * - displacement length I^ S^ L^ B^ W^ unspecified * - mode (many) * - register R0-R15 or absent * - index register R0-R15 or absent * - expression text what we don't parse * - error text(s) why we couldn't understand the operand *//* * To decode output of this, test errtxt. If errtxt[0] == '\0', then * we had no errors that prevented parsing. Also, if we ever report * an internal bug, errtxt[0] is set non-zero. So one test tells you * if the other outputs are to be taken seriously. *//* * Because this module is useful for both VMS and UN*X style assemblers * and because of the variety of UN*X assemblers we must recognise * the different conventions for assembler operand notation. For example * VMS says "#42" for immediate mode, while most UN*X say "$42". * We permit arbitrary sets of (single) characters to represent the * 3 concepts that DEC writes '#', '@', '^'. *//* character tests */#define VIP_IMMEDIATE 01 /* Character is like DEC # */#define VIP_INDIRECT 02 /* Char is like DEC @ */#define VIP_DISPLEN 04 /* Char is like DEC ^ */#define IMMEDIATEP(c) (vip_metacharacters [(c)&0xff]&VIP_IMMEDIATE)#define INDIRECTP(c) (vip_metacharacters [(c)&0xff]&VIP_INDIRECT)#define DISPLENP(c) (vip_metacharacters [(c)&0xff]&VIP_DISPLEN)/* We assume 8 bits per byte. Use vip_op_defaults() to set these up BEFORE we * are ever called. */#if defined(CONST_TABLE)#define _ 0,#define I VIP_IMMEDIATE,#define S VIP_INDIRECT,#define D VIP_DISPLEN,static const charvip_metacharacters[256] ={ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /* ^@ ^A ^B ^C ^D ^E ^F ^G ^H ^I ^J ^K ^L ^M ^N ^O*/ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /* ^P ^Q ^R ^S ^T ^U ^V ^W ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */ _ _
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -