shithub: rgbds

ref: 42007c5c92530338c8319f5b572db286396f5cc5
dir: /src/asm/globlex.c/

View raw version
#include "asm/asm.h"
#include "asm/symbol.h"
#include "asm/rpn.h"
#include "asm/symbol.h"
#include "asm/main.h"
#include "asm/lexer.h"

#include "asmy.h"

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

UBYTE oDontExpandStrings = 0;
SLONG nGBGfxID = -1;
SLONG nBinaryID = -1;

SLONG gbgfx2bin(char ch)
{
	SLONG i;

	for (i = 0; i <= 3; i += 1) {
		if (CurrentOptions.gbgfx[i] == ch) {
			return (i);
		}
	}

	return (0);
}

SLONG binary2bin(char ch)
{
	SLONG i;

	for (i = 0; i <= 1; i += 1) {
		if (CurrentOptions.binary[i] == ch) {
			return (i);
		}

	}

	return (0);
}

SLONG char2bin(char ch)
{
	if (ch >= 'a' && ch <= 'f')
		return (ch - 'a' + 10);

	if (ch >= 'A' && ch <= 'F')
		return (ch - 'A' + 10);

	if (ch >= '0' && ch <= '9')
		return (ch - '0');

	return (0);
}

typedef SLONG(*x2bin) (char ch);

SLONG ascii2bin(char *s)
{
	SLONG radix = 10;
	SLONG result = 0;
	x2bin convertfunc = char2bin;

	switch (*s) {
	case '$':
		radix = 16;
		s += 1;
		convertfunc = char2bin;
		break;
	case '&':
		radix = 8;
		s += 1;
		convertfunc = char2bin;
		break;
	case '`':
		radix = 4;
		s += 1;
		convertfunc = gbgfx2bin;
		break;
	case '%':
		radix = 2;
		s += 1;
		convertfunc = binary2bin;
		break;
	}

	if (radix == 4) {
		SLONG c;

		while (*s != '\0') {
			c = convertfunc(*s++);
			result = result * 2 + ((c & 1) << 8) + ((c & 2) >> 1);
		}
	} else {
		while (*s != '\0')
			result = result * radix + convertfunc(*s++);
	}

	return (result);
}

ULONG ParseFixedPoint(char *s, ULONG size)
{
	char dest[256];
	ULONG i = 0, dot = 0;

	while (size && dot != 2) {
		if (s[i] == '.')
			dot += 1;

		if (dot < 2) {
			dest[i] = s[i];
			size -= 1;
			i += 1;
		}
	}

	dest[i] = 0;

	yyunputbytes(size);

	yylval.nConstValue = (SLONG) (atof(s) * 65536);

	return (1);
}

ULONG ParseNumber(char *s, ULONG size)
{
	char dest[256];

	strncpy(dest, s, size);
	dest[size] = 0;
	yylval.nConstValue = ascii2bin(dest);

	return (1);
}

ULONG ParseSymbol(char *src, ULONG size)
{
	char dest[MAXSYMLEN + 1];
	int copied = 0, size_backup = size;

	while (size && copied < MAXSYMLEN) {
		if (*src == '\\') {
			char *marg;

			src += 1;
			size -= 1;

			if (*src == '@')
				marg = sym_FindMacroArg(-1);
			else if (*src >= '0' && *src <= '9')
				marg = sym_FindMacroArg(*src);
			else {
				fatalerror("Malformed ID");
				return (0);
			}

			src += 1;
			size -= 1;

			if (marg) {
				while (*marg)
					dest[copied++] = *marg++;
			}
		} else {
			dest[copied++] = *src++;
			size -= 1;
		}
	}

	if (copied > MAXSYMLEN)
		fatalerror("Symbol too long");

	dest[copied] = 0;

	if (oDontExpandStrings == 0 && sym_isString(dest)) {
		char *s;

		yyskipbytes(size_backup);
		yyunputstr(s = sym_GetStringValue(dest));

		while (*s) {
			if (*s++ == '\n') {
				nLineNo -= 1;
			}
		}
		return (0);
	} else {
		strcpy(yylval.tzString, dest);
		return (1);
	}
}

ULONG PutMacroArg(char *src, ULONG size)
{
	char *s;

	yyskipbytes(size);
	if ((s = sym_FindMacroArg(src[1] - '0')) != NULL) {
		yyunputstr(s);
	} else {
		yyerror("Macro argument not defined");
	}
	return (0);
}

ULONG PutUniqueArg(char *src, ULONG size)
{
	src = src;
	yyskipbytes(size);
	yyunputstr(sym_FindMacroArg(-1));
	return (0);
}

enum {
	T_LEX_MACROARG = 3000,
	T_LEX_MACROUNIQUE
};

extern struct sLexInitString localstrings[];

