Home | History | Annotate | Line # | Download | only in config
      1      1.1  christos /* kvx-parse.c -- Recursive decent parser driver for the KVX ISA
      2      1.1  christos 
      3  1.1.1.2  christos    Copyright (C) 2009-2025 Free Software Foundation, Inc.
      4      1.1  christos    Contributed by Kalray SA.
      5      1.1  christos 
      6      1.1  christos    This file is part of GAS.
      7      1.1  christos 
      8      1.1  christos    GAS is free software; you can redistribute it and/or modify
      9      1.1  christos    it under the terms of the GNU General Public License as published by
     10      1.1  christos    the Free Software Foundation; either version 3 of the license, or
     11      1.1  christos    (at your option) any later version.
     12      1.1  christos 
     13      1.1  christos    GAS is distributed in the hope that it will be useful,
     14      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16      1.1  christos    GNU General Public License for more details.
     17      1.1  christos 
     18      1.1  christos    You should have received a copy of the GNU General Public License
     19      1.1  christos    along with this program; see the file COPYING3. If not,
     20      1.1  christos    see <http://www.gnu.org/licenses/>.  */
     21      1.1  christos 
     22      1.1  christos #include "as.h"
     23      1.1  christos #include <stdio.h>
     24      1.1  christos #include <stdlib.h>
     25      1.1  christos #include <string.h>
     26      1.1  christos #include <ctype.h>
     27      1.1  christos #include <stdarg.h>
     28      1.1  christos #include <elf/kvx_elfids.h>
     29      1.1  christos #include "kvx-parse.h"
     30      1.1  christos 
     31      1.1  christos /* This is bad! */
     32      1.1  christos struct node_list_s {
     33      1.1  christos   struct node_s *node;
     34      1.1  christos   struct node_list_s *nxt;
     35      1.1  christos };
     36      1.1  christos 
     37      1.1  christos struct node_s {
     38      1.1  christos   char *val;
     39      1.1  christos   int len;
     40      1.1  christos   struct node_list_s *succs;
     41      1.1  christos   int nb_succs;
     42      1.1  christos };
     43      1.1  christos 
     44      1.1  christos 
     45      1.1  christos 
     47      1.1  christos static int
     48      1.1  christos has_relocation_of_size (const struct kvx_reloc **relocs)
     49      1.1  christos {
     50      1.1  christos   const int symbol_size = env.params.arch_size;
     51      1.1  christos 
     52      1.1  christos   /*
     53      1.1  christos    * This is a bit hackish: in case of PCREL here, it means we are
     54      1.1  christos    * trying to fit a symbol in the insn, not a pseudo function
     55      1.1  christos    * (eg. @gotaddr, ...).
     56      1.1  christos    * We don't want to use a GOTADDR (pcrel) in any insn that tries to fit a symbol.
     57      1.1  christos    * One way to filter out these is to use the following assumption:
     58      1.1  christos    * - Any insn that accepts a pcrel immediate has only one immediate variant.
     59      1.1  christos    * Example:
     60      1.1  christos    * - call accepts only a pcrel27 -> allow pcrel reloc here
     61      1.1  christos    * - cb accepts only a pcrel17 -> allow pcrel reloc here
     62      1.1  christos    * - addd accepts signed10,37,64 -> deny pcrel reloc here
     63      1.1  christos    *
     64      1.1  christos    * The motivation here is to prevent the function to allow a 64bits
     65      1.1  christos    * symbol in a 37bits variant of any ALU insn (that would match with
     66      1.1  christos    * the GOTADDR 37bits reloc switch case below)
     67      1.1  christos    */
     68      1.1  christos 
     69      1.1  christos   if (!relocs)
     70      1.1  christos     return 0;
     71  1.1.1.2  christos 
     72      1.1  christos   const struct kvx_reloc **relocs_it = relocs;
     73      1.1  christos   int has_only_one_p = relocs[0] && !relocs[1];
     74      1.1  christos 
     75      1.1  christos   while (*relocs_it)
     76      1.1  christos     {
     77      1.1  christos       switch ((*relocs_it)->relative)
     78      1.1  christos       {
     79      1.1  christos 	/* An absolute reloc needs a full size symbol reloc */
     80      1.1  christos 	case KVX_REL_ABS:
     81      1.1  christos 	  if ((*relocs_it)->bitsize >= symbol_size)
     82      1.1  christos 	    return 1;
     83      1.1  christos 	  break;
     84      1.1  christos 
     85      1.1  christos 	  /* Most likely relative jumps. Let something else check size is
     86      1.1  christos 	     OK. We don't currently have several relocations for such insns */
     87      1.1  christos 	case KVX_REL_PC:
     88      1.1  christos 	  if (has_only_one_p)
     89      1.1  christos 	    return 1;
     90      1.1  christos 	  break;
     91      1.1  christos 
     92      1.1  christos 	  /* These relocations should be handled elsewhere with pseudo functions */
     93      1.1  christos 	case KVX_REL_GP:
     94      1.1  christos 	case KVX_REL_TP:
     95      1.1  christos 	case KVX_REL_GOT:
     96      1.1  christos 	case KVX_REL_BASE:
     97      1.1  christos 	  break;
     98      1.1  christos       }
     99      1.1  christos       relocs_it++;
    100      1.1  christos     }
    101      1.1  christos 
    102      1.1  christos   return 0;
    103      1.1  christos }
    104  1.1.1.2  christos 
    105  1.1.1.2  christos static struct pseudo_func *
    106      1.1  christos kvx_get_pseudo_func2 (symbolS *sym, const struct kvx_reloc **relocs)
    107      1.1  christos {
    108      1.1  christos   if (!relocs)
    109      1.1  christos     return NULL;
    110  1.1.1.2  christos 
    111      1.1  christos   const struct kvx_reloc **relocs_it = relocs;
    112      1.1  christos 
    113      1.1  christos   for (int i = 0; i < 26; i++)
    114      1.1  christos   {
    115      1.1  christos     if (sym == kvx_core_info->pseudo_funcs[i].sym)
    116      1.1  christos     {
    117      1.1  christos       relocs_it = relocs;
    118      1.1  christos       while (*relocs_it)
    119      1.1  christos 	{
    120      1.1  christos 	  if (*relocs_it == kvx_core_info->pseudo_funcs[i].pseudo_relocs.kreloc
    121      1.1  christos 	      && (env.params.arch_size == (int) kvx_core_info->pseudo_funcs[i].pseudo_relocs.avail_modes
    122      1.1  christos 		|| kvx_core_info->pseudo_funcs[i].pseudo_relocs.avail_modes == PSEUDO_ALL))
    123      1.1  christos 	    return &kvx_core_info->pseudo_funcs[i];
    124      1.1  christos 	  relocs_it++;
    125      1.1  christos 	}
    126      1.1  christos     }
    127      1.1  christos   }
    128      1.1  christos 
    129      1.1  christos   return NULL;
    130      1.1  christos }
    131      1.1  christos 
    132      1.1  christos /* Trie */
    134      1.1  christos 
    135      1.1  christos static
    136      1.1  christos struct node_list_s *
    137      1.1  christos insert_in_succ_list (struct node_s *node, struct node_s *base)
    138      1.1  christos {
    139      1.1  christos   struct node_list_s *new_hd = NULL;
    140      1.1  christos   if (!(new_hd = calloc (1, sizeof (*new_hd))))
    141      1.1  christos     return NULL;
    142      1.1  christos 
    143      1.1  christos   new_hd->node = node;
    144      1.1  christos   new_hd->nxt = base->succs;
    145      1.1  christos   base->nb_succs += 1;
    146      1.1  christos   return new_hd;
    147      1.1  christos }
    148      1.1  christos 
    149      1.1  christos static
    150      1.1  christos struct node_s *
    151      1.1  christos make_node (const char *str, int len)
    152      1.1  christos {
    153      1.1  christos   struct node_s *n = NULL;
    154      1.1  christos   if (!(n = calloc (1, sizeof (*n))))
    155      1.1  christos     goto err;
    156      1.1  christos 
    157      1.1  christos   n->len = len;
    158      1.1  christos   n->succs = NULL;
    159      1.1  christos   if (!(n->val = calloc (n->len + 1, sizeof (*n->val))))
    160      1.1  christos     goto err1;
    161      1.1  christos 
    162      1.1  christos   strncpy (n->val, str, n->len);
    163      1.1  christos   return n;
    164      1.1  christos 
    165      1.1  christos err1:
    166      1.1  christos   free (n), n = NULL;
    167      1.1  christos err:
    168      1.1  christos   return NULL;
    169      1.1  christos }
    170      1.1  christos 
    171      1.1  christos static
    172      1.1  christos struct node_s *
    173      1.1  christos insert (const char *str, struct node_s *node)
    174      1.1  christos {
    175      1.1  christos   int i = 0;
    176      1.1  christos   int len = strlen (str);
    177      1.1  christos 
    178      1.1  christos   if (!node)
    179      1.1  christos     {
    180      1.1  christos       struct node_s *n = make_node (str, len);
    181      1.1  christos       n->succs = insert_in_succ_list (NULL, n);
    182      1.1  christos       return n;
    183      1.1  christos     }
    184      1.1  christos 
    185      1.1  christos   while (i < len && i < node->len && str[i] == node->val[i])
    186      1.1  christos     ++i;
    187      1.1  christos 
    188      1.1  christos   /* The strings share a prefix. */
    189      1.1  christos   if (i < len && i < node->len)
    190      1.1  christos     {
    191      1.1  christos       /* Split the current node on that common prefix. */
    192      1.1  christos 
    193      1.1  christos       /* Create a new node with only the unshared suffix, and makes it inherit
    194      1.1  christos          the successor of the node under consideration. */
    195      1.1  christos       struct node_s *suf = make_node (node->val + i, node->len - i);
    196      1.1  christos       suf->succs = node->succs;
    197      1.1  christos       suf->nb_succs = node->nb_succs;
    198      1.1  christos       /* Insert the remainder on the other branch */
    199      1.1  christos       struct node_s *rem = make_node (str + i, len - i);
    200      1.1  christos       rem->succs = insert_in_succ_list (NULL, rem);
    201      1.1  christos 
    202      1.1  christos       node->val[i] = '\0';
    203      1.1  christos       node->len = i;
    204      1.1  christos       node->succs = NULL;
    205      1.1  christos       node->nb_succs = 0;
    206      1.1  christos       node->succs = insert_in_succ_list (suf, node);
    207      1.1  christos       node->succs = insert_in_succ_list (rem, node);
    208      1.1  christos       return node;
    209      1.1  christos     }
    210      1.1  christos 
    211      1.1  christos   /* str is a strict prefix of node->val */
    212      1.1  christos   if (i == len && i < node->len)
    213      1.1  christos     {
    214      1.1  christos       /* Split the current node at position */
    215      1.1  christos       struct node_s *suf = make_node (node->val + i, node->len - i);
    216      1.1  christos       suf->succs = node->succs;
    217      1.1  christos       suf->nb_succs = node->nb_succs;
    218      1.1  christos       node->val[i] = '\0';
    219      1.1  christos       node->len = i;
    220      1.1  christos       /* Insert an empty leaf */
    221      1.1  christos       node->succs = NULL;
    222      1.1  christos       node->nb_succs = 0;
    223      1.1  christos       node->succs = insert_in_succ_list (NULL, node);
    224      1.1  christos       node->succs = insert_in_succ_list (suf, node);
    225      1.1  christos       return node;
    226      1.1  christos     }
    227      1.1  christos 
    228      1.1  christos   /* node->val is a prefix of str */
    229      1.1  christos   if (i == node->len)
    230      1.1  christos     {
    231      1.1  christos       /* Find a successor of node into which the remainder can be inserted. */
    232      1.1  christos       struct node_list_s *cur_succ = node->succs;
    233      1.1  christos       while (cur_succ)
    234      1.1  christos 	{
    235      1.1  christos 	  struct node_s *n = cur_succ->node;
    236      1.1  christos 	  if (n && n->val && n->val[0] == str[i])
    237      1.1  christos 	    {
    238      1.1  christos 	      cur_succ->node = insert (str + i, cur_succ->node);
    239      1.1  christos 	      break;
    240      1.1  christos 	    }
    241      1.1  christos 	  cur_succ = cur_succ->nxt;
    242      1.1  christos 	}
    243      1.1  christos       /* No successor shares a common prefix */
    244      1.1  christos       if (cur_succ == NULL)
    245      1.1  christos 	{
    246      1.1  christos 	  struct node_s *suf = make_node (str + i, len - i);
    247      1.1  christos 	  suf->succs = insert_in_succ_list (NULL, suf);
    248      1.1  christos 	  node->succs = insert_in_succ_list (suf, node);
    249      1.1  christos 	}
    250      1.1  christos       return node;
    251      1.1  christos     }
    252      1.1  christos 
    253      1.1  christos   return node;
    254      1.1  christos }
    255      1.1  christos 
    256      1.1  christos static
    257      1.1  christos void
    258      1.1  christos free_node (struct node_s *node)
    259      1.1  christos {
    260      1.1  christos   if (!node)
    261      1.1  christos     return;
    262      1.1  christos 
    263      1.1  christos   free (node->val);
    264      1.1  christos 
    265      1.1  christos   struct node_list_s *cur_succ = node->succs;
    266      1.1  christos   struct node_list_s *tmp = NULL;
    267      1.1  christos   while ((tmp = cur_succ))
    268      1.1  christos   {
    269      1.1  christos     struct node_s *n = cur_succ->node;
    270      1.1  christos     if (n)
    271      1.1  christos       free_node (n), n = NULL;
    272      1.1  christos     cur_succ = cur_succ->nxt;
    273      1.1  christos     free (tmp);
    274      1.1  christos   }
    275      1.1  christos 
    276      1.1  christos   free (node);
    277      1.1  christos }
    278      1.1  christos 
    279      1.1  christos #define max(a,b) (((a)>(b))?(a):(b))
    280      1.1  christos static
    281      1.1  christos int
    282      1.1  christos longest_match (const char *str, int len, struct node_s *node)
    283      1.1  christos {
    284      1.1  christos   int i = 0;
    285      1.1  christos   int last_mark = 0;
    286      1.1  christos   struct node_s *cur = node;
    287      1.1  christos 
    288      1.1  christos   while (1)
    289      1.1  christos     {
    290      1.1  christos       if (i + cur->len > len
    291      1.1  christos 	  || strncmp (str + i, cur->val, max(0, cur->len)))
    292      1.1  christos 	return last_mark;
    293      1.1  christos 
    294      1.1  christos       i += cur->len;
    295      1.1  christos       struct node_list_s *cur_succ = cur->succs;
    296      1.1  christos       cur = NULL;
    297      1.1  christos       while (cur_succ)
    298      1.1  christos 	{
    299      1.1  christos 	  struct node_s *n = cur_succ->node;
    300      1.1  christos 	  if (!n)
    301      1.1  christos 	    last_mark = i;
    302      1.1  christos 	  else if (n->val[0] == str[i])
    303      1.1  christos 	    cur = n;
    304      1.1  christos 	  cur_succ = cur_succ->nxt;
    305      1.1  christos 	}
    306      1.1  christos       if (!cur)
    307      1.1  christos 	return last_mark;
    308      1.1  christos     }
    309      1.1  christos }
    310      1.1  christos 
    311      1.1  christos __attribute__((unused))
    312      1.1  christos static void
    313      1.1  christos dump_graph_1 (FILE *fd, struct node_s *node, int id)
    314      1.1  christos {
    315      1.1  christos   struct node_list_s *cur_succ = node->succs;
    316      1.1  christos   int i = 0;
    317      1.1  christos 
    318      1.1  christos   if (id == 1)
    319      1.1  christos     fprintf (fd, "\t%d [label=\"%s\"];\n", id, node->val);
    320      1.1  christos 
    321      1.1  christos   while (cur_succ)
    322      1.1  christos     {
    323      1.1  christos       if (cur_succ->node == NULL)
    324      1.1  christos 	fprintf (fd, "\t%d -> \"()\";\n", id);
    325      1.1  christos       else
    326      1.1  christos 	{
    327      1.1  christos 	  fprintf (fd, "\t%d [label=\"%s\"];\n",
    328      1.1  christos 		   node->nb_succs * id + i, cur_succ->node->val);
    329      1.1  christos 	  fprintf (fd, "\t%d -> %d;\n", id, node->nb_succs * id + i);
    330      1.1  christos 	  dump_graph_1 (fd, cur_succ->node, node->nb_succs * id + i);
    331      1.1  christos 	}
    332      1.1  christos       i += 1;
    333      1.1  christos       cur_succ = cur_succ->nxt;
    334      1.1  christos     }
    335      1.1  christos }
    336      1.1  christos 
    337      1.1  christos __attribute__((unused))
    338      1.1  christos static void
    339      1.1  christos dump_graph (char *name, char *path, struct node_s *node)
    340      1.1  christos {
    341      1.1  christos   FILE *fd = fopen (path, "w");
    342      1.1  christos   fprintf (fd, "digraph %s {\n", name);
    343      1.1  christos 
    344      1.1  christos   dump_graph_1 (fd, node, 1);
    345      1.1  christos 
    346      1.1  christos   fprintf (fd, "}\n");
    347      1.1  christos   fclose (fd);
    348      1.1  christos }
    349      1.1  christos 
    350      1.1  christos __attribute__((unused))
    351      1.1  christos static void
    352      1.1  christos print_n (const char *str, int n)
    353      1.1  christos {
    354      1.1  christos   for (int i = 0 ; i < n ; ++i)
    355      1.1  christos     putchar (str[i]);
    356      1.1  christos   putchar('\n');
    357      1.1  christos }
    358      1.1  christos 
    359      1.1  christos 
    360      1.1  christos int debug_level = 0;
    362      1.1  christos 
    363      1.1  christos __attribute__((unused))
    364      1.1  christos static int
    365      1.1  christos printf_debug (int lvl, const char *fmt, ...)
    366      1.1  christos {
    367      1.1  christos   int ret = 0;
    368      1.1  christos   if (debug_level >= lvl)
    369      1.1  christos     {
    370      1.1  christos       va_list args;
    371      1.1  christos       va_start (args, fmt);
    372      1.1  christos       ret = vprintf (fmt, args);
    373      1.1  christos       va_end (args);
    374      1.1  christos     }
    375      1.1  christos 
    376      1.1  christos   return ret;
    377      1.1  christos }
    378      1.1  christos 
    379      1.1  christos static int
    380      1.1  christos is_delim (char c)
    381      1.1  christos {
    382      1.1  christos   char delims[] = { '[', ']', '?', ',', '=' };
    383      1.1  christos   int nb_delims = sizeof (delims) / (sizeof (*delims));
    384      1.1  christos   for (int i = 0; i < nb_delims; ++i)
    385      1.1  christos     if (c == delims[i])
    386      1.1  christos       return 1;
    387      1.1  christos   return 0;
    388      1.1  christos }
    389      1.1  christos 
    390      1.1  christos __attribute__((unused))
    391      1.1  christos static void
    392      1.1  christos print_token (struct token_s token, char *buf, int bufsz)
    393      1.1  christos {
    394      1.1  christos   for (int i = 0; i < token.end - token.begin && i < bufsz; ++i)
    395      1.1  christos     buf[i] = token.insn[token.begin + i];
    396      1.1  christos   for (int i = token.end - token.begin ; i < bufsz; ++i)
    397      1.1  christos     buf[i] = 0;
    398      1.1  christos }
    399      1.1  christos 
    400      1.1  christos static int64_t
    401      1.1  christos promote_token (struct token_s tok)
    402      1.1  christos {
    403      1.1  christos   int64_t cur_class = tok.class_id & -tok.class_id;
    404      1.1  christos   switch (tok.category)
    405      1.1  christos     {
    406      1.1  christos       case CAT_REGISTER:
    407      1.1  christos       case CAT_MODIFIER:
    408      1.1  christos 	return (cur_class != tok.class_id)
    409      1.1  christos 	  ? tok.class_id ^ cur_class
    410  1.1.1.2  christos 	  : tok.class_id;
    411      1.1  christos       case CAT_IMMEDIATE:
    412      1.1  christos 	{
    413      1.1  christos 	  expressionS exp;
    414      1.1  christos 	  char *ilp_save = input_line_pointer;
    415  1.1.1.2  christos 	  input_line_pointer = tok.insn + tok.begin;
    416  1.1.1.2  christos 	  expression (&exp);
    417  1.1.1.2  christos 	  input_line_pointer = ilp_save;
    418  1.1.1.2  christos 	  uint64_t val = tok.val;
    419  1.1.1.2  christos 	  uint64_t pval = ((int64_t) val) < 0 ? -val : val;
    420  1.1.1.2  christos 	  int neg_power2_p = ((int64_t) val) < 0 && !(pval & (pval - 1));
    421  1.1.1.2  christos 	  struct token_class *class = env.token_classes->imm_classes;
    422  1.1.1.2  christos 	  unsigned len = pval ? 8 * sizeof (pval) - __builtin_clzll (pval) : 0;
    423  1.1.1.2  christos 
    424  1.1.1.2  christos 	  /* Find the imm class */
    425  1.1.1.2  christos 	  int imm_idx = 0;
    426  1.1.1.2  christos 	  for (imm_idx = 0 ; class[imm_idx].class_id ; ++imm_idx)
    427  1.1.1.2  christos 	    if (class[imm_idx].class_id == tok.class_id)
    428  1.1.1.2  christos 	      break;
    429  1.1.1.2  christos 
    430  1.1.1.2  christos 	  while (class[imm_idx + 1].class_id != -1
    431  1.1.1.2  christos 	      && ((unsigned int) (class[imm_idx + 1].sz < 0 ? - class[imm_idx + 1].sz - !neg_power2_p : class[imm_idx + 1].sz) < len
    432  1.1.1.2  christos 		 || (exp.X_op == O_symbol && !has_relocation_of_size (str_hash_find (env.reloc_hash, TOKEN_NAME (class[imm_idx + 1].class_id))))
    433  1.1.1.2  christos 		 || (exp.X_op == 64 && !kvx_get_pseudo_func2 (exp.X_op_symbol, str_hash_find (env.reloc_hash, TOKEN_NAME (class[imm_idx + 1].class_id))))))
    434      1.1  christos 	    imm_idx += 1;
    435      1.1  christos 
    436      1.1  christos 	  return class[imm_idx + 1].class_id == -1 ? class[imm_idx].class_id : class[imm_idx + 1].class_id;
    437      1.1  christos 	}
    438      1.1  christos       default:
    439      1.1  christos 	return tok.class_id;
    440      1.1  christos     }
    441      1.1  christos }
    442      1.1  christos 
    443      1.1  christos static int
    444      1.1  christos is_insn (const struct token_s *token, struct token_class *classes)
    445      1.1  christos {
    446      1.1  christos   int res = false;
    447      1.1  christos   int i = 0;
    448      1.1  christos   int tok_sz = token->end - token->begin;
    449      1.1  christos   char *tok = token->insn + token->begin;
    450      1.1  christos   while (!res && classes[i].class_values != NULL)
    451      1.1  christos     {
    452      1.1  christos       res = !strncmp (classes[i].class_values[0], tok, tok_sz);
    453      1.1  christos       i += 1;
    454      1.1  christos     }
    455      1.1  christos 
    456      1.1  christos   return res;
    457      1.1  christos }
    458      1.1  christos 
    459      1.1  christos static int64_t
    460      1.1  christos get_token_class (struct token_s *token, struct token_classes *classes, int insn_p, int modifier_p)
    461  1.1.1.2  christos {
    462      1.1  christos   int cur = 0;
    463  1.1.1.2  christos   int found = 0;
    464      1.1  christos   size_t tok_sz = token->end - token->begin;
    465      1.1  christos   char *tok = token->insn + token->begin;
    466      1.1  christos   expressionS exp;
    467      1.1  christos 
    468      1.1  christos   token->val = 0;
    469      1.1  christos   int token_val_p = 0;
    470      1.1  christos 
    471      1.1  christos   struct token_class *class;
    472      1.1  christos   if (tok[0] == '$')
    473      1.1  christos     {
    474      1.1  christos       class = classes->reg_classes;
    475      1.1  christos       token->category = CAT_REGISTER;
    476      1.1  christos     }
    477      1.1  christos   else if (modifier_p && tok[0] == '.')
    478      1.1  christos     {
    479      1.1  christos       class = classes->mod_classes;
    480      1.1  christos       token->category = CAT_MODIFIER;
    481      1.1  christos     }
    482      1.1  christos   else if (isdigit (tok[0]) || tok[0] == '+' || tok[0] == '-')
    483      1.1  christos     {
    484      1.1  christos       class = classes->imm_classes;
    485      1.1  christos       token->category = CAT_IMMEDIATE;
    486  1.1.1.2  christos       char *ilp_save = input_line_pointer;
    487      1.1  christos       input_line_pointer = tok;
    488      1.1  christos       expression (&exp);
    489      1.1  christos       token->end = token->begin + (input_line_pointer - tok);
    490      1.1  christos       token->val = exp.X_add_number;
    491      1.1  christos       token_val_p = 1;
    492      1.1  christos       input_line_pointer = ilp_save;
    493      1.1  christos     }
    494      1.1  christos   else if (tok_sz == 1 && is_delim (tok[0]))
    495      1.1  christos     {
    496      1.1  christos       class = classes->sep_classes;
    497      1.1  christos       token->category = CAT_SEPARATOR;
    498      1.1  christos     }
    499      1.1  christos   else if (insn_p && is_insn (token, classes->insn_classes))
    500      1.1  christos     {
    501      1.1  christos       class = classes->insn_classes;
    502      1.1  christos       token->category = CAT_INSTRUCTION;
    503      1.1  christos     }
    504      1.1  christos   else
    505      1.1  christos     {
    506      1.1  christos       /* We are in fact dealing with a symbol.  */
    507      1.1  christos       class = classes->imm_classes;
    508      1.1  christos       token->category = CAT_IMMEDIATE;
    509      1.1  christos 
    510      1.1  christos       char *ilp_save = input_line_pointer;
    511      1.1  christos       input_line_pointer = tok;
    512      1.1  christos       expression (&exp);
    513      1.1  christos 
    514      1.1  christos       /* If the symbol can be resolved easily takes it value now.  Otherwise it
    515      1.1  christos          means that is either a symbol which will need a real relocation or an
    516      1.1  christos          internal fixup (ie, a pseudo-function, or a computation on symbols).  */
    517      1.1  christos       if (exp.X_op != O_symbol && exp.X_op != O_pseudo_fixup)
    518      1.1  christos 	{
    519      1.1  christos 	  token->val = exp.X_add_number;
    520      1.1  christos 	  token_val_p = 1;
    521      1.1  christos 	}
    522      1.1  christos 
    523      1.1  christos       input_line_pointer = ilp_save;
    524      1.1  christos     }
    525      1.1  christos 
    526      1.1  christos   if (class == classes->imm_classes)
    527      1.1  christos     {
    528      1.1  christos       uint64_t uval
    529      1.1  christos 	= (token_val_p
    530      1.1  christos 	   ? token->val
    531  1.1.1.2  christos 	   : strtoull (tok + (tok[0] == '-') + (tok[0] == '+'), NULL, 0));
    532      1.1  christos       int64_t val = uval;
    533      1.1  christos       int64_t pval = val < 0 ? -uval : uval;
    534      1.1  christos       int neg_power2_p = val < 0 && !(pval & (pval - 1));
    535      1.1  christos       unsigned len = pval ? 8 * sizeof (pval) - __builtin_clzll (pval) : 0;
    536      1.1  christos       while (class[cur].class_id != -1
    537      1.1  christos 	     && ((unsigned) (class[cur].sz < 0
    538      1.1  christos 			     ? -class[cur].sz - !neg_power2_p
    539      1.1  christos 			     : class[cur].sz) < len
    540      1.1  christos 		 || (exp.X_op == O_symbol
    541      1.1  christos 		     && !(has_relocation_of_size
    542      1.1  christos 			  (str_hash_find (env.reloc_hash,
    543      1.1  christos 					  TOKEN_NAME (class[cur].class_id)))))
    544      1.1  christos 		 || (exp.X_op == O_pseudo_fixup
    545      1.1  christos 		     && !(kvx_get_pseudo_func2
    546      1.1  christos 			  (exp.X_op_symbol,
    547      1.1  christos 			   str_hash_find (env.reloc_hash,
    548      1.1  christos 					  TOKEN_NAME (class[cur].class_id)))))))
    549      1.1  christos 	++cur;
    550      1.1  christos 
    551      1.1  christos       token->val = uval;
    552      1.1  christos //      if (exp.X_op == O_pseudo_fixup)
    553      1.1  christos //	  token->val = (uintptr_t) !kvx_get_pseudo_func2 (exp.X_op_symbol, str_hash_find (env.reloc_hash, TOKEN_NAME (class[cur].class_id)));
    554      1.1  christos       found = 1;
    555      1.1  christos     }
    556      1.1  christos   else
    557      1.1  christos     {
    558      1.1  christos       do
    559      1.1  christos 	{
    560  1.1.1.2  christos 	  for (int i = 0; !found && i < class[cur].sz; ++i)
    561      1.1  christos 	    {
    562      1.1  christos 	      const char *ref = class[cur].class_values[i];
    563      1.1  christos 	      found = (strlen (ref) == tok_sz) && !strncmp (tok, ref, tok_sz);
    564      1.1  christos 	      token->val = i;
    565      1.1  christos 	    }
    566      1.1  christos 
    567      1.1  christos 	  cur += !(found);
    568      1.1  christos 	}
    569      1.1  christos       while (!found && class[cur].class_id != -1);
    570      1.1  christos     }
    571      1.1  christos 
    572      1.1  christos   if (!found)
    573      1.1  christos     {
    574      1.1  christos       token->category = CAT_IMMEDIATE;
    575      1.1  christos       return token->class_id = classes->imm_classes[0].class_id;
    576      1.1  christos     }
    577      1.1  christos 
    578      1.1  christos #define unset(w, rg) ((w) & (~(1ULL << ((rg) - env.fst_reg))))
    579      1.1  christos   if (class == classes->reg_classes && !env.opts.allow_all_sfr)
    580      1.1  christos     return token->class_id = unset (class[cur].class_id, env.sys_reg);
    581      1.1  christos #undef unset
    582      1.1  christos 
    583      1.1  christos   return token->class_id = class[cur].class_id;
    584      1.1  christos }
    585      1.1  christos 
    586      1.1  christos static int
    587      1.1  christos read_token (struct token_s *tok)
    588      1.1  christos {
    589      1.1  christos   int insn_p = tok->begin == 0;
    590      1.1  christos   int modifier_p = 0;
    591  1.1.1.2  christos   char *str = tok->insn;
    592  1.1.1.2  christos   int *begin = &tok->begin;
    593  1.1.1.2  christos   int *end = &tok->end;
    594  1.1.1.2  christos   int last_imm_p = 0;
    595  1.1.1.2  christos 
    596  1.1.1.2  christos   /* Was the last previous token was an immediate?  */
    597  1.1.1.2  christos   for (int i = 1; *begin - i > 0; ++i)
    598  1.1.1.2  christos     {
    599  1.1.1.2  christos       if ('0' <= str[*begin - i] && str[*begin - i] <= '9')
    600  1.1.1.2  christos 	last_imm_p = 1;
    601      1.1  christos       else if (!is_whitespace (str[*begin - i]))
    602      1.1  christos 	break;
    603  1.1.1.2  christos     }
    604      1.1  christos 
    605      1.1  christos   /* Eat up all leading spaces.  */
    606      1.1  christos   while (str[*begin] && (is_whitespace (str[*begin]) || str[*begin] == '\n'))
    607      1.1  christos     *begin += 1;
    608      1.1  christos 
    609      1.1  christos   *end = *begin;
    610      1.1  christos 
    611      1.1  christos   if (!str[*begin])
    612      1.1  christos     return 0;
    613      1.1  christos 
    614      1.1  christos   /* Special case, we're reading an instruction. Try to read as much as possible
    615      1.1  christos      as long as the prefix is a valid instruction.  */
    616      1.1  christos   if (insn_p)
    617      1.1  christos     *end += longest_match (str + *begin, strlen (str + *begin), env.insns);
    618      1.1  christos   else
    619      1.1  christos     {
    620      1.1  christos       if (is_delim (str[*begin]))
    621      1.1  christos       {
    622      1.1  christos 	*end += 1;
    623      1.1  christos 	get_token_class (tok, env.token_classes, insn_p, modifier_p);
    624  1.1.1.2  christos 	return 1;
    625  1.1.1.2  christos       }
    626  1.1.1.2  christos 
    627  1.1.1.2  christos       if (str[*begin] == '.'
    628  1.1.1.2  christos 	  && (!(*begin > 0
    629      1.1  christos 		&& (is_whitespace (str[*begin - 1])
    630      1.1  christos 		    || is_delim (str[*begin - 1])))
    631      1.1  christos 	    || last_imm_p))
    632      1.1  christos 	modifier_p = 1;
    633      1.1  christos 
    634      1.1  christos       /* This is a modifier or a register */
    635      1.1  christos       if (str[*begin] == '.' || str[*begin] == '$')
    636  1.1.1.2  christos 	*end += 1;
    637  1.1.1.2  christos 
    638      1.1  christos       /* Stop when reaching the start of the new token. */
    639      1.1  christos       while (!(!str[*end] || is_delim (str[*end]) || is_whitespace (str[*end])
    640      1.1  christos 	     || (modifier_p && str[*end] == '.')))
    641      1.1  christos 	*end += 1;
    642      1.1  christos 
    643      1.1  christos     }
    644      1.1  christos 
    645      1.1  christos   get_token_class (tok, env.token_classes, insn_p, modifier_p);
    646      1.1  christos   return 1;
    647      1.1  christos }
    648      1.1  christos 
    649      1.1  christos /* Rewrite with as_bad. */
    650      1.1  christos static void
    651      1.1  christos rule_expect_error (int rule_id, char *buf, int bufsz __attribute__((unused)))
    652      1.1  christos {
    653      1.1  christos   int i = 0;
    654      1.1  christos   int pos = 0;
    655      1.1  christos   int comma = 0;
    656      1.1  christos   pos += sprintf (buf + pos, "expected one of [");
    657      1.1  christos   struct steering_rule *rules = env.rules[rule_id].rules;
    658      1.1  christos   while (rules[i].steering != -1)
    659      1.1  christos     {
    660      1.1  christos       if ((env.opts.allow_all_sfr || rules[i].steering != env.sys_reg)
    661      1.1  christos 	  && rules[i].steering != -3)
    662      1.1  christos 	{
    663      1.1  christos 	  pos += sprintf (buf + pos, "%s%s", comma ? ", " : "", TOKEN_NAME (rules[i].steering));
    664      1.1  christos 	  comma = 1;
    665      1.1  christos 	}
    666      1.1  christos       i += 1;
    667      1.1  christos     }
    668      1.1  christos   pos += sprintf (buf + pos, "].");
    669      1.1  christos }
    670      1.1  christos 
    671      1.1  christos static struct token_list *
    672  1.1.1.2  christos create_token (struct token_s tok, int len, int loc)
    673      1.1  christos {
    674      1.1  christos   struct token_list *tl = calloc (1, sizeof *tl);
    675      1.1  christos   size_t tok_sz = tok.end - tok.begin;
    676      1.1  christos   tl->tok = calloc (tok_sz + 1, sizeof (char));
    677      1.1  christos   memcpy (tl->tok, tok.insn + tok.begin, tok_sz * sizeof (char));
    678      1.1  christos   tl->val = tok.val;
    679      1.1  christos   tl->class_id = tok.class_id;
    680      1.1  christos   tl->category = tok.category;
    681      1.1  christos   tl->next = NULL;
    682      1.1  christos   tl->len = len;
    683      1.1  christos   tl->loc = loc;
    684      1.1  christos   return tl;
    685      1.1  christos }
    686      1.1  christos 
    687      1.1  christos void
    688      1.1  christos print_token_list (struct token_list *lst)
    689      1.1  christos {
    690  1.1.1.2  christos   struct token_list *cur = lst;
    691      1.1  christos   while (cur)
    692      1.1  christos     {
    693      1.1  christos       printf_debug (0, "%s (%llu : %s : %llu) / ",
    694  1.1.1.2  christos 	      cur->tok, cur->val, TOKEN_NAME (cur->class_id), cur->loc);
    695      1.1  christos       cur = cur->next;
    696      1.1  christos     }
    697      1.1  christos   printf_debug (0, "\n");
    698      1.1  christos }
    699      1.1  christos 
    700      1.1  christos void
    701      1.1  christos free_token_list (struct token_list *tok_list)
    702      1.1  christos {
    703      1.1  christos   struct token_list *cur = tok_list;
    704      1.1  christos   struct token_list *tmp;
    705      1.1  christos   while (cur)
    706      1.1  christos     {
    707      1.1  christos       tmp = cur->next;
    708      1.1  christos       free (cur->tok);
    709      1.1  christos       free (cur);
    710      1.1  christos       cur = tmp;
    711      1.1  christos     }
    712      1.1  christos }
    713      1.1  christos 
    714      1.1  christos static struct token_list *
    715      1.1  christos token_list_append (struct token_list *lst1, struct token_list *lst2)
    716      1.1  christos {
    717      1.1  christos   if (lst1 == NULL)
    718      1.1  christos     return lst2;
    719      1.1  christos 
    720      1.1  christos   if (lst2 == NULL)
    721      1.1  christos     return NULL;
    722      1.1  christos 
    723      1.1  christos   struct token_list *hd = lst1;
    724      1.1  christos   while (hd->next)
    725      1.1  christos     {
    726      1.1  christos       hd->len += lst2->len;
    727      1.1  christos       hd = hd->next;
    728      1.1  christos     }
    729      1.1  christos 
    730      1.1  christos   hd->len += lst2->len;
    731      1.1  christos   hd->next = lst2;
    732      1.1  christos   return lst1;
    733      1.1  christos }
    734      1.1  christos 
    735      1.1  christos struct error_list
    736      1.1  christos {
    737      1.1  christos   int loc, rule;
    738      1.1  christos   struct error_list *nxt;
    739      1.1  christos };
    740      1.1  christos 
    741      1.1  christos static struct error_list *
    742      1.1  christos error_list_insert (int rule, int loc, struct error_list *nxt)
    743      1.1  christos {
    744      1.1  christos   struct error_list *n = calloc (1, sizeof (*n));
    745      1.1  christos   n->loc = loc > 0 ? loc - 1 : loc;
    746      1.1  christos   n->rule = rule;
    747      1.1  christos   n->nxt = nxt;
    748      1.1  christos   return n;
    749      1.1  christos }
    750      1.1  christos 
    751      1.1  christos static void
    752      1.1  christos free_error_list (struct error_list *l)
    753      1.1  christos {
    754      1.1  christos   struct error_list *tmp, *cur_err = l;
    755      1.1  christos   while ((tmp = cur_err))
    756      1.1  christos   {
    757      1.1  christos     cur_err = cur_err->nxt;
    758      1.1  christos     free (tmp);
    759      1.1  christos   }
    760      1.1  christos }
    761      1.1  christos 
    762      1.1  christos static int
    763      1.1  christos CLASS_ID (struct token_s tok)
    764      1.1  christos {
    765      1.1  christos   int offset = __builtin_ctzll (tok.class_id & -tok.class_id);
    766      1.1  christos   switch (tok.category)
    767      1.1  christos   {
    768      1.1  christos     case CAT_REGISTER:
    769      1.1  christos       return env.fst_reg + offset;
    770      1.1  christos     case CAT_MODIFIER:
    771      1.1  christos       return env.fst_mod + offset;
    772      1.1  christos     default:
    773      1.1  christos       return tok.class_id;
    774      1.1  christos   }
    775      1.1  christos }
    776      1.1  christos 
    777      1.1  christos struct parser {
    778      1.1  christos 
    779      1.1  christos };
    780      1.1  christos 
    781      1.1  christos static struct token_list *
    782      1.1  christos parse_with_restarts (struct token_s tok, int jump_target, struct rule rules[],
    783      1.1  christos 		     struct error_list **errs)
    784      1.1  christos {
    785      1.1  christos   int end_of_line = 0;
    786      1.1  christos   struct steering_rule *cur_rule = rules[jump_target].rules;
    787      1.1  christos 
    788      1.1  christos   if (!tok.insn[tok.begin])
    789      1.1  christos     tok.class_id = -3;
    790      1.1  christos 
    791      1.1  christos   if (CLASS_ID (tok) == -1)
    792      1.1  christos     {
    793      1.1  christos       /* Unknown token */
    794      1.1  christos       *errs = error_list_insert (jump_target, tok.begin, *errs);
    795      1.1  christos       return NULL;
    796      1.1  christos     }
    797      1.1  christos 
    798      1.1  christos   printf_debug (1, "\nEntering rule: %d (Trying to match: (%s)[%d])\n",
    799      1.1  christos 		jump_target, TOKEN_NAME (CLASS_ID (tok)), CLASS_ID (tok));
    800      1.1  christos 
    801      1.1  christos   /* 1. Find a rule that can be used with the current token. */
    802      1.1  christos   int i = 0;
    803      1.1  christos   while (cur_rule[i].steering != -1 && cur_rule[i].steering != CLASS_ID (tok))
    804      1.1  christos     i += 1;
    805      1.1  christos 
    806      1.1  christos   printf_debug (1, "steering: %d (%s), jump_target: %d, stack_it: %d\n",
    807      1.1  christos 		cur_rule[i].steering, TOKEN_NAME (cur_rule[i].steering),
    808      1.1  christos 		cur_rule[i].jump_target, cur_rule[i].stack_it);
    809      1.1  christos 
    810      1.1  christos   struct token_s init_tok = tok;
    811      1.1  christos retry:;
    812      1.1  christos       tok = init_tok;
    813      1.1  christos   if (cur_rule[i].jump_target == -2 && cur_rule[i].stack_it == -2)
    814      1.1  christos     {
    815      1.1  christos       /* We're reading eps. */
    816      1.1  christos       printf_debug (1, "successfully ignored: %s\n", TOKEN_NAME (jump_target));
    817      1.1  christos       struct token_s tok_ =
    818      1.1  christos       { (char *)".", 0, 1, CAT_MODIFIER, jump_target, 0 };
    819      1.1  christos       return create_token (tok_, 0, tok.begin);
    820      1.1  christos     }
    821      1.1  christos   else if (cur_rule[i].jump_target == -1 && cur_rule[i].stack_it == -1)
    822      1.1  christos     {
    823      1.1  christos       /* We're handling the rule for a terminal (not eps) */
    824      1.1  christos       if (cur_rule[i].steering == CLASS_ID (tok))
    825      1.1  christos 	  // && tok.begin != tok.end) -- only fails when eps is last, eg. fence.
    826      1.1  christos 	{
    827      1.1  christos 	  /* We matched a token */
    828      1.1  christos 	  printf_debug (1, "matched %s\n", TOKEN_NAME (CLASS_ID (tok)));
    829      1.1  christos 	  tok.class_id = CLASS_ID (tok);
    830      1.1  christos 	  return create_token (tok, 1, tok.begin);
    831      1.1  christos 	}
    832      1.1  christos       else
    833      1.1  christos 	{
    834      1.1  christos 	  /* This is a mandatory modifier */
    835      1.1  christos 	  *errs = error_list_insert (jump_target, tok.begin, *errs);
    836      1.1  christos 	  return NULL;
    837      1.1  christos 	}
    838      1.1  christos     }
    839      1.1  christos 
    840      1.1  christos   /* Not on a terminal */
    841      1.1  christos   struct token_list *fst_part =
    842      1.1  christos     parse_with_restarts (tok, cur_rule[i].jump_target, rules, errs);
    843      1.1  christos   /* While parsing fails but there is hope since the current token can be
    844      1.1  christos      promoted.  */
    845      1.1  christos   while (!fst_part && tok.class_id != (int64_t) promote_token (tok))
    846      1.1  christos     {
    847      1.1  christos       free_token_list (fst_part);
    848      1.1  christos       tok.class_id = promote_token (tok);
    849      1.1  christos       printf_debug (1, "> Restart with %s?\n", TOKEN_NAME (CLASS_ID (tok)));
    850      1.1  christos       fst_part = parse_with_restarts (tok, cur_rule[i].jump_target, rules, errs);
    851      1.1  christos     };
    852      1.1  christos 
    853      1.1  christos   if (!fst_part)
    854      1.1  christos     {
    855      1.1  christos       i += 1;
    856      1.1  christos       while (cur_rule[i].steering != CLASS_ID(tok) && cur_rule[i].steering != -1)
    857      1.1  christos 	i += 1;
    858      1.1  christos       if (cur_rule[i].steering != -1)
    859      1.1  christos 	goto retry;
    860      1.1  christos     }
    861      1.1  christos 
    862      1.1  christos   if (!fst_part)
    863      1.1  christos     {
    864      1.1  christos       printf_debug (1, "fst_part == NULL (Exiting %d)\n", jump_target);
    865      1.1  christos       return NULL;
    866      1.1  christos     }
    867      1.1  christos 
    868      1.1  christos   for (int _ = 0; _ < fst_part->len; ++_)
    869      1.1  christos     {
    870      1.1  christos       tok.begin = tok.end;
    871      1.1  christos       end_of_line = !read_token (&tok);
    872      1.1  christos     }
    873      1.1  christos 
    874      1.1  christos   if (end_of_line && cur_rule[i].stack_it == -1)
    875      1.1  christos     {
    876      1.1  christos       /* No more tokens and no more place to go */
    877      1.1  christos       printf_debug (1, "return fst_part.\n");
    878      1.1  christos       return fst_part;
    879      1.1  christos     }
    880      1.1  christos   else if (!end_of_line && cur_rule[i].stack_it == -1)
    881      1.1  christos     {
    882      1.1  christos       /* Too much tokens. */
    883      1.1  christos       printf_debug (1, "too much tokens\n");
    884      1.1  christos       *errs = error_list_insert (cur_rule[i].stack_it, tok.begin, *errs);
    885      1.1  christos       return NULL;
    886      1.1  christos     }
    887      1.1  christos   else if (cur_rule[i].stack_it == -1)
    888      1.1  christos     {
    889      1.1  christos       printf_debug (1, "return fst_part. (end of rule)\n");
    890      1.1  christos       return fst_part;
    891      1.1  christos     }
    892      1.1  christos 
    893      1.1  christos   printf_debug (1, "snd_part: Trying to match: %s\n", TOKEN_NAME (CLASS_ID (tok)));
    894      1.1  christos   struct token_list *snd_part = parse_with_restarts (tok, cur_rule[i].stack_it, rules, errs);
    895      1.1  christos   while (!snd_part && tok.class_id != (int64_t) promote_token (tok))
    896      1.1  christos     {
    897      1.1  christos       tok.class_id = promote_token (tok);
    898      1.1  christos       printf_debug (1, ">> Restart with %s?\n", TOKEN_NAME (CLASS_ID (tok)));
    899      1.1  christos       snd_part = parse_with_restarts (tok, cur_rule[i].stack_it, rules, errs);
    900      1.1  christos     }
    901      1.1  christos 
    902      1.1  christos   if (!snd_part)
    903      1.1  christos     {
    904      1.1  christos       free_token_list (fst_part);
    905      1.1  christos       i += 1;
    906      1.1  christos       tok = init_tok;
    907      1.1  christos       while (cur_rule[i].steering != CLASS_ID (tok) && cur_rule[i].steering != -1)
    908      1.1  christos 	i += 1;
    909      1.1  christos       if (cur_rule[i].steering != -1)
    910      1.1  christos 	goto retry;
    911      1.1  christos     }
    912      1.1  christos 
    913      1.1  christos   if (!snd_part)
    914      1.1  christos     {
    915      1.1  christos       printf_debug (1, "snd_part == NULL (Exiting %d)\n", jump_target);
    916      1.1  christos       return NULL;
    917      1.1  christos     }
    918      1.1  christos 
    919      1.1  christos   printf_debug (1, "Exiting rule: %d\n", jump_target,
    920      1.1  christos 		TOKEN_NAME (CLASS_ID (tok)), tok.class_id);
    921      1.1  christos 
    922      1.1  christos   /* Combine fst & snd parts */
    923      1.1  christos   return token_list_append (fst_part, snd_part);
    924      1.1  christos }
    925      1.1  christos 
    926      1.1  christos /* During the parsing the modifiers and registers are handled through pseudo
    927      1.1  christos    classes such that each register and modifier appears in at most one pseudo
    928      1.1  christos    class.  Since the pseudo-classes are not correlated with how the modifiers
    929      1.1  christos    and registers are encoded we fix that after a successful match instead of
    930      1.1  christos    updating it many times during the parsing.
    931      1.1  christos 
    932      1.1  christos    Currently, only assigning correct values to modifiers is of interest.  The
    933      1.1  christos    real value of registers is computed in tc-kvx.c:insert_operand.  */
    934      1.1  christos 
    935      1.1  christos static void
    936      1.1  christos assign_final_values (struct token_list *lst)
    937      1.1  christos {
    938      1.1  christos   (void) lst;
    939      1.1  christos   struct token_list *cur = lst;
    940      1.1  christos 
    941      1.1  christos   while (cur)
    942      1.1  christos     {
    943      1.1  christos       if (cur->category == CAT_MODIFIER)
    944      1.1  christos 	{
    945      1.1  christos 	  int idx = cur->class_id - env.fst_mod;
    946      1.1  christos 	  int found = 0;
    947      1.1  christos 	  for (int i = 0 ; !found && kvx_modifiers[idx][i]; ++i)
    948      1.1  christos 	    if ((found = !strcmp (cur->tok, kvx_modifiers[idx][i])))
    949      1.1  christos 	      cur->val = i;
    950      1.1  christos 	}
    951      1.1  christos       cur = cur->next;
    952      1.1  christos     }
    953      1.1  christos }
    954      1.1  christos 
    955      1.1  christos struct token_list *
    956      1.1  christos parse (struct token_s tok)
    957      1.1  christos {
    958      1.1  christos   int error_code = 0;
    959      1.1  christos   int error_char = 0;
    960      1.1  christos   struct error_list *errs = NULL;
    961      1.1  christos   read_token (&tok);
    962      1.1  christos 
    963      1.1  christos   struct token_list *tok_list =
    964      1.1  christos     parse_with_restarts (tok, 0, env.rules, &errs);
    965      1.1  christos 
    966      1.1  christos   if (!tok_list)
    967      1.1  christos     {
    968      1.1  christos       struct error_list *cur_err = errs;
    969      1.1  christos       while (cur_err)
    970      1.1  christos 	{
    971      1.1  christos 	  if (cur_err->loc > error_char)
    972      1.1  christos 	    {
    973      1.1  christos 	      error_char = cur_err->loc;
    974      1.1  christos 	      error_code = cur_err->rule;
    975      1.1  christos 	    }
    976      1.1  christos 	  cur_err = cur_err->nxt;
    977      1.1  christos 	}
    978      1.1  christos     }
    979      1.1  christos 
    980      1.1  christos   free_error_list (errs);
    981      1.1  christos 
    982      1.1  christos   if (!tok_list)
    983      1.1  christos     {
    984      1.1  christos       if (error_code != -1)
    985      1.1  christos 	{
    986      1.1  christos 	  char buf[256] = { 0 };
    987      1.1  christos 	  const char * msg = "Unexpected token when parsing %s.";
    988      1.1  christos 	    for (int i = 0; i < (int) (strlen (msg) + error_char + 1 - 4) ; ++i)
    989      1.1  christos 	      buf[i] = ' ';
    990      1.1  christos 	    buf[strlen (msg) + error_char + 1 - 4] = '^';
    991      1.1  christos 	  as_bad (msg, tok.insn);
    992      1.1  christos 	  if (env.opts.diagnostics)
    993      1.1  christos 	    {
    994      1.1  christos 	      as_bad ("%s", buf);
    995      1.1  christos 	      char err_buf[10000] = { 0 };
    996      1.1  christos 	      rule_expect_error (error_code, err_buf, 10000);
    997      1.1  christos 	      as_bad ("%s", err_buf);
    998      1.1  christos 	    }
    999      1.1  christos 	}
   1000      1.1  christos       else
   1001      1.1  christos 	{
   1002      1.1  christos 	  char buf[256] = { 0 };
   1003      1.1  christos 	  const char * msg = "Extra token when parsing %s.";
   1004      1.1  christos 	    for (int i = 0; i < (int) (strlen (msg) + error_char + 1 - 4) ; ++i)
   1005      1.1  christos 	      buf[i] = ' ';
   1006      1.1  christos 	    buf[strlen (msg) + error_char + 1 - 4] = '^';
   1007      1.1  christos 	  as_bad (msg, tok.insn);
   1008      1.1  christos 	  if (env.opts.diagnostics)
   1009      1.1  christos 	    as_bad ("%s\n", buf);
   1010      1.1  christos 	}
   1011      1.1  christos     }
   1012      1.1  christos   else
   1013      1.1  christos     {
   1014      1.1  christos       printf_debug (1, "[PASS] Successfully matched %s\n", tok.insn);
   1015      1.1  christos       assign_final_values (tok_list);
   1016      1.1  christos //      print_token_list (tok_list);
   1017      1.1  christos //      free_token_list (tok_list);
   1018      1.1  christos     }
   1019      1.1  christos   return tok_list;
   1020      1.1  christos }
   1021      1.1  christos 
   1022      1.1  christos void
   1023      1.1  christos setup (int core)
   1024      1.1  christos {
   1025      1.1  christos   switch (core)
   1026      1.1  christos   {
   1027      1.1  christos   case ELF_KVX_CORE_KV3_1:
   1028      1.1  christos     setup_kv3_v1 ();
   1029      1.1  christos     break;
   1030      1.1  christos   case ELF_KVX_CORE_KV3_2:
   1031      1.1  christos     setup_kv3_v2 ();
   1032      1.1  christos     break;
   1033      1.1  christos   case ELF_KVX_CORE_KV4_1:
   1034      1.1  christos     setup_kv4_v1 ();
   1035      1.1  christos     break;
   1036      1.1  christos   default:
   1037      1.1  christos     as_bad ("Unknown architecture");
   1038      1.1  christos     abort ();
   1039      1.1  christos   }
   1040      1.1  christos 
   1041      1.1  christos   for (int i = 0; env.token_classes->insn_classes[i].class_values ; ++i)
   1042      1.1  christos     env.insns =
   1043      1.1  christos       insert (env.token_classes->insn_classes[i].class_values[0], env.insns);
   1044      1.1  christos }
   1045      1.1  christos 
   1046      1.1  christos void
   1047      1.1  christos cleanup ()
   1048                    {
   1049                      free_node (env.insns);
   1050                    }
   1051