1214571Sdim/* Assembler interface for targets using CGEN. -*- C -*-
2214571Sdim   CGEN: Cpu tools GENerator
3214571Sdim
4214571Sdim   THIS FILE IS MACHINE GENERATED WITH CGEN.
5214571Sdim   - the resultant file is machine generated, cgen-asm.in isn't
6214571Sdim
7214571Sdim   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2005
8214571Sdim   Free Software Foundation, Inc.
9214571Sdim
10214571Sdim   This file is part of the GNU Binutils and GDB, the GNU debugger.
11214571Sdim
12214571Sdim   This program is free software; you can redistribute it and/or modify
13214571Sdim   it under the terms of the GNU General Public License as published by
14214571Sdim   the Free Software Foundation; either version 2, or (at your option)
15214571Sdim   any later version.
16214571Sdim
17214571Sdim   This program is distributed in the hope that it will be useful,
18214571Sdim   but WITHOUT ANY WARRANTY; without even the implied warranty of
19214571Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20214571Sdim   GNU General Public License for more details.
21214571Sdim
22214571Sdim   You should have received a copy of the GNU General Public License
23214571Sdim   along with this program; if not, write to the Free Software Foundation, Inc.,
24214571Sdim   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
25214571Sdim
26214571Sdim/* ??? Eventually more and more of this stuff can go to cpu-independent files.
27214571Sdim   Keep that in mind.  */
28214571Sdim
29214571Sdim#include "sysdep.h"
30214571Sdim#include <stdio.h>
31214571Sdim#include "ansidecl.h"
32214571Sdim#include "bfd.h"
33214571Sdim#include "symcat.h"
34214571Sdim#include "mep-desc.h"
35214571Sdim#include "mep-opc.h"
36214571Sdim#include "opintl.h"
37214571Sdim#include "xregex.h"
38214571Sdim#include "libiberty.h"
39214571Sdim#include "safe-ctype.h"
40214571Sdim
41214571Sdim#undef  min
42214571Sdim#define min(a,b) ((a) < (b) ? (a) : (b))
43214571Sdim#undef  max
44214571Sdim#define max(a,b) ((a) > (b) ? (a) : (b))
45214571Sdim
46214571Sdimstatic const char * parse_insn_normal
47214571Sdim  (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
48214571Sdim
49214571Sdim/* -- assembler routines inserted here.  */
50214571Sdim
51214571Sdim/* -- asm.c */
52214571Sdim
53214571Sdim#define CGEN_VALIDATE_INSN_SUPPORTED
54214571Sdim
55214571Sdim       const char * parse_csrn       (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *);
56214571Sdim       const char * parse_tpreg      (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *);
57214571Sdim       const char * parse_spreg      (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *);
58214571Sdim       const char * parse_mep_align  (CGEN_CPU_DESC, const char **, enum cgen_operand_type, long *);
59214571Sdim       const char * parse_mep_alignu (CGEN_CPU_DESC, const char **, enum cgen_operand_type, unsigned long *);
60214571Sdimstatic const char * parse_signed16   (CGEN_CPU_DESC, const char **, int, long *);
61214571Sdimstatic const char * parse_unsigned16 (CGEN_CPU_DESC, const char **, int, unsigned long *);
62214571Sdimstatic const char * parse_lo16       (CGEN_CPU_DESC, const char **, int, long *, long);
63214571Sdimstatic const char * parse_unsigned7  (CGEN_CPU_DESC, const char **, enum cgen_operand_type, unsigned long *);
64214571Sdimstatic const char * parse_zero       (CGEN_CPU_DESC, const char **, int, long *);
65214571Sdim
66214571Sdimconst char *
67214571Sdimparse_csrn (CGEN_CPU_DESC cd, const char **strp,
68214571Sdim	    CGEN_KEYWORD *keyword_table, long *field)
69214571Sdim{
70214571Sdim  const char *err;
71214571Sdim  unsigned long value;
72214571Sdim
73214571Sdim  err = cgen_parse_keyword (cd, strp, keyword_table, field);
74214571Sdim  if (!err)
75214571Sdim    return NULL;
76214571Sdim
77214571Sdim  err = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_CSRN_IDX, & value);
78214571Sdim  if (err)
79214571Sdim    return err;
80214571Sdim  *field = value;
81214571Sdim  return NULL;
82214571Sdim}
83214571Sdim
84214571Sdim/* begin-cop-ip-parse-handlers */
85214571Sdimstatic const char *
86214571Sdimparse_fmax_cr (CGEN_CPU_DESC cd,
87214571Sdim	const char **strp,
88214571Sdim	CGEN_KEYWORD *keyword_table  ATTRIBUTE_UNUSED,
89214571Sdim	long *field)
90214571Sdim{
91214571Sdim  return cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_cr_fmax, field);
92214571Sdim}
93214571Sdimstatic const char *
94214571Sdimparse_fmax_ccr (CGEN_CPU_DESC cd,
95214571Sdim	const char **strp,
96214571Sdim	CGEN_KEYWORD *keyword_table  ATTRIBUTE_UNUSED,
97214571Sdim	long *field)
98214571Sdim{
99214571Sdim  return cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_ccr_fmax, field);
100214571Sdim}
101214571Sdim/* end-cop-ip-parse-handlers */
102214571Sdim
103214571Sdimconst char *
104214571Sdimparse_tpreg (CGEN_CPU_DESC cd, const char ** strp,
105214571Sdim	     CGEN_KEYWORD *keyword_table, long *field)
106214571Sdim{
107214571Sdim  const char *err;
108214571Sdim
109214571Sdim  err = cgen_parse_keyword (cd, strp, keyword_table, field);
110214571Sdim  if (err)
111214571Sdim    return err;
112214571Sdim  if (*field != 13)
113214571Sdim    return _("Only $tp or $13 allowed for this opcode");
114214571Sdim  return NULL;
115214571Sdim}
116214571Sdim
117214571Sdimconst char *
118214571Sdimparse_spreg (CGEN_CPU_DESC cd, const char ** strp,
119214571Sdim	     CGEN_KEYWORD *keyword_table, long *field)
120214571Sdim{
121214571Sdim  const char *err;
122214571Sdim
123214571Sdim  err = cgen_parse_keyword (cd, strp, keyword_table, field);
124214571Sdim  if (err)
125214571Sdim    return err;
126214571Sdim  if (*field != 15)
127214571Sdim    return _("Only $sp or $15 allowed for this opcode");
128214571Sdim  return NULL;
129214571Sdim}
130214571Sdim
131214571Sdimconst char *
132214571Sdimparse_mep_align (CGEN_CPU_DESC cd, const char ** strp,
133214571Sdim		 enum cgen_operand_type type, long *field)
134214571Sdim{
135214571Sdim  long lsbs = 0;
136214571Sdim  const char *err;
137214571Sdim
138214571Sdim  switch (type)
139214571Sdim    {
140214571Sdim    case MEP_OPERAND_PCREL8A2:
141214571Sdim    case MEP_OPERAND_PCREL12A2:
142214571Sdim    case MEP_OPERAND_PCREL17A2:
143214571Sdim    case MEP_OPERAND_PCREL24A2:
144214571Sdim    case MEP_OPERAND_CDISP8A2:
145214571Sdim    case MEP_OPERAND_CDISP8A4:
146214571Sdim    case MEP_OPERAND_CDISP8A8:
147214571Sdim      err = cgen_parse_signed_integer   (cd, strp, type, field);
148214571Sdim      break;
149214571Sdim    case MEP_OPERAND_PCABS24A2:
150214571Sdim    case MEP_OPERAND_UDISP7:
151214571Sdim    case MEP_OPERAND_UDISP7A2:
152214571Sdim    case MEP_OPERAND_UDISP7A4:
153214571Sdim    case MEP_OPERAND_UIMM7A4:
154214571Sdim    case MEP_OPERAND_ADDR24A4:
155214571Sdim      err = cgen_parse_unsigned_integer (cd, strp, type, (unsigned long *) field);
156214571Sdim      break;
157214571Sdim    default:
158214571Sdim      abort();
159214571Sdim    }
160214571Sdim  if (err)
161214571Sdim    return err;
162214571Sdim  switch (type)
163214571Sdim    {
164214571Sdim    case MEP_OPERAND_UDISP7:
165214571Sdim      lsbs = 0;
166214571Sdim      break;
167214571Sdim    case MEP_OPERAND_PCREL8A2:
168214571Sdim    case MEP_OPERAND_PCREL12A2:
169214571Sdim    case MEP_OPERAND_PCREL17A2:
170214571Sdim    case MEP_OPERAND_PCREL24A2:
171214571Sdim    case MEP_OPERAND_PCABS24A2:
172214571Sdim    case MEP_OPERAND_UDISP7A2:
173214571Sdim    case MEP_OPERAND_CDISP8A2:
174214571Sdim      lsbs = *field & 1;
175214571Sdim      break;
176214571Sdim    case MEP_OPERAND_UDISP7A4:
177214571Sdim    case MEP_OPERAND_UIMM7A4:
178214571Sdim    case MEP_OPERAND_ADDR24A4:
179214571Sdim    case MEP_OPERAND_CDISP8A4:
180214571Sdim      lsbs = *field & 3;
181214571Sdim      break;
182214571Sdim    case MEP_OPERAND_CDISP8A8:
183214571Sdim      lsbs = *field & 7;
184214571Sdim      break;
185214571Sdim    default:
186214571Sdim      /* Safe assumption?  */
187214571Sdim      abort ();
188214571Sdim    }
189214571Sdim  if (lsbs)
190214571Sdim    return "Value is not aligned enough";
191214571Sdim  return NULL;
192214571Sdim}
193214571Sdim
194214571Sdimconst char *
195214571Sdimparse_mep_alignu (CGEN_CPU_DESC cd, const char ** strp,
196214571Sdim		 enum cgen_operand_type type, unsigned long *field)
197214571Sdim{
198214571Sdim  return parse_mep_align (cd, strp, type, (long *) field);
199214571Sdim}
200214571Sdim
201214571Sdim
202214571Sdim/* Handle %lo(), %tpoff(), %sdaoff(), %hi(), and other signed
203214571Sdim   constants in a signed context.  */
204214571Sdim
205214571Sdimstatic const char *
206214571Sdimparse_signed16 (CGEN_CPU_DESC cd,
207214571Sdim		const char **strp,
208214571Sdim		int opindex,
209214571Sdim		long *valuep)
210214571Sdim{
211214571Sdim  return parse_lo16 (cd, strp, opindex, valuep, 1);
212214571Sdim}
213214571Sdim
214214571Sdimstatic const char *
215214571Sdimparse_lo16 (CGEN_CPU_DESC cd,
216214571Sdim	    const char **strp,
217214571Sdim	    int opindex,
218214571Sdim	    long *valuep,
219214571Sdim	    long signedp)
220214571Sdim{
221214571Sdim  const char *errmsg;
222214571Sdim  enum cgen_parse_operand_result result_type;
223214571Sdim  bfd_vma value;
224214571Sdim
225214571Sdim  if (strncasecmp (*strp, "%lo(", 4) == 0)
226214571Sdim    {
227214571Sdim      *strp += 4;
228214571Sdim      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_LOW16,
229214571Sdim				   & result_type, & value);
230214571Sdim      if (**strp != ')')
231214571Sdim	return _("missing `)'");
232214571Sdim      ++*strp;
233214571Sdim      if (errmsg == NULL
234214571Sdim	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
235214571Sdim	value &= 0xffff;
236214571Sdim      if (signedp)
237214571Sdim	*valuep = (long)(short) value;
238214571Sdim      else
239214571Sdim	*valuep = value;
240214571Sdim      return errmsg;
241214571Sdim    }
242214571Sdim
243214571Sdim  if (strncasecmp (*strp, "%hi(", 4) == 0)
244214571Sdim    {
245214571Sdim      *strp += 4;
246214571Sdim      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16S,
247214571Sdim				   & result_type, & value);
248214571Sdim      if (**strp != ')')
249214571Sdim	return _("missing `)'");
250214571Sdim      ++*strp;
251214571Sdim      if (errmsg == NULL
252214571Sdim	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
253214571Sdim	value = (value + 0x8000) >> 16;
254214571Sdim      *valuep = value;
255214571Sdim      return errmsg;
256214571Sdim    }
257214571Sdim
258214571Sdim  if (strncasecmp (*strp, "%uhi(", 5) == 0)
259214571Sdim    {
260214571Sdim      *strp += 5;
261214571Sdim      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16U,
262214571Sdim				   & result_type, & value);
263214571Sdim      if (**strp != ')')
264214571Sdim	return _("missing `)'");
265214571Sdim      ++*strp;
266214571Sdim      if (errmsg == NULL
267214571Sdim	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
268214571Sdim	value = value >> 16;
269214571Sdim      *valuep = value;
270214571Sdim      return errmsg;
271214571Sdim    }
272214571Sdim
273214571Sdim  if (strncasecmp (*strp, "%sdaoff(", 8) == 0)
274214571Sdim    {
275214571Sdim      *strp += 8;
276214571Sdim      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_GPREL,
277214571Sdim				   NULL, & value);
278214571Sdim      if (**strp != ')')
279214571Sdim	return _("missing `)'");
280214571Sdim      ++*strp;
281214571Sdim      *valuep = value;
282214571Sdim      return errmsg;
283214571Sdim    }
284214571Sdim
285214571Sdim  if (strncasecmp (*strp, "%tpoff(", 7) == 0)
286214571Sdim    {
287214571Sdim      *strp += 7;
288214571Sdim      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_TPREL,
289214571Sdim				   NULL, & value);
290214571Sdim      if (**strp != ')')
291214571Sdim	return _("missing `)'");
292214571Sdim      ++*strp;
293214571Sdim      *valuep = value;
294214571Sdim      return errmsg;
295214571Sdim    }
296214571Sdim
297214571Sdim  if (**strp == '%')
298214571Sdim    return _("invalid %function() here");
299214571Sdim
300214571Sdim  return cgen_parse_signed_integer (cd, strp, opindex, valuep);
301214571Sdim}
302214571Sdim
303214571Sdimstatic const char *
304214571Sdimparse_unsigned16 (CGEN_CPU_DESC cd,
305214571Sdim		  const char **strp,
306214571Sdim		  int opindex,
307214571Sdim		  unsigned long *valuep)
308214571Sdim{
309214571Sdim  return parse_lo16 (cd, strp, opindex, (long *) valuep, 0);
310214571Sdim}
311214571Sdim
312214571Sdim/* A special case of parse_signed16 which accepts only the value zero.  */
313214571Sdim
314214571Sdimstatic const char *
315214571Sdimparse_zero (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
316214571Sdim{
317214571Sdim  const char *errmsg;
318214571Sdim  enum cgen_parse_operand_result result_type;
319214571Sdim  bfd_vma value;
320214571Sdim
321214571Sdim  /*fprintf(stderr, "dj: signed parse opindex `%s'\n", *strp);*/
322214571Sdim
323214571Sdim  /* Prevent ($ry) from being attempted as an expression on 'sw $rx,($ry)'.
324214571Sdim     It will fail and cause ry to be listed as an undefined symbol in the
325214571Sdim     listing.  */
326214571Sdim  if (strncmp (*strp, "($", 2) == 0)
327214571Sdim    return "not zero"; /* any string will do -- will never be seen.  */
328214571Sdim
329214571Sdim  if (strncasecmp (*strp, "%lo(", 4) == 0)
330214571Sdim    {
331214571Sdim      *strp += 4;
332214571Sdim      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_LOW16,
333214571Sdim				   &result_type, &value);
334214571Sdim      if (**strp != ')')
335214571Sdim	return "missing `)'";
336214571Sdim      ++*strp;
337214571Sdim      if (errmsg == NULL
338214571Sdim	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
339214571Sdim	return "not zero"; /* any string will do -- will never be seen.  */
340214571Sdim      *valuep = value;
341214571Sdim      return errmsg;
342214571Sdim    }
343214571Sdim
344214571Sdim  if (strncasecmp (*strp, "%hi(", 4) == 0)
345214571Sdim    {
346214571Sdim      *strp += 4;
347214571Sdim      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16S,
348214571Sdim				   &result_type, &value);
349214571Sdim      if (**strp != ')')
350214571Sdim	return "missing `)'";
351214571Sdim      ++*strp;
352214571Sdim      if (errmsg == NULL
353214571Sdim	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
354214571Sdim	return "not zero"; /* any string will do -- will never be seen.  */
355214571Sdim      *valuep = value;
356214571Sdim      return errmsg;
357214571Sdim    }
358214571Sdim
359214571Sdim  if (strncasecmp (*strp, "%uhi(", 5) == 0)
360214571Sdim    {
361214571Sdim      *strp += 5;
362214571Sdim      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16U,
363214571Sdim				   &result_type, &value);
364214571Sdim      if (**strp != ')')
365214571Sdim	return "missing `)'";
366214571Sdim      ++*strp;
367214571Sdim      if (errmsg == NULL
368214571Sdim	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
369214571Sdim	return "not zero"; /* any string will do -- will never be seen.  */
370214571Sdim      *valuep = value;
371214571Sdim      return errmsg;
372214571Sdim    }
373214571Sdim
374214571Sdim  if (strncasecmp (*strp, "%sdaoff(", 8) == 0)
375214571Sdim    {
376214571Sdim      *strp += 8;
377214571Sdim      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_GPREL,
378214571Sdim				   &result_type, &value);
379214571Sdim      if (**strp != ')')
380214571Sdim	return "missing `)'";
381214571Sdim      ++*strp;
382214571Sdim      if (errmsg == NULL
383214571Sdim	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
384214571Sdim	return "not zero"; /* any string will do -- will never be seen.  */
385214571Sdim      *valuep = value;
386214571Sdim      return errmsg;
387214571Sdim    }
388214571Sdim
389214571Sdim  if (strncasecmp (*strp, "%tpoff(", 7) == 0)
390214571Sdim    {
391214571Sdim      *strp += 7;
392214571Sdim      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_TPREL,
393214571Sdim				   &result_type, &value);
394214571Sdim      if (**strp != ')')
395214571Sdim	return "missing `)'";
396214571Sdim      ++*strp;
397214571Sdim      if (errmsg == NULL
398214571Sdim	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
399214571Sdim	return "not zero"; /* any string will do -- will never be seen.  */
400214571Sdim      *valuep = value;
401214571Sdim      return errmsg;
402214571Sdim    }
403214571Sdim
404214571Sdim  if (**strp == '%')
405214571Sdim    return "invalid %function() here";
406214571Sdim
407214571Sdim  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_NONE,
408214571Sdim			       &result_type, &value);
409214571Sdim  if (errmsg == NULL
410214571Sdim      && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
411214571Sdim    return "not zero"; /* any string will do -- will never be seen.  */
412214571Sdim
413214571Sdim  return errmsg;
414214571Sdim}
415214571Sdim
416214571Sdimstatic const char *
417214571Sdimparse_unsigned7 (CGEN_CPU_DESC cd, const char **strp,
418214571Sdim		 enum cgen_operand_type opindex, unsigned long *valuep)
419214571Sdim{
420214571Sdim  const char *errmsg;
421214571Sdim  bfd_vma value;
422214571Sdim
423214571Sdim  /* fprintf(stderr, "dj: unsigned7 parse `%s'\n", *strp); */
424214571Sdim
425214571Sdim  if (strncasecmp (*strp, "%tpoff(", 7) == 0)
426214571Sdim    {
427214571Sdim      int reloc;
428214571Sdim      *strp += 7;
429214571Sdim      switch (opindex)
430214571Sdim	{
431214571Sdim	case MEP_OPERAND_UDISP7:
432214571Sdim	  reloc = BFD_RELOC_MEP_TPREL7;
433214571Sdim	  break;
434214571Sdim	case MEP_OPERAND_UDISP7A2:
435214571Sdim	  reloc = BFD_RELOC_MEP_TPREL7A2;
436214571Sdim	  break;
437214571Sdim	case MEP_OPERAND_UDISP7A4:
438214571Sdim	  reloc = BFD_RELOC_MEP_TPREL7A4;
439214571Sdim	  break;
440214571Sdim	default:
441214571Sdim	  /* Safe assumption?  */
442214571Sdim	  abort ();
443214571Sdim	}
444214571Sdim      errmsg = cgen_parse_address (cd, strp, opindex, reloc,
445214571Sdim				   NULL, &value);
446214571Sdim      if (**strp != ')')
447214571Sdim	return "missing `)'";
448214571Sdim      ++*strp;
449214571Sdim      *valuep = value;
450214571Sdim      return errmsg;
451214571Sdim    }
452214571Sdim
453214571Sdim  if (**strp == '%')
454214571Sdim    return _("invalid %function() here");
455214571Sdim
456214571Sdim  return parse_mep_alignu (cd, strp, opindex, valuep);
457214571Sdim}
458214571Sdim
459214571Sdim/* BEGIN LIGHTWEIGHT MACRO PROCESSOR.  */
460214571Sdim
461214571Sdim#define MAXARGS 9
462214571Sdim
463214571Sdimtypedef struct
464214571Sdim{
465214571Sdim  char *name;
466214571Sdim  char *expansion;
467214571Sdim}  macro;
468214571Sdim
469214571Sdimtypedef struct
470214571Sdim{
471214571Sdim  const char *start;
472214571Sdim  int len;
473214571Sdim} arg;
474214571Sdim
475214571Sdimmacro macros[] =
476214571Sdim{
477214571Sdim  { "sizeof", "(`1.end + (- `1))"},
478214571Sdim  { "startof", "(`1 | 0)" },
479214571Sdim  { "align4", "(`1&(~3))"},
480214571Sdim/*{ "hi", "(((`1+0x8000)>>16) & 0xffff)" },  */
481214571Sdim/*{ "lo", "(`1 & 0xffff)" },  */
482214571Sdim/*{ "sdaoff", "((`1-__sdabase) & 0x7f)"},  */
483214571Sdim/*{ "tpoff", "((`1-__tpbase) & 0x7f)"},  */
484214571Sdim  { 0,0 }
485214571Sdim};
486214571Sdim
487214571Sdimstatic char  * expand_string    (const char *, int);
488214571Sdim
489214571Sdimstatic const char *
490214571Sdimmep_cgen_expand_macros_and_parse_operand
491214571Sdim  (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
492214571Sdim
493214571Sdimstatic char *
494214571Sdimstr_append (char *dest, const char *input, int len)
495214571Sdim{
496214571Sdim  char *new_dest;
497214571Sdim  int oldlen;
498214571Sdim
499214571Sdim  if (len == 0)
500214571Sdim    return dest;
501214571Sdim  /* printf("str_append: <<%s>>, <<%s>>, %d\n", dest, input, len); */
502214571Sdim  oldlen = (dest ? strlen(dest) : 0);
503214571Sdim  new_dest = realloc (dest, oldlen + len + 1);
504214571Sdim  memset (new_dest + oldlen, 0, len + 1);
505214571Sdim  return strncat (new_dest, input, len);
506214571Sdim}
507214571Sdim
508214571Sdimstatic macro *
509214571Sdimlookup_macro (const char *name)
510214571Sdim{
511214571Sdim  macro *m;
512214571Sdim
513214571Sdim  for (m = macros; m->name; ++m)
514214571Sdim    if (strncmp (m->name, name, strlen(m->name)) == 0)
515214571Sdim      return m;
516214571Sdim
517214571Sdim  return 0;
518214571Sdim}
519214571Sdim
520214571Sdimstatic char *
521214571Sdimexpand_macro (arg *args, int narg, macro *mac)
522214571Sdim{
523214571Sdim  char *result = 0, *rescanned_result = 0;
524214571Sdim  char *e = mac->expansion;
525214571Sdim  char *mark = e;
526214571Sdim  int arg = 0;
527214571Sdim
528214571Sdim  /*  printf("expanding macro %s with %d args\n", mac->name, narg + 1); */
529214571Sdim  while (*e)
530214571Sdim    {
531214571Sdim      if (*e == '`' &&
532214571Sdim	  (*e+1) &&
533214571Sdim	  ((*(e + 1) - '1') <= MAXARGS) &&
534214571Sdim	  ((*(e + 1) - '1') <= narg))
535214571Sdim	{
536214571Sdim	  result = str_append (result, mark, e - mark);
537214571Sdim	  arg = (*(e + 1) - '1');
538214571Sdim	  /* printf("replacing `%d with %s\n", arg+1, args[arg].start); */
539214571Sdim	  result = str_append (result, args[arg].start, args[arg].len);
540214571Sdim	  ++e;
541214571Sdim	  mark = e+1;
542214571Sdim	}
543214571Sdim      ++e;
544214571Sdim    }
545214571Sdim
546214571Sdim  if (mark != e)
547214571Sdim    result = str_append (result, mark, e - mark);
548214571Sdim
549214571Sdim  if (result)
550214571Sdim    {
551214571Sdim      rescanned_result = expand_string (result, 0);
552214571Sdim      free (result);
553214571Sdim      return rescanned_result;
554214571Sdim    }
555214571Sdim  else
556214571Sdim    return result;
557214571Sdim}
558214571Sdim
559214571Sdim#define IN_TEXT 0
560214571Sdim#define IN_ARGS 1
561214571Sdim
562214571Sdimstatic char *
563214571Sdimexpand_string (const char *in, int first_only)
564214571Sdim{
565214571Sdim  int num_expansions = 0;
566214571Sdim  int depth = 0;
567214571Sdim  int narg = -1;
568214571Sdim  arg args[MAXARGS];
569214571Sdim  int state = IN_TEXT;
570214571Sdim  const char *mark = in;
571214571Sdim  macro *macro = 0;
572214571Sdim
573214571Sdim  char *expansion = 0;
574214571Sdim  char *result = 0;
575214571Sdim
576214571Sdim  while (*in)
577214571Sdim    {
578214571Sdim      switch (state)
579214571Sdim	{
580214571Sdim	case IN_TEXT:
581214571Sdim	  if (*in == '%' && *(in + 1) && (!first_only || num_expansions == 0))
582214571Sdim	    {
583214571Sdim	      macro = lookup_macro (in + 1);
584214571Sdim	      if (macro)
585214571Sdim		{
586214571Sdim		  /* printf("entering state %d at '%s'...\n", state, in); */
587214571Sdim		  result = str_append (result, mark, in - mark);
588214571Sdim		  mark = in;
589214571Sdim		  in += 1 + strlen (macro->name);
590214571Sdim		  while (*in == ' ') ++in;
591214571Sdim		  if (*in != '(')
592214571Sdim		    {
593214571Sdim		      state = IN_TEXT;
594214571Sdim		      macro = 0;
595214571Sdim		    }
596214571Sdim		  else
597214571Sdim		    {
598214571Sdim		      state = IN_ARGS;
599214571Sdim		      narg = 0;
600214571Sdim		      args[narg].start = in + 1;
601214571Sdim		      args[narg].len = 0;
602214571Sdim		      mark = in + 1;
603214571Sdim		    }
604214571Sdim		}
605214571Sdim	    }
606214571Sdim	  break;
607214571Sdim	case IN_ARGS:
608214571Sdim	  if (depth == 0)
609214571Sdim	    {
610214571Sdim	      switch (*in)
611214571Sdim		{
612214571Sdim		case ',':
613214571Sdim		  narg++;
614214571Sdim		  args[narg].start = (in + 1);
615214571Sdim		  args[narg].len = 0;
616214571Sdim		  break;
617214571Sdim		case ')':
618214571Sdim		  state = IN_TEXT;
619214571Sdim		  /* printf("entering state %d at '%s'...\n", state, in); */
620214571Sdim		  if (macro)
621214571Sdim		    {
622214571Sdim		      expansion = 0;
623214571Sdim		      expansion = expand_macro (args, narg, macro);
624214571Sdim		      num_expansions++;
625214571Sdim		      if (expansion)
626214571Sdim			{
627214571Sdim			  result = str_append (result, expansion, strlen (expansion));
628214571Sdim			  free (expansion);
629214571Sdim			}
630214571Sdim		    }
631214571Sdim		  else
632214571Sdim		    {
633214571Sdim		      result = str_append (result, mark, in - mark);
634214571Sdim		    }
635214571Sdim		  macro = 0;
636214571Sdim		  mark = in + 1;
637214571Sdim		  break;
638214571Sdim		case '(':
639214571Sdim		  depth++;
640214571Sdim		default:
641214571Sdim		  args[narg].len++;
642214571Sdim		  break;
643214571Sdim		}
644214571Sdim	    }
645214571Sdim	  else
646214571Sdim	    {
647214571Sdim	      if (*in == ')')
648214571Sdim		depth--;
649214571Sdim	      if (narg > -1)
650214571Sdim		args[narg].len++;
651214571Sdim	    }
652214571Sdim
653214571Sdim	}
654214571Sdim      ++in;
655214571Sdim    }
656214571Sdim
657214571Sdim  if (mark != in)
658214571Sdim    result = str_append (result, mark, in - mark);
659214571Sdim
660214571Sdim  return result;
661214571Sdim}
662214571Sdim
663214571Sdim#undef IN_ARGS
664214571Sdim#undef IN_TEXT
665214571Sdim#undef MAXARGS
666214571Sdim
667214571Sdim
668214571Sdim/* END LIGHTWEIGHT MACRO PROCESSOR.  */
669214571Sdim
670214571Sdimconst char * mep_cgen_parse_operand
671214571Sdim  (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
672214571Sdim
673214571Sdimconst char *
674214571Sdimmep_cgen_expand_macros_and_parse_operand (CGEN_CPU_DESC cd, int opindex,
675214571Sdim					  const char ** strp_in, CGEN_FIELDS * fields)
676214571Sdim{
677214571Sdim  const char * errmsg = NULL;
678214571Sdim  char *str = 0, *hold = 0;
679214571Sdim  const char **strp = 0;
680214571Sdim
681214571Sdim  /* Set up a new pointer to macro-expanded string.  */
682214571Sdim  str = expand_string (*strp_in, 1);
683214571Sdim  /* fprintf (stderr, " expanded <<%s>> to <<%s>>\n", *strp_in, str); */
684214571Sdim
685214571Sdim  hold = str;
686214571Sdim  strp = (const char **)(&str);
687214571Sdim
688214571Sdim  errmsg = mep_cgen_parse_operand (cd, opindex, strp, fields);
689214571Sdim
690214571Sdim  /* Now work out the advance.  */
691214571Sdim  if (strlen (str) == 0)
692214571Sdim    *strp_in += strlen (*strp_in);
693214571Sdim
694214571Sdim  else
695214571Sdim    {
696214571Sdim      if (strstr (*strp_in, str))
697214571Sdim	/* A macro-expansion was pulled off the front.  */
698214571Sdim	*strp_in = strstr (*strp_in, str);
699214571Sdim      else
700214571Sdim	/* A non-macro-expansion was pulled off the front.  */
701214571Sdim	*strp_in += (str - hold);
702214571Sdim    }
703214571Sdim
704214571Sdim  if (hold)
705214571Sdim    free (hold);
706214571Sdim
707214571Sdim  return errmsg;
708214571Sdim}
709214571Sdim
710214571Sdim#define CGEN_ASM_INIT_HOOK (cd->parse_operand = mep_cgen_expand_macros_and_parse_operand);
711214571Sdim
712214571Sdim/* -- dis.c */
713214571Sdim
714214571Sdimconst char * mep_cgen_parse_operand
715214571Sdim  (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
716214571Sdim
717214571Sdim/* Main entry point for operand parsing.
718214571Sdim
719214571Sdim   This function is basically just a big switch statement.  Earlier versions
720214571Sdim   used tables to look up the function to use, but
721214571Sdim   - if the table contains both assembler and disassembler functions then
722214571Sdim     the disassembler contains much of the assembler and vice-versa,
723214571Sdim   - there's a lot of inlining possibilities as things grow,
724214571Sdim   - using a switch statement avoids the function call overhead.
725214571Sdim
726214571Sdim   This function could be moved into `parse_insn_normal', but keeping it
727214571Sdim   separate makes clear the interface between `parse_insn_normal' and each of
728214571Sdim   the handlers.  */
729214571Sdim
730214571Sdimconst char *
731214571Sdimmep_cgen_parse_operand (CGEN_CPU_DESC cd,
732214571Sdim			   int opindex,
733214571Sdim			   const char ** strp,
734214571Sdim			   CGEN_FIELDS * fields)
735214571Sdim{
736214571Sdim  const char * errmsg = NULL;
737214571Sdim  /* Used by scalar operands that still need to be parsed.  */
738214571Sdim  long junk ATTRIBUTE_UNUSED;
739214571Sdim
740214571Sdim  switch (opindex)
741214571Sdim    {
742214571Sdim    case MEP_OPERAND_ADDR24A4 :
743214571Sdim      errmsg = parse_mep_alignu (cd, strp, MEP_OPERAND_ADDR24A4, (unsigned long *) (& fields->f_24u8a4n));
744214571Sdim      break;
745214571Sdim    case MEP_OPERAND_CALLNUM :
746214571Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_CALLNUM, (unsigned long *) (& fields->f_callnum));
747214571Sdim      break;
748214571Sdim    case MEP_OPERAND_CCCC :
749214571Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_CCCC, (unsigned long *) (& fields->f_rm));
750214571Sdim      break;
751214571Sdim    case MEP_OPERAND_CCRN :
752214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_ccr, & fields->f_ccrn);
753214571Sdim      break;
754214571Sdim    case MEP_OPERAND_CDISP8 :
755214571Sdim      errmsg = cgen_parse_signed_integer (cd, strp, MEP_OPERAND_CDISP8, (long *) (& fields->f_8s24));
756214571Sdim      break;
757214571Sdim    case MEP_OPERAND_CDISP8A2 :
758214571Sdim      errmsg = parse_mep_align (cd, strp, MEP_OPERAND_CDISP8A2, (long *) (& fields->f_8s24a2));
759214571Sdim      break;
760214571Sdim    case MEP_OPERAND_CDISP8A4 :
761214571Sdim      errmsg = parse_mep_align (cd, strp, MEP_OPERAND_CDISP8A4, (long *) (& fields->f_8s24a4));
762214571Sdim      break;
763214571Sdim    case MEP_OPERAND_CDISP8A8 :
764214571Sdim      errmsg = parse_mep_align (cd, strp, MEP_OPERAND_CDISP8A8, (long *) (& fields->f_8s24a8));
765214571Sdim      break;
766214571Sdim    case MEP_OPERAND_CIMM4 :
767214571Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_CIMM4, (unsigned long *) (& fields->f_rn));
768214571Sdim      break;
769214571Sdim    case MEP_OPERAND_CIMM5 :
770214571Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_CIMM5, (unsigned long *) (& fields->f_5u24));
771214571Sdim      break;
772214571Sdim    case MEP_OPERAND_CODE16 :
773214571Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_CODE16, (unsigned long *) (& fields->f_16u16));
774214571Sdim      break;
775214571Sdim    case MEP_OPERAND_CODE24 :
776214571Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_CODE24, (unsigned long *) (& fields->f_24u4n));
777214571Sdim      break;
778214571Sdim    case MEP_OPERAND_CP_FLAG :
779214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_ccr, & junk);
780214571Sdim      break;
781214571Sdim    case MEP_OPERAND_CRN :
782214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_cr, & fields->f_crn);
783214571Sdim      break;
784214571Sdim    case MEP_OPERAND_CRN64 :
785214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_cr64, & fields->f_crn);
786214571Sdim      break;
787214571Sdim    case MEP_OPERAND_CRNX :
788214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_cr, & fields->f_crnx);
789214571Sdim      break;
790214571Sdim    case MEP_OPERAND_CRNX64 :
791214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_cr64, & fields->f_crnx);
792214571Sdim      break;
793214571Sdim    case MEP_OPERAND_CSRN :
794214571Sdim      errmsg = parse_csrn (cd, strp, & mep_cgen_opval_h_csr, & fields->f_csrn);
795214571Sdim      break;
796214571Sdim    case MEP_OPERAND_CSRN_IDX :
797214571Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_CSRN_IDX, (unsigned long *) (& fields->f_csrn));
798214571Sdim      break;
799214571Sdim    case MEP_OPERAND_DBG :
800214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
801214571Sdim      break;
802214571Sdim    case MEP_OPERAND_DEPC :
803214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
804214571Sdim      break;
805214571Sdim    case MEP_OPERAND_EPC :
806214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
807214571Sdim      break;
808214571Sdim    case MEP_OPERAND_EXC :
809214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
810214571Sdim      break;
811214571Sdim    case MEP_OPERAND_FMAX_CCRN :
812214571Sdim      errmsg = parse_fmax_ccr (cd, strp, & mep_cgen_opval_h_ccr, & fields->f_fmax_4_4);
813214571Sdim      break;
814214571Sdim    case MEP_OPERAND_FMAX_FRD :
815214571Sdim      errmsg = parse_fmax_cr (cd, strp, & mep_cgen_opval_h_cr, & fields->f_fmax_frd);
816214571Sdim      break;
817214571Sdim    case MEP_OPERAND_FMAX_FRD_INT :
818214571Sdim      errmsg = parse_fmax_cr (cd, strp, & mep_cgen_opval_h_cr, & fields->f_fmax_frd);
819214571Sdim      break;
820214571Sdim    case MEP_OPERAND_FMAX_FRM :
821214571Sdim      errmsg = parse_fmax_cr (cd, strp, & mep_cgen_opval_h_cr, & fields->f_fmax_frm);
822214571Sdim      break;
823214571Sdim    case MEP_OPERAND_FMAX_FRN :
824214571Sdim      errmsg = parse_fmax_cr (cd, strp, & mep_cgen_opval_h_cr, & fields->f_fmax_frn);
825214571Sdim      break;
826214571Sdim    case MEP_OPERAND_FMAX_FRN_INT :
827214571Sdim      errmsg = parse_fmax_cr (cd, strp, & mep_cgen_opval_h_cr, & fields->f_fmax_frn);
828214571Sdim      break;
829214571Sdim    case MEP_OPERAND_FMAX_RM :
830214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_fmax_rm);
831214571Sdim      break;
832214571Sdim    case MEP_OPERAND_HI :
833214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
834214571Sdim      break;
835214571Sdim    case MEP_OPERAND_LO :
836214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
837214571Sdim      break;
838214571Sdim    case MEP_OPERAND_LP :
839214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
840214571Sdim      break;
841214571Sdim    case MEP_OPERAND_MB0 :
842214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
843214571Sdim      break;
844214571Sdim    case MEP_OPERAND_MB1 :
845214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
846214571Sdim      break;
847214571Sdim    case MEP_OPERAND_ME0 :
848214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
849214571Sdim      break;
850214571Sdim    case MEP_OPERAND_ME1 :
851214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
852214571Sdim      break;
853214571Sdim    case MEP_OPERAND_NPC :
854214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
855214571Sdim      break;
856214571Sdim    case MEP_OPERAND_OPT :
857214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
858214571Sdim      break;
859214571Sdim    case MEP_OPERAND_PCABS24A2 :
860214571Sdim      errmsg = parse_mep_alignu (cd, strp, MEP_OPERAND_PCABS24A2, (unsigned long *) (& fields->f_24u5a2n));
861214571Sdim      break;
862214571Sdim    case MEP_OPERAND_PCREL12A2 :
863214571Sdim      errmsg = parse_mep_align (cd, strp, MEP_OPERAND_PCREL12A2, (long *) (& fields->f_12s4a2));
864214571Sdim      break;
865214571Sdim    case MEP_OPERAND_PCREL17A2 :
866214571Sdim      errmsg = parse_mep_align (cd, strp, MEP_OPERAND_PCREL17A2, (long *) (& fields->f_17s16a2));
867214571Sdim      break;
868214571Sdim    case MEP_OPERAND_PCREL24A2 :
869214571Sdim      errmsg = parse_mep_align (cd, strp, MEP_OPERAND_PCREL24A2, (long *) (& fields->f_24s5a2n));
870214571Sdim      break;
871214571Sdim    case MEP_OPERAND_PCREL8A2 :
872214571Sdim      errmsg = parse_mep_align (cd, strp, MEP_OPERAND_PCREL8A2, (long *) (& fields->f_8s8a2));
873214571Sdim      break;
874214571Sdim    case MEP_OPERAND_PSW :
875214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
876214571Sdim      break;
877214571Sdim    case MEP_OPERAND_R0 :
878214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & junk);
879214571Sdim      break;
880214571Sdim    case MEP_OPERAND_R1 :
881214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & junk);
882214571Sdim      break;
883214571Sdim    case MEP_OPERAND_RL :
884214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rl);
885214571Sdim      break;
886214571Sdim    case MEP_OPERAND_RM :
887214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rm);
888214571Sdim      break;
889214571Sdim    case MEP_OPERAND_RMA :
890214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rm);
891214571Sdim      break;
892214571Sdim    case MEP_OPERAND_RN :
893214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rn);
894214571Sdim      break;
895214571Sdim    case MEP_OPERAND_RN3 :
896214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rn3);
897214571Sdim      break;
898214571Sdim    case MEP_OPERAND_RN3C :
899214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rn3);
900214571Sdim      break;
901214571Sdim    case MEP_OPERAND_RN3L :
902214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rn3);
903214571Sdim      break;
904214571Sdim    case MEP_OPERAND_RN3S :
905214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rn3);
906214571Sdim      break;
907214571Sdim    case MEP_OPERAND_RN3UC :
908214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rn3);
909214571Sdim      break;
910214571Sdim    case MEP_OPERAND_RN3UL :
911214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rn3);
912214571Sdim      break;
913214571Sdim    case MEP_OPERAND_RN3US :
914214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rn3);
915214571Sdim      break;
916214571Sdim    case MEP_OPERAND_RNC :
917214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rn);
918214571Sdim      break;
919214571Sdim    case MEP_OPERAND_RNL :
920214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rn);
921214571Sdim      break;
922214571Sdim    case MEP_OPERAND_RNS :
923214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rn);
924214571Sdim      break;
925214571Sdim    case MEP_OPERAND_RNUC :
926214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rn);
927214571Sdim      break;
928214571Sdim    case MEP_OPERAND_RNUL :
929214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rn);
930214571Sdim      break;
931214571Sdim    case MEP_OPERAND_RNUS :
932214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & fields->f_rn);
933214571Sdim      break;
934214571Sdim    case MEP_OPERAND_SAR :
935214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_csr, & junk);
936214571Sdim      break;
937214571Sdim    case MEP_OPERAND_SDISP16 :
938214571Sdim      errmsg = parse_signed16 (cd, strp, MEP_OPERAND_SDISP16, (long *) (& fields->f_16s16));
939214571Sdim      break;
940214571Sdim    case MEP_OPERAND_SIMM16 :
941214571Sdim      errmsg = parse_signed16 (cd, strp, MEP_OPERAND_SIMM16, (long *) (& fields->f_16s16));
942214571Sdim      break;
943214571Sdim    case MEP_OPERAND_SIMM6 :
944214571Sdim      errmsg = cgen_parse_signed_integer (cd, strp, MEP_OPERAND_SIMM6, (long *) (& fields->f_6s8));
945214571Sdim      break;
946214571Sdim    case MEP_OPERAND_SIMM8 :
947214571Sdim      errmsg = cgen_parse_signed_integer (cd, strp, MEP_OPERAND_SIMM8, (long *) (& fields->f_8s8));
948214571Sdim      break;
949214571Sdim    case MEP_OPERAND_SP :
950214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & junk);
951214571Sdim      break;
952214571Sdim    case MEP_OPERAND_SPR :
953214571Sdim      errmsg = parse_spreg (cd, strp, & mep_cgen_opval_h_gpr, & junk);
954214571Sdim      break;
955214571Sdim    case MEP_OPERAND_TP :
956214571Sdim      errmsg = cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_gpr, & junk);
957214571Sdim      break;
958214571Sdim    case MEP_OPERAND_TPR :
959214571Sdim      errmsg = parse_tpreg (cd, strp, & mep_cgen_opval_h_gpr, & junk);
960214571Sdim      break;
961214571Sdim    case MEP_OPERAND_UDISP2 :
962214571Sdim      errmsg = cgen_parse_signed_integer (cd, strp, MEP_OPERAND_UDISP2, (long *) (& fields->f_2u6));
963214571Sdim      break;
964214571Sdim    case MEP_OPERAND_UDISP7 :
965214571Sdim      errmsg = parse_unsigned7 (cd, strp, MEP_OPERAND_UDISP7, (unsigned long *) (& fields->f_7u9));
966214571Sdim      break;
967214571Sdim    case MEP_OPERAND_UDISP7A2 :
968214571Sdim      errmsg = parse_unsigned7 (cd, strp, MEP_OPERAND_UDISP7A2, (unsigned long *) (& fields->f_7u9a2));
969214571Sdim      break;
970214571Sdim    case MEP_OPERAND_UDISP7A4 :
971214571Sdim      errmsg = parse_unsigned7 (cd, strp, MEP_OPERAND_UDISP7A4, (unsigned long *) (& fields->f_7u9a4));
972214571Sdim      break;
973214571Sdim    case MEP_OPERAND_UIMM16 :
974214571Sdim      errmsg = parse_unsigned16 (cd, strp, MEP_OPERAND_UIMM16, (unsigned long *) (& fields->f_16u16));
975214571Sdim      break;
976214571Sdim    case MEP_OPERAND_UIMM2 :
977214571Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_UIMM2, (unsigned long *) (& fields->f_2u10));
978214571Sdim      break;
979214571Sdim    case MEP_OPERAND_UIMM24 :
980214571Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_UIMM24, (unsigned long *) (& fields->f_24u8n));
981214571Sdim      break;
982214571Sdim    case MEP_OPERAND_UIMM3 :
983214571Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_UIMM3, (unsigned long *) (& fields->f_3u5));
984214571Sdim      break;
985214571Sdim    case MEP_OPERAND_UIMM4 :
986214571Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_UIMM4, (unsigned long *) (& fields->f_4u8));
987214571Sdim      break;
988214571Sdim    case MEP_OPERAND_UIMM5 :
989214571Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_UIMM5, (unsigned long *) (& fields->f_5u8));
990214571Sdim      break;
991214571Sdim    case MEP_OPERAND_UIMM7A4 :
992214571Sdim      errmsg = parse_mep_alignu (cd, strp, MEP_OPERAND_UIMM7A4, (unsigned long *) (& fields->f_7u9a4));
993214571Sdim      break;
994214571Sdim    case MEP_OPERAND_ZERO :
995214571Sdim      errmsg = parse_zero (cd, strp, MEP_OPERAND_ZERO, (long *) (& junk));
996214571Sdim      break;
997214571Sdim
998214571Sdim    default :
999214571Sdim      /* xgettext:c-format */
1000214571Sdim      fprintf (stderr, _("Unrecognized field %d while parsing.\n"), opindex);
1001214571Sdim      abort ();
1002214571Sdim  }
1003214571Sdim
1004214571Sdim  return errmsg;
1005214571Sdim}
1006214571Sdim
1007214571Sdimcgen_parse_fn * const mep_cgen_parse_handlers[] =
1008214571Sdim{
1009214571Sdim  parse_insn_normal,
1010214571Sdim};
1011214571Sdim
1012214571Sdimvoid
1013214571Sdimmep_cgen_init_asm (CGEN_CPU_DESC cd)
1014214571Sdim{
1015214571Sdim  mep_cgen_init_opcode_table (cd);
1016214571Sdim  mep_cgen_init_ibld_table (cd);
1017214571Sdim  cd->parse_handlers = & mep_cgen_parse_handlers[0];
1018214571Sdim  cd->parse_operand = mep_cgen_parse_operand;
1019214571Sdim#ifdef CGEN_ASM_INIT_HOOK
1020214571SdimCGEN_ASM_INIT_HOOK
1021214571Sdim#endif
1022214571Sdim}
1023214571Sdim
1024214571Sdim
1025214571Sdim
1026214571Sdim/* Regex construction routine.
1027214571Sdim
1028214571Sdim   This translates an opcode syntax string into a regex string,
1029214571Sdim   by replacing any non-character syntax element (such as an
1030214571Sdim   opcode) with the pattern '.*'
1031214571Sdim
1032214571Sdim   It then compiles the regex and stores it in the opcode, for
1033214571Sdim   later use by mep_cgen_assemble_insn
1034214571Sdim
1035214571Sdim   Returns NULL for success, an error message for failure.  */
1036214571Sdim
1037214571Sdimchar *
1038214571Sdimmep_cgen_build_insn_regex (CGEN_INSN *insn)
1039214571Sdim{
1040214571Sdim  CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
1041214571Sdim  const char *mnem = CGEN_INSN_MNEMONIC (insn);
1042214571Sdim  char rxbuf[CGEN_MAX_RX_ELEMENTS];
1043214571Sdim  char *rx = rxbuf;
1044214571Sdim  const CGEN_SYNTAX_CHAR_TYPE *syn;
1045214571Sdim  int reg_err;
1046214571Sdim
1047214571Sdim  syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
1048214571Sdim
1049214571Sdim  /* Mnemonics come first in the syntax string.  */
1050214571Sdim  if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
1051214571Sdim    return _("missing mnemonic in syntax string");
1052214571Sdim  ++syn;
1053214571Sdim
1054214571Sdim  /* Generate a case sensitive regular expression that emulates case
1055214571Sdim     insensitive matching in the "C" locale.  We cannot generate a case
1056214571Sdim     insensitive regular expression because in Turkish locales, 'i' and 'I'
1057214571Sdim     are not equal modulo case conversion.  */
1058214571Sdim
1059214571Sdim  /* Copy the literal mnemonic out of the insn.  */
1060214571Sdim  for (; *mnem; mnem++)
1061214571Sdim    {
1062214571Sdim      char c = *mnem;
1063214571Sdim
1064214571Sdim      if (ISALPHA (c))
1065214571Sdim	{
1066214571Sdim	  *rx++ = '[';
1067214571Sdim	  *rx++ = TOLOWER (c);
1068214571Sdim	  *rx++ = TOUPPER (c);
1069214571Sdim	  *rx++ = ']';
1070214571Sdim	}
1071214571Sdim      else
1072214571Sdim	*rx++ = c;
1073214571Sdim    }
1074214571Sdim
1075214571Sdim  /* Copy any remaining literals from the syntax string into the rx.  */
1076214571Sdim  for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
1077214571Sdim    {
1078214571Sdim      if (CGEN_SYNTAX_CHAR_P (* syn))
1079214571Sdim	{
1080214571Sdim	  char c = CGEN_SYNTAX_CHAR (* syn);
1081214571Sdim
1082214571Sdim	  switch (c)
1083214571Sdim	    {
1084214571Sdim	      /* Escape any regex metacharacters in the syntax.  */
1085214571Sdim	    case '.': case '[': case '\\':
1086214571Sdim	    case '*': case '^': case '$':
1087214571Sdim
1088214571Sdim#ifdef CGEN_ESCAPE_EXTENDED_REGEX
1089214571Sdim	    case '?': case '{': case '}':
1090214571Sdim	    case '(': case ')': case '*':
1091214571Sdim	    case '|': case '+': case ']':
1092214571Sdim#endif
1093214571Sdim	      *rx++ = '\\';
1094214571Sdim	      *rx++ = c;
1095214571Sdim	      break;
1096214571Sdim
1097214571Sdim	    default:
1098214571Sdim	      if (ISALPHA (c))
1099214571Sdim		{
1100214571Sdim		  *rx++ = '[';
1101214571Sdim		  *rx++ = TOLOWER (c);
1102214571Sdim		  *rx++ = TOUPPER (c);
1103214571Sdim		  *rx++ = ']';
1104214571Sdim		}
1105214571Sdim	      else
1106214571Sdim		*rx++ = c;
1107214571Sdim	      break;
1108214571Sdim	    }
1109214571Sdim	}
1110214571Sdim      else
1111214571Sdim	{
1112214571Sdim	  /* Replace non-syntax fields with globs.  */
1113214571Sdim	  *rx++ = '.';
1114214571Sdim	  *rx++ = '*';
1115214571Sdim	}
1116214571Sdim    }
1117214571Sdim
1118214571Sdim  /* Trailing whitespace ok.  */
1119214571Sdim  * rx++ = '[';
1120214571Sdim  * rx++ = ' ';
1121214571Sdim  * rx++ = '\t';
1122214571Sdim  * rx++ = ']';
1123214571Sdim  * rx++ = '*';
1124214571Sdim
1125214571Sdim  /* But anchor it after that.  */
1126214571Sdim  * rx++ = '$';
1127214571Sdim  * rx = '\0';
1128214571Sdim
1129214571Sdim  CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
1130214571Sdim  reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
1131214571Sdim
1132214571Sdim  if (reg_err == 0)
1133214571Sdim    return NULL;
1134214571Sdim  else
1135214571Sdim    {
1136214571Sdim      static char msg[80];
1137214571Sdim
1138214571Sdim      regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
1139214571Sdim      regfree ((regex_t *) CGEN_INSN_RX (insn));
1140214571Sdim      free (CGEN_INSN_RX (insn));
1141214571Sdim      (CGEN_INSN_RX (insn)) = NULL;
1142214571Sdim      return msg;
1143214571Sdim    }
1144214571Sdim}
1145214571Sdim
1146214571Sdim
1147214571Sdim/* Default insn parser.
1148214571Sdim
1149214571Sdim   The syntax string is scanned and operands are parsed and stored in FIELDS.
1150214571Sdim   Relocs are queued as we go via other callbacks.
1151214571Sdim
1152214571Sdim   ??? Note that this is currently an all-or-nothing parser.  If we fail to
1153214571Sdim   parse the instruction, we return 0 and the caller will start over from
1154214571Sdim   the beginning.  Backtracking will be necessary in parsing subexpressions,
1155214571Sdim   but that can be handled there.  Not handling backtracking here may get
1156214571Sdim   expensive in the case of the m68k.  Deal with later.
1157214571Sdim
1158214571Sdim   Returns NULL for success, an error message for failure.  */
1159214571Sdim
1160214571Sdimstatic const char *
1161214571Sdimparse_insn_normal (CGEN_CPU_DESC cd,
1162214571Sdim		   const CGEN_INSN *insn,
1163214571Sdim		   const char **strp,
1164214571Sdim		   CGEN_FIELDS *fields)
1165214571Sdim{
1166214571Sdim  /* ??? Runtime added insns not handled yet.  */
1167214571Sdim  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
1168214571Sdim  const char *str = *strp;
1169214571Sdim  const char *errmsg;
1170214571Sdim  const char *p;
1171214571Sdim  const CGEN_SYNTAX_CHAR_TYPE * syn;
1172214571Sdim#ifdef CGEN_MNEMONIC_OPERANDS
1173214571Sdim  /* FIXME: wip */
1174214571Sdim  int past_opcode_p;
1175214571Sdim#endif
1176214571Sdim
1177214571Sdim  /* For now we assume the mnemonic is first (there are no leading operands).
1178214571Sdim     We can parse it without needing to set up operand parsing.
1179214571Sdim     GAS's input scrubber will ensure mnemonics are lowercase, but we may
1180214571Sdim     not be called from GAS.  */
1181214571Sdim  p = CGEN_INSN_MNEMONIC (insn);
1182214571Sdim  while (*p && TOLOWER (*p) == TOLOWER (*str))
1183214571Sdim    ++p, ++str;
1184214571Sdim
1185214571Sdim  if (* p)
1186214571Sdim    return _("unrecognized instruction");
1187214571Sdim
1188214571Sdim#ifndef CGEN_MNEMONIC_OPERANDS
1189214571Sdim  if (* str && ! ISSPACE (* str))
1190214571Sdim    return _("unrecognized instruction");
1191214571Sdim#endif
1192214571Sdim
1193214571Sdim  CGEN_INIT_PARSE (cd);
1194214571Sdim  cgen_init_parse_operand (cd);
1195214571Sdim#ifdef CGEN_MNEMONIC_OPERANDS
1196214571Sdim  past_opcode_p = 0;
1197214571Sdim#endif
1198214571Sdim
1199214571Sdim  /* We don't check for (*str != '\0') here because we want to parse
1200214571Sdim     any trailing fake arguments in the syntax string.  */
1201214571Sdim  syn = CGEN_SYNTAX_STRING (syntax);
1202214571Sdim
1203214571Sdim  /* Mnemonics come first for now, ensure valid string.  */
1204214571Sdim  if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
1205214571Sdim    abort ();
1206214571Sdim
1207214571Sdim  ++syn;
1208214571Sdim
1209214571Sdim  while (* syn != 0)
1210214571Sdim    {
1211214571Sdim      /* Non operand chars must match exactly.  */
1212214571Sdim      if (CGEN_SYNTAX_CHAR_P (* syn))
1213214571Sdim	{
1214214571Sdim	  /* FIXME: While we allow for non-GAS callers above, we assume the
1215214571Sdim	     first char after the mnemonic part is a space.  */
1216214571Sdim	  /* FIXME: We also take inappropriate advantage of the fact that
1217214571Sdim	     GAS's input scrubber will remove extraneous blanks.  */
1218214571Sdim	  if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
1219214571Sdim	    {
1220214571Sdim#ifdef CGEN_MNEMONIC_OPERANDS
1221214571Sdim	      if (CGEN_SYNTAX_CHAR(* syn) == ' ')
1222214571Sdim		past_opcode_p = 1;
1223214571Sdim#endif
1224214571Sdim	      ++ syn;
1225214571Sdim	      ++ str;
1226214571Sdim	    }
1227214571Sdim	  else if (*str)
1228214571Sdim	    {
1229214571Sdim	      /* Syntax char didn't match.  Can't be this insn.  */
1230214571Sdim	      static char msg [80];
1231214571Sdim
1232214571Sdim	      /* xgettext:c-format */
1233214571Sdim	      sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
1234214571Sdim		       CGEN_SYNTAX_CHAR(*syn), *str);
1235214571Sdim	      return msg;
1236214571Sdim	    }
1237214571Sdim	  else
1238214571Sdim	    {
1239214571Sdim	      /* Ran out of input.  */
1240214571Sdim	      static char msg [80];
1241214571Sdim
1242214571Sdim	      /* xgettext:c-format */
1243214571Sdim	      sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
1244214571Sdim		       CGEN_SYNTAX_CHAR(*syn));
1245214571Sdim	      return msg;
1246214571Sdim	    }
1247214571Sdim	  continue;
1248214571Sdim	}
1249214571Sdim
1250214571Sdim      /* We have an operand of some sort.  */
1251214571Sdim      errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn),
1252214571Sdim					  &str, fields);
1253214571Sdim      if (errmsg)
1254214571Sdim	return errmsg;
1255214571Sdim
1256214571Sdim      /* Done with this operand, continue with next one.  */
1257214571Sdim      ++ syn;
1258214571Sdim    }
1259214571Sdim
1260214571Sdim  /* If we're at the end of the syntax string, we're done.  */
1261214571Sdim  if (* syn == 0)
1262214571Sdim    {
1263214571Sdim      /* FIXME: For the moment we assume a valid `str' can only contain
1264214571Sdim	 blanks now.  IE: We needn't try again with a longer version of
1265214571Sdim	 the insn and it is assumed that longer versions of insns appear
1266214571Sdim	 before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
1267214571Sdim      while (ISSPACE (* str))
1268214571Sdim	++ str;
1269214571Sdim
1270214571Sdim      if (* str != '\0')
1271214571Sdim	return _("junk at end of line"); /* FIXME: would like to include `str' */
1272214571Sdim
1273214571Sdim      return NULL;
1274214571Sdim    }
1275214571Sdim
1276214571Sdim  /* We couldn't parse it.  */
1277214571Sdim  return _("unrecognized instruction");
1278214571Sdim}
1279214571Sdim
1280214571Sdim/* Main entry point.
1281214571Sdim   This routine is called for each instruction to be assembled.
1282214571Sdim   STR points to the insn to be assembled.
1283214571Sdim   We assume all necessary tables have been initialized.
1284214571Sdim   The assembled instruction, less any fixups, is stored in BUF.
1285214571Sdim   Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
1286214571Sdim   still needs to be converted to target byte order, otherwise BUF is an array
1287214571Sdim   of bytes in target byte order.
1288214571Sdim   The result is a pointer to the insn's entry in the opcode table,
1289214571Sdim   or NULL if an error occured (an error message will have already been
1290214571Sdim   printed).
1291214571Sdim
1292214571Sdim   Note that when processing (non-alias) macro-insns,
1293214571Sdim   this function recurses.
1294214571Sdim
1295214571Sdim   ??? It's possible to make this cpu-independent.
1296214571Sdim   One would have to deal with a few minor things.
1297214571Sdim   At this point in time doing so would be more of a curiosity than useful
1298214571Sdim   [for example this file isn't _that_ big], but keeping the possibility in
1299214571Sdim   mind helps keep the design clean.  */
1300214571Sdim
1301214571Sdimconst CGEN_INSN *
1302214571Sdimmep_cgen_assemble_insn (CGEN_CPU_DESC cd,
1303214571Sdim			   const char *str,
1304214571Sdim			   CGEN_FIELDS *fields,
1305214571Sdim			   CGEN_INSN_BYTES_PTR buf,
1306214571Sdim			   char **errmsg)
1307214571Sdim{
1308214571Sdim  const char *start;
1309214571Sdim  CGEN_INSN_LIST *ilist;
1310214571Sdim  const char *parse_errmsg = NULL;
1311214571Sdim  const char *insert_errmsg = NULL;
1312214571Sdim  int recognized_mnemonic = 0;
1313214571Sdim
1314214571Sdim  /* Skip leading white space.  */
1315214571Sdim  while (ISSPACE (* str))
1316214571Sdim    ++ str;
1317214571Sdim
1318214571Sdim  /* The instructions are stored in hashed lists.
1319214571Sdim     Get the first in the list.  */
1320214571Sdim  ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
1321214571Sdim
1322214571Sdim  /* Keep looking until we find a match.  */
1323214571Sdim  start = str;
1324214571Sdim  for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
1325214571Sdim    {
1326214571Sdim      const CGEN_INSN *insn = ilist->insn;
1327214571Sdim      recognized_mnemonic = 1;
1328214571Sdim
1329214571Sdim#ifdef CGEN_VALIDATE_INSN_SUPPORTED
1330214571Sdim      /* Not usually needed as unsupported opcodes
1331214571Sdim	 shouldn't be in the hash lists.  */
1332214571Sdim      /* Is this insn supported by the selected cpu?  */
1333214571Sdim      if (! mep_cgen_insn_supported (cd, insn))
1334214571Sdim	continue;
1335214571Sdim#endif
1336214571Sdim      /* If the RELAXED attribute is set, this is an insn that shouldn't be
1337214571Sdim	 chosen immediately.  Instead, it is used during assembler/linker
1338214571Sdim	 relaxation if possible.  */
1339214571Sdim      if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
1340214571Sdim	continue;
1341214571Sdim
1342214571Sdim      str = start;
1343214571Sdim
1344214571Sdim      /* Skip this insn if str doesn't look right lexically.  */
1345214571Sdim      if (CGEN_INSN_RX (insn) != NULL &&
1346214571Sdim	  regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
1347214571Sdim	continue;
1348214571Sdim
1349214571Sdim      /* Allow parse/insert handlers to obtain length of insn.  */
1350214571Sdim      CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
1351214571Sdim
1352214571Sdim      parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
1353214571Sdim      if (parse_errmsg != NULL)
1354214571Sdim	continue;
1355214571Sdim
1356214571Sdim      /* ??? 0 is passed for `pc'.  */
1357214571Sdim      insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
1358214571Sdim						 (bfd_vma) 0);
1359214571Sdim      if (insert_errmsg != NULL)
1360214571Sdim        continue;
1361214571Sdim
1362214571Sdim      /* It is up to the caller to actually output the insn and any
1363214571Sdim         queued relocs.  */
1364214571Sdim      return insn;
1365214571Sdim    }
1366214571Sdim
1367214571Sdim  {
1368214571Sdim    static char errbuf[150];
1369214571Sdim#ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
1370214571Sdim    const char *tmp_errmsg;
1371214571Sdim
1372214571Sdim    /* If requesting verbose error messages, use insert_errmsg.
1373214571Sdim       Failing that, use parse_errmsg.  */
1374214571Sdim    tmp_errmsg = (insert_errmsg ? insert_errmsg :
1375214571Sdim		  parse_errmsg ? parse_errmsg :
1376214571Sdim		  recognized_mnemonic ?
1377214571Sdim		  _("unrecognized form of instruction") :
1378214571Sdim		  _("unrecognized instruction"));
1379214571Sdim
1380214571Sdim    if (strlen (start) > 50)
1381214571Sdim      /* xgettext:c-format */
1382214571Sdim      sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
1383214571Sdim    else
1384214571Sdim      /* xgettext:c-format */
1385214571Sdim      sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
1386214571Sdim#else
1387214571Sdim    if (strlen (start) > 50)
1388214571Sdim      /* xgettext:c-format */
1389214571Sdim      sprintf (errbuf, _("bad instruction `%.50s...'"), start);
1390214571Sdim    else
1391214571Sdim      /* xgettext:c-format */
1392214571Sdim      sprintf (errbuf, _("bad instruction `%.50s'"), start);
1393214571Sdim#endif
1394214571Sdim
1395214571Sdim    *errmsg = errbuf;
1396214571Sdim    return NULL;
1397214571Sdim  }
1398214571Sdim}
1399