|
|
|
@ -34,6 +34,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., |
|
|
|
#include "@prefix@-desc.h" |
|
|
|
#include "@prefix@-opc.h" |
|
|
|
#include "opintl.h" |
|
|
|
#include "xregex.h" |
|
|
|
|
|
|
|
#undef min |
|
|
|
#define min(a,b) ((a) < (b) ? (a) : (b)) |
|
|
|
@ -44,6 +45,104 @@ static const char * parse_insn_normal |
|
|
|
PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *)); |
|
|
|
|
|
|
|
/* -- assembler routines inserted here */ |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
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 @arch@_cgen_assemble_insn |
|
|
|
|
|
|
|
returns NULL for success, an error message for failure |
|
|
|
*/ |
|
|
|
|
|
|
|
char * |
|
|
|
@arch@_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. |
|
|
|
|
|
|
|
@ -211,6 +310,7 @@ const CGEN_INSN * |
|
|
|
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)) |
|
|
|
@ -226,6 +326,7 @@ const CGEN_INSN * |
|
|
|
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 */ |
|
|
|
@ -242,6 +343,11 @@ const CGEN_INSN * |
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
@ -269,6 +375,7 @@ const CGEN_INSN * |
|
|
|
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) |
|
|
|
|