2000-05-28 13:40:48 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* ulabel.c */
|
|
|
|
/* */
|
|
|
|
/* Unnamed labels for the ca65 macroassembler */
|
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* */
|
2011-01-16 16:05:43 +00:00
|
|
|
/* (C) 2000-2011, Ullrich von Bassewitz */
|
|
|
|
/* Roemerstrasse 52 */
|
|
|
|
/* D-70794 Filderstadt */
|
|
|
|
/* EMail: uz@cc65.org */
|
2000-05-28 13:40:48 +00:00
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* 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. */
|
|
|
|
/* */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-08-01 15:17:43 +00:00
|
|
|
/* common */
|
|
|
|
#include "check.h"
|
2004-03-21 16:15:55 +00:00
|
|
|
#include "coll.h"
|
2000-08-01 15:17:43 +00:00
|
|
|
#include "xmalloc.h"
|
2001-08-30 08:17:06 +00:00
|
|
|
|
2000-08-01 15:17:43 +00:00
|
|
|
/* ca65 */
|
2000-05-28 13:40:48 +00:00
|
|
|
#include "error.h"
|
|
|
|
#include "expr.h"
|
2011-01-27 21:40:37 +00:00
|
|
|
#include "lineinfo.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
#include "scanner.h"
|
|
|
|
#include "ulabel.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2004-03-21 16:15:55 +00:00
|
|
|
/* Data */
|
2000-05-28 13:40:48 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Struct that describes an unnamed label */
|
2001-08-30 08:17:06 +00:00
|
|
|
typedef struct ULabel ULabel;
|
|
|
|
struct ULabel {
|
2011-01-27 21:40:37 +00:00
|
|
|
Collection LineInfos; /* Position of the label in the source */
|
|
|
|
ExprNode* Val; /* The label value - may be NULL */
|
|
|
|
unsigned Ref; /* Number of references */
|
2000-05-28 13:40:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* List management */
|
2004-03-21 16:15:55 +00:00
|
|
|
static Collection ULabList = STATIC_COLLECTION_INITIALIZER;
|
2000-05-28 13:40:48 +00:00
|
|
|
static unsigned ULabDefCount = 0; /* Number of defined labels */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* Code */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ULabel* NewULabel (ExprNode* Val)
|
2004-03-21 16:15:55 +00:00
|
|
|
/* Create a new ULabel and insert it into the collection. The created label
|
|
|
|
* structure is returned.
|
2000-05-28 13:40:48 +00:00
|
|
|
*/
|
|
|
|
{
|
|
|
|
/* Allocate memory for the ULabel structure */
|
2000-06-14 09:32:22 +00:00
|
|
|
ULabel* L = xmalloc (sizeof (ULabel));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Initialize the fields */
|
2011-01-27 21:40:37 +00:00
|
|
|
L->LineInfos = EmptyCollection;
|
2011-08-18 14:36:38 +00:00
|
|
|
GetFullLineInfo (&L->LineInfos);
|
2011-01-27 21:40:37 +00:00
|
|
|
L->Val = Val;
|
|
|
|
L->Ref = 0;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-03-21 16:15:55 +00:00
|
|
|
/* Insert the label into the collection */
|
|
|
|
CollAppend (&ULabList, L);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
{
|
2004-03-21 16:15:55 +00:00
|
|
|
int Index;
|
2000-05-28 13:40:48 +00:00
|
|
|
ULabel* L;
|
|
|
|
|
|
|
|
/* Which can never be 0 */
|
|
|
|
PRECONDITION (Which != 0);
|
|
|
|
|
2004-03-21 16:15:55 +00:00
|
|
|
/* Get the index of the referenced label */
|
|
|
|
if (Which > 0) {
|
|
|
|
--Which;
|
|
|
|
}
|
2004-07-17 22:14:30 +00:00
|
|
|
Index = (int) ULabDefCount + Which;
|
2004-03-21 16:15:55 +00:00
|
|
|
|
|
|
|
/* We cannot have negative label indices */
|
|
|
|
if (Index < 0) {
|
|
|
|
/* Label does not exist */
|
|
|
|
Error ("Undefined label");
|
|
|
|
/* We must return something valid */
|
|
|
|
return GenCurrentPC();
|
|
|
|
}
|
|
|
|
|
2004-07-17 22:14:30 +00:00
|
|
|
/* Check if the label exists. If not, generate enough forward labels. */
|
2004-03-21 16:15:55 +00:00
|
|
|
if (Index < (int) CollCount (&ULabList)) {
|
2004-07-17 22:14:30 +00:00
|
|
|
/* The label exists, get it. */
|
2004-03-21 16:15:55 +00:00
|
|
|
L = CollAtUnchecked (&ULabList, Index);
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2004-07-17 22:14:30 +00:00
|
|
|
/* Generate new, undefined labels */
|
2004-03-21 16:15:55 +00:00
|
|
|
while (Index >= (int) CollCount (&ULabList)) {
|
|
|
|
L = NewULabel (0);
|
2001-08-30 08:17:06 +00:00
|
|
|
}
|
2004-07-17 22:14:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ULabDef (void)
|
|
|
|
/* Define an unnamed label at the current PC */
|
|
|
|
{
|
2004-03-21 16:15:55 +00:00
|
|
|
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);
|
2011-08-18 14:36:38 +00:00
|
|
|
L->Val = GenCurrentPC ();
|
|
|
|
ReleaseFullLineInfo (&L->LineInfos);
|
|
|
|
GetFullLineInfo (&L->LineInfos);
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2004-03-21 16:15:55 +00:00
|
|
|
/* There is no such label, create it */
|
|
|
|
NewULabel (GenCurrentPC ());
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-03-21 16:15:55 +00:00
|
|
|
|
|
|
|
/* We have one more defined label */
|
2000-05-28 13:40:48 +00:00
|
|
|
++ULabDefCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ULabCanResolve (void)
|
|
|
|
/* Return true if we can resolve arbitrary ULabels. */
|
|
|
|
{
|
2004-03-21 16:15:55 +00:00
|
|
|
/* We can resolve labels if we don't have any undefineds */
|
|
|
|
return (ULabDefCount == CollCount (&ULabList));
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
{
|
2004-03-21 16:15:55 +00:00
|
|
|
/* Get the label and check that it is defined */
|
|
|
|
ULabel* L = CollAt (&ULabList, Index);
|
|
|
|
CHECK (L->Val != 0);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-03-21 16:15:55 +00:00
|
|
|
/* Return the label value */
|
|
|
|
return CloneExpr (L->Val);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-08-18 14:36:38 +00:00
|
|
|
void ULabDone (void)
|
|
|
|
/* Run through all unnamed labels, check for anomalies and errors and do
|
|
|
|
* necessary cleanups.
|
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
|
|
|
/* Check if there are undefined labels */
|
2004-03-21 16:15:55 +00:00
|
|
|
unsigned I = ULabDefCount;
|
|
|
|
while (I < CollCount (&ULabList)) {
|
|
|
|
ULabel* L = CollAtUnchecked (&ULabList, I);
|
2011-01-27 21:40:37 +00:00
|
|
|
LIError (&L->LineInfos, "Undefined label");
|
2004-03-21 16:15:55 +00:00
|
|
|
++I;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
2004-03-21 16:15:55 +00:00
|
|
|
/* Walk over all labels and emit a warning if any unreferenced ones
|
2011-08-18 14:36:38 +00:00
|
|
|
* are found. Remove line infos because they're no longer needed.
|
2000-05-28 13:40:48 +00:00
|
|
|
*/
|
2004-03-21 16:15:55 +00:00
|
|
|
for (I = 0; I < CollCount (&ULabList); ++I) {
|
|
|
|
ULabel* L = CollAtUnchecked (&ULabList, I);
|
|
|
|
if (L->Ref == 0) {
|
2011-01-27 21:40:37 +00:00
|
|
|
LIWarning (&L->LineInfos, 1, "No reference to unnamed label");
|
2004-03-21 16:15:55 +00:00
|
|
|
}
|
2011-08-18 14:36:38 +00:00
|
|
|
ReleaseFullLineInfo (&L->LineInfos);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-01-27 21:40:37 +00:00
|
|
|
|