1
0
mirror of https://github.com/fachat/xa65.git synced 2024-06-08 07:29:39 +00:00
xa65/xa/src/xaa.c
2023-12-07 23:34:19 +01:00

299 lines
6.5 KiB
C

/* xa65 - 65xx/65816 cross-assembler and utility suite
*
* Copyright (C) 1989-1997 Andre Fachat (afachat@gmx.de)
*
* Preprocessing arithmetic module
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include "xah.h"
#include "xad.h"
#include "xar.h"
#include "xa.h"
#include "xal.h"
#include "xaa.h"
#include "xat.h"
static int pr[] = { P_START, P_ADD, P_ADD, P_MULT, P_MULT, P_SHIFT, P_SHIFT,
P_CMP,
P_CMP, P_EQU, P_CMP, P_CMP, P_EQU, P_AND, P_XOR, P_OR,
P_LAND, P_LOR, P_EQU, P_START };
static int pp, pcc;
static int fundef;
static int ag_term(signed char*, int, int*, int*, int*);
static int get_op(signed char*, int*);
static int do_op(int*, int, int);
/* s = string, v = variable */
int a_term(signed char *s, int *v, int *l, int xpc, int *pfl, int *label, int f) {
int er = E_OK;
int afl = 0, bfl;
*pfl = 0;
fundef = f;
pp = 0;
pcc = xpc;
if (s[0] == '<') {
pp++;
er = ag_term(s, P_START, v, &afl, label);
bfl = afl & (A_MASK >> 8);
if (bfl && (bfl != (A_ADR >> 8)) && (bfl != (A_LOW >> 8))) {
/*fprintf(stderr,"low byte relocation for a high byte - won't work!\n");*/
errout(W_LOWACC);
}
if (afl)
*pfl = A_LOW | ((afl << 8) & A_FMASK);
*v = *v & 255;
} else if (s[pp] == '>') {
pp++;
er = ag_term(s, P_START, v, &afl, label);
bfl = afl & (A_MASK >> 8);
if (bfl && (bfl != (A_ADR >> 8)) && (bfl != (A_HIGH >> 8))) {
/*fprintf(stderr,"high byte relocation for a low byte - won't work!\n");*/
errout(W_HIGHACC);
}
if (afl)
*pfl = A_HIGH | ((afl << 8) & A_FMASK) | (*v & 255);
*v = (*v >> 8) & 255;
} else if (s[pp] != T_END) {
er = ag_term(s, P_START, v, &afl, label);
bfl = afl & (A_MASK >> 8);
if (bfl && (bfl != (A_ADR >> 8))) {
/*fprintf(stderr,"address relocation for a low or high byte - won't work!\n");*/
errout(W_ADDRACC);
}
if (afl)
*pfl = A_ADR | ((afl << 8) & A_FMASK);
} else {
er = E_SYNTAX;
}
*l = pp;
//fprintf(stderr, "a_term: nolink=%d, noundef=%d ->er=%d; l=%d, pp=%d, afl->%04x *pfl=%04x, (pc=%04x)\n",nolink, noundef ,er, *l, pp, afl,*pfl, xpc);
return (er);
}
static int ag_term(signed char *s, int p, int *v, int *nafl, int *label) {
int er = E_OK, o, w, mf = 1, afl;
afl = 0;
//fprintf(stderr, "ag_term(%02x %02x %02x %02x %02x %02x\n",s[0],s[1],s[2],s[3],s[4],s[5]);
while (s[pp] == '-') {
pp++;
mf = -mf;
}
#if(0) /* NYI: this is hacked into .assert for now */
if(s[pp]==18) /* logical not */
{
pp++;
if(!(er=ag_term(s,P_START,v,&afl,label)))
{
if(s[pp]!=')')
er=E_SYNTAX;
else
pp++;
}
*v = !(*v);
} else
#endif
if (s[pp] == '(') {
pp++;
if (!(er = ag_term(s, P_START, v, &afl, label))) {
if (s[pp] != ')')
er = E_SYNTAX;
else
pp++;
}
} else if (s[pp] == T_LABEL) {
er = l_get(cval(s + pp + 1), v, &afl);
/*
printf("label: er=%d, seg=%d, afl=%d, nolink=%d, fundef=%d\n",
er, segment, afl, nolink, fundef);
*/
if (er == E_NODEF && segment != SEG_ABS && fundef) {
if (nolink || ((afl == SEG_UNDEF) || (afl == SEG_UNDEFZP))) {
er = E_OK;
*v = 0;
if (afl != SEG_UNDEFZP) {
afl = SEG_UNDEF;
}
*label = cval(s + pp + 1);
}
}
pp += 3;
} else if (s[pp] == T_VALUE || s[pp] == T_CAST) {
while (s[pp] == T_CAST) {
pp += 2;
}
*v = lval(s + pp + 1);
pp += 5;
/*
printf("value: v=%04x\n",*v);
*/
} else if (s[pp] == T_POINTER) {
afl = s[pp + 1];
*v = cval(s + pp + 2);
pp += 6;
/*
printf("pointer: v=%04x, afl=%04x\n",*v,afl);
*/
} else if (s[pp] == '*') {
*v = pcc;
pp++;
afl = segment;
} else {
er = E_SYNTAX;
}
*v *= mf;
while (!er && s[pp] != ')' && s[pp] != ']' && s[pp] != ',' && s[pp] != T_END
&& s[pp] != T_COMMENT) {
//fprintf(stderr, "ag_term while: s[pp=%d]=%02x\n", pp, s[pp]);
er = get_op(s, &o);
if (!er && pr[o] > p) {
pp += 1;
if (!(er = ag_term(s, pr[o], &w, nafl, label))) {
if (afl || *nafl) { /* check pointer arithmetic */
if ((afl == *nafl) && (afl != SEG_UNDEFZP)
&& (afl != SEG_UNDEF) && o == 2) {
afl = 0; /* subtract two pointers */
} else if (((afl && !*nafl) || (*nafl && !afl)) && o == 1) {
afl = (afl | *nafl); /* add constant to pointer */
} else if ((afl && !*nafl) && o == 2) {
afl = (afl | *nafl); /* subtract constant from pointer */
} else {
if ((!afl && *nafl) && o == 2) {
/* subtract pointer from constant */
errout(W_SUBTRACT);
}
/* allow math in the same segment */
if (segment != SEG_ABS && segment != afl) {
if (!dsb_len) {
/*printf("ILLPOINTER=dsb_len=%d,segment=%d\n",dsb_len, segment);*/
/* e.g. adding two pointers, adding two undefined values */
er = E_ILLSEGMENT;
}
}
afl = 0;
}
}
if (!er)
er = do_op(v, w, o);
}
} else {
break;
}
}
*nafl = afl;
return (er);
}
static int get_op(signed char *s, int *o) {
int er;
*o = s[pp];
if (*o < 1 || *o > 17) {
/*
printf("*o=%d, pp=%d, s=%s\n", *o, pp, s);
for (int i=0; i< 10; i++) {
printf(" %02x", s[i]);
}
printf("\n");
*/
er = E_SYNTAX;
} else {
er = E_OK;
}
return (er);
}
static int do_op(int *w, int w2, int o) {
int er = E_OK;
switch (o) {
case 1:
*w += w2;
break;
case 2:
*w -= w2;
break;
case 3:
*w *= w2;
break;
case 4:
if (w2 != 0)
*w /= w2;
else
er = E_DIV;
break;
case 5:
*w >>= w2;
break;
case 6:
*w <<= w2;
break;
case 7:
*w = *w < w2;
break;
case 8:
*w = *w > w2;
break;
case 9:
*w = *w == w2;
break;
case 10:
*w = *w <= w2;
break;
case 11:
*w = *w >= w2;
break;
case 12:
*w = *w != w2;
break;
case 13:
*w &= w2;
break;
case 14:
*w ^= w2;
break;
case 15:
*w |= w2;
break;
case 16:
*w = *w && w2;
break;
case 17:
*w = *w || w2;
break;
}
return (er);
}