struct sLexInitString staticstrings[] = {
	{ "||", T_OP_LOGICOR },
	{ "&&", T_OP_LOGICAND },
	{ "==", T_OP_LOGICEQU },
	{ ">", T_OP_LOGICGT },
	{ "<", T_OP_LOGICLT },
	{ ">=", T_OP_LOGICGE },
	{ "<=", T_OP_LOGICLE },
	{ "!=", T_OP_LOGICNE },
	{ "!", T_OP_LOGICNOT },
	{ "|", T_OP_OR },
	{ "^", T_OP_XOR },
	{ "&", T_OP_AND },
	{ "<<", T_OP_SHL },
	{ ">>", T_OP_SHR },
	{ "+", T_OP_ADD },
	{ "-", T_OP_SUB },
	{ "*", T_OP_MUL },
	{ "/", T_OP_DIV },
	{ "%", T_OP_MOD },
	{ "~", T_OP_NOT },

	{ "def", T_OP_DEF },

	{ "bank", T_OP_BANK },

	{ "div", T_OP_FDIV },
	{ "mul", T_OP_FMUL },
	{ "sin", T_OP_SIN },
	{ "cos", T_OP_COS },
	{ "tan", T_OP_TAN },
	{ "asin", T_OP_ASIN },
	{ "acos", T_OP_ACOS },
	{ "atan", T_OP_ATAN },
	{ "atan2", T_OP_ATAN2 },

	{ "strcmp", T_OP_STRCMP },
	{ "strin", T_OP_STRIN },
	{ "strsub", T_OP_STRSUB },
	{ "strlen", T_OP_STRLEN },
	{ "strcat", T_OP_STRCAT },
	{ "strupr", T_OP_STRUPR },
	{ "strlwr", T_OP_STRLWR },

	{ "include", T_POP_INCLUDE },
	{ "printt", T_POP_PRINTT },
	{ "printv", T_POP_PRINTV },
	{ "printf", T_POP_PRINTF },
	{ "export", T_POP_EXPORT },
	{ "xdef", T_POP_EXPORT },
	{ "import", T_POP_IMPORT },
	{ "xref", T_POP_IMPORT },
	{ "global", T_POP_GLOBAL },
	{ "ds", T_POP_DS },
	{ NAME_DB, T_POP_DB },
	{ NAME_DW, T_POP_DW },
#ifdef NAME_DL
	{ NAME_DL, T_POP_DL },
#endif
	{ "section", T_POP_SECTION },
	{ "purge", T_POP_PURGE },

	{ "rsreset", T_POP_RSRESET },
	{ "rsset", T_POP_RSSET },

	{ "incbin", T_POP_INCBIN },

	{ "fail", T_POP_FAIL },
	{ "warn", T_POP_WARN },

	{ "macro", T_POP_MACRO },

	/* Not needed but we have it here just to protect the name */
	{ "endm", T_POP_ENDM },
	{ "shift", T_POP_SHIFT },

	{ "rept", T_POP_REPT },
	/* Not needed but we have it here just to protect the name */
	{ "endr", T_POP_ENDR },

	{ "if", T_POP_IF },
	{ "else", T_POP_ELSE },
	{ "endc", T_POP_ENDC },

	{ "bss", T_SECT_BSS },
#if defined(GAMEBOY) || defined(PCENGINE)
	{ "vram", T_SECT_VRAM },
#endif
	{ "code", T_SECT_CODE },
	{ "data", T_SECT_CODE },
#ifdef GAMEBOY
	{ "home", T_SECT_HOME },
	{ "hram", T_SECT_HRAM },
#endif

	{ NAME_RB, T_POP_RB },
	{ NAME_RW, T_POP_RW },
#ifdef NAME_RL
	{ NAME_RL, T_POP_RL },
#endif
	{ "equ", T_POP_EQU },
	{ "equs", T_POP_EQUS },

	{ "set", T_POP_SET },
	{ "=", T_POP_SET },

	{ "pushs", T_POP_PUSHS },
	{ "pops", T_POP_POPS },
	{ "pusho", T_POP_PUSHO },
	{ "popo", T_POP_POPO },

	{ "opt", T_POP_OPT },

	{ NULL, 0 }
};

struct sLexFloat tNumberToken = {
	ParseNumber,
	T_NUMBER
};

struct sLexFloat tFixedPointToken = {
	ParseFixedPoint,
	T_NUMBER
};

struct sLexFloat tIDToken = {
	ParseSymbol,
	T_ID
};

struct sLexFloat tMacroArgToken = {
	PutMacroArg,
	T_LEX_MACROARG
};

struct sLexFloat tMacroUniqueToken = {
	PutUniqueArg,
	T_LEX_MACROUNIQUE
};

void setuplex(void)
{
	ULONG id;

	lex_Init();
	lex_AddStrings(staticstrings);
	lex_AddStrings(localstrings);

	//      Macro arguments

	id = lex_FloatAlloc(&tMacroArgToken);
	lex_FloatAddFirstRange(id, '\\', '\\');
	lex_FloatAddSecondRange(id, '0', '9');
	id = lex_FloatAlloc(&tMacroUniqueToken);
	lex_FloatAddFirstRange(id, '\\', '\\');
	lex_FloatAddSecondRange(id, '@', '@');

	//      Decimal constants

	id = lex_FloatAlloc(&tNumberToken);
	lex_FloatAddFirstRange(id, '0', '9');
	lex_FloatAddSecondRange(id, '0', '9');
	lex_FloatAddRange(id, '0', '9');

	//      Binary constants

	nBinaryID = id = lex_FloatAlloc(&tNumberToken);
	lex_FloatAddFirstRange(id, '%', '%');
	lex_FloatAddSecondRange(id, CurrentOptions.binary[0],
				CurrentOptions.binary[0]);
	lex_FloatAddSecondRange(id, CurrentOptions.binary[1],
				CurrentOptions.binary[1]);
	lex_FloatAddRange(id, CurrentOptions.binary[0],
			  CurrentOptions.binary[0]);
	lex_FloatAddRange(id, CurrentOptions.binary[1],
			  CurrentOptions.binary[1]);

	//      Octal constants

	id = lex_FloatAlloc(&tNumberToken);
	lex_FloatAddFirstRange(id, '&', '&');
	lex_FloatAddSecondRange(id, '0', '7');
	lex_FloatAddRange(id, '0', '7');

	//      Gameboy gfx constants

	nGBGfxID = id = lex_FloatAlloc(&tNumberToken);
	lex_FloatAddFirstRange(id, '`', '`');
	lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[0],
				CurrentOptions.gbgfx[0]);
	lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[1],
				CurrentOptions.gbgfx[1]);
	lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[2],
				CurrentOptions.gbgfx[2]);
	lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[3],
				CurrentOptions.gbgfx[3]);
	lex_FloatAddRange(id, CurrentOptions.gbgfx[0], CurrentOptions.gbgfx[0]);
	lex_FloatAddRange(id, CurrentOptions.gbgfx[1], CurrentOptions.gbgfx[1]);
	lex_FloatAddRange(id, CurrentOptions.gbgfx[2], CurrentOptions.gbgfx[2]);
	lex_FloatAddRange(id, CurrentOptions.gbgfx[3], CurrentOptions.gbgfx[3]);

	//      Hex constants

	id = lex_FloatAlloc(&tNumberToken);
	lex_FloatAddFirstRange(id, '$', '$');
	lex_FloatAddSecondRange(id, '0', '9');
	lex_FloatAddSecondRange(id, 'A', 'F');
	lex_FloatAddSecondRange(id, 'a', 'f');
	lex_FloatAddRange(id, '0', '9');
	lex_FloatAddRange(id, 'A', 'F');
	lex_FloatAddRange(id, 'a', 'f');

	//      ID's

	id = lex_FloatAlloc(&tIDToken);
	lex_FloatAddFirstRange(id, 'a', 'z');
	lex_FloatAddFirstRange(id, 'A', 'Z');
	lex_FloatAddFirstRange(id, '_', '_');
	lex_FloatAddSecondRange(id, 'a', 'z');
	lex_FloatAddSecondRange(id, 'A', 'Z');
	lex_FloatAddSecondRange(id, '0', '9');
	lex_FloatAddSecondRange(id, '_', '_');
	lex_FloatAddSecondRange(id, '\\', '\\');
	lex_FloatAddSecondRange(id, '@', '@');
	lex_FloatAddSecondRange(id, '#', '#');
	lex_FloatAddRange(id, 'a', 'z');
	lex_FloatAddRange(id, 'A', 'Z');
	lex_FloatAddRange(id, '0', '9');
	lex_FloatAddRange(id, '_', '_');
	lex_FloatAddRange(id, '\\', '\\');
	lex_FloatAddRange(id, '@', '@');
	lex_FloatAddRange(id, '#', '#');

	//      Local ID

	id = lex_FloatAlloc(&tIDToken);
	lex_FloatAddFirstRange(id, '.', '.');
	lex_FloatAddSecondRange(id, 'a', 'z');
	lex_FloatAddSecondRange(id, 'A', 'Z');
	lex_FloatAddSecondRange(id, '_', '_');
	lex_FloatAddRange(id, 'a', 'z');
	lex_FloatAddRange(id, 'A', 'Z');
	lex_FloatAddRange(id, '0', '9');
	lex_FloatAddRange(id, '_', '_');
	lex_FloatAddRange(id, '\\', '\\');
	lex_FloatAddRange(id, '@', '@');
	lex_FloatAddRange(id, '#', '#');

	//      @ ID

	id = lex_FloatAlloc(&tIDToken);
	lex_FloatAddFirstRange(id, '@', '@');

	//      Fixed point constants

	id = lex_FloatAlloc(&tFixedPointToken);
	lex_FloatAddFirstRange(id, '.', '.');
	lex_FloatAddFirstRange(id, '0', '9');
	lex_FloatAddSecondRange(id, '.', '.');
	lex_FloatAddSecondRange(id, '0', '9');
	lex_FloatAddRange(id, '.', '.');
	lex_FloatAddRange(id, '0', '9');

}