OSDN Git Service

3f26b18562ccb9ada3eedd540961bc82033153dc
[pf3gnuchains/pf3gnuchains4x.git] / opcodes / xstormy16-asm.c
1 /* Assembler interface for targets using CGEN. -*- C -*-
2    CGEN: Cpu tools GENerator
3
4 THIS FILE IS MACHINE GENERATED WITH CGEN.
5 - the resultant file is machine generated, cgen-asm.in isn't
6
7 Copyright 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
8
9 This file is part of the GNU Binutils and GDB, the GNU debugger.
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software Foundation, Inc.,
23 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
24
25 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
26    Keep that in mind.  */
27
28 #include "sysdep.h"
29 #include <stdio.h>
30 #include "ansidecl.h"
31 #include "bfd.h"
32 #include "symcat.h"
33 #include "xstormy16-desc.h"
34 #include "xstormy16-opc.h"
35 #include "opintl.h"
36 #include "xregex.h"
37 #include "libiberty.h"
38 #include "safe-ctype.h"
39
40 #undef  min
41 #define min(a,b) ((a) < (b) ? (a) : (b))
42 #undef  max
43 #define max(a,b) ((a) > (b) ? (a) : (b))
44
45 static const char * parse_insn_normal
46      PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *));
47 \f
48 /* -- assembler routines inserted here.  */
49
50 /* -- asm.c */
51 static const char * parse_mem8
52   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
53 static const char * parse_small_immediate
54   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
55
56 /* The machine-independent code doesn't know how to disambiguate
57      mov (foo),r3
58    and
59      mov (r2),r3
60    where 'foo' is a label.  This helps it out. */
61
62 static const char *
63 parse_mem8 (cd, strp, opindex, valuep)
64      CGEN_CPU_DESC cd;
65      const char **strp;
66      int opindex;
67      unsigned long *valuep;
68 {
69   if (**strp == '(')
70     {
71       const char *s = *strp;
72       
73       if (s[1] == '-' && s[2] == '-')
74         return _("Bad register in preincrement");
75
76       while (isalnum (*++s))
77         ;
78       if (s[0] == '+' && s[1] == '+' && (s[2] == ')' || s[2] == ','))
79         return _("Bad register in postincrement");
80       if (s[0] == ',' || s[0] == ')')
81         return _("Bad register name");
82     }
83   else if (cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names, 
84                                valuep) == NULL)
85     return _("Label conflicts with register name");
86   else if (strncasecmp (*strp, "rx,", 3) == 0
87            || strncasecmp (*strp, "rxl,", 3) == 0
88            || strncasecmp (*strp, "rxh,", 3) == 0)
89     return _("Label conflicts with `Rx'");
90   else if (**strp == '#')
91     return _("Bad immediate expression");
92   
93   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
94 }
95
96 /* For the add and subtract instructions, there are two immediate forms,
97    one for small operands and one for large ones.  We want to use
98    the small one when possible, but we do not want to generate relocs
99    of the small size.  This is somewhat tricky.  */
100    
101 static const char *
102 parse_small_immediate (cd, strp, opindex, valuep)
103      CGEN_CPU_DESC cd;
104      const char **strp;
105      int opindex;
106      unsigned long *valuep;
107 {
108   bfd_vma value;
109   enum cgen_parse_operand_result result;
110   const char *errmsg;
111
112   errmsg = (* cd->parse_operand_fn)
113     (cd, CGEN_PARSE_OPERAND_INTEGER, strp, opindex, BFD_RELOC_NONE,
114      &result, &value);
115   
116   if (errmsg)
117     return errmsg;
118
119   if (result != CGEN_PARSE_OPERAND_RESULT_NUMBER)
120     return _("Small operand was not an immediate number");
121
122   *valuep = value;
123   return NULL;
124 }
125 /* -- */
126
127 const char * xstormy16_cgen_parse_operand
128   PARAMS ((CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *));
129
130 /* Main entry point for operand parsing.
131
132    This function is basically just a big switch statement.  Earlier versions
133    used tables to look up the function to use, but
134    - if the table contains both assembler and disassembler functions then
135      the disassembler contains much of the assembler and vice-versa,
136    - there's a lot of inlining possibilities as things grow,
137    - using a switch statement avoids the function call overhead.
138
139    This function could be moved into `parse_insn_normal', but keeping it
140    separate makes clear the interface between `parse_insn_normal' and each of
141    the handlers.  */
142
143 const char *
144 xstormy16_cgen_parse_operand (cd, opindex, strp, fields)
145      CGEN_CPU_DESC cd;
146      int opindex;
147      const char ** strp;
148      CGEN_FIELDS * fields;
149 {
150   const char * errmsg = NULL;
151   /* Used by scalar operands that still need to be parsed.  */
152   long junk ATTRIBUTE_UNUSED;
153
154   switch (opindex)
155     {
156     case XSTORMY16_OPERAND_RB :
157       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_Rb_names, & fields->f_Rb);
158       break;
159     case XSTORMY16_OPERAND_RBJ :
160       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_Rb_names, & fields->f_Rbj);
161       break;
162     case XSTORMY16_OPERAND_RD :
163       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names, & fields->f_Rd);
164       break;
165     case XSTORMY16_OPERAND_RDM :
166       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names, & fields->f_Rdm);
167       break;
168     case XSTORMY16_OPERAND_RM :
169       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names, & fields->f_Rm);
170       break;
171     case XSTORMY16_OPERAND_RS :
172       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names, & fields->f_Rs);
173       break;
174     case XSTORMY16_OPERAND_ABS24 :
175       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_ABS24, &fields->f_abs24);
176       break;
177     case XSTORMY16_OPERAND_BCOND2 :
178       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_h_branchcond, & fields->f_op2);
179       break;
180     case XSTORMY16_OPERAND_BCOND5 :
181       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_h_branchcond, & fields->f_op5);
182       break;
183     case XSTORMY16_OPERAND_HMEM8 :
184       errmsg = parse_mem8 (cd, strp, XSTORMY16_OPERAND_HMEM8, &fields->f_hmem8);
185       break;
186     case XSTORMY16_OPERAND_IMM12 :
187       errmsg = cgen_parse_signed_integer (cd, strp, XSTORMY16_OPERAND_IMM12, &fields->f_imm12);
188       break;
189     case XSTORMY16_OPERAND_IMM16 :
190       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_IMM16, &fields->f_imm16);
191       break;
192     case XSTORMY16_OPERAND_IMM2 :
193       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_IMM2, &fields->f_imm2);
194       break;
195     case XSTORMY16_OPERAND_IMM3 :
196       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_IMM3, &fields->f_imm3);
197       break;
198     case XSTORMY16_OPERAND_IMM3B :
199       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_IMM3B, &fields->f_imm3b);
200       break;
201     case XSTORMY16_OPERAND_IMM4 :
202       errmsg = parse_small_immediate (cd, strp, XSTORMY16_OPERAND_IMM4, &fields->f_imm4);
203       break;
204     case XSTORMY16_OPERAND_IMM8 :
205       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_IMM8, &fields->f_imm8);
206       break;
207     case XSTORMY16_OPERAND_IMM8SMALL :
208       errmsg = parse_small_immediate (cd, strp, XSTORMY16_OPERAND_IMM8SMALL, &fields->f_imm8);
209       break;
210     case XSTORMY16_OPERAND_LMEM8 :
211       errmsg = parse_mem8 (cd, strp, XSTORMY16_OPERAND_LMEM8, &fields->f_lmem8);
212       break;
213     case XSTORMY16_OPERAND_REL12 :
214       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_REL12, &fields->f_rel12);
215       break;
216     case XSTORMY16_OPERAND_REL12A :
217       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_REL12A, &fields->f_rel12a);
218       break;
219     case XSTORMY16_OPERAND_REL8_2 :
220       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_REL8_2, &fields->f_rel8_2);
221       break;
222     case XSTORMY16_OPERAND_REL8_4 :
223       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_REL8_4, &fields->f_rel8_4);
224       break;
225     case XSTORMY16_OPERAND_WS2 :
226       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_h_wordsize, & fields->f_op2m);
227       break;
228
229     default :
230       /* xgettext:c-format */
231       fprintf (stderr, _("Unrecognized field %d while parsing.\n"), opindex);
232       abort ();
233   }
234
235   return errmsg;
236 }
237
238 cgen_parse_fn * const xstormy16_cgen_parse_handlers[] = 
239 {
240   parse_insn_normal,
241 };
242
243 void
244 xstormy16_cgen_init_asm (cd)
245      CGEN_CPU_DESC cd;
246 {
247   xstormy16_cgen_init_opcode_table (cd);
248   xstormy16_cgen_init_ibld_table (cd);
249   cd->parse_handlers = & xstormy16_cgen_parse_handlers[0];
250   cd->parse_operand = xstormy16_cgen_parse_operand;
251 }
252
253 \f
254
255 /* Regex construction routine.
256
257    This translates an opcode syntax string into a regex string,
258    by replacing any non-character syntax element (such as an
259    opcode) with the pattern '.*'
260
261    It then compiles the regex and stores it in the opcode, for
262    later use by xstormy16_cgen_assemble_insn
263
264    Returns NULL for success, an error message for failure.  */
265
266 char * 
267 xstormy16_cgen_build_insn_regex (insn)
268      CGEN_INSN *insn;
269 {  
270   CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
271   const char *mnem = CGEN_INSN_MNEMONIC (insn);
272   char rxbuf[CGEN_MAX_RX_ELEMENTS];
273   char *rx = rxbuf;
274   const CGEN_SYNTAX_CHAR_TYPE *syn;
275   int reg_err;
276
277   syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
278
279   /* Mnemonics come first in the syntax string.  */
280   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
281     return _("missing mnemonic in syntax string");
282   ++syn;
283
284   /* Generate a case sensitive regular expression that emulates case
285      insensitive matching in the "C" locale.  We cannot generate a case
286      insensitive regular expression because in Turkish locales, 'i' and 'I'
287      are not equal modulo case conversion.  */
288
289   /* Copy the literal mnemonic out of the insn.  */
290   for (; *mnem; mnem++)
291     {
292       char c = *mnem;
293
294       if (ISALPHA (c))
295         {
296           *rx++ = '[';
297           *rx++ = TOLOWER (c);
298           *rx++ = TOUPPER (c);
299           *rx++ = ']';
300         }
301       else
302         *rx++ = c;
303     }
304
305   /* Copy any remaining literals from the syntax string into the rx.  */
306   for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
307     {
308       if (CGEN_SYNTAX_CHAR_P (* syn)) 
309         {
310           char c = CGEN_SYNTAX_CHAR (* syn);
311
312           switch (c) 
313             {
314               /* Escape any regex metacharacters in the syntax.  */
315             case '.': case '[': case '\\': 
316             case '*': case '^': case '$': 
317
318 #ifdef CGEN_ESCAPE_EXTENDED_REGEX
319             case '?': case '{': case '}': 
320             case '(': case ')': case '*':
321             case '|': case '+': case ']':
322 #endif
323               *rx++ = '\\';
324               *rx++ = c;
325               break;
326
327             default:
328               if (ISALPHA (c))
329                 {
330                   *rx++ = '[';
331                   *rx++ = TOLOWER (c);
332                   *rx++ = TOUPPER (c);
333                   *rx++ = ']';
334                 }
335               else
336                 *rx++ = c;
337               break;
338             }
339         }
340       else
341         {
342           /* Replace non-syntax fields with globs.  */
343           *rx++ = '.';
344           *rx++ = '*';
345         }
346     }
347
348   /* Trailing whitespace ok.  */
349   * rx++ = '['; 
350   * rx++ = ' '; 
351   * rx++ = '\t'; 
352   * rx++ = ']'; 
353   * rx++ = '*'; 
354
355   /* But anchor it after that.  */
356   * rx++ = '$'; 
357   * rx = '\0';
358
359   CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
360   reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
361
362   if (reg_err == 0) 
363     return NULL;
364   else
365     {
366       static char msg[80];
367
368       regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
369       regfree ((regex_t *) CGEN_INSN_RX (insn));
370       free (CGEN_INSN_RX (insn));
371       (CGEN_INSN_RX (insn)) = NULL;
372       return msg;
373     }
374 }
375
376 \f
377 /* Default insn parser.
378
379    The syntax string is scanned and operands are parsed and stored in FIELDS.
380    Relocs are queued as we go via other callbacks.
381
382    ??? Note that this is currently an all-or-nothing parser.  If we fail to
383    parse the instruction, we return 0 and the caller will start over from
384    the beginning.  Backtracking will be necessary in parsing subexpressions,
385    but that can be handled there.  Not handling backtracking here may get
386    expensive in the case of the m68k.  Deal with later.
387
388    Returns NULL for success, an error message for failure.  */
389
390 static const char *
391 parse_insn_normal (cd, insn, strp, fields)
392      CGEN_CPU_DESC cd;
393      const CGEN_INSN *insn;
394      const char **strp;
395      CGEN_FIELDS *fields;
396 {
397   /* ??? Runtime added insns not handled yet.  */
398   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
399   const char *str = *strp;
400   const char *errmsg;
401   const char *p;
402   const CGEN_SYNTAX_CHAR_TYPE * syn;
403 #ifdef CGEN_MNEMONIC_OPERANDS
404   /* FIXME: wip */
405   int past_opcode_p;
406 #endif
407
408   /* For now we assume the mnemonic is first (there are no leading operands).
409      We can parse it without needing to set up operand parsing.
410      GAS's input scrubber will ensure mnemonics are lowercase, but we may
411      not be called from GAS.  */
412   p = CGEN_INSN_MNEMONIC (insn);
413   while (*p && TOLOWER (*p) == TOLOWER (*str))
414     ++p, ++str;
415
416   if (* p)
417     return _("unrecognized instruction");
418
419 #ifndef CGEN_MNEMONIC_OPERANDS
420   if (* str && ! ISSPACE (* str))
421     return _("unrecognized instruction");
422 #endif
423
424   CGEN_INIT_PARSE (cd);
425   cgen_init_parse_operand (cd);
426 #ifdef CGEN_MNEMONIC_OPERANDS
427   past_opcode_p = 0;
428 #endif
429
430   /* We don't check for (*str != '\0') here because we want to parse
431      any trailing fake arguments in the syntax string.  */
432   syn = CGEN_SYNTAX_STRING (syntax);
433
434   /* Mnemonics come first for now, ensure valid string.  */
435   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
436     abort ();
437
438   ++syn;
439
440   while (* syn != 0)
441     {
442       /* Non operand chars must match exactly.  */
443       if (CGEN_SYNTAX_CHAR_P (* syn))
444         {
445           /* FIXME: While we allow for non-GAS callers above, we assume the
446              first char after the mnemonic part is a space.  */
447           /* FIXME: We also take inappropriate advantage of the fact that
448              GAS's input scrubber will remove extraneous blanks.  */
449           if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
450             {
451 #ifdef CGEN_MNEMONIC_OPERANDS
452               if (CGEN_SYNTAX_CHAR(* syn) == ' ')
453                 past_opcode_p = 1;
454 #endif
455               ++ syn;
456               ++ str;
457             }
458           else if (*str)
459             {
460               /* Syntax char didn't match.  Can't be this insn.  */
461               static char msg [80];
462
463               /* xgettext:c-format */
464               sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
465                        CGEN_SYNTAX_CHAR(*syn), *str);
466               return msg;
467             }
468           else
469             {
470               /* Ran out of input.  */
471               static char msg [80];
472
473               /* xgettext:c-format */
474               sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
475                        CGEN_SYNTAX_CHAR(*syn));
476               return msg;
477             }
478           continue;
479         }
480
481       /* We have an operand of some sort.  */
482       errmsg = xstormy16_cgen_parse_operand (cd, CGEN_SYNTAX_FIELD (*syn),
483                                           &str, fields);
484       if (errmsg)
485         return errmsg;
486
487       /* Done with this operand, continue with next one.  */
488       ++ syn;
489     }
490
491   /* If we're at the end of the syntax string, we're done.  */
492   if (* syn == 0)
493     {
494       /* FIXME: For the moment we assume a valid `str' can only contain
495          blanks now.  IE: We needn't try again with a longer version of
496          the insn and it is assumed that longer versions of insns appear
497          before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
498       while (ISSPACE (* str))
499         ++ str;
500
501       if (* str != '\0')
502         return _("junk at end of line"); /* FIXME: would like to include `str' */
503
504       return NULL;
505     }
506
507   /* We couldn't parse it.  */
508   return _("unrecognized instruction");
509 }
510 \f
511 /* Main entry point.
512    This routine is called for each instruction to be assembled.
513    STR points to the insn to be assembled.
514    We assume all necessary tables have been initialized.
515    The assembled instruction, less any fixups, is stored in BUF.
516    Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
517    still needs to be converted to target byte order, otherwise BUF is an array
518    of bytes in target byte order.
519    The result is a pointer to the insn's entry in the opcode table,
520    or NULL if an error occured (an error message will have already been
521    printed).
522
523    Note that when processing (non-alias) macro-insns,
524    this function recurses.
525
526    ??? It's possible to make this cpu-independent.
527    One would have to deal with a few minor things.
528    At this point in time doing so would be more of a curiosity than useful
529    [for example this file isn't _that_ big], but keeping the possibility in
530    mind helps keep the design clean.  */
531
532 const CGEN_INSN *
533 xstormy16_cgen_assemble_insn (cd, str, fields, buf, errmsg)
534      CGEN_CPU_DESC cd;
535      const char *str;
536      CGEN_FIELDS *fields;
537      CGEN_INSN_BYTES_PTR buf;
538      char **errmsg;
539 {
540   const char *start;
541   CGEN_INSN_LIST *ilist;
542   const char *parse_errmsg = NULL;
543   const char *insert_errmsg = NULL;
544   int recognized_mnemonic = 0;
545
546   /* Skip leading white space.  */
547   while (ISSPACE (* str))
548     ++ str;
549
550   /* The instructions are stored in hashed lists.
551      Get the first in the list.  */
552   ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
553
554   /* Keep looking until we find a match.  */
555   start = str;
556   for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
557     {
558       const CGEN_INSN *insn = ilist->insn;
559       recognized_mnemonic = 1;
560
561 #ifdef CGEN_VALIDATE_INSN_SUPPORTED 
562       /* Not usually needed as unsupported opcodes
563          shouldn't be in the hash lists.  */
564       /* Is this insn supported by the selected cpu?  */
565       if (! xstormy16_cgen_insn_supported (cd, insn))
566         continue;
567 #endif
568       /* If the RELAX attribute is set, this is an insn that shouldn't be
569          chosen immediately.  Instead, it is used during assembler/linker
570          relaxation if possible.  */
571       if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAX) != 0)
572         continue;
573
574       str = start;
575
576       /* Skip this insn if str doesn't look right lexically.  */
577       if (CGEN_INSN_RX (insn) != NULL &&
578           regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
579         continue;
580
581       /* Allow parse/insert handlers to obtain length of insn.  */
582       CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
583
584       parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
585       if (parse_errmsg != NULL)
586         continue;
587
588       /* ??? 0 is passed for `pc'.  */
589       insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
590                                                  (bfd_vma) 0);
591       if (insert_errmsg != NULL)
592         continue;
593
594       /* It is up to the caller to actually output the insn and any
595          queued relocs.  */
596       return insn;
597     }
598
599   {
600     static char errbuf[150];
601 #ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
602     const char *tmp_errmsg;
603
604     /* If requesting verbose error messages, use insert_errmsg.
605        Failing that, use parse_errmsg.  */
606     tmp_errmsg = (insert_errmsg ? insert_errmsg :
607                   parse_errmsg ? parse_errmsg :
608                   recognized_mnemonic ?
609                   _("unrecognized form of instruction") :
610                   _("unrecognized instruction"));
611
612     if (strlen (start) > 50)
613       /* xgettext:c-format */
614       sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
615     else 
616       /* xgettext:c-format */
617       sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
618 #else
619     if (strlen (start) > 50)
620       /* xgettext:c-format */
621       sprintf (errbuf, _("bad instruction `%.50s...'"), start);
622     else 
623       /* xgettext:c-format */
624       sprintf (errbuf, _("bad instruction `%.50s'"), start);
625 #endif
626       
627     *errmsg = errbuf;
628     return NULL;
629   }
630 }
631 \f
632 #if 0 /* This calls back to GAS which we can't do without care.  */
633
634 /* Record each member of OPVALS in the assembler's symbol table.
635    This lets GAS parse registers for us.
636    ??? Interesting idea but not currently used.  */
637
638 /* Record each member of OPVALS in the assembler's symbol table.
639    FIXME: Not currently used.  */
640
641 void
642 xstormy16_cgen_asm_hash_keywords (cd, opvals)
643      CGEN_CPU_DESC cd;
644      CGEN_KEYWORD *opvals;
645 {
646   CGEN_KEYWORD_SEARCH search = cgen_keyword_search_init (opvals, NULL);
647   const CGEN_KEYWORD_ENTRY * ke;
648
649   while ((ke = cgen_keyword_search_next (& search)) != NULL)
650     {
651 #if 0 /* Unnecessary, should be done in the search routine.  */
652       if (! xstormy16_cgen_opval_supported (ke))
653         continue;
654 #endif
655       cgen_asm_record_register (cd, ke->name, ke->value);
656     }
657 }
658
659 #endif /* 0 */