meow.git
direct.c
/* meow - 6502 assembler
* Copyright (C) 2024-2025 ArcNyxx
* see LICENCE file for licensing information */
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "direct.h"
#include "label.h"
#include "meow.h"
extern char ps[0xffff];
extern uint16_t pc;
static void
org(void)
{
char *next;
if ((next = strtok(NULL, " \t\n\r")) == NULL) {
meow("error: .org directive without address");
return;
}
if (strtok(NULL, " \t\n\r") != NULL)
meow("warn: .org directive followed by extraneous information");
char *endptr;
unsigned long num = strnum(next, &endptr);
if (errno != 0 || num > USHRT_MAX)
meow("warn: .org directive address too large: %s", next);
if (endptr[0] != '\0')
meow("warn: .org directive invalid address: %s", next);
pc = num & 0xffff;
}
static void
data(void)
{
char *next;
while ((next = strtok(NULL, " \t\n\r")) != NULL) {
char *endptr;
long num = strnum(next, &endptr);
if (errno != 0 || num > SHRT_MAX || num < SHRT_MIN)
meow("warn: .data directive immediate is too large: %s",
next);
if (endptr[0] != '\0')
meow("warn: .data directive immediate invalid: %s",
next);
if (num > SCHAR_MAX || num < SCHAR_MIN) {
int16_t snum = num;
ps[pc++] = snum & 0xff;
ps[pc++] = (snum & 0xff00) >> 2;
} else {
ps[pc++] = (int8_t)num;
}
}
}
static void
addr(void)
{
char *next;
while ((next = strtok(NULL, " \t\n\r")) != NULL) {
bool zp = next[0] == '!';
if (islabel(next)) {
labeladd(next + zp, pc, zp ? BIT8 : BIT16);
pc += 1 + !zp;
continue;
}
char *endptr;
long num = strnum(next + zp, &endptr);
if (endptr[0] == '\0')
meow("warn: .addr directive address invalid: %s",
next);
if (zp) {
if (errno != 0 || num > SCHAR_MAX || num < SCHAR_MIN)
meow("warn: .addr directive zero page address "
"is out of 8-bit range: %s",
next);
ps[pc++] = (int8_t)num;
} else {
if (errno != 0 || num > SHRT_MAX || num < SHRT_MIN)
meow("warn: .addr directive address is out of "
"16-bit range: %s", next);
int16_t snum = num;
ps[pc++] = snum & 0xff;
ps[pc++] = (snum & 0xff00) >> 2;
}
}
}
static void
str(void)
{
char *str;
if ((str = strtok(NULL, "\n\r")) == NULL)
return;
for (size_t i = 0; str[i] != '\0'; ++i) {
if (str[i] == '\\') {
switch (str[++i]) {
case '\\':
ps[pc++] = '\\';
break;
case 'n':
ps[pc++] = '\n';
break;
default:
meow("warn: .str directive invalid escape "
"sequence");
}
} else {
ps[pc++] = str[i];
}
}
}
void
direct(const char *dir)
{
if (!strcasecmp(dir, "org"))
org();
else if (!strcasecmp(dir, "data"))
data();
else if (!strcasecmp(dir, "addr"))
addr();
else if (!strcasecmp(dir, "str"))
str();
else
meow("error: unrecognised directive: %s", dir);
}