+#ifdef CGEN_ASM_INIT_HOOK
+CGEN_ASM_INIT_HOOK
+#endif
+}
+
+\f
+
+/* 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 m32r_cgen_assemble_insn
+
+ Returns NULL for success, an error message for failure. */
+
+char *
+m32r_cgen_build_insn_regex (CGEN_INSN *insn)
+{
+ CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
+ const char *mnem = CGEN_INSN_MNEMONIC (insn);
+ 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;
+
+ /* Generate a case sensitive regular expression that emulates case
+ insensitive matching in the "C" locale. We cannot generate a case
+ insensitive regular expression because in Turkish locales, 'i' and 'I'
+ are not equal modulo case conversion. */
+
+ /* Copy the literal mnemonic out of the insn. */
+ for (; *mnem; mnem++)
+ {
+ char c = *mnem;
+
+ if (ISALPHA (c))
+ {
+ *rx++ = '[';
+ *rx++ = TOLOWER (c);
+ *rx++ = TOUPPER (c);
+ *rx++ = ']';
+ }
+ else
+ *rx++ = c;
+ }
+
+ /* Copy any remaining literals from the syntax string into the rx. */
+ for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
+ {
+ if (CGEN_SYNTAX_CHAR_P (* syn))
+ {
+ char c = CGEN_SYNTAX_CHAR (* syn);
+
+ switch (c)
+ {
+ /* 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++ = '\\';
+ *rx++ = c;
+ break;
+
+ default:
+ if (ISALPHA (c))
+ {
+ *rx++ = '[';
+ *rx++ = TOLOWER (c);
+ *rx++ = TOUPPER (c);
+ *rx++ = ']';
+ }
+ else
+ *rx++ = c;
+ break;
+ }
+ }
+ 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);
+
+ 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;
+ }