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