📄 m68k-parse.y
字号:
zpc: LPC | LZPC ;/* ',' zapc when it may be omitted. */optczapc: /* empty */ { $$ = ZADDR0; } | ',' zapc { $$ = $2; } ;/* ',' EXPR when it may be omitted. */optcexpr: /* empty */ { $$.exp.X_op = O_absent; $$.size = SIZE_UNSPEC; } | ',' EXPR { $$ = $2; } ;/* EXPR ',' when it may be omitted. */optexprc: /* empty */ { $$.exp.X_op = O_absent; $$.size = SIZE_UNSPEC; } | EXPR ',' { $$ = $1; } ;/* A register list for the movem instruction. */reglist: reglistpair | reglistpair '/' ireglist { $$ = $1 | $3; } | reglistreg '/' ireglist { $$ = (1 << $1) | $3; } ;/* We use ireglist when we know we are looking at a reglist, and we can safely reduce a simple register to reglistreg. If we permitted reglist to reduce to reglistreg, it would be ambiguous whether a plain register were a DREG/AREG/FPREG or a REGLST. */ireglist: reglistreg { $$ = 1 << $1; } | reglistpair | reglistpair '/' ireglist { $$ = $1 | $3; } | reglistreg '/' ireglist { $$ = (1 << $1) | $3; } ;reglistpair: reglistreg '-' reglistreg { if ($1 <= $3) $$ = (1 << ($3 + 1)) - 1 - ((1 << $1) - 1); else $$ = (1 << ($1 + 1)) - 1 - ((1 << $3) - 1); } ;reglistreg: DR { $$ = $1 - DATA0; } | AR { $$ = $1 - ADDR0 + 8; } | FPR { $$ = $1 - FP0 + 16; } | FPCR { if ($1 == FPI) $$ = 24; else if ($1 == FPS) $$ = 25; else $$ = 26; } ;%%/* The string to parse is stored here, and modified by yylex. */static char *str;/* The original string pointer. */static char *strorig;/* If *CCP could be a register, return the register number and advance *CCP. Otherwise don't change *CCP, and return 0. */static enum m68k_registerm68k_reg_parse (ccp) register char **ccp;{ char *start = *ccp; char c; char *p; symbolS *symbolp; if (flag_reg_prefix_optional) { if (*start == REGISTER_PREFIX) start++; p = start; } else { if (*start != REGISTER_PREFIX) return 0; p = start + 1; } if (! is_name_beginner (*p)) return 0; p++; while (is_part_of_name (*p) && *p != '.' && *p != ':' && *p != '*') p++; c = *p; *p = 0; symbolp = symbol_find (start); *p = c; if (symbolp != NULL && S_GET_SEGMENT (symbolp) == reg_section) { *ccp = p; return S_GET_VALUE (symbolp); } /* In MRI mode, something like foo.bar can be equated to a register name. */ while (flag_mri && c == '.') { ++p; while (is_part_of_name (*p) && *p != '.' && *p != ':' && *p != '*') p++; c = *p; *p = '\0'; symbolp = symbol_find (start); *p = c; if (symbolp != NULL && S_GET_SEGMENT (symbolp) == reg_section) { *ccp = p; return S_GET_VALUE (symbolp); } } return 0;}/* The lexer. */static intyylex (){ enum m68k_register reg; char *s; int parens; int c = 0; int tail = 0; char *hold; if (*str == ' ') ++str; if (*str == '\0') return 0; /* Various special characters are just returned directly. */ switch (*str) { case '@': /* In MRI mode, this can be the start of an octal number. */ if (flag_mri) { if (isdigit (str[1]) || ((str[1] == '+' || str[1] == '-') && isdigit (str[2]))) break; } /* Fall through. */ case '#': case '&': case ',': case ')': case '/': case '[': case ']': return *str++; case '+': /* It so happens that a '+' can only appear at the end of an operand. If it appears anywhere else, it must be a unary plus on an expression. */ if (str[1] == '\0') return *str++; break; case '-': /* A '-' can only appear in -(ar), rn-rn, or ar@-. If it appears anywhere else, it must be a unary minus on an expression. */ if (str[1] == '\0') return *str++; s = str + 1; if (*s == '(') ++s; if (m68k_reg_parse (&s) != 0) return *str++; break; case '(': /* A '(' can only appear in `(reg)', `(expr,...', `([', `@(', or `)('. If it appears anywhere else, it must be starting an expression. */ if (str[1] == '[' || (str > strorig && (str[-1] == '@' || str[-1] == ')'))) return *str++; s = str + 1; if (m68k_reg_parse (&s) != 0) return *str++; /* Check for the case of '(expr,...' by scanning ahead. If we find a comma outside of balanced parentheses, we return '('. If we find an unbalanced right parenthesis, then presumably the '(' really starts an expression. */ parens = 0; for (s = str + 1; *s != '\0'; s++) { if (*s == '(') ++parens; else if (*s == ')') { if (parens == 0) break; --parens; } else if (*s == ',' && parens == 0) { /* A comma can not normally appear in an expression, so this is a case of '(expr,...'. */ return *str++; } } } /* See if it's a register. */ reg = m68k_reg_parse (&str); if (reg != 0) { int ret; yylval.reg = reg; if (reg >= DATA0 && reg <= DATA7) ret = DR; else if (reg >= ADDR0 && reg <= ADDR7) ret = AR; else if (reg >= FP0 && reg <= FP7) return FPR; else if (reg == FPI || reg == FPS || reg == FPC) return FPCR; else if (reg == PC) return LPC; else if (reg >= ZDATA0 && reg <= ZDATA7) ret = ZDR; else if (reg >= ZADDR0 && reg <= ZADDR7) ret = ZAR; else if (reg == ZPC) return LZPC; else return CREG; /* If we get here, we have a data or address register. We must check for a size or scale; if we find one, we must return INDEXREG. */ s = str; if (*s != '.' && *s != ':' && *s != '*') return ret; yylval.indexreg.reg = reg; if (*s != '.' && *s != ':') yylval.indexreg.size = SIZE_UNSPEC; else { ++s; switch (*s) { case 'w': case 'W': yylval.indexreg.size = SIZE_WORD; ++s; break; case 'l': case 'L': yylval.indexreg.size = SIZE_LONG; ++s; break; default: yyerror (_("illegal size specification")); yylval.indexreg.size = SIZE_UNSPEC; break; } } yylval.indexreg.scale = 1; if (*s == '*' || *s == ':') { expressionS scale; ++s; hold = input_line_pointer; input_line_pointer = s; expression (&scale); s = input_line_pointer; input_line_pointer = hold; if (scale.X_op != O_constant) yyerror (_("scale specification must resolve to a number")); else { switch (scale.X_add_number) { case 1: case 2: case 4: case 8: yylval.indexreg.scale = scale.X_add_number; break; default: yyerror (_("invalid scale value")); break; } } } str = s; return INDEXREG; } /* It must be an expression. Before we call expression, we need to look ahead to see if there is a size specification. We must do that first, because otherwise foo.l will be treated as the symbol foo.l, rather than as the symbol foo with a long size specification. The grammar requires that all expressions end at the end of the operand, or with ',', '(', ']', ')'. */ parens = 0; for (s = str; *s != '\0'; s++) { if (*s == '(') { if (parens == 0 && s > str && (s[-1] == ')' || isalnum ((unsigned char) s[-1]))) break; ++parens; } else if (*s == ')') { if (parens == 0) break; --parens; } else if (parens == 0 && (*s == ',' || *s == ']')) break; } yylval.exp.size = SIZE_UNSPEC; if (s <= str + 2 || (s[-2] != '.' && s[-2] != ':')) tail = 0; else { switch (s[-1]) { case 's': case 'S': case 'b': case 'B': yylval.exp.size = SIZE_BYTE; break; case 'w': case 'W': yylval.exp.size = SIZE_WORD; break; case 'l': case 'L': yylval.exp.size = SIZE_LONG; break; default: break; } if (yylval.exp.size != SIZE_UNSPEC) tail = 2; }#ifdef OBJ_ELF { /* Look for @PLTPC, etc. */ char *cp; yylval.exp.pic_reloc = pic_none; cp = s - tail; if (cp - 6 > str && cp[-6] == '@') { if (strncmp (cp - 6, "@PLTPC", 6) == 0) { yylval.exp.pic_reloc = pic_plt_pcrel; tail += 6; } else if (strncmp (cp - 6, "@GOTPC", 6) == 0) { yylval.exp.pic_reloc = pic_got_pcrel; tail += 6; } } else if (cp - 4 > str && cp[-4] == '@') { if (strncmp (cp - 4, "@PLT", 4) == 0) { yylval.exp.pic_reloc = pic_plt_off; tail += 4; } else if (strncmp (cp - 4, "@GOT", 4) == 0) { yylval.exp.pic_reloc = pic_got_off; tail += 4; } } }#endif if (tail != 0) { c = s[-tail]; s[-tail] = 0; } hold = input_line_pointer; input_line_pointer = str; expression (&yylval.exp.exp); str = input_line_pointer; input_line_pointer = hold; if (tail != 0) { s[-tail] = c; str = s; } return EXPR;}/* Parse an m68k operand. This is the only function which is called from outside this file. */intm68k_ip_op (s, oparg) char *s; struct m68k_op *oparg;{ memset (oparg, 0, sizeof *oparg); oparg->error = NULL; oparg->index.reg = ZDATA0; oparg->index.scale = 1; oparg->disp.exp.X_op = O_absent; oparg->odisp.exp.X_op = O_absent; str = strorig = s; op = oparg; return yyparse ();}/* The error handler. */static voidyyerror (s) const char *s;{ op->error = s;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -