OSDN Git Service

Improve documentation on local labels and add documenation about dollar labels.
[pf3gnuchains/pf3gnuchains3x.git] / opcodes / openrisc-asm.c
index 7f2e951..5dc75a8 100644 (file)
@@ -26,14 +26,15 @@ along with this program; if not, write to the Free Software Foundation, Inc.,
    Keep that in mind.  */
 
 #include "sysdep.h"
-#include <ctype.h>
 #include <stdio.h>
 #include "ansidecl.h"
+#include "safe-ctype.h"
 #include "bfd.h"
 #include "symcat.h"
 #include "openrisc-desc.h"
 #include "openrisc-opc.h"
 #include "opintl.h"
+#include "xregex.h"
 
 #undef min
 #define min(a,b) ((a) < (b) ? (a) : (b))
@@ -257,6 +258,104 @@ openrisc_cgen_init_asm (cd)
 }
 
 \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 openrisc_cgen_assemble_insn
+
+  returns NULL for success, an error message for failure 
+*/
+
+char * 
+openrisc_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;
+    }
+}
+
+\f
 /* Default insn parser.
 
    The syntax string is scanned and operands are parsed and stored in FIELDS.
@@ -294,14 +393,14 @@ parse_insn_normal (cd, insn, strp, fields)
      GAS's input scrubber will ensure mnemonics are lowercase, but we may
      not be called from GAS.  */
   p = CGEN_INSN_MNEMONIC (insn);
-  while (*p && tolower (*p) == tolower (*str))
+  while (*p && TOLOWER (*p) == TOLOWER (*str))
     ++p, ++str;
 
   if (* p)
     return _("unrecognized instruction");
 
 #ifndef CGEN_MNEMONIC_OPERANDS
-  if (* str && !isspace (* str))
+  if (* str && !ISSPACE (* str))
     return _("unrecognized instruction");
 #endif
 
@@ -330,7 +429,7 @@ parse_insn_normal (cd, insn, strp, fields)
             first char after the mnemonic part is a space.  */
          /* FIXME: We also take inappropriate advantage of the fact that
             GAS's input scrubber will remove extraneous blanks.  */
-         if (tolower (*str) == tolower (CGEN_SYNTAX_CHAR (* syn)))
+         if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
            {
 #ifdef CGEN_MNEMONIC_OPERANDS
              if (CGEN_SYNTAX_CHAR(* syn) == ' ')
@@ -377,7 +476,7 @@ parse_insn_normal (cd, insn, strp, fields)
         blanks now.  IE: We needn't try again with a longer version of
         the insn and it is assumed that longer versions of insns appear
         before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
-      while (isspace (* str))
+      while (ISSPACE (* str))
        ++ str;
 
       if (* str != '\0')
@@ -423,9 +522,10 @@ openrisc_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))
+  while (ISSPACE (* str))
     ++ str;
 
   /* The instructions are stored in hashed lists.
@@ -438,6 +538,7 @@ openrisc_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 */
@@ -454,6 +555,11 @@ openrisc_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);
 
@@ -481,6 +587,7 @@ openrisc_cgen_assemble_insn (cd, str, fields, buf, 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)