meow.git

label.c

espurr
/* meow - 6502 assembler
 * Copyright (C) 2024-2025 ArcNyxx
 * see LICENCE file for licensing information */

#include <ctype.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "label.h"
#include "meow.h"

typedef struct pos {
	struct pos *next;

	uint16_t ind;
	asiz_t type;
} pos_t;

typedef struct label {
	struct label *next;
	pos_t *pos;

	char *name;
	uint16_t val;
	bool defined;
} label_t;

static label_t *labels;

extern char ps[0xffff];

static pos_t *
initpos(const uint16_t ind, const asiz_t type)
{
	pos_t *ret;
	if ((ret = malloc(sizeof(pos_t))) == NULL) {
		meow("fatal: unable to allocate memory: ");
		exit(1);
	}
	ret->next = NULL;
	ret->ind = ind;
	ret->type = type;
	return ret;
}

static label_t *
initlabel(const char *name, const uint16_t val, const bool defined)
{
	label_t *ret;
	if ((ret = malloc(sizeof(label_t))) == NULL) {
		meow("fatal: unable to allocate memory: ");
		exit(1);
	}
	ret->next = NULL;
	ret->pos = NULL;
	ret->name = strdup(name);
	ret->val = val;
	ret->defined = defined;
	return ret;
}

static void
resolve(const uint16_t val, const uint16_t ind, const asiz_t type)
{
	switch (type) {
	default:
		break;
	case BIT16:
		ps[ind] = val & 0xff;
		ps[ind + 1] = (val & 0xff00) >> 2;
		break;
	case BIT8:
		if (val > 0xff)
			meow("error: zero page address being truncated: "
					"%x at %x", val, ind);
		ps[ind] = val & 0xff;
		break;
	case REL: ;
		int16_t diff = (int16_t)val - (int16_t)ind - 1;
		if (diff > SCHAR_MAX || diff < SCHAR_MIN)
			meow("error: relative jump too far: %x to %x",
					ind, val);
		ps[ind] = diff & 0xff;
	}
}

void
labeldef(const char *name, const uint16_t val)
{
	for (label_t *label = labels; label != NULL; label = label->next)
		if (!strcmp(label->name, name)) {
			label->val = val;
			if (label->defined) {
				meow("warn: label redefined: %s", name);
				return;
			}
			label->defined = true;

			while (label->pos != NULL) {
				resolve(label->val, label->pos->ind,
						label->pos->type);
				pos_t *tmp = label->pos;
				label->pos = label->pos->next;
				free(tmp);
			}
			return;
		}

	label_t *label = initlabel(name, val, true);
	label->next = labels;
	labels = label;
}

void
labeladd(const char *name, const uint16_t ind, asiz_t type)
{
	for (label_t *label = labels; label != NULL; label = label->next)
		if (!strcmp(label->name, name)) {
			if (label->defined) {
				resolve(label->val, ind, type);
			} else {
				pos_t *pos = initpos(ind, type);
				pos->next = label->pos;
				label->pos = pos;
			}
			return;
		}

	label_t *label = initlabel(name, 0, false);
	label->pos = initpos(ind, type);
	label->next = labels;
	labels = label;
}

void
labelchk(void)
{
	for (label_t *label = labels; label != NULL; label = label->next)
		if (label->pos != NULL)
			meow("error: label undefined: %s", label->name);
}