]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gas/config/loongarch-parse.y
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gas / config / loongarch-parse.y
1 /*
2 Copyright (C) 2021-2023 Free Software Foundation, Inc.
3
4 This file is part of GAS, the GNU Assembler.
5
6 GAS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 GAS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; see the file COPYING3. If not,
18 see <http://www.gnu.org/licenses/>. */
19 %{
20 #include "as.h"
21 #include "loongarch-lex.h"
22 #include "loongarch-parse.h"
23 static void yyerror (const char *s ATTRIBUTE_UNUSED)
24 {
25 };
26 int yylex (void);
27
28
29 static struct reloc_info *top, *end;
30
31 static expressionS const_0 =
32 {
33 .X_op = O_constant,
34 .X_add_number = 0
35 };
36
37 static int
38 is_const (struct reloc_info *info)
39 {
40 return (info->type == BFD_RELOC_LARCH_SOP_PUSH_ABSOLUTE
41 && info->value.X_op == O_constant);
42 }
43
44 int
45 loongarch_parse_expr (const char *expr,
46 struct reloc_info *reloc_stack_top,
47 size_t max_reloc_num,
48 size_t *reloc_num,
49 offsetT *imm)
50 {
51 int ret;
52 struct yy_buffer_state *buffstate;
53 top = reloc_stack_top;
54 end = top + max_reloc_num;
55 buffstate = yy_scan_string (expr);
56 ret = yyparse ();
57
58 if (ret == 0)
59 {
60 if (is_const (top - 1))
61 *imm = (--top)->value.X_add_number;
62 else
63 *imm = 0;
64 *reloc_num = top - reloc_stack_top;
65 }
66 yy_delete_buffer (buffstate);
67
68 return ret;
69 }
70
71 static void
72 emit_const (offsetT imm)
73 {
74 if (end <= top)
75 as_fatal (_("expr too huge"));
76 top->type = BFD_RELOC_LARCH_SOP_PUSH_ABSOLUTE;
77 top->value.X_op = O_constant;
78 top->value.X_add_number = imm;
79 top++;
80 }
81
82 static const char *
83 my_getExpression (expressionS *ep, const char *str)
84 {
85 char *save_in, *ret;
86
87 if (*str == ':')
88 {
89 unsigned long j;
90 char *str_1 = (char *) str;
91 j = strtol (str_1, &str_1, 10);
92 get_internal_label (ep, j, *str_1 == 'f');
93 return NULL;
94 }
95 save_in = input_line_pointer;
96 input_line_pointer = (char *)str;
97 expression (ep);
98 ret = input_line_pointer;
99 input_line_pointer = save_in;
100 return ret;
101 }
102
103 static void
104 emit_const_var (const char *op)
105 {
106 expressionS ep;
107
108 if (end <= top)
109 as_fatal (_("expr too huge"));
110
111 my_getExpression (&ep, op);
112
113 if (ep.X_op != O_constant)
114 as_bad ("illegal operand: %s", op);
115
116 top->value.X_op = O_constant;
117 top->value.X_add_number = ep.X_add_number;
118 top->type = BFD_RELOC_LARCH_SOP_PUSH_ABSOLUTE;
119 top++;
120 }
121
122 static void
123 reloc (const char *op_c_str, const char *id_c_str, offsetT addend)
124 {
125 expressionS id_sym_expr;
126 bfd_reloc_code_real_type btype;
127
128 if (end <= top)
129 as_fatal (_("expr too huge"));
130
131 /* For compatible old asm code. */
132 if (0 == strcmp (op_c_str, "plt"))
133 btype = BFD_RELOC_LARCH_B26;
134 else
135 btype = loongarch_larch_reloc_name_lookup (NULL, op_c_str);
136
137 if (id_c_str)
138 {
139 my_getExpression (&id_sym_expr, id_c_str);
140 id_sym_expr.X_add_number += addend;
141 }
142 else
143 {
144 id_sym_expr.X_op = O_constant;
145 id_sym_expr.X_add_number = addend;
146 }
147
148 top->value = id_sym_expr;
149 top->type = btype;
150 top++;
151 }
152
153 static void
154 emit_unary (char op)
155 {
156 struct reloc_info *s_top = top - 1;
157 if (is_const (s_top))
158 {
159 offsetT opr = s_top->value.X_add_number;
160 switch (op)
161 {
162 case '+':
163 break;
164 case '-':
165 opr = -opr;
166 break;
167 case '~':
168 opr = ~opr;
169 break;
170 case '!':
171 opr = !opr;
172 break;
173 default:
174 abort ();
175 }
176 s_top->value.X_add_number = opr;
177 }
178 else
179 {
180 if (end <= top)
181 as_fatal (_("expr too huge"));
182 switch (op)
183 {
184 case '!':
185 top->type = BFD_RELOC_LARCH_SOP_NOT;
186 break;
187 default:
188 abort ();
189 }
190 top->value = const_0;
191 top++;
192 }
193 }
194
195 static void
196 emit_bin (int op)
197 {
198 struct reloc_info *last_1st = top - 1, *last_2nd = top - 2;
199 if (is_const (last_1st) && is_const (last_2nd))
200 {
201 offsetT opr1 = last_2nd->value.X_add_number;
202 offsetT opr2 = last_1st->value.X_add_number;
203 switch (op)
204 {
205 case '*':
206 opr1 = opr1 * opr2;
207 break;
208 case '/':
209 opr1 = opr1 / opr2;
210 break;
211 case '%':
212 opr1 = opr1 % opr2;
213 break;
214 case '+':
215 opr1 = opr1 + opr2;
216 break;
217 case '-':
218 opr1 = opr1 - opr2;
219 break;
220 case LEFT_OP:
221 opr1 = opr1 << opr2;
222 break;
223 case RIGHT_OP:
224 /* Algorithm right shift. */
225 opr1 = (offsetT)opr1 >> (offsetT)opr2;
226 break;
227 case '<':
228 opr1 = opr1 < opr2;
229 break;
230 case '>':
231 opr1 = opr1 > opr2;
232 break;
233 case LE_OP:
234 opr1 = opr1 <= opr2;
235 break;
236 case GE_OP:
237 opr1 = opr1 >= opr2;
238 break;
239 case EQ_OP:
240 opr1 = opr1 == opr2;
241 break;
242 case NE_OP:
243 opr1 = opr1 != opr2;
244 break;
245 case '&':
246 opr1 = opr1 & opr2;
247 break;
248 case '^':
249 opr1 = opr1 ^ opr2;
250 break;
251 case '|':
252 opr1 = opr1 | opr2;
253 break;
254 case AND_OP:
255 opr1 = opr1 && opr2;
256 break;
257 case OR_OP:
258 opr1 = opr1 || opr2;
259 break;
260 default:
261 abort ();
262 }
263 last_2nd->value.X_add_number = opr1;
264 last_1st->type = 0;
265 top--;
266 }
267 else
268 {
269 if (end <= top)
270 as_fatal (_("expr too huge"));
271 switch (op)
272 {
273 case '+':
274 top->type = BFD_RELOC_LARCH_SOP_ADD;
275 break;
276 case '-':
277 top->type = BFD_RELOC_LARCH_SOP_SUB;
278 break;
279 case LEFT_OP:
280 top->type = BFD_RELOC_LARCH_SOP_SL;
281 break;
282 case RIGHT_OP:
283 top->type = BFD_RELOC_LARCH_SOP_SR;
284 break;
285 case '&':
286 top->type = BFD_RELOC_LARCH_SOP_AND;
287 break;
288 default:
289 abort ();
290 }
291 top->value = const_0;
292 top++;
293 }
294 }
295
296 static void
297 emit_if_else (void)
298 {
299 struct reloc_info *last_1st = top - 1;
300 struct reloc_info *last_2nd = top - 2;
301 struct reloc_info *last_3rd = top - 3;
302 if (is_const (last_1st) && is_const (last_2nd) && is_const (last_3rd))
303 {
304 offsetT opr1 = last_3rd->value.X_add_number;
305 offsetT opr2 = last_2nd->value.X_add_number;
306 offsetT opr3 = last_1st->value.X_add_number;
307 opr1 = opr1 ? opr2 : opr3;
308 last_3rd->value.X_add_number = opr1;
309 last_2nd->type = 0;
310 last_1st->type = 0;
311 top -= 2;
312 }
313 else
314 {
315 if (end <= top)
316 as_fatal (_("expr too huge"));
317 top->type = BFD_RELOC_LARCH_SOP_IF_ELSE;
318 top->value = const_0;
319 top++;
320 }
321 }
322
323 %}
324
325 %union {
326 char *c_str;
327 offsetT imm;
328 }
329
330 %token <imm> INTEGER
331 %token <c_str> IDENTIFIER
332 %type <imm> addend
333
334 %token LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP AND_OP OR_OP
335 %start expression
336 %%
337
338 primary_expression
339 : INTEGER {emit_const ($1);}
340 | IDENTIFIER {emit_const_var ($1);}
341 | '(' expression ')'
342 | '%' IDENTIFIER '(' IDENTIFIER addend ')' {reloc ($2, $4, $5); free ($2); free ($4);}
343 | '%' IDENTIFIER '(' INTEGER addend ')' {reloc ($2, NULL, $4 + $5); free ($2);}
344 ;
345
346 addend
347 : addend '-' INTEGER {$$ -= $3;}
348 | addend '+' INTEGER {$$ += $3;}
349 | {$$ = 0;}
350 ;
351
352 unary_expression
353 : primary_expression
354 | '+' unary_expression {emit_unary ('+');}
355 | '-' unary_expression {emit_unary ('-');}
356 | '~' unary_expression {emit_unary ('~');}
357 | '!' unary_expression {emit_unary ('!');}
358 ;
359
360 multiplicative_expression
361 : unary_expression
362 | multiplicative_expression '*' unary_expression {emit_bin ('*');}
363 | multiplicative_expression '/' unary_expression {emit_bin ('/');}
364 | multiplicative_expression '%' unary_expression {emit_bin ('%');}
365 ;
366
367 additive_expression
368 : multiplicative_expression
369 | additive_expression '+' multiplicative_expression {emit_bin ('+');}
370 | additive_expression '-' multiplicative_expression {emit_bin ('-');}
371 ;
372
373 shift_expression
374 : additive_expression
375 | shift_expression LEFT_OP additive_expression {emit_bin (LEFT_OP);}
376 | shift_expression RIGHT_OP additive_expression {emit_bin (RIGHT_OP);}
377 ;
378
379 relational_expression
380 : shift_expression
381 | relational_expression '<' shift_expression {emit_bin ('<');}
382 | relational_expression '>' shift_expression {emit_bin ('>');}
383 | relational_expression LE_OP shift_expression {emit_bin (LE_OP);}
384 | relational_expression GE_OP shift_expression {emit_bin (GE_OP);}
385 ;
386
387 equality_expression
388 : relational_expression
389 | equality_expression EQ_OP relational_expression {emit_bin (EQ_OP);}
390 | equality_expression NE_OP relational_expression {emit_bin (NE_OP);}
391 ;
392
393 and_expression
394 : equality_expression
395 | and_expression '&' equality_expression {emit_bin ('&');}
396 ;
397
398 exclusive_or_expression
399 : and_expression
400 | exclusive_or_expression '^' and_expression {emit_bin ('^');}
401 ;
402
403 inclusive_or_expression
404 : exclusive_or_expression
405 | inclusive_or_expression '|' exclusive_or_expression {emit_bin ('|');}
406 ;
407
408 logical_and_expression
409 : inclusive_or_expression
410 | logical_and_expression AND_OP inclusive_or_expression {emit_bin (AND_OP);}
411 ;
412
413 logical_or_expression
414 : logical_and_expression
415 | logical_or_expression OR_OP logical_and_expression {emit_bin (OR_OP);}
416 ;
417
418 conditional_expression
419 : logical_or_expression
420 | logical_or_expression '?' expression ':' conditional_expression {emit_if_else ();}
421 ;
422
423 expression
424 : conditional_expression
425 ;
426 %%
427