cc65/src/ca65/ulabel.c

243 lines
7.6 KiB
C
Raw Normal View History

/*****************************************************************************/
/* */
/* ulabel.c */
/* */
/* Unnamed labels for the ca65 macroassembler */
/* */
/* */
/* */
/* (C) 2000-2003 Ullrich von Bassewitz */
/* R<>merstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
/* common */
#include "check.h"
#include "filepos.h"
#include "xmalloc.h"
/* ca65 */
#include "error.h"
#include "expr.h"
#include "scanner.h"
#include "ulabel.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Struct that describes an unnamed label */
typedef struct ULabel ULabel;
struct ULabel {
ULabel* Prev; /* Pointer to previous node in list */
ULabel* Next; /* Pointer to next node in list */
FilePos Pos; /* Position of the label in the source */
ExprNode* Val; /* The label value - may be NULL */
};
/* List management */
static ULabel* ULabRoot = 0; /* Root of the list */
static ULabel* ULabLast = 0; /* Last ULabel */
static ULabel* ULabLastDef = 0; /* Last defined ULabel */
static unsigned ULabCount = 0; /* Number of labels */
static unsigned ULabDefCount = 0; /* Number of defined labels */
static ULabel** ULabList = 0; /* Array with pointers to all labels */
/*****************************************************************************/
/* Code */
/*****************************************************************************/
static ULabel* NewULabel (ExprNode* Val)
/* Create a new ULabel and insert it into the list. The function will move
* ULabelLast, but not ULabelLastDef. The created label structure is returned.
*/
{
/* Allocate memory for the ULabel structure */
ULabel* L = xmalloc (sizeof (ULabel));
/* Initialize the fields */
L->Pos = CurPos;
L->Val = Val;
/* Insert the label into the list */
L->Next = 0;
if (ULabRoot == 0) {
/* First label */
L->Prev = 0;
ULabRoot = L;
} else {
ULabLast->Next = L;
L->Prev = ULabLast;
}
ULabLast = L;
/* One label more */
++ULabCount;
/* Return the created label */
return L;
}
ExprNode* ULabRef (int Which)
/* Get an unnamed label. If Which is negative, it is a backreference (a
* reference to an already defined label), and the function will return a
* segment relative expression. If Which is positive, it is a forward ref,
* and the function will return a expression node for an unnamed label that
* must be resolved later.
*/
{
ULabel* L;
/* Which can never be 0 */
PRECONDITION (Which != 0);
/* Which is never really big (usually -3..+3), so a linear search is
* the best we can do here.
*/
L = ULabLastDef;
if (Which < 0) {
/* Backward reference */
while (Which < -1 && L != 0) {
L = L->Prev;
++Which;
}
if (L == 0) {
/* Label does not exist */
Error (ERR_UNDEFINED_LABEL);
/* We must return something valid */
return GenCurrentPC();
} else {
/* Return a copy of the label value */
return CloneExpr (L->Val);
}
} else {
/* Forward reference. Create labels as needed */
unsigned LabelNum = ULabDefCount + Which - 1;
while (LabelNum < ULabCount) {
NewULabel (0);
}
/* Return an unnamed label expression */
return GenULabelExpr (LabelNum);
}
}
void ULabDef (void)
/* Define an unnamed label at the current PC */
{
/* Create a new label if needed, or use an existing one */
if (ULabLastDef == 0 || ULabLastDef->Next == 0) {
/* The last label is also the last defined label, we need a new one */
ULabLastDef = NewULabel (GenCurrentPC ());
} else {
/* We do already have the label, but it's undefined until now */
ULabLastDef = ULabLastDef->Next;
ULabLastDef->Val = GenCurrentPC ();
ULabLastDef->Pos = CurPos;
}
++ULabDefCount;
}
int ULabCanResolve (void)
/* Return true if we can resolve arbitrary ULabels. */
{
/* We can resolve labels if we have built the necessary access array */
return (ULabList != 0);
}
ExprNode* ULabResolve (unsigned Index)
/* Return a valid expression for the unnamed label with the given index. This
* is used to resolve unnamed labels when assembly is done, so it is an error
* if a label is still undefined in this phase.
*/
{
ULabel* L;
/* Must be in resolve phase and the index must be valid */
CHECK (ULabList != 0 && Index < ULabCount);
/* Get the label */
L = ULabList [Index];
/* If the label is open (not defined), return some valid value */
if (L->Val == 0) {
return GenLiteralExpr (0);
} else {
return CloneExpr (L->Val);
}
}
void ULabCheck (void)
/* Run through all unnamed labels and check for anomalies and errors */
{
ULabel* L;
/* Check if there are undefined labels */
if (ULabLastDef) {
L = ULabLastDef->Next;
while (L) {
PError (&L->Pos, ERR_UNDEFINED_LABEL);
L = L->Next;
}
}
/* Create an array that holds pointers to all labels. This allows us to
* access the labels quickly by index in the resolver phase at the end of
* the assembly.
*/
if (ULabCount) {
unsigned I = 0;
ULabList = xmalloc (ULabCount * sizeof (ULabel*));
L = ULabRoot;
while (L) {
ULabList[I] = L;
++I;
L = L->Next;
}
CHECK (I == ULabCount);
}
}