mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
513 lines
9.8 KiB
C
513 lines
9.8 KiB
C
#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 ((size == 2 && src[1] >= '1' && src[1] <= '9')) {
|
|
if ((s = sym_FindMacroArg(src[1] - '0')) != NULL) {
|
|
yyunputstr(s);
|
|
} else {
|
|
yyerror("Macro argument not defined");
|
|
}
|
|
} else {
|
|
yyerror("Invalid macro argument");
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
ULONG
|
|
PutUniqueArg(char *src, ULONG size)
|
|
{
|
|
char *s;
|
|
|
|
src = src;
|
|
yyskipbytes(size);
|
|
if ((s = sym_FindMacroArg(-1)) != NULL) {
|
|
yyunputstr(s);
|
|
} else {
|
|
yyerror("Macro unique label string not defined");
|
|
}
|
|
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},
|
|
{"charmap", T_POP_CHARMAP},
|
|
|
|
{"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},
|
|
|
|
{"wram0", T_SECT_WRAM0},
|
|
{"bss", T_SECT_WRAM0}, /* deprecated */
|
|
{"vram", T_SECT_VRAM},
|
|
{"code", T_SECT_ROMX}, /* deprecated */
|
|
{"data", T_SECT_ROMX}, /* deprecated */
|
|
{"romx", T_SECT_ROMX},
|
|
{"home", T_SECT_ROM0}, /* deprecated */
|
|
{"rom0", T_SECT_ROM0},
|
|
{"hram", T_SECT_HRAM},
|
|
{"wramx", T_SECT_WRAMX},
|
|
{"sram", T_SECT_SRAM},
|
|
|
|
{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, '1', '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');
|
|
|
|
}
|