Collection SegInfoById; /* Segment infos sorted by id */
Collection SpanInfoById; /* Span infos sorted by id */
Collection SymInfoById; /* Symbol infos sorted by id */
+ Collection TypeInfoById; /* Type infos sorted by id */
/* Collections with other sort criteria */
Collection FileInfoByName; /* File infos sorted by name */
typedef struct SegInfo SegInfo;
typedef struct SpanInfo SpanInfo;
typedef struct SymInfo SymInfo;
+typedef struct TypeInfo TypeInfo;
/* Internally used file info struct */
struct FileInfo {
unsigned Id; /* Id of segment */
SegInfo* Info; /* Pointer to segment */
} Seg;
+ union {
+ unsigned Id; /* Id of type */
+ TypeInfo* Info; /* Pointer to type */
+ } Type;
Collection* ScopeInfoList; /* Scopes for this span */
Collection* LineInfoList; /* Lines for this span */
};
char Name[1]; /* Name of symbol */
};
+/* Internally used type info struct */
+struct TypeInfo {
+ unsigned Id; /* Id of type */
+ unsigned Length; /* Length of following data */
+ unsigned char Data[1]; /* Data, dynamically allocated */
+};
+
/*****************************************************************************/
D->span_start = S->Start;
D->span_end = S->End;
D->segment_id = S->Seg.Info->Id;
+ if (S->Type.Info) {
+ D->type_id = S->Type.Info->Id;
+ } else {
+ D->type_id = CC65_INV_ID;
+ }
if (S->ScopeInfoList) {
D->scope_count = CollCount (S->ScopeInfoList);
} else {
+/*****************************************************************************/
+/* Type info */
+/*****************************************************************************/
+
+
+
+static unsigned HexValue (char C)
+/* Convert the ascii representation of a hex nibble into the hex nibble */
+{
+ if (isdigit (C)) {
+ return C - '0';
+ } else if (islower (C)) {
+ return C - 'a' + 10;
+ } else {
+ return C - 'A' + 10;
+ }
+}
+
+
+
+static TypeInfo* NewTypeInfo (const StrBuf* ReadableValue)
+/* Create a new TypeInfo struct, intialize and return it */
+{
+ unsigned I;
+ const char* P;
+
+ /* Calculate the length of the final data. Since we have hex encoding, it
+ * is half of the length of ReadableValue.
+ */
+ unsigned Length = SB_GetLen (ReadableValue) / 2;
+
+ /* Allocate memory */
+ TypeInfo* T = xmalloc (sizeof (TypeInfo) + Length - 1);
+
+ /* Initialize it as necessary */
+ T->Length = Length;
+ P = SB_GetConstBuf (ReadableValue);
+ for (I = 0; I < Length; ++I) {
+ unsigned char V = (HexValue (*P++) << 4);
+ T->Data[I] = (V | HexValue (*P++));
+ }
+
+ /* Return it */
+ return T;
+}
+
+
+
+static void FreeTypeInfo (TypeInfo* T)
+/* Free a TypeInfo struct */
+{
+ xfree (T);
+}
+
+
+
/*****************************************************************************/
/* SpanInfoList */
/*****************************************************************************/
CollInit (&Info->SegInfoById);
CollInit (&Info->SpanInfoById);
CollInit (&Info->SymInfoById);
+ CollInit (&Info->TypeInfoById);
CollInit (&Info->FileInfoByName);
CollInit (&Info->ModInfoByName);
for (I = 0; I < CollCount (&Info->SymInfoById); ++I) {
FreeSymInfo (CollAt (&Info->SymInfoById, I));
}
+ for (I = 0; I < CollCount (&Info->TypeInfoById); ++I) {
+ FreeTypeInfo (CollAt (&Info->TypeInfoById, I));
+ }
/* Free the memory used by the id collections */
CollDone (&Info->FileInfoById);
CollDone (&Info->SegInfoById);
CollDone (&Info->SpanInfoById);
CollDone (&Info->SymInfoById);
+ CollDone (&Info->TypeInfoById);
/* Free the memory used by the other collections */
CollDone (&Info->FileInfoByName);
if (D->Tok != TOK_FILE && D->Tok != TOK_LIBRARY &&
D->Tok != TOK_LINE && D->Tok != TOK_MODULE &&
D->Tok != TOK_SCOPE && D->Tok != TOK_SEGMENT &&
- D->Tok != TOK_SPAN && D->Tok != TOK_SYM) {
+ D->Tok != TOK_SPAN && D->Tok != TOK_SYM &&
+ D->Tok != TOK_TYPE) {
/* Try smart error recovery */
if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
CollGrow (&D->Info->SymInfoByVal, D->IVal);
break;
+ case TOK_TYPE:
+ CollGrow (&D->Info->TypeInfoById, D->IVal);
+ break;
+
default:
/* NOTREACHED */
UnexpectedToken (D);
cc65_addr Start = 0;
cc65_addr Size = 0;
unsigned SegId = CC65_INV_ID;
- StrBuf Type = STRBUF_INITIALIZER;
+ unsigned TypeId = CC65_INV_ID;
SpanInfo* S;
enum {
ibNone = 0x000,
break;
case TOK_TYPE:
- if (!StrConstFollows (D)) {
+ if (!IntConstFollows (D)) {
goto ErrorExit;
}
- SB_Copy (&Type, &D->SVal);
- SB_Terminate (&Type);
- InfoBits |= ibType;
+ TypeId = D->IVal;
NextToken (D);
+ InfoBits |= ibType;
break;
default:
/* Create the span info and remember it */
S = NewSpanInfo ();
- S->Id = Id;
- S->Seg.Id = SegId;
- S->Start = Start;
- S->End = Start + Size - 1;
+ S->Id = Id;
+ S->Start = Start;
+ S->End = Start + Size - 1;
+ S->Seg.Id = SegId;
+ S->Type.Id = TypeId;
CollReplaceExpand (&D->Info->SpanInfoById, S, Id);
ErrorExit:
/* Entry point in case of errors */
- SB_Done (&Type);
return;
}
+static void ParseType (InputData* D)
+/* Parse a TYPE line */
+{
+ /* Most of the following variables are initialized with a value that is
+ * overwritten later. This is just to avoid compiler warnings.
+ */
+ unsigned Id = CC65_INV_ID;
+ StrBuf Value = STRBUF_INITIALIZER;
+
+ TypeInfo* T;
+ enum {
+ ibNone = 0x0000,
+
+ ibId = 0x01,
+ ibValue = 0x02,
+
+ ibRequired = ibId | ibValue,
+ } InfoBits = ibNone;
+
+ /* Skip the SYM token */
+ NextToken (D);
+
+ /* More stuff follows */
+ while (1) {
+
+ Token Tok;
+
+ /* Something we know? */
+ if (D->Tok != TOK_ID && D->Tok != TOK_VALUE) {
+
+ /* Try smart error recovery */
+ if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
+ UnknownKeyword (D);
+ continue;
+ }
+
+ /* Done */
+ break;
+ }
+
+ /* Remember the token, skip it, check for equal */
+ Tok = D->Tok;
+ NextToken (D);
+ if (!ConsumeEqual (D)) {
+ goto ErrorExit;
+ }
+
+ /* Check what the token was */
+ switch (Tok) {
+
+ case TOK_ID:
+ if (!IntConstFollows (D)) {
+ goto ErrorExit;
+ }
+ Id = D->IVal;
+ NextToken (D);
+ InfoBits |= ibId;
+ break;
+
+ case TOK_VALUE:
+ if (!StrConstFollows (D)) {
+ goto ErrorExit;
+ }
+ SB_Copy (&Value, &D->SVal);
+ InfoBits |= ibValue;
+ NextToken (D);
+ break;
+
+ default:
+ /* NOTREACHED */
+ UnexpectedToken (D);
+ goto ErrorExit;
+
+ }
+
+ /* Comma or done */
+ if (D->Tok != TOK_COMMA) {
+ break;
+ }
+ NextToken (D);
+ }
+
+ /* Check for end of line */
+ if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
+ UnexpectedToken (D);
+ SkipLine (D);
+ goto ErrorExit;
+ }
+
+ /* Check for required and/or matched information */
+ if ((InfoBits & ibRequired) != ibRequired) {
+ ParseError (D, CC65_ERROR, "Required attributes missing");
+ goto ErrorExit;
+ }
+
+ /* Check Value */
+ if (SB_GetLen (&Value) < 2 || (SB_GetLen (&Value) & 0x01) != 0) {
+ ParseError (D, CC65_ERROR, "Invalid type value");
+ goto ErrorExit;
+ }
+
+ /* Create the type info */
+ T = NewTypeInfo (&Value);
+ T->Id = Id;
+
+ /* Remember it */
+ CollReplaceExpand (&D->Info->TypeInfoById, T, Id);
+
+ErrorExit:
+ /* Entry point in case of errors */
+ SB_Done (&Value);
+ return;
+}
+
+
+
static void ParseVersion (InputData* D)
/* Parse a VERSION line */
{
S->End += S->Seg.Info->Start;
}
+ /* Resolve the type if we have it */
+ if (S->Type.Id == CC65_INV_ID) {
+ S->Type.Info = 0;
+ } else if (S->Type.Id >= CollCount (&D->Info->TypeInfoById)) {
+ ParseError (D,
+ CC65_ERROR,
+ "Invalid type id %u for span with id %u",
+ S->Type.Id, S->Id);
+ S->Type.Info = 0;
+ } else {
+ S->Type.Info = CollAt (&D->Info->TypeInfoById, S->Type.Id);
+ }
+
/* Append this span info to the temporary collection that is later
* sorted by address.
*/
ParseSym (&D);
break;
+ case TOK_TYPE:
+ ParseType (&D);
+ break;
+
case TOK_IDENT:
/* Output a warning, then skip the line with the unknown
* keyword that may have been added by a later version.