This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / opcodes / cgen-asm.c
1 /* CGEN generic assembler support code.
2
3 Copyright (C) 1996, 1997 Free Software Foundation, Inc.
4
5 This file is part of the GNU Binutils and GDB, the GNU debugger.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #include "config.h"
22 #include <stdio.h>
23 #ifdef HAVE_STRING_H
24 #include <string.h>
25 #endif
26 #ifdef HAVE_STRINGS_H
27 #include <strings.h>
28 #endif
29 #include "ansidecl.h"
30 #include "libiberty.h"
31 #include "bfd.h"
32 #include "opcode/cgen.h"
33
34 /* Operand parsing callback.  */
35 const char * (*cgen_parse_operand_fn)
36      PARAMS ((enum cgen_parse_operand_type, const char **, int, int,
37               enum cgen_parse_operand_result *, bfd_vma *));
38
39 /* This is not published as part of the public interface so we don't
40    declare this in cgen.h.  */
41 extern CGEN_OPCODE_DATA *cgen_current_opcode_data;
42
43 /* Assembler instruction hash table.  */
44 static CGEN_INSN_LIST **asm_hash_table;
45
46 /* Called once at startup and whenever machine/endian change.  */
47
48 void
49 cgen_asm_init ()
50 {
51   if (asm_hash_table)
52     {
53       free (asm_hash_table);
54       asm_hash_table = NULL;
55     }
56 }
57
58 /* Called whenever starting to parse an insn.  */
59
60 void
61 cgen_init_parse_operand ()
62 {
63   /* This tells the callback to re-initialize.  */
64   (void) (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INIT, NULL, 0, 0,
65                                    NULL, NULL);
66 }
67
68 /* Build the assembler instruction hash table.  */
69
70 static void
71 build_asm_hash_table ()
72 {
73   int i;
74   unsigned int hash;
75   int count = cgen_insn_count ();
76   CGEN_OPCODE_DATA *data = cgen_current_opcode_data;
77   CGEN_INSN_TABLE *insn_table = data->insn_table;
78   unsigned int hash_size = insn_table->asm_hash_table_size;
79   const CGEN_INSN *insn;
80   CGEN_INSN_LIST *insn_lists,*new_insns;
81
82   /* The space allocated for the hash table consists of two parts:
83      the hash table and the hash lists.  */
84
85   asm_hash_table = (CGEN_INSN_LIST **)
86     xmalloc (hash_size * sizeof (CGEN_INSN_LIST *)
87              + count * sizeof (CGEN_INSN_LIST));
88   memset (asm_hash_table, 0,
89           hash_size * sizeof (CGEN_INSN_LIST *)
90           + count * sizeof (CGEN_INSN_LIST));
91   insn_lists = (CGEN_INSN_LIST *) (asm_hash_table + hash_size);
92
93   /* Add compiled in insns.
94      The table is scanned backwards as later additions are inserted in
95      front of earlier ones and we want earlier ones to be prefered.
96      We stop at the first one as it is a reserved entry.  */
97
98   for (insn = insn_table->init_entries + insn_table->num_init_entries - 1;
99        insn > insn_table->init_entries;
100        --insn, ++insn_lists)
101     {
102       hash = (*insn_table->asm_hash) (insn->syntax.mnemonic);
103       insn_lists->next = asm_hash_table[hash];
104       insn_lists->insn = insn;
105       asm_hash_table[hash] = insn_lists;
106     }
107
108   /* Add runtime added insns.
109      ??? Currently later added insns will be prefered over earlier ones.
110      Not sure this is a bug or not.  */
111   for (new_insns = insn_table->new_entries;
112        new_insns != NULL;
113        new_insns = new_insns->next, ++insn_lists)
114     {
115       hash = (*insn_table->asm_hash) (new_insns->insn->syntax.mnemonic);
116       insn_lists->next = asm_hash_table[hash];
117       insn_lists->insn = new_insns->insn;
118       asm_hash_table[hash] = insn_lists;
119     }
120 }
121
122 /* Return the first entry in the hash list for INSN.  */
123
124 CGEN_INSN_LIST *
125 cgen_asm_lookup_insn (insn)
126      const char *insn;
127 {
128   unsigned int hash;
129
130   if (asm_hash_table == NULL)
131     build_asm_hash_table ();
132
133   hash = (*cgen_current_opcode_data->insn_table->asm_hash) (insn);
134   return asm_hash_table[hash];
135 }
136 \f
137 /* Keyword parser.
138    The result is NULL upon success or an error message.
139    If successful, *STRP is updated to point passed the keyword.
140
141    ??? At present we have a static notion of how to pick out a keyword.
142    Later we can allow a target to customize this if necessary [say by
143    recording something in the keyword table].  */
144
145 const char *
146 cgen_parse_keyword (strp, keyword_table, valuep)
147      const char **strp;
148      struct cgen_keyword *keyword_table;
149      long *valuep;
150 {
151   const struct cgen_keyword_entry *ke;
152   char buf[256];
153   const char *p;
154
155   p = *strp;
156
157   /* Allow any first character.  */
158   if (*p)
159     ++p;
160
161   /* Now allow letters, digits, and _.  */
162   while (isalnum (*p) || *p == '_')
163     ++p;
164
165   if (p - *strp > 255)
166     return "unrecognized keyword/register name";
167
168   memcpy (buf, *strp, p - *strp);
169   buf[p - *strp] = 0;
170
171   ke = cgen_keyword_lookup_name (keyword_table, buf);
172
173   if (ke != NULL)
174     {
175       *valuep = ke->value;
176       *strp = p;
177       return NULL;
178     }
179
180   return "unrecognized keyword/register name";
181 }
182
183 /* Signed integer parser.  */
184
185 const char *
186 cgen_parse_signed_integer (strp, opindex, min, max, valuep)
187      const char **strp;
188      int opindex;
189      long min, max;
190      long *valuep;
191 {
192   long value;
193   enum cgen_parse_operand_result result;
194   const char *errmsg;
195
196   errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
197                                      opindex, BFD_RELOC_NONE,
198                                      &result, &value);
199   /* FIXME: Examine `result'.  */
200   if (!errmsg)
201     {
202       if (value < min || value > max)
203         return "integer operand out of range";
204       *valuep = value;
205     }
206   return errmsg;
207 }
208
209 /* Unsigned integer parser.  */
210
211 const char *
212 cgen_parse_unsigned_integer (strp, opindex, min, max, valuep)
213      const char **strp;
214      int opindex;
215      unsigned long min, max;
216      unsigned long *valuep;
217 {
218   unsigned long value;
219   enum cgen_parse_operand_result result;
220   const char *errmsg;
221
222   errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
223                                      opindex, BFD_RELOC_NONE,
224                                      &result, &value);
225   /* FIXME: Examine `result'.  */
226   if (!errmsg)
227     {
228       if (value < min || value > max)
229         return "integer operand out of range";
230       *valuep = value;
231     }
232   return errmsg;
233 }
234
235 /* Address parser.  */
236
237 const char *
238 cgen_parse_address (strp, opindex, opinfo, valuep)
239      const char **strp;
240      int opindex;
241      int opinfo;
242      long *valuep;
243 {
244   long value;
245   enum cgen_parse_operand_result result;
246   const char *errmsg;
247
248   errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_ADDRESS, strp,
249                                      opindex, opinfo,
250                                      &result, &value);
251   /* FIXME: Examine `result'.  */
252   if (!errmsg)
253     {
254       *valuep = value;
255     }
256   return errmsg;
257 }
258 \f
259 /* Signed integer validation routine.  */
260
261 const char *
262 cgen_validate_signed_integer (value, min, max)
263      long value, min, max;
264 {
265   if (value < min || value > max)
266     {
267       const char *err =
268         "operand out of range (%ld not between %ld and %ld)";
269       static char buf[100];
270
271       sprintf (buf, err, value, min, max);
272       return buf;
273     }
274
275   return NULL;
276 }
277
278 /* Unsigned integer validation routine.
279    Supplying `min' here may seem unnecessary, but we also want to handle
280    cases where min != 0 (and max > LONG_MAX).  */
281
282 const char *
283 cgen_validate_unsigned_integer (value, min, max)
284      unsigned long value, min, max;
285 {
286   if (value < min || value > max)
287     {
288       const char *err =
289         "operand out of range (%lu not between %lu and %lu)";
290       static char buf[100];
291
292       sprintf (buf, err, value, min, max);
293       return buf;
294     }
295
296   return NULL;
297 }