Updated French translations for GOLD and LD
[binutils-gdb.git] / gas / config / kvx-parse.c
blob5cfb1fb676c85e6d099c778af3f9efa985dfb04d
1 /* kvx-parse.c -- Recursive decent parser driver for the KVX ISA
3 Copyright (C) 2009-2024 Free Software Foundation, Inc.
4 Contributed by Kalray SA.
6 This file is part of GAS.
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.
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.
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/>. */
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"
31 /* This is bad! */
32 struct node_list_s {
33 struct node_s *node;
34 struct node_list_s *nxt;
37 struct node_s {
38 char *val;
39 int len;
40 struct node_list_s *succs;
41 int nb_succs;
46 static int
47 has_relocation_of_size (const struct kvx_reloc **relocs)
49 const int symbol_size = env.params.arch_size;
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
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)
68 if (!relocs)
69 return 0;
71 struct kvx_reloc **relocs_it = (struct kvx_reloc **) relocs;
72 int has_only_one_p = relocs[0] && !relocs[1];
74 while (*relocs_it)
76 switch ((*relocs_it)->relative)
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;
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;
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;
98 relocs_it++;
101 return 0;
104 struct pseudo_func *
105 kvx_get_pseudo_func2 (symbolS * sym, struct kvx_reloc **relocs);
106 struct pseudo_func *
107 kvx_get_pseudo_func2 (symbolS *sym, struct kvx_reloc **relocs)
109 if (!relocs)
110 return NULL;
112 struct kvx_reloc **relocs_it = (struct kvx_reloc **) relocs;
114 for (int i = 0; i < 26; i++)
116 if (sym == kvx_core_info->pseudo_funcs[i].sym)
118 relocs_it = relocs;
119 while (*relocs_it)
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++;
130 return NULL;
133 /* Trie */
135 static
136 struct node_list_s *
137 insert_in_succ_list (struct node_s *node, struct node_s *base)
139 struct node_list_s *new_hd = NULL;
140 if (!(new_hd = calloc (1, sizeof (*new_hd))))
141 return NULL;
143 new_hd->node = node;
144 new_hd->nxt = base->succs;
145 base->nb_succs += 1;
146 return new_hd;
149 static
150 struct node_s *
151 make_node (const char *str, int len)
153 struct node_s *n = NULL;
154 if (!(n = calloc (1, sizeof (*n))))
155 goto err;
157 n->len = len;
158 n->succs = NULL;
159 if (!(n->val = calloc (n->len + 1, sizeof (*n->val))))
160 goto err1;
162 strncpy (n->val, str, n->len);
163 return n;
165 err1:
166 free (n), n = NULL;
167 err:
168 return NULL;
171 static
172 struct node_s *
173 insert (const char *str, struct node_s *node)
175 int i = 0;
176 int len = strlen (str);
178 if (!node)
180 struct node_s *n = make_node (str, len);
181 n->succs = insert_in_succ_list (NULL, n);
182 return n;
185 while (i < len && i < node->len && str[i] == node->val[i])
186 ++i;
188 /* The strings share a prefix. */
189 if (i < len && i < node->len)
191 /* Split the current node on that common prefix. */
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);
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;
211 /* str is a strict prefix of node->val */
212 if (i == len && i < node->len)
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;
228 /* node->val is a prefix of str */
229 if (i == node->len)
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)
235 struct node_s *n = cur_succ->node;
236 if (n && n->val && n->val[0] == str[i])
238 cur_succ->node = insert (str + i, cur_succ->node);
239 break;
241 cur_succ = cur_succ->nxt;
243 /* No successor shares a common prefix */
244 if (cur_succ == NULL)
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);
250 return node;
253 return node;
256 static
257 void
258 free_node (struct node_s *node)
260 if (!node)
261 return;
263 free (node->val);
265 struct node_list_s *cur_succ = node->succs;
266 struct node_list_s *tmp = NULL;
267 while ((tmp = cur_succ))
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);
276 free (node);
279 #define max(a,b) (((a)>(b))?(a):(b))
280 static
282 longest_match (const char *str, int len, struct node_s *node)
284 int i = 0;
285 int last_mark = 0;
286 struct node_s *cur = node;
288 while (1)
290 if (i + cur->len > len
291 || strncmp (str + i, cur->val, max(0, cur->len)))
292 return last_mark;
294 i += cur->len;
295 struct node_list_s *cur_succ = cur->succs;
296 cur = NULL;
297 while (cur_succ)
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;
306 if (!cur)
307 return last_mark;
311 __attribute__((unused))
312 static void
313 dump_graph_1 (FILE *fd, struct node_s *node, int id)
315 struct node_list_s *cur_succ = node->succs;
316 int i = 0;
318 if (id == 1)
319 fprintf (fd, "\t%d [label=\"%s\"];\n", id, node->val);
321 while (cur_succ)
323 if (cur_succ->node == NULL)
324 fprintf (fd, "\t%d -> \"()\";\n", id);
325 else
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);
332 i += 1;
333 cur_succ = cur_succ->nxt;
337 __attribute__((unused))
338 static void
339 dump_graph (char *name, char *path, struct node_s *node)
341 FILE *fd = fopen (path, "w");
342 fprintf (fd, "digraph %s {\n", name);
344 dump_graph_1 (fd, node, 1);
346 fprintf (fd, "}\n");
347 fclose (fd);
350 __attribute__((unused))
351 static void
352 print_n (const char *str, int n)
354 for (int i = 0 ; i < n ; ++i)
355 putchar (str[i]);
356 putchar('\n');
360 int debug_level = 0;
362 __attribute__((unused))
363 static int
364 printf_debug (int lvl, const char *fmt, ...)
366 int ret = 0;
367 if (debug_level >= lvl)
369 va_list args;
370 va_start (args, fmt);
371 ret = vprintf (fmt, args);
372 va_end (args);
375 return ret;
378 static int
379 is_delim (char c)
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;
389 __attribute__((unused))
390 static void
391 print_token (struct token_s token, char *buf, int bufsz)
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;
399 static int64_t
400 promote_token (struct token_s tok)
402 int64_t cur_class = tok.class_id & -tok.class_id;
403 switch (tok.category)
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:
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;
433 default:
434 return tok.class_id;
438 static int
439 is_insn (const struct token_s *token, struct token_class *classes)
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)
447 res = !strncmp (classes[i].class_values[0], tok, tok_sz);
448 i += 1;
451 return res;
454 static int64_t
455 get_token_class (struct token_s *token, struct token_classes *classes, int insn_p, int modifier_p)
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};
463 token->val = 0;
464 int token_val_p = 0;
466 struct token_class *class;
467 if (tok[0] == '$')
469 class = classes->reg_classes;
470 token->category = CAT_REGISTER;
472 else if (modifier_p && tok[0] == '.')
474 class = classes->mod_classes;
475 token->category = CAT_MODIFIER;
477 else if (isdigit (tok[0]) || tok[0] == '+' || tok[0] == '-')
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;
488 else if (tok_sz == 1 && is_delim (tok[0]))
490 class = classes->sep_classes;
491 token->category = CAT_SEPARATOR;
493 else if (insn_p && is_insn (token, classes->insn_classes))
495 class = classes->insn_classes;
496 token->category = CAT_INSTRUCTION;
498 else
500 /* We are in fact dealing with a symbol. */
501 class = classes->imm_classes;
502 token->category = CAT_IMMEDIATE;
504 char *ilp_save = input_line_pointer;
505 input_line_pointer = tok;
506 expression (&exp);
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)
513 token->val = exp.X_add_number;
514 token_val_p = 1;
517 input_line_pointer = ilp_save;
520 if (class == classes->imm_classes)
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;
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;
550 else
554 for (int i = 0; !found && i < class[cur].sz; ++i)
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;
561 cur += !(found);
563 while (!found && class[cur].class_id != -1);
566 if (!found)
568 token->category = CAT_IMMEDIATE;
569 return token->class_id = classes->imm_classes[0].class_id;
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
577 return token->class_id = class[cur].class_id;
580 static int
581 read_token (struct token_s *tok)
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;
589 /* Eat up all leading spaces. */
590 while (str[*begin] && (str[*begin] == ' ' || str[*begin] == '\n'))
591 *begin += 1;
593 *end = *begin;
595 if (!str[*begin])
596 return 0;
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
604 if (is_delim (str[*begin]))
606 *end += 1;
607 get_token_class (tok, env.token_classes, insn_p, modifier_p);
608 return 1;
611 if (str[*begin] == '.' && !(*begin > 0 && (str[*begin - 1] == ' ' || is_delim(str[*begin - 1]))))
612 modifier_p = 1;
614 /* This is a modifier or a register */
615 if (str[*begin] == '.' || str[*begin] == '$')
616 *end += 1;
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;
624 get_token_class (tok, env.token_classes, insn_p, modifier_p);
625 return 1;
628 /* Rewrite with as_bad. */
629 static void
630 rule_expect_error (int rule_id, char *buf, int bufsz __attribute__((unused)))
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)
639 if ((env.opts.allow_all_sfr || rules[i].steering != env.sys_reg)
640 && rules[i].steering != -3)
642 pos += sprintf (buf + pos, "%s%s", comma ? ", " : "", TOKEN_NAME (rules[i].steering));
643 comma = 1;
645 i += 1;
647 pos += sprintf (buf + pos, "].");
650 static struct token_list *
651 create_token (struct token_s tok, int len, int loc)
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;
666 void
667 print_token_list (struct token_list *lst)
669 struct token_list *cur = lst;
670 while (cur)
672 printf_debug (1, "%s (%d : %s : %d) / ",
673 cur->tok, cur->val, TOKEN_NAME (cur->class_id), cur->loc);
674 cur = cur->next;
676 printf_debug (1, "\n");
679 void
680 free_token_list (struct token_list *tok_list)
682 struct token_list *cur = tok_list;
683 struct token_list *tmp;
684 while (cur)
686 tmp = cur->next;
687 free (cur->tok);
688 free (cur);
689 cur = tmp;
693 static struct token_list *
694 token_list_append (struct token_list *lst1, struct token_list *lst2)
696 if (lst1 == NULL)
697 return lst2;
699 if (lst2 == NULL)
700 return NULL;
702 struct token_list *hd = lst1;
703 while (hd->next)
705 hd->len += lst2->len;
706 hd = hd->next;
709 hd->len += lst2->len;
710 hd->next = lst2;
711 return lst1;
714 struct error_list
716 int loc, rule;
717 struct error_list *nxt;
720 static struct error_list *
721 error_list_insert (int rule, int loc, struct error_list *nxt)
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;
730 static void
731 free_error_list (struct error_list *l)
733 struct error_list *tmp, *cur_err = l;
734 while ((tmp = cur_err))
736 cur_err = cur_err->nxt;
737 free (tmp);
741 static int
742 CLASS_ID (struct token_s tok)
744 int offset = __builtin_ctzll (tok.class_id & -tok.class_id);
745 switch (tok.category)
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;
756 struct parser {
760 static struct token_list *
761 parse_with_restarts (struct token_s tok, int jump_target, struct rule rules[],
762 struct error_list **errs)
764 int end_of_line = 0;
765 struct steering_rule *cur_rule = rules[jump_target].rules;
767 if (!tok.insn[tok.begin])
768 tok.class_id = -3;
770 if (CLASS_ID (tok) == -1)
772 /* Unknown token */
773 *errs = error_list_insert (jump_target, tok.begin, *errs);
774 return NULL;
777 printf_debug (1, "\nEntering rule: %d (Trying to match: (%s)[%d])\n",
778 jump_target, TOKEN_NAME (CLASS_ID (tok)), CLASS_ID (tok));
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;
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);
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)
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);
800 else if (cur_rule[i].jump_target == -1 && cur_rule[i].stack_it == -1)
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.
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);
811 else
813 /* This is a mandatory modifier */
814 *errs = error_list_insert (jump_target, tok.begin, *errs);
815 return NULL;
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))
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);
832 if (!fst_part)
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;
841 if (!fst_part)
843 printf_debug (1, "fst_part == NULL (Exiting %d)\n", jump_target);
844 return NULL;
847 for (int _ = 0; _ < fst_part->len; ++_)
849 tok.begin = tok.end;
850 end_of_line = !read_token (&tok);
853 if (end_of_line && cur_rule[i].stack_it == -1)
855 /* No more tokens and no more place to go */
856 printf_debug (1, "return fst_part.\n");
857 return fst_part;
859 else if (!end_of_line && cur_rule[i].stack_it == -1)
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;
866 else if (cur_rule[i].stack_it == -1)
868 printf_debug (1, "return fst_part. (end of rule)\n");
869 return fst_part;
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))
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);
881 if (!snd_part)
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;
892 if (!snd_part)
894 printf_debug (1, "snd_part == NULL (Exiting %d)\n", jump_target);
895 return NULL;
898 printf_debug (1, "Exiting rule: %d\n", jump_target,
899 TOKEN_NAME (CLASS_ID (tok)), tok.class_id);
901 /* Combine fst & snd parts */
902 return token_list_append (fst_part, snd_part);
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.
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. */
914 static void
915 assign_final_values (struct token_list *lst)
917 (void) lst;
918 struct token_list *cur = lst;
920 while (cur)
922 if (cur->category == CAT_MODIFIER)
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;
930 cur = cur->next;
934 struct token_list *
935 parse (struct token_s tok)
937 int error_code = 0;
938 int error_char = 0;
939 struct error_list *errs = NULL;
940 read_token (&tok);
942 struct token_list *tok_list =
943 parse_with_restarts (tok, 0, env.rules, &errs);
945 if (!tok_list)
947 struct error_list *cur_err = errs;
948 while (cur_err)
950 if (cur_err->loc > error_char)
952 error_char = cur_err->loc;
953 error_code = cur_err->rule;
955 cur_err = cur_err->nxt;
959 free_error_list (errs);
961 if (!tok_list)
963 if (error_code != -1)
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)
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);
979 else
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);
991 else
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);
998 return tok_list;
1001 void
1002 setup (int core)
1004 switch (core)
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 ();
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);
1025 void
1026 cleanup ()
1028 free_node (env.insns);