void DbgInfoLine (void) /* Parse and handle LINE subcommand of the .dbg pseudo instruction */ { long Line; FilePos Pos = STATIC_FILEPOS_INITIALIZER; /* Any new line info terminates the last one */ if (CurLineInfo) { EndLine (CurLineInfo); CurLineInfo = 0; } /* If a parameters follow, this is actual line info. If no parameters ** follow, the last line info is terminated. */ if (CurTok.Tok == TOK_SEP) { return; } /* Parameters are separated by a comma */ ConsumeComma (); /* The name of the file follows */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } /* Get the index in the file table for the name */ Pos.Name = GetFileIndex (&CurTok.SVal); /* Skip the name */ NextTok (); /* Comma expected */ ConsumeComma (); /* Line number */ Line = ConstExpression (); if (Line < 0) { ErrorSkip ("Line number is out of valid range"); return; } Pos.Line = Line; /* Generate a new external line info */ CurLineInfo = StartLine (&Pos, LI_TYPE_EXT, 0); }
void ParseRepeat (void) /* Parse and handle the .REPEAT statement */ { char* Name; TokList* List; /* Repeat count follows */ long RepCount = ConstExpression (); if (RepCount < 0) { Error ("Range error"); RepCount = 0; } /* Optional there is a comma and a counter variable */ Name = 0; if (Tok == TOK_COMMA) { /* Skip the comma */ NextTok (); /* Check for an identifier */ if (Tok != TOK_IDENT) { ErrorSkip ("Identifier expected"); } else { /* Remember the name and skip it */ SB_Terminate (&SVal); Name = xstrdup (SB_GetConstBuf (&SVal)); NextTok (); } } /* Separator */ ConsumeSep (); /* Read the token list */ List = CollectRepeatTokens (); /* If we had an error, bail out */ if (List == 0) { xfree (Name); return; } /* Update the token list for replay */ List->RepMax = (unsigned) RepCount; List->Data = Name; List->Check = RepeatTokenCheck; /* If the list is empty, or repeat count zero, there is nothing * to repeat. */ if (List->Count == 0 || RepCount == 0) { FreeTokList (List); return; } /* Read input from the repeat descriptor */ PushTokList (List, ".REPEAT"); }
void ExpectSep (void) /* Check if we've reached a line separator, and output an error if not. Do * not skip the line separator. */ { if (!TokIsSep (CurTok.Tok)) { ErrorSkip ("Unexpected trailing garbage characters"); } }
static int ValidateType (StrBuf* Type) /* Check if the given type is valid and if so, return a string id for it. If ** the type isn't valid, return -1. Type is overwritten when checking. */ { unsigned I; const char* A; char* B; /* The length must not be zero and divideable by two */ unsigned Length = SB_GetLen (Type); if (Length < 2 || (Length & 0x01) != 0) { ErrorSkip ("Type value has invalid length"); return -1; } /* The string must consist completely of hex digit chars */ A = SB_GetConstBuf (Type); for (I = 0; I < Length; ++I) { if (!IsXDigit (A[I])) { ErrorSkip ("Type value contains invalid characters"); return -1; } } /* Convert the type to binary */ B = SB_GetBuf (Type); while (A < SB_GetConstBuf (Type) + Length) { /* Since we know, there are only hex digits, there can't be any errors */ *B++ = (HexValue (A[0]) << 4) | HexValue (A[1]); A += 2; } Type->Len = (Length /= 2); /* Allocate the type and return it */ return GetStrBufId (Type); }
static long Member (long AllocSize) /* Read one struct member and return its size */ { long Multiplicator; /* A multiplicator may follow */ if (CurTok.Tok != TOK_SEP) { Multiplicator = ConstExpression (); if (Multiplicator <= 0) { ErrorSkip ("Range error"); Multiplicator = 1; } AllocSize *= Multiplicator; } /* Check the size for a reasonable value */ if (AllocSize >= 0x10000) { ErrorSkip ("Range error"); } /* Return the size */ return AllocSize; }
void DbgInfoFile (void) /* Parse and handle FILE subcommand of the .dbg pseudo instruction */ { StrBuf Name = STATIC_STRBUF_INITIALIZER; unsigned long Size; unsigned long MTime; /* Parameters are separated by a comma */ ConsumeComma (); /* Name */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } SB_Copy (&Name, &CurTok.SVal); NextTok (); /* Comma expected */ ConsumeComma (); /* Size */ Size = ConstExpression (); /* Comma expected */ ConsumeComma (); /* MTime */ MTime = ConstExpression (); /* Insert the file into the table */ AddFile (&Name, FT_DBGINFO, Size, MTime); /* Free memory used for Name */ SB_Done (&Name); }
static long DoStructInternal (long Offs, unsigned Type) /* Handle the .STRUCT command */ { long Size = 0; /* Outside of other structs, we need a name. Inside another struct or ** union, the struct may be anonymous, in which case no new lexical level ** is started. */ int Anon = (CurTok.Tok != TOK_IDENT); if (!Anon) { /* Enter a new scope, then skip the name */ SymEnterLevel (&CurTok.SVal, SCOPE_STRUCT, ADDR_SIZE_ABS, 0); NextTok (); /* Start at zero offset in the new scope */ Offs = 0; } /* Test for end of line */ ConsumeSep (); /* Read until end of struct */ while (CurTok.Tok != TOK_ENDSTRUCT && CurTok.Tok != TOK_ENDUNION && CurTok.Tok != TOK_EOF) { long MemberSize; SymTable* Struct; SymEntry* Sym; /* Allow empty and comment lines */ if (CurTok.Tok == TOK_SEP) { NextTok (); continue; } /* The format is "[identifier] storage-allocator [, multiplicator]" */ Sym = 0; if (CurTok.Tok == TOK_IDENT) { /* Beware: An identifier may also be a macro, in which case we have ** to start over. */ Macro* M = FindMacro (&CurTok.SVal); if (M) { MacExpandStart (M); continue; } /* We have an identifier, generate a symbol */ Sym = SymFind (CurrentScope, &CurTok.SVal, SYM_ALLOC_NEW); /* Assign the symbol the offset of the current member */ SymDef (Sym, GenLiteralExpr (Offs), ADDR_SIZE_DEFAULT, SF_NONE); /* Skip the member name */ NextTok (); } /* Read storage allocators */ MemberSize = 0; /* In case of errors, use zero */ switch (CurTok.Tok) { case TOK_BYTE: NextTok (); MemberSize = Member (1); break; case TOK_DBYT: case TOK_WORD: case TOK_ADDR: NextTok (); MemberSize = Member (2); break; case TOK_FARADDR: NextTok (); MemberSize = Member (3); break; case TOK_DWORD: NextTok (); MemberSize = Member (4); break; case TOK_RES: NextTok (); if (CurTok.Tok == TOK_SEP) { ErrorSkip ("Size is missing"); } else { MemberSize = Member (1); } break; case TOK_TAG: NextTok (); Struct = ParseScopedSymTable (); if (Struct == 0) { ErrorSkip ("Unknown struct/union"); } else if (GetSymTabType (Struct) != SCOPE_STRUCT) { ErrorSkip ("Not a struct/union"); } else { SymEntry* SizeSym = GetSizeOfScope (Struct); if (!SymIsDef (SizeSym) || !SymIsConst (SizeSym, &MemberSize)) { ErrorSkip ("Size of struct/union is unknown"); } } MemberSize = Member (MemberSize); break; case TOK_STRUCT: NextTok (); MemberSize = DoStructInternal (Offs, STRUCT); break; case TOK_UNION: NextTok (); MemberSize = DoStructInternal (Offs, UNION); break; default: if (!CheckConditionals ()) { /* Not a conditional directive */ ErrorSkip ("Invalid storage allocator in struct/union"); } } /* Assign the size to the member if it has a name */ if (Sym) { DefSizeOfSymbol (Sym, MemberSize); } /* Next member */ if (Type == STRUCT) { /* Struct */ Offs += MemberSize; Size += MemberSize; } else { /* Union */ if (MemberSize > Size) { Size = MemberSize; } } /* Expect end of line */ ConsumeSep (); } /* If this is not a anon struct, enter a special symbol named ".size" ** into the symbol table of the struct that holds the size of the ** struct. Since the symbol starts with a dot, it cannot be accessed ** by user code. ** Leave the struct scope level. */ if (!Anon) { /* Add a symbol */ SymEntry* SizeSym = GetSizeOfScope (CurrentScope); SymDef (SizeSym, GenLiteralExpr (Size), ADDR_SIZE_DEFAULT, SF_NONE); /* Close the struct scope */ SymLeaveLevel (); } /* End of struct/union definition */ if (Type == STRUCT) { Consume (TOK_ENDSTRUCT, "'.ENDSTRUCT' expected"); } else { Consume (TOK_ENDUNION, "'.ENDUNION' expected"); } /* Return the size of the struct */ return Size; }
void ParseAttribute (Declaration* D) /* Parse an additional __attribute__ modifier */ { /* Do we have an attribute? */ if (CurTok.Tok != TOK_ATTRIBUTE) { /* No attribute, bail out */ return; } /* Skip the attribute token */ NextToken (); /* Expect two(!) open braces */ ConsumeLParen (); ConsumeLParen (); /* Read a list of attributes */ while (1) { ident AttrName; const AttrDesc* Attr = 0; /* Identifier follows */ if (CurTok.Tok != TOK_IDENT) { /* No attribute name */ Error ("Attribute name expected"); /* Skip until end of attribute */ ErrorSkip (); /* Bail out */ return; } /* Map the attribute name to its id, then skip the identifier */ strcpy (AttrName, CurTok.Ident); Attr = FindAttribute (AttrName); NextToken (); /* Did we find a valid attribute? */ if (Attr) { /* Call the handler */ Attr->Handler (D); } else { /* Attribute not known, maybe typo */ Error ("Illegal attribute: `%s'", AttrName); /* Skip until end of attribute */ ErrorSkip (); /* Bail out */ return; } /* If a comma follows, there's a next attribute. Otherwise this is the ** end of the attribute list. */ if (CurTok.Tok != TOK_COMMA) { break; } NextToken (); } /* The declaration is terminated with two closing braces */ ConsumeRParen (); ConsumeRParen (); }
void DbgInfoSym (void) /* Parse and handle SYM subcommand of the .dbg pseudo instruction */ { static const char* const StorageKeys[] = { "AUTO", "EXTERN", "REGISTER", "STATIC", }; unsigned Name; int Type; unsigned AsmName = EMPTY_STRING_ID; unsigned Flags; int Offs = 0; HLLDbgSym* S; /* Parameters are separated by a comma */ ConsumeComma (); /* Name */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } Name = GetStrBufId (&CurTok.SVal); NextTok (); /* Comma expected */ ConsumeComma (); /* Type */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } Type = ValidateType (&CurTok.SVal); if (Type < 0) { return; } NextTok (); /* Comma expected */ ConsumeComma (); /* The storage class follows */ if (CurTok.Tok != TOK_IDENT) { ErrorSkip ("Storage class specifier expected"); return; } switch (GetSubKey (StorageKeys, sizeof (StorageKeys)/sizeof (StorageKeys[0]))) { case 0: Flags = HLL_SC_AUTO; break; case 1: Flags = HLL_SC_EXTERN; break; case 2: Flags = HLL_SC_REG; break; case 3: Flags = HLL_SC_STATIC; break; default: ErrorSkip ("Storage class specifier expected"); return; } /* Skip the storage class token and the following comma */ NextTok (); ConsumeComma (); /* The next tokens depend on the storage class */ if (Flags == HLL_SC_AUTO) { /* Auto: Stack offset follows */ Offs = ConstExpression (); } else { /* Register, extern or static: Assembler name follows */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } AsmName = GetStrBufId (&CurTok.SVal); NextTok (); /* For register, an offset follows */ if (Flags == HLL_SC_REG) { ConsumeComma (); Offs = ConstExpression (); } } /* Add the function */ S = NewHLLDbgSym (Flags | HLL_TYPE_SYM, Name, Type); S->AsmName = AsmName; S->Offs = Offs; CollAppend (&HLLDbgSyms, S); }
void DbgInfoFunc (void) /* Parse and handle func subcommand of the .dbg pseudo instruction */ { static const char* const StorageKeys[] = { "EXTERN", "STATIC", }; unsigned Name; int Type; unsigned AsmName; unsigned Flags; HLLDbgSym* S; /* Parameters are separated by a comma */ ConsumeComma (); /* Name */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } Name = GetStrBufId (&CurTok.SVal); NextTok (); /* Comma expected */ ConsumeComma (); /* Type */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } Type = ValidateType (&CurTok.SVal); if (Type < 0) { return; } NextTok (); /* Comma expected */ ConsumeComma (); /* The storage class follows */ if (CurTok.Tok != TOK_IDENT) { ErrorSkip ("Storage class specifier expected"); return; } switch (GetSubKey (StorageKeys, sizeof (StorageKeys)/sizeof (StorageKeys[0]))) { case 0: Flags = HLL_TYPE_FUNC | HLL_SC_EXTERN; break; case 1: Flags = HLL_TYPE_FUNC | HLL_SC_STATIC; break; default: ErrorSkip ("Storage class specifier expected"); return; } NextTok (); /* Comma expected */ ConsumeComma (); /* Assembler name follows */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } AsmName = GetStrBufId (&CurTok.SVal); NextTok (); /* There may only be one function per scope */ if (CurrentScope == RootScope) { ErrorSkip ("Functions may not be used in the root scope"); return; } else if (CurrentScope->Type != SCOPE_SCOPE || CurrentScope->Label == 0) { ErrorSkip ("Functions can only be tagged to .PROC scopes"); return; } else if (CurrentScope->Label->HLLSym != 0) { ErrorSkip ("Only one HLL symbol per asm symbol is allowed"); return; } else if (CurrentScope->Label->Name != AsmName) { ErrorSkip ("Scope label and asm name for function must match"); return; } /* Add the function */ S = NewHLLDbgSym (Flags, Name, Type); S->Sym = CurrentScope->Label; CurrentScope->Label->HLLSym = S; CollAppend (&HLLDbgSyms, S); }
static void StartExpDefine (MacExp* E) /* Start expanding a DEFINE style macro */ { /* A define style macro must be called with as many actual parameters * as there are formal ones. Get the parameter count. */ unsigned Count = E->M->ParamCount; /* Skip the current token */ NextTok (); /* Read the actual parameters */ while (Count--) { TokNode* Last; /* The macro may optionally be enclosed in curly braces */ token_t Term = GetTokListTerm (TOK_COMMA); /* Check if there is really a parameter */ if (TokIsSep (CurTok.Tok) || CurTok.Tok == Term) { ErrorSkip ("Macro parameter #%u is empty", E->ParamCount+1); FreeMacExp (E); return; } /* Read tokens for one parameter */ Last = 0; do { TokNode* T; /* Get the next token in a node */ T = NewTokNode (); /* Insert it into the list */ if (Last == 0) { E->Params [E->ParamCount] = T; } else { Last->Next = T; } Last = T; /* And skip it... */ NextTok (); } while (CurTok.Tok != Term && !TokIsSep (CurTok.Tok)); /* One parameter more */ ++E->ParamCount; /* If the macro argument was enclosed in curly braces, end-of-line * is an error. Skip the closing curly brace. */ if (Term == TOK_RCURLY) { if (TokIsSep (CurTok.Tok)) { Error ("End of line encountered within macro argument"); break; } NextTok (); } /* Check for a comma */ if (Count > 0) { if (CurTok.Tok == TOK_COMMA) { NextTok (); } else { Error ("`,' expected"); } } } /* Macro expansion will overwrite the current token. This is a problem * for define style macros since these are called from the scanner level. * To avoid it, remember the current token and re-insert it, once macro * expansion is done. */ E->Final = NewTokNode (); /* Insert a new token input function */ PushInput (MacExpand, E, ".DEFINE"); }
static void StartExpClassic (MacExp* E) /* Start expanding a classic macro */ { token_t Term; /* Skip the macro name */ NextTok (); /* Read the actual parameters */ while (!TokIsSep (CurTok.Tok)) { TokNode* Last; /* Check for maximum parameter count */ if (E->ParamCount >= E->M->ParamCount) { ErrorSkip ("Too many macro parameters"); break; } /* The macro may optionally be enclosed in curly braces */ Term = GetTokListTerm (TOK_COMMA); /* Read tokens for one parameter, accept empty params */ Last = 0; while (CurTok.Tok != Term && CurTok.Tok != TOK_SEP) { TokNode* T; /* Check for end of file */ if (CurTok.Tok == TOK_EOF) { Error ("Unexpected end of file"); FreeMacExp (E); return; } /* Get the next token in a node */ T = NewTokNode (); /* Insert it into the list */ if (Last == 0) { E->Params [E->ParamCount] = T; } else { Last->Next = T; } Last = T; /* And skip it... */ NextTok (); } /* One parameter more */ ++E->ParamCount; /* If the macro argument was enclosed in curly braces, end-of-line * is an error. Skip the closing curly brace. */ if (Term == TOK_RCURLY) { if (CurTok.Tok == TOK_SEP) { Error ("End of line encountered within macro argument"); break; } NextTok (); } /* Check for a comma */ if (CurTok.Tok == TOK_COMMA) { NextTok (); } else { break; } } /* We must be at end of line now, otherwise something is wrong */ ExpectSep (); /* Insert a new token input function */ PushInput (MacExpand, E, ".MACRO"); }