Files
rgbds/src/asm/symbol.c
Antonio Niño Díaz 5cfa15f963 Add equates with ISO 8601 date and time
Added `__TIMESTAMP_ISO_8601_LOCAL__` and `__TIMESTAMP_ISO_8601_UTC__`,
with the correct ISO 8601 representation of time and date from years to
seconds (including local timezone in the local time string).

Also, if the current time cannot be obtained from the OS, it will output
a warning and the time strings will be filled with '?' instead of
numbers and characters.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-04-09 16:49:34 +01:00

868 lines
16 KiB
C

/*
* Symboltable and macroargs stuff
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "asm/asm.h"
#include "asm/symbol.h"
#include "asm/main.h"
#include "asm/mymath.h"
#include "asm/output.h"
#include "extern/err.h"
struct sSymbol *tHashedSymbols[HASHSIZE];
struct sSymbol *pScope = NULL;
struct sSymbol *pPCSymbol = NULL;
struct sSymbol *p_NARGSymbol = NULL;
char *currentmacroargs[MAXMACROARGS + 1];
char *newmacroargs[MAXMACROARGS + 1];
char SavedTIME[256];
char SavedDATE[256];
char SavedTIMESTAMP_ISO8601_LOCAL[256];
char SavedTIMESTAMP_ISO8601_UTC[256];
bool exportall;
SLONG
Callback_NARG(struct sSymbol * sym)
{
ULONG i = 0;
while (currentmacroargs[i] && i < MAXMACROARGS)
i += 1;
return (i);
}
/*
* Get the nValue field of a symbol
*/
SLONG
getvaluefield(struct sSymbol * sym)
{
if (sym->Callback) {
return (sym->Callback(sym));
} else
return (sym->nValue);
}
/*
* Calculate the hash value for a string
*/
ULONG
calchash(char *s)
{
ULONG hash = 5381;
while (*s != 0)
hash = (hash * 33) ^ (*s++);
return (hash % HASHSIZE);
}
/*
* Create a new symbol by name
*/
struct sSymbol *
createsymbol(char *s)
{
struct sSymbol **ppsym;
ULONG hash;
hash = calchash(s);
ppsym = &(tHashedSymbols[hash]);
while ((*ppsym) != NULL)
ppsym = &((*ppsym)->pNext);
if (((*ppsym) = malloc(sizeof(struct sSymbol))) != NULL) {
strcpy((*ppsym)->tzName, s);
(*ppsym)->nValue = 0;
(*ppsym)->nType = 0;
(*ppsym)->pScope = NULL;
(*ppsym)->pNext = NULL;
(*ppsym)->pMacro = NULL;
(*ppsym)->pSection = NULL;
(*ppsym)->Callback = NULL;
return (*ppsym);
} else {
fatalerror("No memory for symbol");
return (NULL);
}
}
/*
* Find a symbol by name and scope
*/
struct sSymbol *
findsymbol(char *s, struct sSymbol * scope)
{
struct sSymbol **ppsym;
SLONG hash;
hash = calchash(s);
ppsym = &(tHashedSymbols[hash]);
while ((*ppsym) != NULL) {
if ((strcmp(s, (*ppsym)->tzName) == 0)
&& ((*ppsym)->pScope == scope)) {
return (*ppsym);
} else
ppsym = &((*ppsym)->pNext);
}
return (NULL);
}
/*
* Find the pointer to a symbol by name and scope
*/
struct sSymbol **
findpsymbol(char *s, struct sSymbol * scope)
{
struct sSymbol **ppsym;
SLONG hash;
hash = calchash(s);
ppsym = &(tHashedSymbols[hash]);
while ((*ppsym) != NULL) {
if ((strcmp(s, (*ppsym)->tzName) == 0)
&& ((*ppsym)->pScope == scope)) {
return (ppsym);
} else
ppsym = &((*ppsym)->pNext);
}
return (NULL);
}
/*
* Find a symbol by name and scope
*/
struct sSymbol *
sym_FindSymbol(char *tzName)
{
struct sSymbol *pscope;
if (*tzName == '.')
pscope = pScope;
else
pscope = NULL;
return (findsymbol(tzName, pscope));
}
/*
* Purge a symbol
*/
void
sym_Purge(char *tzName)
{
struct sSymbol **ppSym;
struct sSymbol *pscope;
if (*tzName == '.')
pscope = pScope;
else
pscope = NULL;
ppSym = findpsymbol(tzName, pscope);
if (ppSym) {
struct sSymbol *pSym;
pSym = *ppSym;
*ppSym = pSym->pNext;
if (pSym->pMacro)
free(pSym->pMacro);
free(pSym);
} else {
yyerror("'%s' not defined", tzName);
}
}
/*
* Determine if a symbol has been defined
*/
ULONG
sym_isConstDefined(char *tzName)
{
struct sSymbol *psym, *pscope;
if (*tzName == '.')
pscope = pScope;
else
pscope = NULL;
psym = findsymbol(tzName, pscope);
if (psym && (psym->nType & SYMF_DEFINED)) {
if (psym->
nType & (SYMF_EQU | SYMF_SET | SYMF_MACRO | SYMF_STRING)) {
return (1);
} else {
fatalerror("'%s' is not allowed as argument to the "
"DEF function", tzName);
}
}
return (0);
}
ULONG
sym_isDefined(char *tzName)
{
struct sSymbol *psym, *pscope;
if (*tzName == '.')
pscope = pScope;
else
pscope = NULL;
psym = findsymbol(tzName, pscope);
if (psym && (psym->nType & SYMF_DEFINED))
return (1);
else
return (0);
}
/*
* Determine if the symbol is a constant
*/
ULONG
sym_isConstant(char *s)
{
struct sSymbol *psym, *pscope;
if (*s == '.')
pscope = pScope;
else
pscope = NULL;
if ((psym = findsymbol(s, pscope)) != NULL) {
if (psym->nType & SYMF_CONST)
return (1);
}
return (0);
}
/*
* Get a string equate's value
*/
char *
sym_GetStringValue(char *tzSym)
{
struct sSymbol *pSym;
if ((pSym = sym_FindSymbol(tzSym)) != NULL)
return (pSym->pMacro);
else {
yyerror("Stringsymbol '%s' not defined", tzSym);
}
return (NULL);
}
/*
* Return a constant symbols value
*/
ULONG
sym_GetConstantValue(char *s)
{
struct sSymbol *psym, *pscope;
if (*s == '.')
pscope = pScope;
else
pscope = NULL;
if ((psym = findsymbol(s, pscope)) != NULL) {
if (psym->nType & SYMF_CONST)
return (getvaluefield(psym));
else {
fatalerror("Expression must have a constant value");
}
} else {
yyerror("'%s' not defined", s);
}
return (0);
}
/*
* Return a symbols value... "estimated" if not defined yet
*/
ULONG
sym_GetValue(char *s)
{
struct sSymbol *psym, *pscope;
if (*s == '.')
pscope = pScope;
else
pscope = NULL;
if ((psym = findsymbol(s, pscope)) != NULL) {
if (psym->nType & SYMF_DEFINED) {
if (psym->nType & (SYMF_MACRO | SYMF_STRING)) {
yyerror("'%s' is a macro or string symbol", s);
}
return (getvaluefield(psym));
} else {
if (nPass == 2) {
/* Assume undefined symbols are imported from somewhere else */
psym->nType |= SYMF_IMPORT;
}
/* 0x80 seems like a good default value... */
return (0x80);
}
} else {
if (nPass == 1) {
createsymbol(s);
return (0x80);
} else {
yyerror("'%s' not defined", s);
}
}
return (0);
}
/*
* Return a defined symbols value... aborts if not defined yet
*/
ULONG
sym_GetDefinedValue(char *s)
{
struct sSymbol *psym, *pscope;
if (*s == '.')
pscope = pScope;
else
pscope = NULL;
if ((psym = findsymbol(s, pscope)) != NULL) {
if ((psym->nType & SYMF_DEFINED)) {
if (psym->nType & (SYMF_MACRO | SYMF_STRING)) {
yyerror("'%s' is a macro or string symbol", s);
}
return (getvaluefield(psym));
} else {
yyerror("'%s' not defined", s);
}
} else {
yyerror("'%s' not defined", s);
}
return (0);
}
/*
* Macro argument stuff
*/
void
sym_ShiftCurrentMacroArgs(void)
{
SLONG i;
free(currentmacroargs[0]);
for (i = 0; i < MAXMACROARGS - 1; i += 1) {
currentmacroargs[i] = currentmacroargs[i + 1];
}
currentmacroargs[MAXMACROARGS - 1] = NULL;
}
char *
sym_FindMacroArg(SLONG i)
{
if (i == -1)
i = MAXMACROARGS + 1;
assert(i-1 >= 0);
assert((size_t)(i-1) < sizeof(currentmacroargs)/sizeof(*currentmacroargs));
return (currentmacroargs[i - 1]);
}
void
sym_UseNewMacroArgs(void)
{
SLONG i;
for (i = 0; i <= MAXMACROARGS; i += 1) {
currentmacroargs[i] = newmacroargs[i];
newmacroargs[i] = NULL;
}
}
void
sym_SaveCurrentMacroArgs(char *save[])
{
SLONG i;
for (i = 0; i <= MAXMACROARGS; i += 1)
save[i] = currentmacroargs[i];
}
void
sym_RestoreCurrentMacroArgs(char *save[])
{
SLONG i;
for (i = 0; i <= MAXMACROARGS; i += 1)
currentmacroargs[i] = save[i];
}
void
sym_FreeCurrentMacroArgs(void)
{
SLONG i;
for (i = 0; i <= MAXMACROARGS; i += 1) {
free(currentmacroargs[i]);
currentmacroargs[i] = NULL;
}
}
void
sym_AddNewMacroArg(char *s)
{
SLONG i = 0;
while (i < MAXMACROARGS && newmacroargs[i] != NULL)
i += 1;
if (i < MAXMACROARGS) {
if (s)
newmacroargs[i] = strdup(s);
else
newmacroargs[i] = NULL;
} else
yyerror("A maximum of %d arguments allowed", MAXMACROARGS);
}
void
sym_SetMacroArgID(ULONG nMacroCount)
{
char s[256];
sprintf(s, "_%ld", nMacroCount);
newmacroargs[MAXMACROARGS] = strdup(s);
}
void
sym_UseCurrentMacroArgs(void)
{
SLONG i;
for (i = 1; i <= MAXMACROARGS; i += 1)
sym_AddNewMacroArg(sym_FindMacroArg(i));
}
/*
* Find a macro by name
*/
struct sSymbol *
sym_FindMacro(char *s)
{
return (findsymbol(s, NULL));
}
/*
* Add an equated symbol
*/
void
sym_AddEqu(char *tzSym, SLONG value)
{
if ((nPass == 1)
|| ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
/* only add equated symbols in pass 1 */
struct sSymbol *nsym;
if ((nsym = findsymbol(tzSym, NULL)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
yyerror("'%s' already defined", tzSym);
}
} else
nsym = createsymbol(tzSym);
if (nsym) {
nsym->nValue = value;
nsym->nType |= SYMF_EQU | SYMF_DEFINED | SYMF_CONST;
nsym->pScope = NULL;
}
}
}
/*
* Add a string equated symbol.
*
* If the desired symbol is a string it needs to be passed to this function with
* quotes inside the string, like sym_AddString("name", "\"test\"), or the
* assembler won't be able to use it with DB and similar. This is equivalent as
* ``` name EQUS "\"test\"" ```
*
* If the desired symbol is a register or a number, just the terminator quotes
* of the string are enough: sym_AddString("M_PI", "3.1415"). This is the same
* as ``` M_PI EQUS "3.1415" ```
*/
void
sym_AddString(char *tzSym, char *tzValue)
{
struct sSymbol *nsym;
if ((nsym = findsymbol(tzSym, NULL)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
yyerror("'%s' already defined", tzSym);
}
} else
nsym = createsymbol(tzSym);
if (nsym) {
if ((nsym->pMacro = malloc(strlen(tzValue) + 1)) != NULL)
strcpy(nsym->pMacro, tzValue);
else
fatalerror("No memory for stringequate");
nsym->nType |= SYMF_STRING | SYMF_DEFINED;
nsym->ulMacroSize = strlen(tzValue);
nsym->pScope = NULL;
}
}
/*
* check if symbol is a string equated symbol
*/
ULONG
sym_isString(char *tzSym)
{
struct sSymbol *pSym;
if ((pSym = findsymbol(tzSym, NULL)) != NULL) {
if (pSym->nType & SYMF_STRING)
return (1);
}
return (0);
}
/*
* Alter a SET symbols value
*/
void
sym_AddSet(char *tzSym, SLONG value)
{
struct sSymbol *nsym;
if ((nsym = findsymbol(tzSym, NULL)) != NULL) {
} else
nsym = createsymbol(tzSym);
if (nsym) {
nsym->nValue = value;
nsym->nType |= SYMF_SET | SYMF_DEFINED | SYMF_CONST;
nsym->pScope = NULL;
}
}
/*
* Add a local (.name) relocatable symbol
*/
void
sym_AddLocalReloc(char *tzSym)
{
if ((nPass == 1)
|| ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
/* only add local reloc symbols in pass 1 */
struct sSymbol *nsym;
if (pScope) {
if ((nsym = findsymbol(tzSym, pScope)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
yyerror("'%s' already defined", tzSym);
}
} else
nsym = createsymbol(tzSym);
if (nsym) {
nsym->nValue = nPC;
nsym->nType |=
SYMF_RELOC | SYMF_LOCAL | SYMF_DEFINED;
if (exportall) {
nsym->nType |= SYMF_EXPORT;
}
nsym->pScope = pScope;
nsym->pSection = pCurrentSection;
}
} else
fatalerror("Local label in main scope");
}
}
/*
* Add a relocatable symbol
*/
void
sym_AddReloc(char *tzSym)
{
if ((nPass == 1)
|| ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
/* only add reloc symbols in pass 1 */
struct sSymbol *nsym;
if ((nsym = findsymbol(tzSym, NULL)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
yyerror("'%s' already defined", tzSym);
}
} else
nsym = createsymbol(tzSym);
if (nsym) {
nsym->nValue = nPC;
nsym->nType |= SYMF_RELOC | SYMF_DEFINED;
if (exportall) {
nsym->nType |= SYMF_EXPORT;
}
nsym->pScope = NULL;
nsym->pSection = pCurrentSection;
}
}
pScope = findsymbol(tzSym, NULL);
}
/*
* Check if the subtraction of two symbols is defined. That is, either both
* symbols are defined and the result is a constant, or both symbols are
* relocatable and belong to the same section.
*
* It returns 1 if the difference is defined, 0 if not.
*/
int
sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2)
{
/* Do nothing the first pass. */
if (nPass != 2)
return 1;
struct sSymbol *nsym1, *nsym2;
/* Do the symbols exist? */
if ((nsym1 = sym_FindSymbol(tzSym1)) == NULL)
fatalerror("Symbol \"%s\" isn't defined.", tzSym1);
if ((nsym2 = sym_FindSymbol(tzSym2)) == NULL)
fatalerror("Symbol \"%s\" isn't defined.", tzSym2);
int s1reloc = (nsym1->nType & SYMF_RELOC) != 0;
int s2reloc = (nsym2->nType & SYMF_RELOC) != 0;
/* Both are non-relocatable */
if (!s1reloc && !s2reloc) return 1;
/* One of them relocatable, the other one not. */
if (s1reloc ^ s2reloc) return 0;
/* Both of them are relocatable. Make sure they are defined (internal
* coherency with sym_AddReloc and sym_AddLocalReloc). */
if (!(nsym1->nType & SYMF_DEFINED))
fatalerror("Relocatable symbol \"%s\" isn't defined.", tzSym1);
if (!(nsym2->nType & SYMF_DEFINED))
fatalerror("Relocatable symbol \"%s\" isn't defined.", tzSym2);
/* Both of them must be in the same section for the difference to be
* defined. */
return nsym1->pSection == nsym2->pSection;
}
/*
* Export a symbol
*/
void
sym_Export(char *tzSym)
{
if (nPass == 1) {
/* only export symbols in pass 1 */
struct sSymbol *nsym;
if ((nsym = findsymbol(tzSym, 0)) == NULL)
nsym = createsymbol(tzSym);
if (nsym)
nsym->nType |= SYMF_EXPORT;
} else {
struct sSymbol *nsym;
if ((nsym = findsymbol(tzSym, 0)) != NULL) {
if (nsym->nType & SYMF_DEFINED)
return;
}
yyerror("'%s' not defined", tzSym);
}
}
/*
* Globalize a symbol (export if defined, import if not)
*/
void
sym_Global(char *tzSym)
{
if (nPass == 2) {
/* only globalize symbols in pass 2 */
struct sSymbol *nsym;
nsym = findsymbol(tzSym, 0);
if ((nsym == NULL) || ((nsym->nType & SYMF_DEFINED) == 0)) {
if (nsym == NULL)
nsym = createsymbol(tzSym);
if (nsym)
nsym->nType |= SYMF_IMPORT;
} else {
if (nsym)
nsym->nType |= SYMF_EXPORT;
}
}
}
/*
* Add a macro definition
*/
void
sym_AddMacro(char *tzSym)
{
if ((nPass == 1)
|| ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
/* only add macros in pass 1 */
struct sSymbol *nsym;
if ((nsym = findsymbol(tzSym, NULL)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
yyerror("'%s' already defined", tzSym);
}
} else
nsym = createsymbol(tzSym);
if (nsym) {
nsym->nValue = nPC;
nsym->nType |= SYMF_MACRO | SYMF_DEFINED;
nsym->pScope = NULL;
nsym->ulMacroSize = ulNewMacroSize;
nsym->pMacro = tzNewMacro;
}
}
}
/*
* Set whether to export all relocable symbols by default
*/
void sym_SetExportAll(BBOOL set) {
exportall = set;
}
/*
* Prepare for pass #1
*/
void
sym_PrepPass1(void)
{
sym_Init();
}
/*
* Prepare for pass #2
*/
void
sym_PrepPass2(void)
{
SLONG i;
for (i = 0; i < HASHSIZE; i += 1) {
struct sSymbol **ppSym = &(tHashedSymbols[i]);
while (*ppSym) {
if ((*ppSym)->
nType & (SYMF_SET | SYMF_STRING | SYMF_EQU)) {
struct sSymbol *pTemp;
pTemp = (*ppSym)->pNext;
free(*ppSym);
*ppSym = pTemp;
} else
ppSym = &((*ppSym)->pNext);
}
}
pScope = NULL;
pPCSymbol->nValue = 0;
sym_AddString("__TIME__", SavedTIME);
sym_AddString("__DATE__", SavedDATE);
sym_AddString("__TIMESTAMP_ISO_8601_LOCAL__", SavedTIMESTAMP_ISO8601_LOCAL);
sym_AddString("__TIMESTAMP_ISO_8601_UTC__", SavedTIMESTAMP_ISO8601_UTC);
sym_AddSet("_RS", 0);
sym_AddEqu("_NARG", 0);
p_NARGSymbol = findsymbol("_NARG", NULL);
p_NARGSymbol->Callback = Callback_NARG;
math_DefinePI();
}
/*
* Initialize the symboltable
*/
void
sym_Init(void)
{
SLONG i;
time_t now;
for (i = 0; i < MAXMACROARGS; i += 1) {
currentmacroargs[i] = NULL;
newmacroargs[i] = NULL;
}
for (i = 0; i < HASHSIZE; i += 1)
tHashedSymbols[i] = NULL;
sym_AddReloc("@");
pPCSymbol = findsymbol("@", NULL);
sym_AddEqu("_NARG", 0);
p_NARGSymbol = findsymbol("_NARG", NULL);
p_NARGSymbol->Callback = Callback_NARG;
sym_AddSet("_RS", 0);
if (time(&now) != -1) {
struct tm *time_local = localtime(&now);
strftime(SavedTIME, sizeof(SavedTIME), "\"%H:%M:%S\"", time_local);
strftime(SavedDATE, sizeof(SavedDATE), "\"%d %B %Y\"", time_local);
strftime(SavedTIMESTAMP_ISO8601_LOCAL,
sizeof(SavedTIMESTAMP_ISO8601_LOCAL), "\"%FT%T%z\"", time_local);
struct tm *time_utc = gmtime(&now);
strftime(SavedTIMESTAMP_ISO8601_UTC,
sizeof(SavedTIMESTAMP_ISO8601_UTC), "\"%FT%TZ\"", time_utc);
} else {
warnx("Couldn't determine current time.");
/* The '?' have to be escaped or they will be treated as
* trigraphs... */
strcpy(SavedTIME, "\"\?\?:\?\?:\?\?\"");
strcpy(SavedDATE, "\"\?\? \?\?\? \?\?\?\?\"");
strcpy(SavedTIMESTAMP_ISO8601_LOCAL, "\"\?\?\?\?-\?\?-\?\?T\?\?:\?\?:\?\?+\?\?\?\?\"");
strcpy(SavedTIMESTAMP_ISO8601_UTC, "\"\?\?\?\?-\?\?-\?\?T\?\?:\?\?:\?\?Z\"");
}
sym_AddString("__TIME__", SavedTIME);
sym_AddString("__DATE__", SavedDATE);
sym_AddString("__TIMESTAMP_ISO_8601_LOCAL__", SavedTIMESTAMP_ISO8601_LOCAL);
sym_AddString("__TIMESTAMP_ISO_8601_UTC__", SavedTIMESTAMP_ISO8601_UTC);
pScope = NULL;
math_DefinePI();
}