cc65/src/ca65/ulabel.c

226 lines
7.6 KiB
C

/*****************************************************************************/
/* */
/* ulabel.c */
/* */
/* Unnamed labels for the ca65 macroassembler */
/* */
/* */
/* */
/* (C) 2000-2011, Ullrich von Bassewitz */
/* Roemerstrasse 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 "coll.h"
#include "xmalloc.h"
/* ca65 */
#include "error.h"
#include "expr.h"
#include "lineinfo.h"
#include "scanner.h"
#include "ulabel.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Struct that describes an unnamed label */
typedef struct ULabel ULabel;
struct ULabel {
Collection LineInfos; /* Position of the label in the source */
ExprNode* Val; /* The label value - may be NULL */
unsigned Ref; /* Number of references */
};
/* List management */
static Collection ULabList = STATIC_COLLECTION_INITIALIZER;
static unsigned ULabDefCount = 0; /* Number of defined labels */
/*****************************************************************************/
/* Code */
/*****************************************************************************/
static ULabel* NewULabel (ExprNode* Val)
/* Create a new ULabel and insert it into the collection. The created label
** structure is returned.
*/
{
/* Allocate memory for the ULabel structure */
ULabel* L = xmalloc (sizeof (ULabel));
/* Initialize the fields */
L->LineInfos = EmptyCollection;
GetFullLineInfo (&L->LineInfos);
L->Val = Val;
L->Ref = 0;
/* Insert the label into the collection */
CollAppend (&ULabList, L);
/* 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.
*/
{
int Index;
ULabel* L;
/* Which can never be 0 */
PRECONDITION (Which != 0);
/* Get the index of the referenced label */
if (Which > 0) {
--Which;
}
Index = (int) ULabDefCount + Which;
/* We cannot have negative label indices */
if (Index < 0) {
/* Label does not exist */
Error ("Undefined label");
/* We must return something valid */
return GenCurrentPC();
}
/* Check if the label exists. If not, generate enough forward labels. */
if (Index < (int) CollCount (&ULabList)) {
/* The label exists, get it. */
L = CollAtUnchecked (&ULabList, Index);
} else {
/* Generate new, undefined labels */
while (Index >= (int) CollCount (&ULabList)) {
L = NewULabel (0);
}
}
/* Mark the label as referenced */
++L->Ref;
/* If the label is already defined, return its value, otherwise return
** just a reference.
*/
if (L->Val) {
return CloneExpr (L->Val);
} else {
return GenULabelExpr (Index);
}
}
void ULabDef (void)
/* Define an unnamed label at the current PC */
{
if (ULabDefCount < CollCount (&ULabList)) {
/* We did already have a forward reference to this label, so has
** already been generated, but doesn't have a value. Use the current
** PC for the label value.
*/
ULabel* L = CollAtUnchecked (&ULabList, ULabDefCount);
CHECK (L->Val == 0);
L->Val = GenCurrentPC ();
ReleaseFullLineInfo (&L->LineInfos);
GetFullLineInfo (&L->LineInfos);
} else {
/* There is no such label, create it */
NewULabel (GenCurrentPC ());
}
/* We have one more defined label */
++ULabDefCount;
}
int ULabCanResolve (void)
/* Return true if we can resolve arbitrary ULabels. */
{
/* We can resolve labels if we don't have any undefineds */
return (ULabDefCount == CollCount (&ULabList));
}
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.
*/
{
/* Get the label and check that it is defined */
ULabel* L = CollAt (&ULabList, Index);
CHECK (L->Val != 0);
/* Return the label value */
return CloneExpr (L->Val);
}
void ULabDone (void)
/* Run through all unnamed labels, check for anomalies and errors and do
** necessary cleanups.
*/
{
/* Check if there are undefined labels */
unsigned I = ULabDefCount;
while (I < CollCount (&ULabList)) {
ULabel* L = CollAtUnchecked (&ULabList, I);
LIError (&L->LineInfos, "Undefined label");
++I;
}
/* Walk over all labels and emit a warning if any unreferenced ones
** are found. Remove line infos because they're no longer needed.
*/
for (I = 0; I < CollCount (&ULabList); ++I) {
ULabel* L = CollAtUnchecked (&ULabList, I);
if (L->Ref == 0) {
LIWarning (&L->LineInfos, 1, "No reference to unnamed label");
}
ReleaseFullLineInfo (&L->LineInfos);
}
}