expression (op);
   if (op->X_op == O_absent)
     as_bad (_("missing operand"));
+  /* Our caller is likely to check that the entire expression was parsed.
+     If we have found a hex constant with an 'h' suffix, ilp will be left
+     pointing at the 'h', so skip it here.  */
+  if (input_line_pointer != NULL
+      && op->X_op == O_constant
+      && (*input_line_pointer == 'h' || *input_line_pointer == 'H'))
+    ++ input_line_pointer;
   return input_line_pointer;
 }
 
       /* Now get profiling info.  */
       halt = extract_operand (input_line_pointer, str, 1024);
       /* Process like ".word xxx" directive.  */
-      parse_exp (str, & exp);
+      (void) parse_exp (str, & exp);
       emit_expr (& exp, 2);
       input_line_pointer = halt;
     }
                   bfd_boolean allow_20bit_values,
                   bfd_boolean constants_allowed)
 {
+  char * end;
   char *__tl = l;
 
   /* Check if an immediate #VALUE.  The hash sign should be only at the beginning!  */
       op->mode = OP_EXP;
       op->vshift = vshift;
 
-      parse_exp (__tl, &(op->exp));
+      end = parse_exp (__tl, &(op->exp));
+      if (end != NULL && *end != 0 && *end != ')' )
+       {
+         as_bad (_("extra characters '%s' at end of immediate expression '%s'"), end, l);
+         return 1;
+       }
       if (op->exp.X_op == O_constant)
        {
          int x = op->exp.X_add_number;
       op->am = 1;              /* mode As == 01 bin.  */
       op->ol = 1;              /* Immediate value followed by instruction.  */
       __tl = h + 1;
-      parse_exp (__tl, &(op->exp));
+      end = parse_exp (__tl, &(op->exp));
+      if (end != NULL && *end != 0)
+       {
+         as_bad (_("extra characters '%s' at the end of absolute operand '%s'"), end, l);
+         return 1;
+       }
       op->mode = OP_EXP;
       op->vshift = 0;
       if (op->exp.X_op == O_constant)
       *h = 0;
       op->mode = OP_EXP;
       op->vshift = 0;
-      parse_exp (__tl, &(op->exp));
+      end = parse_exp (__tl, &(op->exp));
+      if (end != NULL && *end != 0)
+       {
+         as_bad (_("extra characters '%s' at end of operand '%s'"), end, l);
+         return 1;
+       }
       if (op->exp.X_op == O_constant)
        {
          int x = op->exp.X_add_number;
     }
 
   /* Symbolic mode 'mov a, b' == 'mov x(pc), y(pc)'.  */
-  do
+  op->mode = OP_EXP;
+  op->reg = 0;         /* PC relative... be careful.  */
+  /* An expression starting with a minus sign is a constant, not an address.  */
+  op->am = (*l == '-' ? 3 : 1);
+  op->ol = 1;
+  op->vshift = 0;
+  __tl = l;
+  end = parse_exp (__tl, &(op->exp));
+  if (end != NULL && * end != 0)
     {
-      op->mode = OP_EXP;
-      op->reg = 0;             /* PC relative... be careful.  */
-      /* An expression starting with a minus sign is a constant, not an address.  */
-      op->am = (*l == '-' ? 3 : 1);
-      op->ol = 1;
-      op->vshift = 0;
-      __tl = l;
-      parse_exp (__tl, &(op->exp));
-      return 0;
+      as_bad (_("extra characters '%s' at end of operand '%s'"), end, l);
+      return 1;
     }
-  while (0);
-
-  /* Unreachable.  */
-  as_bad (_("unknown addressing mode for operand %s"), l);
-  return 1;
+  return 0;
 }
 
 
       op->am = 1;
       op->ol = 1;
       op->vshift = 0;
-      parse_exp (__tl, &(op->exp));
+      (void) parse_exp (__tl, &(op->exp));
 
       if (op->exp.X_op != O_constant || op->exp.X_add_number != 0)
        {
   int insn_length = 0;
   char l1[MAX_OP_LEN], l2[MAX_OP_LEN];
   char *frag;
+  char *end;
   int where;
   struct msp430_operand_s op1, op2;
   int res = 0;
                as_bad (_("expected #n as first argument of %s"), opcode->name);
                break;
              }
-           parse_exp (l1 + 1, &(op1.exp));
+           end = parse_exp (l1 + 1, &(op1.exp));
+           if (end != NULL && *end != 0)
+             {
+               as_bad (_("extra characters '%s' at end of constant expression '%s'"), end, l1);
+               break;
+             }
            if (op1.exp.X_op != O_constant)
              {
                as_bad (_("expected constant expression as first argument of %s"),
                as_bad (_("expected #n as first argument of %s"), opcode->name);
                break;
              }
-           parse_exp (l1 + 1, &(op1.exp));
+           end = parse_exp (l1 + 1, &(op1.exp));
+           if (end != NULL && *end != 0)
+             {
+               as_bad (_("extra characters '%s' at end of operand '%s'"), end, l1);
+               break;
+             }
            if (op1.exp.X_op != O_constant)
              {
                as_bad (_("expected constant expression as first argument of %s"),
 
            if (*l1 == '#')
              {
-               parse_exp (l1 + 1, &(op1.exp));
+               end = parse_exp (l1 + 1, &(op1.exp));
+               if (end != NULL && *end != 0)
+                 {
+                   as_bad (_("extra characters '%s' at end of operand '%s'"), end, l1);
+                   break;
+                 }
 
                if (op1.exp.X_op == O_constant)
                  {
          /* The RPT instruction only accepted immediates and registers.  */
          if (*l1 == '#')
            {
-             parse_exp (l1 + 1, &(op1.exp));
+             end = parse_exp (l1 + 1, &(op1.exp));
+             if (end != NULL && *end != 0)
+               {
+                 as_bad (_("extra characters '%s' at end of operand '%s'"), end, l1);
+                 break;
+               }
              if (op1.exp.X_op != O_constant)
                {
                  as_bad (_("expected constant value as argument to RPT"));
          if (*m == '$')
            m++;
 
-         parse_exp (m, &exp);
+         end = parse_exp (m, &exp);
+         if (end != NULL && *end != 0)
+           {
+             as_bad (_("extra characters '%s' at end of operand '%s'"), end, l1);
+             break;
+           }
 
          /* In order to handle something like:
 
          if (*m == '#' || *m == '$')
            m++;
 
-         parse_exp (m, & exp);
+         end = parse_exp (m, & exp);
+         if (end != NULL && *end != 0)
+           {
+             as_bad (_("extra characters '%s' at end of operand '%s'"), end, l1);
+             break;
+           }
          if (exp.X_op == O_symbol)
            {
              /* Relaxation required.  */
          if (*m == '#' || *m == '$')
            m++;
 
-         parse_exp (m, & exp);
+         end = parse_exp (m, & exp);
+         if (end != NULL && *end != 0)
+           {
+             as_bad (_("extra characters '%s' at end of operand '%s'"), end, l1);
+             break;
+           }
          if (exp.X_op == O_symbol)
            {
              /* Relaxation required.  */