Add missing prototypes for alloc() and fixstring()
[a56.git] / a56.y
1 %{
2 /*******************************************************
3  *
4  *  a56 - a DSP56001 assembler
5  *
6  *  Written by Quinn C. Jensen
7  *  July 1990
8  *
9  *******************************************************/
10
11 /*
12  * Copyright (C) 1990-1994 Quinn C. Jensen
13  *
14  * Permission to use, copy, modify, distribute, and sell this software
15  * and its documentation for any purpose is hereby granted without fee,
16  * provided that the above copyright notice appear in all copies and
17  * that both that copyright notice and this permission notice appear
18  * in supporting documentation.  The author makes no representations
19  * about the suitability of this software for any purpose.  It is
20  * provided "as is" without express or implied warranty.
21  *
22  */
23
24 /*
25  *  a56.y - The YACC grammar for the assembler.
26  *
27  *  Note:  This module requires a "BIG" version of YACC.  I had to
28  *  recompile YACC in the largest mode available.
29  *
30  *  Other notes:
31  *
32  *  MOVEC, MOVEM and MOVEP must be used explicitly--MOVE can't yet figure
33  *  out which form to use.
34  *
35  */
36
37 #include "a56.h"
38 #include <math.h>
39
40 unsigned int w0, w1;                    /* workspace for the actual generated code */
41 BOOL uses_w1;                                   /* says whether w1 is alive */
42 unsigned int pc;                                /* current program counter */
43 int seg;                                                /* current segment P: X: Y: or L: */
44 int expr_seg;                                   /* segment of current expression */
45
46 int just_rep = 0;                               /* keeps track of REP instruction */
47 int hot_rreg = -1;                              /* rreg loaded by prev inst. or -1 */
48 int hot_nreg = -1;                              /* nreg loaded by prev inst. or -1 */
49 int hot_mreg = -1;                              /* mreg loaded by prev inst. or -1 */
50 int prev_hot_rreg = -1;                 /* rreg loaded by prev inst. or -1 */
51 int prev_hot_nreg = -1;                 /* nreg loaded by prev inst. or -1 */
52 int prev_hot_mreg = -1;                 /* mreg loaded by prev inst. or -1 */
53
54 int substatement = 0;                   /* in a substatement */
55 BOOL long_symbolic_expr = FALSE; /* a parser flag */
56 char *new_include = NULL;               /* file to be included */
57
58 /* listing stuff */
59
60 char segs[] = "uPXYL*";
61 extern BOOL list_on_next;               /* listing to turn on or off */
62 BOOL list_on;                                   /* listing on at the moment */
63 extern char *cur_line;                  /* points to line being lex'd */
64 char list_buf[1024 + 80];               /* listing buffer */
65 char list_buf2[1024 + 80];              /* listing buffer for two-line code */
66 BOOL uses_buf2 = FALSE;                 /* list_buf2 is alive */
67 BOOL list_print_line = FALSE;   /* whether or not to print line in listing */
68 char *spaces(), *luntab();
69
70 struct n binary_op();
71 struct n unary_op();
72 struct n sym_ref();
73
74 #define R_R6                            0x0001
75 #define R_R5                            0x0002
76 #define R_R4                            0x0004
77 #define R_DATA_ALU_ACCUM        0x0008
78 #define R_CTL_REG                       0x0010
79 #define R_FUNKY_CTL_REG         0x0020
80 #define R_SDX                           0x0040
81 #define R_SDY                           0x0080
82 #define R_LSD                           0x0100
83 #define R_AB                            0x0200
84 #define R_XREG                          0x0400
85 #define R_YREG                          0x0800
86 /* registers to which short immediate move is an unsigned int */
87 #define R_UINT                          0x1000
88 /* registers to which short immediate move is an signed frac */
89 #define R_SFRAC                         0x2000
90 %}
91
92 %union {
93         int ival;                       /* integer value */
94         struct n n;                     /* just like in struct sym */
95         double dval;            /* floating point value */
96         char *sval;                     /* string */
97         int cval;                       /* character */
98         char cond;                      /* condition */
99         struct regs {
100                 int r6, r5, r4, data_alu_accum, ctl_reg, funky_ctl_reg;
101                 int sdx, sdy, lsd, ab, xreg, yreg;
102                 int flags;
103         } regs;
104         struct ea {
105                 int mode;
106                 int ext;
107                 int pp;
108         } ea;
109 }
110
111 %token <n> CHEX CDEC FRAC 
112 %token <ival> AREG BREG MREG NREG RREG XREG YREG
113 %token <ival> OP OPA OPP
114 %token <cond> OP_JCC OP_JSCC OP_TCC
115 %token <sval> SYM
116 %token <sval> STRING
117 %token <cval> CHAR
118 %token XMEM
119 %token YMEM
120 %token LMEM
121 %token PMEM
122 %token AAAA
123 %token A10
124 %token BBBB
125 %token B10
126 %token AABB
127 %token BBAA
128 %token XXXX
129 %token YYYY
130 %token SR
131 %token MR
132 %token CCR
133 %token OMR
134 %token SP
135 %token SSH
136 %token SSL
137 %token LA
138 %token LC
139 %token EOL
140 %token EOS
141 %token LEXBAD
142
143 %token OP_ABS
144 %token OP_ADC
145 %token OP_ADD
146 %token OP_ADDL
147 %token OP_ADDR
148 %token OP_ASL
149 %token OP_ASR
150 %token OP_CLR
151 %token OP_CMP
152 %token OP_CMPM
153 %token OP_DIV
154 %token OP_MAC
155 %token OP_MACR
156 %token OP_MPY
157 %token OP_MPYR
158 %token OP_NEG
159 %token OP_NORM
160 %token OP_RND
161 %token OP_SBC
162 %token OP_SUB
163 %token OP_SUBL
164 %token OP_SUBR
165 %token OP_TFR
166 %token OP_TST
167 %token OP_AND
168 %token OP_ANDI
169 %token OP_EOR
170 %token OP_LSL
171 %token OP_LSR
172 %token OP_NOT
173 %token OP_OR
174 %token OP_ORI
175 %token OP_ROL
176 %token OP_ROR
177 %token OP_BCLR
178 %token OP_BSET
179 %token OP_BCHG
180 %token OP_BTST
181 %token OP_DO
182 %token OP_ENDDO
183 %token OP_LUA
184 %token OP_MOVE
185 %token OP_MOVEC
186 %token OP_MOVEM
187 %token OP_MOVEP
188 %token OP_ILLEGAL
189 %token OP_INCLUDE
190 %token OP_JMP
191 %token OP_JCLR
192 %token OP_JSET
193 %token OP_JSR
194 %token OP_JSCLR
195 %token OP_JSSET
196 %token OP_NOP
197 %token OP_REP
198 %token OP_RESET
199 %token OP_RTI
200 %token OP_RTS
201 %token OP_STOP
202 %token OP_SWI
203 %token OP_WAIT
204 %token OP_EQU
205 %token OP_ORG
206 %token OP_DC
207 %token OP_DS
208 %token OP_DSM
209 %token OP_END
210 %token OP_PAGE
211 %token OP_PSECT
212 %token OP_ALIGN
213 %token OP_INT
214 %token SHL
215 %token SHR
216 %token OP_PI
217 %token OP_SIN
218 %token OP_COS
219 %token OP_TAN
220 %token OP_ATAN
221 %token OP_ASIN
222 %token OP_ACOS
223 %token OP_EXP
224 %token OP_LN
225 %token OP_LOG
226 %token OP_POW
227
228 %type <n> num num_or_sym 
229 %type <n> num_or_sym_expr
230 %type <n> expr
231 %type <n> ix
232 %type <n> ix_long
233
234 %type <ival> abs_addr abs_short_addr io_short_addr 
235 %type <ival> a_b x_or_y ea b5_10111_max
236 %type <ival> p6_ean_a6 ea_no_ext p6_ea_a6 ea_a6 ea_a12
237 %type <ival> ea_short
238 %type <ival> prog_ctl_reg
239 %type <ival> op8_1 op8_2 op8_3 op8_4 op8_5 op8_6 op8_7 op8_8
240 %type <ival> mpy_arg mpy_srcs plus_minus
241 %type <ival> sd3
242 %type <ival> funky_ctl_reg tcc_sd space
243 %type <sval> opt_label
244
245 %type <regs> regs
246 %type <ea> movep_ea_pp
247
248 %left '|'
249 %left '^'
250 %left SHL SHR
251 %left '&'
252 %left '+' '-'
253 %left '*' '/' '%'
254 %right '~'
255
256 %start input
257
258 %%
259
260 /*%%%********************* top syntax ***********************/
261
262 input   :       /* empty */
263         |       input statement
264         ;
265
266 statement
267         :       good_stuff EOL
268                         {
269                         if(pass == 2 && list_on && list_print_line) {
270                                 printf(ldebug ? "\n(%s|%s)\n" : "%s%s\n",
271                                         list_buf, substatement == 0 ? luntab(cur_line) : "");
272                                 if(uses_buf2)
273                                         printf(ldebug ? "\n(%s|)\n" : "%s\n",
274                                                 list_buf2);
275                                 list_buf[0] = list_buf2[0] = '\0';
276                         }
277                         curline++;
278                         uses_buf2 = FALSE;
279                         list_print_line = TRUE;
280                         list_on = list_on_next;
281                         substatement = 0;
282                         if(NOT check_psect(seg, pc) && pass == 2)
283                                 yyerror("%04X: psect violation", pc);
284                         }
285         |       good_stuff EOS
286                         {
287                         if(pass == 2 && list_on && list_print_line) {
288                                 printf(ldebug ? "\n(%s" : "%s", list_buf);
289                                 if(substatement == 0)
290                                         printf(ldebug ? "|%s)\n" : "%s\n", luntab(cur_line));
291                                 else
292                                         printf(ldebug ? ")\n" : "\n");
293                                 if(uses_buf2)
294                                         printf(ldebug ? "\n(%s|)\n" : "%s\n",
295                                                 list_buf2);
296                                 list_buf[0] = list_buf2[0] = '\0';
297                         }
298                         substatement++;
299                         uses_buf2 = FALSE;
300                         list_print_line = TRUE;
301                         list_on = list_on_next;
302                         if(NOT check_psect(seg, pc) && pass == 2)
303                                 yyerror("%04X: psect violation", pc);
304                         }
305         |       error EOL
306                         {curline++; substatement = 0;}
307         ;
308
309 good_stuff
310         :       /* empty */
311                         {sprintf(list_buf, "%s", spaces(0));}
312         |       cpp_droppings
313                         {list_print_line = FALSE;}
314         |       assembler_ops
315                         {long_symbolic_expr = FALSE;}
316         |       label_field operation_field
317                         {char *printcode();
318                         if(pass == 2) {
319                                 gencode(seg, pc, w0);
320                                 sprintf(list_buf, "%c:%04X %s ", segs[seg], pc, printcode(w0));
321                                 pc++;
322                                 if(uses_w1) {
323                                         gencode(seg, pc, w1);
324                                         sprintf(list_buf2, "%c:%04X %s", segs[seg], pc,
325                                                 printcode(w1 & 0xFFFFFF));
326                                         uses_buf2++;
327                                         pc++;
328                                 }
329                         } else {
330                                 pc++;
331                                 if(uses_w1)
332                                         pc++;
333                         }
334                         w0 = w1 = 0; uses_w1 = FALSE; 
335                         long_symbolic_expr = FALSE;}
336         |       SYM 
337                         {sym_def($1, INT, seg, pc);
338                         free($1);
339                         if(pass == 2 && list_on) {
340                                 sprintf(list_buf, "%c:%04X%s", segs[seg], pc, spaces(14-8));
341                         long_symbolic_expr = FALSE;
342                         }}
343         ;
344
345 cpp_droppings
346         :       '#' num STRING
347                         {if(strlen($3) > 0)
348                                 curfile = $3;
349                         else
350                                 curfile = "<stdin>";
351                         curline = $2.val.i - 1;}
352         ;
353
354 assembler_ops
355         :       SYM OP_EQU expr
356                         {sym_def($1, $3.type, ANY, $3.val.i, $3.val.f);
357                         free($1);
358                         if(pass == 2 && list_on) {
359                                 if($3.type == INT)
360                                         sprintf(list_buf, "%06X%s",
361                                                 $3.val.i & 0xFFFFFF,
362                                                 spaces(14-8));
363                                 else
364                                         sprintf(list_buf, "%10g%s", $3.val.f,
365                                                 spaces(14-4));
366                         }}
367         |       OP_ALIGN expr
368                         {int ival = n2int($2);
369                         if($2.type == UNDEF) {
370                                 yyerror("illegal forward reference");
371                         } else if (ival <= 1) {
372                                 yyerror("%d: illegal alignment", ival);
373                         } else {
374                                 if(pc % ival != 0)
375                                         pc += ival - pc % ival;
376                         }
377                         if(pass == 2 && list_on)
378                                 sprintf(list_buf, "%c:%04X%s", segs[seg], pc, 
379                                         spaces(14-8));
380                         }
381         |       OP_PSECT SYM
382                         {struct psect *pp = find_psect($2);
383                         if(NOT pp) {
384                                 if(pass == 2)
385                                         yyerror("%s: undefined psect", $2);
386                         } else {
387                                 seg = pp->seg;
388                                 pc = pp->pc;
389                                 set_psect(pp);
390                                 if(pass == 2 && list_on)
391                                         sprintf(list_buf, "%c:%04X%s", segs[seg], pc,
392                                                 spaces(14-8));
393                         }
394                         free($2);}
395         |       OP_PSECT SYM space expr ':' expr
396                         {new_psect($2, $3, n2int($4), n2int($6));
397                         if(pass == 2 && list_on)
398                                 sprintf(list_buf, "%c:%04X %04X%s", 
399                                         segs[$3], n2int($4), n2int($6), spaces(14-8+4+1));
400                         }
401         |       OP_ORG space expr
402                         {pc = n2int($3);
403                         seg = $2;
404                         if(pass == 2 && list_on)
405                                 sprintf(list_buf, "%c:%04X%s", segs[seg], pc, 
406                                         spaces(14-8));
407                         }
408         |       OP_ORG space expr ',' space expr
409                         {pc = n2int($3);
410                         seg = $2;
411                         if(pass == 2 && list_on)
412                                 sprintf(list_buf, "%c:%04X%s", segs[seg], pc, 
413                                         spaces(14-8));
414                         }
415         |       label_field OP_DC dc_list
416         |       label_field OP_DS expr
417                         {pc += n2int($3);
418                         if(pass == 2 && list_on)
419                                 sprintf(list_buf, "%c:%04X%s", segs[seg], pc, 
420                                         spaces(14-8));
421                         }
422         |       opt_label OP_DSM expr
423                         {int size = n2int($3);
424                         if(size)
425                         {    int align = 1;
426                              while(align < size)
427                                  align <<= 1;
428                              pc += (align - (pc % align));
429                         }
430                         if($1)
431                         {   sym_def($1, INT, seg, pc);
432                             free($1);
433                         }
434                         pc += size;
435                         }
436         |       OP_PAGE num ',' num ',' num ',' num
437                         {if(pass == 2 && list_on) {
438                                 sprintf(list_buf, "%s", spaces(0));
439                         }}
440         |       OP_INCLUDE STRING
441                         {if(pass == 2 && list_on) {
442                                 printf(ldebug ? "\n(%s|%s)\n" : "%s%s\n",
443                                         spaces(0), luntab(cur_line));
444                                 list_print_line = FALSE;
445                         }
446                         include($2); /* free($2); */
447                         }
448         |       OP_END
449                         {if(pass == 2 && list_on) {
450                                 sprintf(list_buf, "%s", spaces(0));
451                         }}
452         ;
453
454 dc_list
455         :       dc_list ',' dc_stuff
456         |       dc_stuff
457         ;
458
459 dc_stuff
460         :       STRING
461                         {int len = strlen($1), i; char *cp; w0 = 0;
462                         if(len % 3 == 2)
463                                 len++;  /* force empty word */
464                         for(i = 0, cp = $1; i < len; i++, cp++) {
465                                 w0 |= (*cp & 0xFF) << (2 - (i % 3)) * 8;
466                                 if(i % 3 == 2 || i == len - 1) {
467                                         if(pass == 2) {
468                                                 if(list_on) sprintf(list_buf, "%c:%04X %06X%s",
469                                                         segs[seg], pc, w0, 
470                                                         spaces(14-6+5));
471                                                 gencode(seg, pc, w0);
472                                         }
473                                         pc++; w0 = 0;
474                                 }
475                         }
476                         free($1);}
477         |       expr
478                         {int frac = n2frac($1);
479                         if(pass == 2) {
480                                 if(list_on) {
481                                         sprintf(list_buf, "%c:%04X %06X%s", segs[seg], pc, 
482                                                 frac & 0xFFFFFF, spaces(14-6+5));
483                                 }
484                                 gencode(seg, pc, frac);
485                         }
486                         pc++;}
487
488 space
489         :       PMEM
490                         {$$ = PROG;}
491         |       XMEM
492                         {$$ = XDATA;}
493         |       YMEM
494                         {$$ = YDATA;}
495         |       LMEM
496                         {$$ = LDATA;}
497         ;       
498
499 label_field
500         :       SYM
501                         {sym_def($1, INT, seg, pc);
502                         free($1);}
503         |       /* empty */
504         ;
505
506 opt_label
507         :       SYM             {$$ = $1;}
508         |       /* empty */     {$$ = NULL;}
509         ;
510
511 operation_field
512         :       operation
513                         {prev_hot_rreg = hot_rreg;
514                         prev_hot_nreg = hot_nreg;
515                         prev_hot_mreg = hot_mreg;
516                         hot_rreg = hot_nreg = hot_mreg = -1;
517                         if(just_rep) 
518                                 just_rep--;}
519         ;
520
521 operation
522         :       no_parallel
523         |       parallel_ok
524                         {w0 |= 0x200000;}
525         |       parallel_ok parallel_move
526         ;
527
528 /*%%%************* instructions that allow parallel moves ****************/
529
530 parallel_ok
531         :
532                 OP_MPY mpy_arg
533                         {w0 |= 0x80 | $2 << 2;}
534         |       OP_MPYR mpy_arg
535                         {w0 |= 0x81 | $2 << 2;}
536         |       OP_MAC mpy_arg
537                         {w0 |= 0x82 | $2 << 2;}
538         |       OP_MACR mpy_arg
539                         {w0 |= 0x83 | $2 << 2;}
540
541         |       OP_SUB op8_1
542                         {w0 |= 0x04 | $2 << 3;}
543         |       OP_ADD op8_1
544                         {w0 |= 0x00 | $2 << 3;}
545         |       OP_MOVE
546                         {w0 |= 0x00;}
547
548         |       OP_TFR op8_2
549                         {w0 |= 0x01 | $2 << 3;}
550         |       OP_CMP op8_2
551                         {w0 |= 0x05 | $2 << 3;}
552         |       OP_CMPM op8_2
553                         {w0 |= 0x07 | $2 << 3;}
554
555         |       OP_RND op8_3
556                         {w0 |= 0x11 | $2 << 3;}
557         |       OP_ADDL op8_3
558                         {w0 |= 0x12 | $2 << 3;}
559         |       OP_CLR op8_3
560                         {w0 |= 0x13 | $2 << 3;}
561         |       OP_SUBL op8_3
562                         {w0 |= 0x16 | $2 << 3;}
563         |       OP_NOT op8_3
564                         {w0 |= 0x17 | $2 << 3;}
565
566         |       OP_ADDR op8_4
567                         {w0 |= 0x02 | $2 << 3;}
568         |       OP_TST op8_4
569                         {w0 |= 0x03 | $2 << 3;}
570         |       OP_SUBR op8_4
571                         {w0 |= 0x06 | $2 << 3;}
572
573         |       OP_AND op8_5
574                         {w0 |= 0x46 | $2 << 3;}
575         |       OP_OR op8_5
576                         {w0 |= 0x42 | $2 << 3;}
577         |       OP_EOR op8_5
578                         {w0 |= 0x43 | $2 << 3;}
579
580         |       OP_ASR op8_6
581                         {w0 |= 0x22 | $2 << 3;}
582         |       OP_LSR op8_6
583                         {w0 |= 0x23 | $2 << 3;}
584         |       OP_ABS op8_6
585                         {w0 |= 0x26 | $2 << 3;}
586         |       OP_ROR op8_6
587                         {w0 |= 0x27 | $2 << 3;}
588
589         |       OP_ASL op8_7
590                         {w0 |= 0x32 | $2 << 3;}
591         |       OP_LSL op8_7
592                         {w0 |= 0x33 | $2 << 3;}
593         |       OP_NEG op8_7
594                         {w0 |= 0x36 | $2 << 3;}
595         |       OP_ROL op8_7
596                         {w0 |= 0x37 | $2 << 3;}
597
598         |       OP_ADC op8_8
599                         {w0 |= 0x21 | $2 << 3;}
600         |       OP_SBC op8_8
601                         {w0 |= 0x25 | $2 << 3;}
602         ;
603
604 mpy_arg :       plus_minus mpy_srcs ',' a_b
605                         {$$ = $1 | $4 << 1 | $2 << 2;}
606         ;
607
608 plus_minus
609         :       '+'    
610                         {$$ = 0;}
611         |       '-'    
612                         {$$ = 1;}
613         |       
614                         {$$ = 0;}
615         ;
616
617 mpy_srcs
618         :       XREG ',' XREG
619                         {switch ($1 << 4 | $3) {
620                                 case 0x00: $$ = 0x0; break;
621                                 case 0x01: 
622                                 case 0x10: $$ = 0x2; break;
623                                 case 0x11: 
624                                         yyerror("illegal source operands"); 
625                                         break;
626                         }}                              
627         |       YREG ',' YREG
628                         {switch ($1 << 4 | $3) {
629                                 case 0x00: $$ = 0x1; break;
630                                 case 0x01: 
631                                 case 0x10: $$ = 0x3; break;
632                                 case 0x11: 
633                                         yyerror("illegal source operands"); 
634                                         break;
635                         }}                              
636         |       XREG ',' YREG
637                         {switch ($1 << 4 | $3) {
638                                 case 0x00: $$ = 0x5; break;
639                                 case 0x01: $$ = 0x4; break;
640                                 case 0x10: $$ = 0x6; break;
641                                 case 0x11: $$ = 0x7; break;
642                         }}                              
643         |       YREG ',' XREG
644                         {switch ($1 << 4 | $3) {
645                                 case 0x00: $$ = 0x5; break;
646                                 case 0x01: $$ = 0x6; break;
647                                 case 0x10: $$ = 0x4; break;
648                                 case 0x11: $$ = 0x7; break;
649                         }}                              
650         ;
651
652 op8_1   :       BBBB ',' AAAA
653                         {$$ = 0x2;}
654         |       AAAA ',' BBBB
655                         {$$ = 0x3;}
656         |       XXXX ',' a_b
657                         {$$ = 0x4 | $3;}
658         |       YYYY ',' a_b
659                         {$$ = 0x6 | $3;}
660         |       XREG ',' a_b
661                         {$$ = 0x8 | $1 << 2 | $3;}
662         |       YREG ',' a_b
663                         {$$ = 0xA | $1 << 2 | $3;}
664         ;
665
666 op8_2   :       BBBB ',' AAAA
667                         {$$ = 0x0;}
668         |       AAAA ',' BBBB
669                         {$$ = 0x1;}
670         |       XREG ',' a_b
671                         {$$ = 0x8 | $1 << 2 | $3;}
672         |       YREG ',' a_b
673                         {$$ = 0xA | $1 << 2 | $3;}
674         ;
675
676 op8_3   :       AAAA
677                         {$$ = 0x0;}
678         |       BBBB
679                         {$$ = 0x1;}
680         |       BBBB ',' AAAA
681                         {$$ = 0x0;}
682         |       AAAA ',' BBBB
683                         {$$ = 0x1;}
684         ;
685
686 op8_4   :       op8_3
687                         {$$ = $1;}
688         ;
689
690 op8_5   :       XREG ',' a_b
691                         {$$ = 0x0 | $1 << 2 | $3;}
692         |       YREG ',' a_b
693                         {$$ = 0x2 | $1 << 2 | $3;}
694         ;
695
696 op8_6   :       a_b
697                         {$$ = $1;}
698         ;
699
700 op8_7   :       a_b
701                         {$$ = $1;}
702         ;
703
704 op8_8   :       XXXX ',' a_b
705                         {$$ = 0x0 | $3;}
706         |       YYYY ',' a_b
707                         {$$ = 0x2 | $3;}
708         ;
709
710 a_b     :       AAAA
711                         {$$ = 0;}
712         |       BBBB
713                         {$$ = 1;}
714         ;
715
716 no_parallel
717         :       control_inst
718                         {if(just_rep == 1)
719                                 yyerror("instruction not allowed after REP");}
720         |       bit_inst
721         |       move_inst
722         |       arith_inst
723         ;
724
725 /*%%%************** non-parallel arithmetic and logical ********************/
726
727 arith_inst
728         :       OP_NORM RREG ',' a_b
729                         {w0 |= 0x01D815 | $2 << 8 | $4 << 3;}
730         |       OP_DIV sd3
731                         {w0 |= 0x018040 | $2 << 3;}
732         |       or_op ix ',' funky_ctl_reg
733                         {w0 |= 0x0000F8 | (n2int($2) & 0xFF) << 8 | $4;}
734         |       and_op ix ',' funky_ctl_reg
735                         {w0 |= 0x0000B8 | (n2int($2) & 0xFF) << 8 | $4;}
736         ;
737
738 or_op   :       OP_OR
739         |       OP_ORI
740         ;
741
742 and_op  :       OP_AND
743         |       OP_ANDI
744         ;
745
746 /*%%%******************************* control instructions **********************/
747
748 control_inst
749         :       OP_JSCC ea_a12
750                         {if($2) {
751                                 w0 |= 0x0BC0A0 | $1 << 0;
752                         } else {
753                                 w0 |= 0x0F0000 | $1 << 12;
754                         }}
755         |       OP_JCC ea_a12
756                         {if($2) {
757                                 w0 |= 0x0AC0A0 | $1 << 0;
758                         } else {
759                                 w0 |= 0x0E0000 | $1 << 12;
760                         }}
761         |       OP_JSR ea_a12
762                         {if($2) {
763                                 w0 |= 0x0BC080;
764                         } else {
765                                 w0 |= 0x0D0000;
766                         }}
767         |       OP_JMP ea_a12
768                         {if($2) {
769                                 w0 |= 0x0AC080;
770                         } else {
771                                 w0 |= 0x0C0000;
772                         }}
773
774         |       OP_JSSET control_args
775                         {w0 |= 0x0B0020;}
776         |       OP_JSCLR control_args
777                         {w0 |= 0x0B0000;}
778         |       OP_JSET control_args
779                         {w0 |= 0x0A0020;}
780         |       OP_JCLR control_args
781                         {w0 |= 0x0A0000;}
782
783         |       OP_REP rep_args
784                         {just_rep = 2;}
785         |       OP_DO do_args
786                         {uses_w1++;}
787         |       OP_ENDDO
788                         {w0 |= 0x00008C;}
789         |       OP_STOP
790                         {w0 |= 0x000087;}
791         |       OP_WAIT
792                         {w0 |= 0x000086;}
793         |       OP_RESET
794                         {w0 |= 0x000084;}
795         |       OP_RTS
796                         {w0 |= 0x00000C;}
797         |       OP_SWI
798                         {w0 |= 0x000006;}
799         |       OP_ILLEGAL
800                         {w0 |= 0x000005;}
801         |       OP_RTI
802                         {w0 |= 0x000004;}
803         |       OP_NOP
804                         {w0 |= 0x000000;
805                         just_rep = 0;}
806         ;
807
808 do_args
809         :       ix ',' abs_addr
810                         {int ival = n2int($1);
811                         w0 |= 0x060080 | (ival & 0xFF) << 8 | (ival & 0xF00)>> 8;
812                         if(ival > 0xFFF && pass == 2) {
813                                 yywarning("warning: immediate operand truncated");
814                         }
815                         w1 |= $3-1;}
816         |       regs ',' abs_addr
817                         {w0 |= 0x06C000 | $1.r6 << 8;
818                         hot_rreg = hot_nreg = hot_mreg = -1;
819                         w1 |= $3-1;}
820         |       x_or_y ea_no_ext ',' abs_addr
821                         {w0 |= 0x064000 | $2 << 8 | $1 << 6;
822                         w1 |= $4-1;}
823         |       x_or_y abs_short_addr ',' abs_addr      /* allow forced */
824                         {w0 |= 0x060000 | ($2 & 0x3F) << 8 | $1 << 6;
825                         /*
826                          * $$$ oops, can't check expr_seg because both abs_short_addr and
827                          * abs_addr touch it
828                          */
829                         if($2 > 0x003F && pass == 2)
830                                 yywarning("warning: address operand truncated");
831                         w1 |= $4-1;}
832         |       x_or_y abs_addr ',' abs_addr
833                         {w0 |= 0x060000 | ($2 & 0x3F) << 8 | $1 << 6;
834                         /*
835                          * $$$ oops, can't check expr_seg because both abs_short_addr and
836                          * abs_addr touch it
837                          */
838                         if($2 > 0x003F && pass == 2)
839                                 yywarning("warning: address operand truncated");
840                         w1 |= $4-1;}
841         ;                       
842
843 rep_args
844         :       ix
845                         {int ival = n2int($1);
846                         w0 |= 0x0600A0 | (ival & 0xFF) << 8 | (ival & 0xF00)>> 8;
847                         if(ival > 0xFFF && pass == 2) {
848                                 yywarning("warning: immediate operand truncated");
849                         }}
850         |       regs
851                         {w0 |= 0x06C020 | $1.r6 << 8;
852                         hot_rreg = hot_nreg = hot_mreg = -1;}
853         |       x_or_y ea_no_ext
854                         {w0 |= 0x064020 | $1 << 6 | $2 << 8;}
855         |       x_or_y abs_addr
856                         {w0 |= 0x060020 | $1 << 6 | ($2 & 0x3F) << 8;
857                         if(expr_seg != ANY && ($1 == 0 && expr_seg != XDATA ||
858                                 $1 == 1 && expr_seg != YDATA))
859                                 yywarning("warning: space mismatch");
860                         if($2 > 0x003F && pass == 2)
861                                 yywarning("warning: address operand truncated");
862                         }
863         |       x_or_y abs_short_addr   /* forced */
864                         {w0 |= 0x060020 | $1 << 6 | ($2 & 0x3F) << 8;
865                         if(expr_seg != ANY && ($1 == 0 && expr_seg != XDATA ||
866                                 $1 == 1 && expr_seg != YDATA))
867                                 yywarning("warning: space mismatch");
868                         if($2 > 0x003F && pass == 2)
869                                 yywarning("warning: address operand truncated");
870                         }
871         ;
872
873 control_args
874         :       b5_10111_max ',' x_or_y p6_ean_a6 ',' abs_addr
875                         {w0 |= $1 << 0 | $3 << 6;
876                         uses_w1++;
877                         w1 = $6;}
878         |       b5_10111_max ',' regs ',' abs_addr
879                         {w0 |= 0x00C000 | $1 << 0 | $3.r6 << 8;
880                         hot_rreg = hot_nreg = hot_mreg = -1;
881                         uses_w1++;
882                         w1 = $5;}
883         ;
884
885 p6_ean_a6
886         :       abs_addr        /* in pass 2 can always discern size. */
887                                 /* Sometimes in pass one, too.  But since */
888                                 /* address extension is always used for the */
889                                 /* branch target, pass 1 can assume the */
890                                 /* symbol value will fit; warning in pass 2 */
891                                 /* if it doesn't */
892                         {if($1 != -1) { /* symbol defined */
893                                 w0 |= ($1 & 0x3F) << 8;
894                                 if($1 >= 0xFFC0) {
895                                         w0 |= 0x008080;
896                                 } else {
897                                         w0 |= 0x000080;
898                                         if($1 > 0x003F && pass == 2)
899                                                 yywarning("warning: address operand truncated");
900                                 }
901                         }}
902         |       abs_short_addr
903                         {if($1 != -1) {
904                                 if($1 > 0x3F && pass == 2)
905                                         yywarning("warning: address operand truncated");
906                                 w0 |= 0x000080 | ($1 & 0x3F) << 8;
907                         }}
908         |       io_short_addr
909                         {if($1 != -1) {
910                                 if($1 < 0xFFC0 && pass == 2)
911                                         yywarning("warning: address operand truncated");
912                                 w0 |= 0x008080 | ($1 & 0x3F) << 8;
913                         }}
914         |       ea_no_ext
915                         {w0 |= 0x004080 | $1 << 8;}
916         ;
917
918 /*%%%**************************** bit instructions ***************************/
919
920 bit_inst
921         :       OP_BTST bit_args
922                         {w0 |= 0x0B0020;}
923         |       OP_BCHG bit_args
924                         {w0 |= 0x0B0000;}
925         |       OP_BSET bit_args
926                         {w0 |= 0x0A0020;}
927         |       OP_BCLR bit_args
928                         {w0 |= 0x0A0000;}
929         ;                       
930
931 bit_args
932         :       b5_10111_max ',' x_or_y p6_ea_a6
933                         {w0 |= $1 << 0 | $3 << 6;
934                         }
935         |       b5_10111_max ',' regs
936                         {w0 |= 0x00C040 | $1 << 0 | $3.r6 << 8;}
937         ;               
938
939 p6_ea_a6
940         :       io_short_addr   /* must be forced to tell from abs_addr */
941                         {if($1 != -1) {
942                                 w0 |= ($1 & 0x3F) << 8 | 0x008000;
943                                 if($1 < 0xFFC0 && pass == 2)
944                                         yywarning("warning: address operand truncated");
945                         }}
946         |       abs_short_addr  /* must be forced to tell from abs_addr */
947                         {if($1 != -1) {
948                                 w0 |= ($1 & 0x3F) << 8 | 0x000000;
949                                 if($1 > 0x003F && pass == 2)
950                                         yywarning("warning: address operand truncated");
951                         }}
952         |       ea      /* can use abs_addr */
953                         {w0 |= 0x004000;}
954         ;
955
956 /*%%%************************** move instructions **********************/
957
958 move_inst
959         :       OP_MOVEP movep_args
960         |       OP_MOVEM movem_args
961         |       OP_MOVEC movec_args
962         |       OP_LUA ea_short ',' regs
963                         {w0 |= 0x044010 | $2 << 8 | $4.r4;}
964         |       OP_TCC tcc_args
965                         {w0 |= $1 << 12;}
966         ;               
967
968 tcc_args
969         :       tcc_sd
970                         {w0 |= 0x020000 | $1 << 3;}
971         |       tcc_sd RREG ',' RREG
972                         {w0 |= 0x030000 | $1 << 3 | $2 << 8 | $4;}
973         ;
974
975 tcc_sd
976         :       regs /* a_b */ ',' regs /* a_b */
977                         {hot_rreg = hot_nreg = hot_mreg = -1;
978                         if($1.flags & R_AB && $3.flags & R_AB) {
979                                 if($1.ab == $3.ab) 
980                                         yyerror("source and dest must be different");
981                                 $$ = $3.ab;
982                         } else if($1.flags & R_XREG && $3.flags & R_AB) {
983                                 $$ = 0x8 | $1.xreg << 2 | $3.ab;
984                         } else if($1.flags & R_YREG && $3.flags & R_AB) {
985                                 $$ = 0xA | $1.yreg << 2 | $3.ab;
986                         } else 
987                                 yyerror("illegal TCC operands");
988                         }
989         ;
990
991 sd3     :       regs /* XREG */ ',' regs /* a_b */
992                         {hot_rreg = hot_nreg = hot_mreg = -1;
993                         if($1.flags & R_XREG && $3.flags & R_AB) {
994                                 $$ = $1.xreg << 2 | $3.ab;
995                         } else if($1.flags & R_YREG && $3.flags & R_AB) {
996                                 $$ = $1.yreg << 2 | 2 | $3.ab;
997                         }}
998         ;
999
1000 movec_args
1001         :       x_or_y ea ',' regs /* ctl_reg */
1002                         {if(NOT ($4.flags & R_CTL_REG))
1003                                 yyerror("bad MOVEC target register");
1004                         if(expr_seg != ANY && ($1 == 0 && expr_seg != XDATA ||
1005                                 $1 == 1 && expr_seg != YDATA))
1006                                 yywarning("warning: space mismatch");
1007                         if($1 == 0) {
1008                                 w0 |= 0x05C020 | $4.ctl_reg;
1009                         } else {
1010                                 w0 |= 0x05C060 | $4.ctl_reg;
1011                         }}
1012         |       regs /* ctl_reg */ ',' x_or_y ea
1013                         {hot_rreg = hot_nreg = hot_mreg = -1;
1014                         if(NOT ($1.flags & R_CTL_REG))
1015                                 yyerror("bad MOVEC source register");
1016                         if($3 == 0) {
1017                                 w0 |= 0x054020 | $1.ctl_reg;
1018                         } else {
1019                                 w0 |= 0x054060 | $1.ctl_reg;
1020                         }}
1021         |       ix ',' regs /* ctl_reg */
1022                         {int ival = n2int($1);
1023                         if(NOT ($3.flags & R_CTL_REG))
1024                                 yyerror("bad MOVEC target register");
1025                         if(ival < 256 && NOT long_symbolic_expr) {
1026                                 w0 |= 0x0500A0 | (ival & 0xFF) << 8 | $3.ctl_reg; 
1027                         } else {
1028                                 w0 |= 0x05C020 | 0x003400 | $3.ctl_reg;
1029                                 uses_w1++; w1 = ival & 0xFFFF;
1030                         }}
1031         |       x_or_y abs_short_addr ',' regs /* ctl_reg */
1032                         {if($1 == 0) {
1033                                 w0 |= 0x058020 | ($2 & 0x3F) << 8 | $4.ctl_reg;
1034                         } else {
1035                                 w0 |= 0x058060 | ($2 & 0x3F) << 8 | $4.ctl_reg;
1036                         }
1037                         if(NOT ($4.flags & R_CTL_REG))
1038                                 yyerror("bad MOVEC target register");
1039                         if($2 > 0x003F && pass == 2)
1040                                 yywarning("warning: address operand truncated");
1041                         }
1042         |       regs /* ctl_reg */ ',' x_or_y abs_short_addr
1043                         {hot_rreg = hot_nreg = hot_mreg = -1;
1044                         if($3 == 0) {
1045                                 w0 |= 0x050020 | ($4 & 0x3F) << 8 | $1.ctl_reg;
1046                         } else {
1047                                 w0 |= 0x050060 | ($4 & 0x3F) << 8 | $1.ctl_reg;
1048                         }
1049                         if(NOT ($1.flags & R_CTL_REG))
1050                                 yyerror("bad MOVEC source register");
1051                         if($4 > 0x003F && pass == 2)
1052                                 yywarning("warning: address operand truncated");
1053                         }
1054         |       regs /* ctl_reg */ ',' regs
1055                         {if($1.flags & R_CTL_REG) {
1056                                 w0 |= 0x0440A0 | $3.r6 << 8 | $1.ctl_reg;
1057                         } else if($3.flags & R_CTL_REG) {
1058                                 w0 |= 0x04C0A0 | $1.r6 << 8 | $3.ctl_reg;
1059                         } else if($1.flags & $3.flags & R_CTL_REG) {
1060                                 /* bogus? $$$ */
1061                                 w0 |= 0x04C0A0 | ($1.ctl_reg | 0x20) << 8 | 
1062                                 $3.ctl_reg;
1063                         } else {
1064                                 yyerror("MOVEC must reference a control reg");
1065                         }}
1066         ;
1067
1068 movep_args
1069         :       x_or_y movep_ea_pp ',' x_or_y movep_ea_pp
1070                         {w0 |= 0x084080;
1071                         switch($2.pp << 1 | $5.pp) {
1072                                 case 0: case 3:
1073                                         yyerror("illegal MOVEP; can't move EA to EA or IO to IO");
1074                                         break;
1075                                 case 1: /* ea, pp */
1076                                         w0 |= $4 << 16 | 1 << 15 | $1 << 6 |
1077                                                 ($5.ext & 0x3F);
1078                                         if($2.mode == 0x003000) {
1079                                                 w0 |= 0x003000;
1080                                                 uses_w1++;
1081                                                 w1 = $2.ext;
1082                                         } else {
1083                                                 w0 |= $2.mode;
1084                                         }
1085                                         break;
1086                                 case 2: /* pp, ea */
1087                                         w0 |= $1 << 16 | 0 << 15 | $4 << 6 |
1088                                                 ($2.ext & 0x3F);
1089                                         if($5.mode == 0x003000) {
1090                                                 w0 |= 0x003000;
1091                                                 uses_w1++;
1092                                                 w1 = $5.ext;
1093                                         } else {
1094                                                 w0 |= $5.mode;
1095                                         }
1096                                         break;
1097                         }}
1098         |       ix ',' x_or_y num_or_sym
1099                         {w0 |= 0x084080;
1100                         w0 |= $3 << 16 | 1 << 15 | 0x34 << 8 | 
1101                                 (n2int($4) & 0x3F);
1102                         uses_w1++;
1103                         w1 = n2int($1);}
1104         |       PMEM ea ',' x_or_y num_or_sym
1105                         {w0 |= 0x084040;
1106                         w0 |= $4 << 16 | 1 << 15 | (n2int($5) & 0x3F);}
1107         |       x_or_y movep_ea_pp ',' PMEM ea
1108                         {w0 |= 0x084040;
1109                         if($2.mode != 0x003000 && $2.mode != 0)
1110                                 yyerror("illegal MOVEP");
1111                         w0 |= $1 << 16 | 0 << 15 | ($2.ext & 0x3F);}
1112         |       regs ',' x_or_y num_or_sym
1113                         {hot_rreg = hot_nreg = hot_mreg = -1;
1114                         w0 |= 0x084000;
1115                         w0 |= $3 << 16 | 1 << 15 | $1.r6 << 8 | 
1116                                 (n2int($4) & 0x3F);}
1117         |       x_or_y movep_ea_pp ',' regs
1118                         {hot_rreg = hot_nreg = hot_mreg = -1;
1119                         w0 |= 0x084000;
1120                         if(!$2.pp)
1121                                 yyerror("illegal MOVEP");
1122                         w0 |= $1 << 16 | 0 << 15 | $4.r6 << 8 | ($2.ext & 0x3F);}
1123         ;
1124
1125 movep_ea_pp
1126         :       abs_addr
1127                         {if($1 != UNDEF && $1 >= 0xFFC0) {
1128                                 /* defined symbol or constant, in i/o range */
1129                                 $$.pp = 1;
1130                                 $$.mode = 0;
1131                         } else {
1132                                 /* either out of i/o range or symbol not */
1133                                 /* yet defined:  assume ea extension */
1134                                 $$.pp = 0;
1135                                 $$.mode = 0x003000;
1136                         }
1137                         $$.ext = $1;}
1138         |       io_short_addr   /* forced i/o short */
1139                         {$$.pp = 1;
1140                         $$.mode = 0;
1141                         if($1 < 0xFFC0 && pass == 2)
1142                                 yywarning("warning: address operand truncated");
1143                         $$.ext = $1;}
1144         |       ea_no_ext
1145                         {$$.pp = 0;
1146                         $$.mode = $1 << 8;
1147                         $$.ext = $1;}
1148         ;
1149
1150 movem_args
1151         :       regs ',' PMEM ea_a6
1152                         {w0 |= 0x070000 | 0 << 15 | $1.r6;}
1153         |       PMEM ea_a6 ',' regs
1154                         {hot_rreg = hot_nreg = hot_mreg = -1;
1155                         w0 |= 0x070000 | 1 << 15 | $4.r6;}
1156         ;
1157
1158 /*%%%**************** memory reference fields ************************/
1159
1160 b5_10111_max
1161         :       ix
1162                         {int ival = n2int($1);
1163                         $$ = ival; if(ival > 0x17) 
1164                                 yyerror("%d: illegal bit number", ival);}
1165         ;
1166
1167 x_or_y
1168         :       XMEM
1169                         {$$ = 0;}
1170         |       YMEM
1171                         {$$ = 1;}
1172         ;
1173
1174 /*%%%**************** effective address fields ************************/
1175
1176 ea_a6
1177         :       ea
1178                         {w0 |= 0x004080;}
1179         |       abs_short_addr
1180                         {w0 |= ($1 & 0x3F) << 8;
1181                         if($1 > 0x003F && pass == 2)
1182                                 yywarning("warning: address operand truncated");
1183                         }
1184         ;
1185
1186 ea_a12
1187         :       ea
1188                         {$$ = 1;}
1189         |       abs_short_addr
1190                         {w0 |= $1 & 0xFFF; $$ = 0;
1191                         if($1 > 0x0FFF && pass == 2)
1192                                 yywarning("warning: address operand truncated");
1193                         }
1194         ;
1195
1196 ea      :       abs_addr
1197                         {w0 |= 0x003000;
1198                         uses_w1++;
1199                         w1 |= $1;
1200                         $$ = 0x003000;}
1201         |       ea_no_ext
1202                         {w0 |= $1 << 8;
1203                         $$ = $1 << 8;
1204                         expr_seg = ANY;}
1205         ;
1206
1207 ea_no_ext
1208         :       ea_short
1209                         {$$ = $1;}
1210         |       '(' RREG ')'
1211                         {if($2 == prev_hot_rreg) yywarning("warning: r%d just loaded", $2);
1212                         $$ = 4 << 3 | $2;}
1213         |       '(' RREG '+' NREG ')'
1214                         {if($2 == prev_hot_rreg) yywarning("warning: r%d just loaded", $2);
1215                         if($4 == prev_hot_nreg) yywarning("warning: n%d just loaded", $4);
1216                         if($2 == prev_hot_mreg) yywarning("warning: m%d just loaded", $2);
1217                         $$ = 5 << 3 | $2;
1218                         if($2 != $4) yyerror("Rn and Nn must be same number");}
1219         |       '-' '(' RREG ')'
1220                         {if($3 == prev_hot_rreg) yywarning("warning: r%d just loaded", $3);
1221                         if($3 == prev_hot_mreg) yywarning("warning: m%d just loaded", $3);
1222                         $$ = 7 << 3 | $3;}
1223         ;
1224
1225 ea_short
1226         :       '(' RREG ')' '-' NREG
1227                         {if($2 == prev_hot_rreg) yywarning("warning: r%d just loaded", $2);
1228                         if($5 == prev_hot_nreg) yywarning("warning: n%d just loaded", $5);
1229                         if($2 == prev_hot_mreg) yywarning("warning: m%d just loaded", $2);
1230                         $$ = 0 << 3 | $2;
1231                         expr_seg = ANY;
1232                         if($2 != $5) yyerror("Rn and Nn must be same number");}
1233         |       '(' RREG ')' '+' NREG
1234                         {if($2 == prev_hot_rreg) yywarning("warning: r%d just loaded", $2);
1235                         if($5 == prev_hot_nreg) yywarning("warning: n%d just loaded", $5);
1236                         if($2 == prev_hot_mreg) yywarning("warning: m%d just loaded", $2);
1237                         $$ = 1 << 3 | $2;
1238                         expr_seg = ANY;
1239                         if($2 != $5) yyerror("Rn and Nn must be same number");}
1240         |       '(' RREG ')' '-'
1241                         {if($2 == prev_hot_rreg) yywarning("warning: r%d just loaded", $2);
1242                         if($2 == prev_hot_mreg) yywarning("warning: m%d just loaded", $2);
1243                         expr_seg = ANY;
1244                         $$ = 2 << 3 | $2;}
1245         |       '(' RREG ')' '+'
1246                         {if($2 == prev_hot_rreg) yywarning("warning: r%d just loaded", $2);
1247                         if($2 == prev_hot_mreg) yywarning("warning: m%d just loaded", $2);
1248                         expr_seg = ANY;
1249                         $$ = 3 << 3 | $2;}
1250         ;
1251
1252 /*%%%******************* register fields ******************************/
1253
1254 regs
1255         :       XREG
1256                         {$$.r6 = $$.r5 = 0x04 | $1;
1257                         $$.sdx = $1;
1258                         $$.xreg = $1;
1259                         $$.flags = R_R6|R_R5|R_XREG|R_SDX|R_SFRAC;}
1260         |       YREG
1261                         {$$.r6 = $$.r5 = 0x06 | $1;
1262                         $$.sdy = $1;
1263                         $$.yreg = $1;
1264                         $$.flags = R_R6|R_R5|R_SDY|R_YREG|R_SFRAC;}
1265         |       AREG
1266                         {switch($1) {
1267                                 case 0: 
1268                                         $$.r6 = $$.r5 = 0x08 | 0; 
1269                                         break;
1270                                 case 1: 
1271                                         $$.r6 = $$.r5 = 0x08 | 4; 
1272                                         break;
1273                                 case 2: 
1274                                         $$.r6 = $$.r5 = 0x08 | 2; 
1275                                         break;
1276                         }
1277                         $$.flags = R_R6|R_R5|R_UINT;}
1278         |       BREG
1279                         {switch($1) {
1280                                 case 0: 
1281                                         $$.r6 = $$.r5 = 0x08 | 1; break;
1282                                 case 1: 
1283                                         $$.r6 = $$.r5 = 0x08 | 5; break;
1284                                 case 2: 
1285                                         $$.r6 = $$.r5 = 0x08 | 3; break;
1286                         }
1287                         $$.flags = R_R6|R_R5|R_UINT;}
1288         |       AAAA
1289                         {$$.r6 = $$.r5 = 0x0E;
1290                         $$.sdx = $$.sdy = 0x2;
1291                         $$.ab = 0;
1292                         $$.lsd = 4;
1293                         $$.flags = R_R6|R_R5|R_SDX|R_SDY|R_AB|R_LSD|R_SFRAC;}
1294         |       BBBB
1295                         {$$.r6 = $$.r5 = 0x0F;
1296                         $$.sdx = $$.sdy = 0x3;
1297                         $$.ab = 1;
1298                         $$.lsd = 5;
1299                         $$.flags = R_R6|R_R5|R_SDX|R_SDY|R_AB|R_LSD|R_SFRAC;}
1300         |       RREG
1301                         {$$.r6 = $$.r5 = 0x10 | $1;
1302                         $$.r4 = 0x00 | $1;
1303                         $$.flags = R_R6|R_R5|R_R4|R_UINT;
1304                         hot_rreg = $1;}
1305         |       NREG
1306                         {$$.r6 = $$.r5 = 0x18 | $1;
1307                         $$.r4 = 0x08 | $1;
1308                         $$.flags = R_R6|R_R5|R_R4|R_UINT;
1309                         hot_nreg = $1;}
1310         |       MREG
1311                         {$$.r6 = 0x20 | $1;
1312                         $$.r5 = -1;
1313                         $$.ctl_reg = $1;
1314                         $$.flags = R_R6|R_R5|R_CTL_REG|R_UINT;
1315                         hot_mreg = $1;}
1316         |       prog_ctl_reg
1317                         {$$.r6 = 0x38 | $1;
1318                         $$.r5 = -1;
1319                         $$.ctl_reg = 0x18 | $1;
1320                         $$.flags = R_R6|R_R5|R_CTL_REG|R_UINT;}
1321         |       A10
1322                         {$$.lsd  = 0;
1323                         $$.flags = R_LSD;}
1324         |       B10
1325                         {$$.lsd = 1;
1326                         $$.flags = R_LSD;}
1327         |       XXXX
1328                         {$$.lsd = 2;
1329                         $$.flags = R_LSD;}
1330         |       YYYY
1331                         {$$.lsd = 3;
1332                         $$.flags = R_LSD;}
1333         |       AABB
1334                         {$$.lsd = 6;
1335                         $$.flags = R_LSD;}
1336         |       BBAA
1337                         {$$.lsd = 7;
1338                         $$.flags = R_LSD;}
1339         ;
1340
1341 prog_ctl_reg
1342         :       SR
1343                         {$$ = 1;}
1344         |       OMR
1345                         {$$ = 2;}
1346         |       SP
1347                         {$$ = 3;}
1348         |       SSH
1349                         {$$ = 4;}
1350         |       SSL
1351                         {$$ = 5;}
1352         |       LA
1353                         {$$ = 6;}
1354         |       LC
1355                         {$$ = 7;}
1356         ;
1357
1358 funky_ctl_reg
1359         :       MR
1360                         {$$ = 0;}
1361         |       CCR
1362                         {$$ = 1;}
1363         |       OMR
1364                         {$$ = 2;}
1365         ;
1366
1367 /*%%%************************* parallel moves *************/
1368
1369 parallel_move
1370         :       i_move
1371         |       u_move
1372         |       x_or_y_move
1373         |       xr_move
1374         |       ry_move
1375         |       r_move
1376         |       xy_move
1377         |       l_move
1378         ;
1379
1380 i_move  :       ix ',' regs
1381                         {int ival = n2int($1);
1382                         int frac = n2frac($1);
1383                         int value;
1384                         BOOL shortform = FALSE;
1385                         if($3.flags & R_CTL_REG) {
1386                                 yyerror("please use MOVEC for control register moves");
1387                                 break;
1388                         }
1389                         if(($3.flags & R_SFRAC) && $1.type == FLT) {
1390                                 if((frac & 0xFFFF) == 0 && 
1391                                         NOT long_symbolic_expr) {
1392                                         value = frac >> 16;
1393                                         shortform++;
1394                                 } else {
1395                                         value = frac;
1396                                 }
1397                         } else {
1398                                 if(ival <= 0xFF && ival >= -0xFF && NOT long_symbolic_expr) {
1399                                         value = ival;
1400                                         shortform++;
1401                                 } else {
1402                                         value = ival;
1403                                 }
1404                         }
1405
1406                         if(shortform) {
1407                                 w0 |= 0x200000 | (value & 0xFF) << 8 |
1408                                         $3.r5 << 16;
1409                         } else {
1410                                 w0 |= 0x400000 | 0x00F400 |
1411                                         ($3.r5 >> 3 & 3) << 20 | 
1412                                         ($3.r5 & 7) << 16;
1413                                 uses_w1++; w1 = value;
1414                         }}
1415         ;
1416
1417 r_move  :       regs ',' regs
1418                         {
1419                                 if($3.flags & R_CTL_REG) {
1420                                         yyerror("please use MOVEC for control register moves");
1421                                         break;
1422                                 }
1423                                 if($1.flags & R_R5 & $3.flags) 
1424                                         w0 |= 0x200000 | $3.r5 << 8 | $1.r5 << 13;
1425                                 else
1426                                         yyerror("illegal R move");
1427                         }       
1428         ;
1429
1430 u_move  :       ea_short
1431                         {w0 |= 0x204000 | $1 << 8;}
1432         ;
1433
1434 x_or_y_move
1435         :       x_or_y ea ',' regs
1436                         {w0 |= 0x40C000 | $1 << 19;
1437                         if(expr_seg != ANY && ($1 == 0 && expr_seg != XDATA ||
1438                                 $1 == 1 && expr_seg != YDATA))
1439                                 yywarning("warning: space mismatch");
1440                         if($4.flags & R_CTL_REG) {
1441                                 yyerror("please use MOVEC for control register moves");
1442                                 break;
1443                         }
1444                         w0 |= ($4.r5 >> 3 & 3) << 20 | ($4.r5 & 7) << 16;}
1445         |       x_or_y abs_short_addr ',' regs
1446                         {w0 |= 0x408000 | $1 << 19 | ($2 & 0x3F) << 8;
1447                         if(expr_seg != ANY && ($1 == 0 && expr_seg != XDATA ||
1448                                 $1 == 1 && expr_seg != YDATA))
1449                                 yywarning("warning: space mismatch");
1450                         if($4.flags & R_CTL_REG) {
1451                                 yyerror("please use MOVEC for control register moves");
1452                                 break;
1453                         }
1454                         if($2 > 0x003F && pass == 2)
1455                                 yywarning("warning: address operand truncated");
1456                         w0 |= ($4.r5>> 3 & 3) << 20 | ($4.r5 & 7) << 16;}
1457         |       regs ',' x_or_y ea
1458                         {hot_rreg = hot_nreg = hot_mreg = -1;
1459                         w0 |= 0x404000 | $3 << 19;
1460                         if(expr_seg != ANY && ($3 == 0 && expr_seg != XDATA ||
1461                                 $3 == 1 && expr_seg != YDATA))
1462                                 yywarning("warning: space mismatch");
1463                         if($1.flags & R_CTL_REG) {
1464                                 yyerror("please use MOVEC for control register moves");
1465                                 break;
1466                         }
1467                         w0 |= ($1.r5 >> 3 & 3) << 20 | ($1.r5 & 7) << 16;}
1468         |       regs ',' x_or_y abs_short_addr
1469                         {hot_rreg = hot_nreg = hot_mreg = -1;
1470                         w0 |= 0x400000 | $3 << 19 | ($4 & 0x3F) << 8;
1471                         if($1.flags & R_CTL_REG) {
1472                                 yyerror("please use MOVEC for control register moves");
1473                                 break;
1474                         }
1475                         if(expr_seg != ANY && ($3 == 0 && expr_seg != XDATA ||
1476                                 $3 == 1 && expr_seg != YDATA))
1477                                 yywarning("warning: space mismatch");
1478                         if($4 > 0x003F && pass == 2)
1479                                 yywarning("warning: address operand truncated");
1480                         w0 |= ($1.r5 >> 3 & 3) << 20 | ($1.r5 & 7) << 16;}
1481         |       ix_long ',' regs
1482                         {w0 |= 0x400000 | 0x00F400 | ($3.r5 >> 3 & 3) << 20 |
1483                             ($3.r5 & 7) << 16;
1484                         if($3.flags & R_CTL_REG) {
1485                                 yyerror("please use MOVEC for control register moves");
1486                                 break;
1487                         }
1488                         uses_w1++; w1 = n2frac($1);
1489                         }
1490         ;
1491
1492 xr_move
1493         :       x_or_y /* XMEM */ ea ',' regs   regs /* a_b */ ',' YREG
1494                         {hot_rreg = hot_nreg = hot_mreg = -1;
1495                         if(expr_seg != ANY && ($1 == 0 && expr_seg != XDATA ||
1496                                 $1 == 1 && expr_seg != YDATA))
1497                                 yywarning("warning: space mismatch");
1498                         if($1 == 0 && $5.flags & R_AB) {
1499                                 w0 |= 0x108000 | $4.sdx << 18 | $5.ab << 17 |
1500                                         $7 << 16;
1501                         } else {
1502                                 yyerror("illegal X:R move");
1503                         }}
1504         |       ix ',' regs             regs /* a_b */ ',' YREG
1505                         {hot_rreg = hot_nreg = hot_mreg = -1;
1506                         if($4.flags & R_AB) {
1507                                 w0 |= 0x10B400 | $3.sdx << 18 | $4.ab << 17 |
1508                                         $6 << 16;
1509                                 uses_w1++;
1510                                 w1 |= n2frac($1) & 0xFFFFFF;
1511                         } else {
1512                                 yyerror("illegal X:R move");
1513                         }}
1514         |       regs ',' x_or_y /* XMEM */ ea   regs /* a_b */ ',' regs/*YREG*/
1515                         {hot_rreg = hot_nreg = hot_mreg = -1;
1516                         if(expr_seg != ANY && ($3 == 0 && expr_seg != XDATA ||
1517                                 $3 == 1 && expr_seg != YDATA))
1518                                 yywarning("warning: space mismatch");
1519                         if($1.flags & R_SDX && $3 == 0 && $5.flags & R_AB &&
1520                                 $7.flags & R_YREG) {
1521                                 w0 |= 0x100000 | $1.sdx << 18 | $5.ab << 17 |
1522                                         $7.yreg << 16;
1523                         } else if($1.flags & R_AB && $3 == 0 && 
1524                                 $5.flags & R_XREG && $7.flags & R_AB) {
1525                                 if($5.xreg != 0) yyerror("must use X0");
1526                                 if($1.ab == 0 && $7.ab == 0)
1527                                         w0 |= 0x080000;
1528                                 else if($1.ab == 1 && $7.ab == 1)
1529                                         w0 |= 0x090000;
1530                                 else
1531                                         yyerror("illegal X:R move");
1532                         } else {
1533                                 yyerror("illegal X:R move");
1534                         }}
1535         ;
1536
1537 ry_move :       regs /* a_b */ ',' regs /* XREG */      YMEM ea ',' regs
1538                         {hot_rreg = hot_nreg = hot_mreg = -1;
1539                         if($3.flags & R_XREG && $7.flags & (R_YREG|R_AB)) {
1540                                 w0 |= 0x10C000 | $1.ab << 19 | $3.xreg << 18 |
1541                                         $7.sdy << 16;
1542                         } else {
1543                                 yyerror("illegal R:Y move");
1544                         }}
1545         |       regs /* a_b */ ',' regs /* XREG */      ix ',' regs
1546                         {hot_rreg = hot_nreg = hot_mreg = -1;
1547                         if($3.flags & R_XREG && $6.flags & (R_YREG|R_AB)) {
1548                                 w0 |= 0x10F400 | $1.ab << 19 | $3.xreg << 18 |
1549                                         $6.sdy << 16;
1550                                 uses_w1++;
1551                                 w1 |= n2frac($4) & 0xFFFFFF;
1552                         } else {
1553                                 yyerror("illegal R:Y move");
1554                         }}
1555         |       regs /* a_b */ ',' regs /* XREG */      regs ',' YMEM ea
1556                         {hot_rreg = hot_nreg = hot_mreg = -1;
1557                         if($1.flags & R_AB && $3.flags & R_XREG) {
1558                                 w0 |= 0x104000 | $1.ab << 19 | $3.xreg << 18 |
1559                                 $4.sdy << 16;
1560                         } else if ($1.flags & R_YREG && $3.flags & R_AB &&
1561                                 $4.flags & R_AB) {
1562                                 if($1.yreg != 0) yyerror("must use Y0");
1563                                 if($3.ab == 0 && $4.ab == 0)
1564                                         w0 |= 0x088000;
1565                                 else if($3.ab == 1 && $4.ab == 1)
1566                                         w0 |= 0x098000;
1567                                 else
1568                                         yyerror("illegal R:Y move");
1569                         } else {
1570                                 yyerror("illegal R:Y move");
1571                         }}
1572         ;
1573
1574 l_move
1575         :       LMEM ea ',' regs /* lsd */
1576                         {if($4.flags & R_CTL_REG) {
1577                                 yyerror("please use MOVEC for control register moves");
1578                                 break;
1579                         }
1580                         w0 |= 0x40C000 | ($4.lsd & 3) << 16 | ($4.lsd >> 2) << 19;}
1581         |       regs /* lsd */ ',' LMEM ea
1582                         {hot_rreg = hot_nreg = hot_mreg = -1;
1583                         if($1.flags & R_CTL_REG) {
1584                                 yyerror("please use MOVEC for control register moves");
1585                                 break;
1586                         }
1587                         w0 |= 0x404000 | ($1.lsd & 3) << 16 | ($1.lsd >> 2) << 19;}
1588         |       LMEM abs_short_addr ',' regs /* lsd */
1589                         {w0 |= 0x408000 | ($4.lsd & 3) << 16 | ($4.lsd >> 2) << 19;
1590                         if($4.flags & R_CTL_REG) {
1591                                 yyerror("please use MOVEC for control register moves");
1592                                 break;
1593                         }
1594                         if($2 > 0x003F && pass == 2)
1595                                 yywarning("warning: address operand truncated");
1596                         w0 |= ($2 & 0x3F) << 8;}
1597         |       regs /* lsd */ ',' LMEM abs_short_addr
1598                         {hot_rreg = hot_nreg = hot_mreg = -1;
1599                         w0 |= 0x400000 | ($1.lsd & 3) << 16 | ($1.lsd >> 2) << 19;
1600                         if($1.flags & R_CTL_REG) {
1601                                 yyerror("please use MOVEC for control register moves");
1602                                 break;
1603                         }
1604                         if($4 > 0x003F && pass == 2)
1605                                 yywarning("warning: address operand truncated");
1606                         w0 |= ($4 & 0x3F) << 8;}
1607         ;
1608
1609 xy_move
1610         :       x_or_y /*XMEM*/ ea /*ea_strange*/ ',' regs      YMEM ea /*ea_strange*/ ',' regs
1611                         {int eax = $2, eay = $6,
1612                              regx = ($4.flags & R_AB) ? $4.ab | 2 : $4.xreg,
1613                              regy = ($8.flags & R_AB) ? $8.ab | 2 : $8.yreg;
1614                         hot_rreg = hot_nreg = hot_mreg = -1;
1615                         if((eax & 0x400) == (eay & 0x400))
1616                                 yyerror("registers must be in opposite halves");
1617                         if(!($4.flags & (R_AB | R_XREG)))
1618                                 yyerror("invalid X move register");
1619                         if(!($8.flags & (R_AB | R_YREG)))
1620                                 yyerror("invalid Y move register");
1621                         if($4.flags & R_AB &&
1622                            $8.flags & R_AB &&
1623                            $4.ab == $8.ab)
1624                                 yyerror("duplicate destination register");
1625                         w0 = w0 & 0xFF | 0xC08000;      /* both write */
1626                         w0 |= eax & 0x1f00 | (eay & 0x300) << 5 | (eay & 0x1800) << 9 | regx << 18 | regy << 16;}
1627         |       x_or_y /*XMEM*/ ea /*ea_strange*/ ',' regs      regs ',' YMEM ea /*ea_strange*/
1628                         {int eax = $2, eay = $8,
1629                              regx = ($4.flags & R_AB) ? $4.ab | 2 : $4.xreg,
1630                              regy = ($5.flags & R_AB) ? $5.ab | 2 : $5.yreg;
1631                         hot_rreg = hot_nreg = hot_mreg = -1;
1632                         if((eax & 0x400) == (eay & 0x400))
1633                                 yyerror("registers must be in opposite halves");
1634                         if(!($4.flags & (R_AB | R_XREG)))
1635                                 yyerror("invalid X move register");
1636                         if(!($5.flags & (R_AB | R_YREG)))
1637                                 yyerror("invalid Y move register");
1638                         w0 = w0 & 0xFF | 0x808000;      /* X:write, Y:read */
1639                         w0 |= eax & 0x1f00 | (eay & 0x300) << 5 | (eay & 0x1800) << 9 | regx << 18 | regy << 16;}
1640         |       regs ',' x_or_y /*XMEM*/ ea /*ea_strange*/      YMEM ea /*ea_strange*/ ',' regs
1641                         {int eax = $4, eay = $6,
1642                              regx = ($1.flags & R_AB) ? $1.ab | 2 : $1.xreg,
1643                              regy = ($8.flags & R_AB) ? $8.ab | 2 : $8.yreg;
1644                         hot_rreg = hot_nreg = hot_mreg = -1;
1645                         if((eax & 0x400) == (eay & 0x400))
1646                                 yyerror("registers must be in opposite halves");
1647                         if(!($1.flags & (R_AB | R_XREG)))
1648                                 yyerror("invalid X move register");
1649                         if(!($8.flags & (R_AB | R_YREG)))
1650                                 yyerror("invalid Y move register");
1651                         w0 = w0 & 0xFF | 0xC00000;      /* X:read, Y:write */
1652                         w0 |= eax & 0x1f00 | (eay & 0x300) << 5 | (eay & 0x1800) << 9 | regx << 18 | regy << 16;}
1653         |       regs ',' x_or_y /*XMEM*/ ea /*ea_strange*/      regs ',' YMEM ea /*ea_strange*/
1654                         {int eax = $4, eay = $8,
1655                              regx = ($1.flags & R_AB) ? $1.ab | 2 : $1.xreg,
1656                              regy = ($5.flags & R_AB) ? $5.ab | 2 : $5.yreg;
1657                         hot_rreg = hot_nreg = hot_mreg = -1;
1658                         if((eax & 0x400) == (eay & 0x400))
1659                                 yyerror("registers must be in opposite halves");
1660                         if(!($1.flags & (R_AB | R_XREG)))
1661                                 yyerror("invalid X move register");
1662                         if(!($5.flags & (R_AB | R_YREG)))
1663                                 yyerror("invalid Y move register");
1664                         w0 = w0 & 0xFF | 0x800000;      /* both read */
1665                         w0 |= eax & 0x1f00 | (eay & 0x300) << 5 | (eay & 0x1800) << 9 | regx << 18 | regy << 16;}
1666         ;
1667
1668 /*%%%******* absolute address and immediate data fields ************/
1669
1670 num     :       CHEX
1671                         {$$ = $1;}
1672         |       CDEC
1673                         {$$ = $1;}
1674         |       FRAC
1675                         {$$ = $1;}
1676         ;
1677
1678 ix      :       '#' expr
1679                         {$$ = $2; expr_seg = ANY;}
1680         |       '#' '<' expr
1681                         {$$.val.i = n2int($3) & 0xFF;
1682                         $$.type = INT;
1683                         expr_seg = ANY;
1684                         long_symbolic_expr = FALSE;}
1685         ;
1686
1687 ix_long :       '#' '>' expr
1688                         {$$ = $3; expr_seg = ANY;}
1689         ;
1690
1691 abs_addr
1692         :       expr
1693                         {$$ = n2int($1);
1694                         expr_seg = $1.seg;}
1695         ;
1696
1697 abs_short_addr
1698         :       '<' expr
1699                         {$$ = n2int($2);
1700                         expr_seg = $2.seg;}
1701         ;
1702
1703 io_short_addr
1704         :       SHL expr
1705                         {$$ = n2int($2);
1706                         expr_seg = $2.seg;} 
1707         ;
1708
1709 num_or_sym
1710         :       num
1711                         {$$ = $1;}
1712         |       SYM
1713                         {$$ = sym_ref($1); free($1);}
1714         |       io_short_addr
1715                         {$$.type = INT; $$.val.i = $1; $$.seg = expr_seg;}
1716         ;
1717
1718 num_or_sym_expr
1719         :       num
1720                         {$$ = $1; expr_seg = $1.seg;}
1721         |       SYM
1722                         {$$ = sym_ref($1);
1723                         free($1);
1724                         long_symbolic_expr++;
1725                         expr_seg = $$.seg;
1726                         }
1727         |       CHAR
1728                         {$$.type = INT; $$.val.i = $1 & 0xFFFFFF; expr_seg = $$.seg = ANY;}
1729         |       '*'
1730                         {$$.type = INT; $$.val.i = pc; expr_seg = $$.seg = ANY;}
1731         |       OP_PI
1732                         {$$.type = FLT; $$.val.f = acos(-1.0); expr_seg = $$.seg = ANY;}
1733         ;
1734
1735 expr
1736         :       OP_INT '(' expr ')'
1737                         {$$.type = INT; 
1738                         if($3.type == INT)
1739                                 $$.val.i = $3.val.i;
1740                         else
1741                                 $$.val.i = $3.val.f;
1742                         $$.seg = $3.seg;
1743                         }
1744         |       expr '|' expr
1745                         {$$ = binary_op($1, '|', $3);}
1746         |       expr '^' expr
1747                         {$$ = binary_op($1, '^', $3);}
1748         |       expr '&' expr
1749                         {$$ = binary_op($1, '&', $3);}
1750         |       expr SHR expr
1751                         {$$ = binary_op($1, SHR, $3);}
1752         |       expr SHL expr
1753                         {$$ = binary_op($1, SHL, $3);}
1754         |       expr '-' expr
1755                         {$$ = binary_op($1, '-', $3);}
1756         |       expr '+' expr
1757                         {$$ = binary_op($1, '+', $3);}
1758         |       expr '%' expr
1759                         {$$ = binary_op($1, '%', $3);}
1760         |       expr '/' expr
1761                         {$$ = binary_op($1, '/', $3);}
1762         |       expr '*' expr
1763                         {$$ = binary_op($1, '*', $3);}
1764         |       '-' expr %prec '~'
1765                         {$$ = unary_op('-', $2);}
1766         |       '~' expr
1767                         {$$ = unary_op('~', $2);}
1768         |       OP_SIN '(' expr ')'
1769                         {$$ = unary_op('s', $3);}
1770         |       OP_COS '(' expr ')'
1771                         {$$ = unary_op('c', $3);}
1772         |       OP_TAN '(' expr ')'
1773                         {$$ = unary_op('t', $3);}
1774         |       OP_ASIN '(' expr ')'
1775                         {$$ = unary_op('S', $3);}
1776         |       OP_ACOS '(' expr ')'
1777                         {$$ = unary_op('C', $3);}
1778         |       OP_ATAN '(' expr ')'
1779                         {$$ = unary_op('T', $3);}
1780         |       OP_EXP '(' expr ')'
1781                         {$$ = unary_op('e', $3);}
1782         |       OP_LN '(' expr ')'
1783                         {$$ = unary_op('l', $3);}
1784         |       OP_LOG '(' expr ')'
1785                         {$$ = unary_op('L', $3);}
1786         |       OP_ABS '(' expr ')'
1787                         {$$ = unary_op('a', $3);}
1788         |       OP_POW '(' expr ',' expr ')'
1789                         {$$ = binary_op($3, 'p', $5);}
1790         |       '(' expr ')'
1791                         {$$ = $2;}
1792         |       num_or_sym_expr
1793                         {$$ = $1;}
1794         ;
1795
1796 /*%%%****************** end ******************************/
1797
1798 %%
1799
1800 #include <stdio.h>
1801 #include <setjmp.h>
1802 #include <sys/signal.h>
1803
1804 int yydebug;
1805
1806 struct n binary_op(a1, op, a2)
1807 struct n a1, a2;
1808 int op;
1809 {
1810         struct n result;
1811         int iarg1, iarg2;
1812         double farg1, farg2;
1813
1814         if(a1.type == UNDEF || a2.type == UNDEF) {
1815                 result.type = UNDEF;
1816                 return result;
1817         }
1818
1819         iarg1 = a1.type == INT ? a1.val.i : a1.val.f;
1820         iarg2 = a2.type == INT ? a2.val.i : a2.val.f;
1821
1822         farg1 = a1.type == INT ? a1.val.i : a1.val.f;
1823         farg2 = a2.type == INT ? a2.val.i : a2.val.f;
1824
1825         /* figure out target segment */
1826
1827         if(a1.seg == a2.seg)
1828                 result.seg = a1.seg;
1829         else if(a1.seg == ANY)
1830                 result.seg = a2.seg;
1831         else if(a2.seg == ANY)
1832                 result.seg = a1.seg;
1833         else
1834                 result.seg = NONE;
1835
1836         /* promote to float automatically */
1837
1838         if(a1.type != a2.type) {
1839                 if(a1.type == INT) {
1840                         a1.val.f = a1.val.i;            /* truncate */
1841                         a1.type = FLT;
1842                 } else {
1843                         a2.val.f = a2.val.i;            /* truncate */
1844                 }
1845         }
1846         result.type = a1.type;
1847
1848         /* do the op */
1849
1850         switch(op) {
1851         case '+':
1852                 if(result.type == INT) result.val.i = a1.val.i + a2.val.i;
1853                 else result.val.f = a1.val.f + a2.val.f;
1854                 break;
1855         case '-':
1856                 if(result.type == INT) result.val.i = a1.val.i - a2.val.i;
1857                 else result.val.f = a1.val.f - a2.val.f;
1858                 break;
1859         case '*':
1860                 if(result.type == INT) result.val.i = a1.val.i * a2.val.i;
1861                 else result.val.f = a1.val.f * a2.val.f;
1862                 break;
1863         case '/':
1864                 if(result.type == INT) result.val.i = a1.val.i / a2.val.i;
1865                 else result.val.f = a1.val.f / a2.val.f;
1866                 break;
1867         case '%':
1868                 result.val.i = iarg1 % iarg2;
1869                 result.type = INT;
1870                 break;
1871         case SHL:
1872                 result.val.i = iarg1 << iarg2;
1873                 result.type = INT;
1874                 break;
1875         case SHR:
1876                 result.val.i = iarg1 >> iarg2;
1877                 result.type = INT;
1878                 break;
1879         case '|':
1880                 result.val.i = iarg1 | iarg2;
1881                 result.type = INT;
1882                 break;
1883         case '&':
1884                 result.val.i = iarg1 & iarg2;
1885                 result.type = INT;
1886                 break;
1887         case '^':
1888                 result.val.i = iarg1 ^ iarg2;
1889                 result.type = INT;
1890                 break;
1891         case 'p':
1892                 result.val.f = pow(farg1, farg2);
1893                 result.type = FLT;
1894         }
1895
1896         return result;
1897 }
1898
1899 jmp_buf unary_env;
1900
1901 void
1902 sigfpu()
1903 {
1904         longjmp(unary_env, 1);
1905 }
1906
1907 char *unary_name(op)
1908 {
1909         switch(op) {
1910         case 's':       return "sin";
1911         case 'c':       return "cos";
1912         case 't':       return "tan";
1913         case 'S':       return "asin";
1914         case 'C':       return "acos";
1915         case 'T':       return "atan";
1916         case 'e':       return "exp";
1917         case 'l':       return "ln";
1918         case 'L':       return "log";
1919         case 'a':       return "abs";
1920         }
1921 }
1922
1923 struct n unary_op(op, a1)
1924 int op;
1925 struct n a1;
1926 {
1927         struct n result;
1928         void (*orig)();
1929         double farg;
1930
1931         if(a1.type == UNDEF) {
1932                 result.type = UNDEF;
1933                 return result;
1934         }
1935
1936         result.seg = a1.seg;
1937
1938         /* do the op */
1939
1940         orig = signal(SIGFPE, sigfpu);
1941         if(setjmp(unary_env)) {
1942                 yyerror("floating point exception in function %s", unary_name(op));
1943                 result.val.i = result.val.f = 0;
1944         } else {
1945                 farg = a1.type == INT ? (double)a1.val.i : a1.val.f;
1946                 switch(op) {
1947                 case '-':
1948                         result.type = a1.type;
1949                         if(a1.type == INT) result.val.i = -a1.val.i;
1950                         else result.val.f = -a1.val.f;
1951                         break;
1952                 case '~':
1953                         result.type = a1.type;
1954                         if(a1.type == INT) result.val.i = ~a1.val.i;
1955                         else result.val.f = ~(int)a1.val.f;
1956                         break;
1957                 case 'a':
1958                         result.type = a1.type;
1959                         if(a1.type == INT) result.val.i = a1.val.i < 0 ? -a1.val.i : a1.val.i;
1960                         else result.val.f = result.val.f = a1.val.f < 0 ? -a1.val.f : a1.val.f;
1961                         break;
1962                 case 's':
1963                         result.type = FLT;
1964                         result.val.f = sin(farg);
1965                         break;
1966                 case 'c':
1967                         result.type = FLT;
1968                         result.val.f = cos(farg);
1969                         break;
1970                 case 't':
1971                         result.type = FLT;
1972                         result.val.f = tan(farg);
1973                         break;
1974                 case 'S':
1975                         result.type = FLT;
1976                         result.val.f = asin(farg);
1977                         break;
1978                 case 'C':
1979                         result.type = FLT;
1980                         result.val.f = acos(farg);
1981                         break;
1982                 case 'T':
1983                         result.type = FLT;
1984                         result.val.f = atan(farg);
1985                         break;
1986                 case 'e':
1987                         result.type = FLT;
1988                         result.val.f = exp(farg);
1989                         break;
1990                 case 'l':
1991                         result.type = FLT;
1992                         result.val.f = log(farg);
1993                         break;
1994                 case 'L':
1995                         result.type = FLT;
1996                         result.val.f = log10(farg);
1997                         break;
1998                 }
1999         }
2000         signal(SIGFPE, orig);
2001
2002         return result;
2003 }
2004
2005 n2int(n)
2006 struct n n;
2007 {
2008         if(n.type == UNDEF)
2009                 return UNDEF;
2010         else if(n.type == INT)
2011                 return n.val.i;
2012         else
2013                 return n.val.f;
2014 }
2015
2016 n2frac(n)
2017 struct n n;
2018 {
2019         double adval = n.val.f >= 0.0 ? n.val.f : -n.val.f;
2020
2021         if(n.type == UNDEF)
2022                 return UNDEF;
2023         else if(n.type == INT)
2024                 return n.val.i;
2025         else if(n.val.f == -1.0)
2026                 return 0x800000;
2027
2028         adval -= (double)(int)adval;
2029         adval *= (double)0x800000;
2030         adval += 0.5;
2031
2032         if(n.val.f >= 0.0)
2033                 return adval;
2034         else
2035                 return -adval;
2036 }
2037
2038 extern struct {int n; char *name;} tok_tab[];
2039 extern int n_tok;
2040
2041 char *tok_print(tok)
2042 int tok;
2043 {
2044         int i;
2045         static char buf[32];
2046
2047         if(tok == '1') {
2048                 i = 1;
2049         }
2050
2051         if(tok < 256) {
2052                 sprintf(buf, tok < ' ' ? "\\z%02X" : "%c", tok & 0xFF);
2053                 return buf;
2054         } else {
2055                 for(i = 0; i < n_tok; i++) {
2056                         if(tok == tok_tab[i].n)
2057                                 return tok_tab[i].name;
2058                 }
2059         }
2060         return "*bogus*";
2061 }
2062
2063 yyerror(s, a0, a1, a2, a3)
2064 char *s, *a0, *a1, *a2, *a3;
2065 {
2066         extern int error;
2067         char buf[1024];
2068
2069         error++;
2070         sprintf(buf, s, a0, a1, a2, a3);
2071
2072         if(pass == 2) {
2073                 fprintf(stderr, "%s: line %d: %s (tok=%s)\n", curfile, curline,
2074                         buf, tok_print(yychar));
2075                 fprintf(stderr, "%s\n", cur_line);
2076                 printf("%s: line %d: %s (tok=%s)\n", curfile, curline,
2077                         buf, tok_print(yychar));
2078         }
2079 }
2080
2081 yywarning(s, a0, a1, a2, a3)
2082 char *s, *a0, *a1, *a2, *a3;
2083 {
2084         extern int warning;
2085         char buf[1024];
2086
2087         warning++;
2088         sprintf(buf, s, a0, a1, a2, a3);
2089
2090         if(pass == 2) {
2091                 fprintf(stderr, "%s: line %d: %s (tok=%s)\n", curfile, curline,
2092                         buf, tok_print(yychar));
2093                 fprintf(stderr, "%s\n", cur_line);
2094                 printf("%s: line %d: %s (tok=%s)\n", curfile, curline,
2095                         buf, tok_print(yychar));
2096         }
2097 }
2098
2099 char *luntab(s)
2100 char *s;
2101 {
2102         static char buf[1024];
2103         int p;
2104
2105         strcpy(buf, s);
2106
2107         untab(buf);
2108         p = strlen(buf);
2109
2110         if(buf[p - 1] == '\n')
2111                 buf[p - 1] = '\0';
2112
2113         return buf;
2114 }