diff options
Diffstat (limited to 'opcodes/fr30-asm.c')
-rw-r--r-- | opcodes/fr30-asm.c | 109 |
1 files changed, 108 insertions, 1 deletions
diff --git a/opcodes/fr30-asm.c b/opcodes/fr30-asm.c index b2a95e3..9ad3f2c 100644 --- a/opcodes/fr30-asm.c +++ b/opcodes/fr30-asm.c @@ -34,6 +34,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., #include "fr30-desc.h" #include "fr30-opc.h" #include "opintl.h" +#include "xregex.h" #undef min #define min(a,b) ((a) < (b) ? (a) : (b)) @@ -325,6 +326,104 @@ fr30_cgen_init_asm (cd) } + +/* + Regex construction routine. + + This translates an opcode syntax string into a regex string, + by replacing any non-character syntax element (such as an + opcode) with the pattern '.*' + + It then compiles the regex and stores it in the opcode, for + later use by fr30_cgen_assemble_insn + + returns NULL for success, an error message for failure +*/ + +char * +fr30_cgen_build_insn_regex (insn) + CGEN_INSN *insn; +{ + CGEN_OPCODE *opc = CGEN_INSN_OPCODE (insn); + const char *mnem = CGEN_INSN_MNEMONIC (insn); + int mnem_len; + char rxbuf[CGEN_MAX_RX_ELEMENTS]; + char *rx = rxbuf; + const CGEN_SYNTAX_CHAR_TYPE *syn; + int reg_err; + + syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc)); + + /* Mnemonics come first in the syntax string */ + if (! CGEN_SYNTAX_MNEMONIC_P (* syn)) return "missing mnemonic in syntax string"; + ++syn; + + /* copy the literal mnemonic out of the insn */ + memset (rx, 0, CGEN_MAX_RX_ELEMENTS); + mnem_len = strlen(mnem); + memcpy (rx, mnem, mnem_len); + rx += mnem_len; + + /* copy any remaining literals from the syntax string into the rx */ + for(; * syn != 0 && rx < rxbuf + (CGEN_MAX_RX_ELEMENTS - 9); ++syn, ++rx) + { + if (CGEN_SYNTAX_CHAR_P (* syn)) + { + char tmp = CGEN_SYNTAX_CHAR (* syn); + switch (tmp) + { + /* escape any regex metacharacters in the syntax */ + case '.': case '[': case '\\': + case '*': case '^': case '$': + +#ifdef CGEN_ESCAPE_EXTENDED_REGEX + case '?': case '{': case '}': + case '(': case ')': case '*': + case '|': case '+': case ']': +#endif + + * rx++ = '\\'; + break; + } + /* insert syntax char into rx */ + * rx = tmp; + } + else + { + /* replace non-syntax fields with globs */ + * rx = '.'; + * ++rx = '*'; + } + } + + /* trailing whitespace ok */ + * rx++ = '['; + * rx++ = ' '; + * rx++ = '\t'; + * rx++ = ']'; + * rx++ = '*'; + + /* but anchor it after that */ + * rx++ = '$'; + * rx = '\0'; + + CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t)); + reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB|REG_ICASE); + + if (reg_err == 0) + return NULL; + else + { + static char msg[80]; + regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80); + regfree ((regex_t *) CGEN_INSN_RX (insn)); + free (CGEN_INSN_RX (insn)); + (CGEN_INSN_RX (insn)) = NULL; + return msg; + } +} + + /* Default insn parser. The syntax string is scanned and operands are parsed and stored in FIELDS. @@ -491,6 +590,7 @@ fr30_cgen_assemble_insn (cd, str, fields, buf, errmsg) CGEN_INSN_LIST *ilist; const char *parse_errmsg = NULL; const char *insert_errmsg = NULL; + int recognized_mnemonic = 0; /* Skip leading white space. */ while (isspace (* str)) @@ -506,6 +606,7 @@ fr30_cgen_assemble_insn (cd, str, fields, buf, errmsg) for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist)) { const CGEN_INSN *insn = ilist->insn; + recognized_mnemonic = 1; #ifdef CGEN_VALIDATE_INSN_SUPPORTED /* not usually needed as unsupported opcodes shouldn't be in the hash lists */ @@ -522,6 +623,11 @@ fr30_cgen_assemble_insn (cd, str, fields, buf, errmsg) str = start; + /* skip this insn if str doesn't look right lexically */ + if (CGEN_INSN_RX (insn) != NULL && + regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH) + continue; + /* Allow parse/insert handlers to obtain length of insn. */ CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn); @@ -542,13 +648,14 @@ fr30_cgen_assemble_insn (cd, str, fields, buf, errmsg) { static char errbuf[150]; +#ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS const char *tmp_errmsg; -#ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS /* If requesting verbose error messages, use insert_errmsg. Failing that, use parse_errmsg */ tmp_errmsg = (insert_errmsg ? insert_errmsg : parse_errmsg ? parse_errmsg : + recognized_mnemonic ? _("unrecognized form of instruction") : _("unrecognized instruction")); if (strlen (start) > 50) |