static void FuncString (void) /* Handle the .STRING function */ { StrBuf Buf = STATIC_STRBUF_INITIALIZER; /* Skip it */ NextTok (); /* Left paren expected */ ConsumeLParen (); /* Accept identifiers or numeric expressions */ if (CurTok.Tok == TOK_LOCAL_IDENT) { /* Save the identifier, then skip it */ SB_Copy (&Buf, &CurTok.SVal); NextTok (); } else if (CurTok.Tok == TOK_NAMESPACE || CurTok.Tok == TOK_IDENT) { /* Parse a fully qualified symbol name. We cannot use * ParseScopedSymName here since the name may be invalid. */ int NameSpace; do { NameSpace = (CurTok.Tok == TOK_NAMESPACE); if (NameSpace) { SB_AppendStr (&Buf, "::"); } else { SB_Append (&Buf, &CurTok.SVal); } NextTok (); } while ((NameSpace != 0 && CurTok.Tok == TOK_IDENT) || (NameSpace == 0 && CurTok.Tok == TOK_NAMESPACE)); } else { /* Numeric expression */ long Val = ConstExpression (); SB_Printf (&Buf, "%ld", Val); } /* We expect a closing parenthesis, but will not skip it but replace it * by the string token just created. */ if (CurTok.Tok != TOK_RPAREN) { Error ("`)' expected"); } else { CurTok.Tok = TOK_STRCON; SB_Copy (&CurTok.SVal, &Buf); SB_Terminate (&CurTok.SVal); } /* Free string memory */ SB_Done (&Buf); }
static Macro* NewMacro (const StrBuf* Name, unsigned char Style) /* Generate a new macro entry, initialize and return it */ { /* Allocate memory */ Macro* M = xmalloc (sizeof (Macro)); /* Initialize the macro struct */ InitHashNode (&M->Node); M->LocalCount = 0; M->Locals = 0; M->ParamCount = 0; M->Params = 0; M->TokCount = 0; M->TokRoot = 0; M->TokLast = 0; SB_Init (&M->Name); SB_Copy (&M->Name, Name); M->Expansions = 0; M->Style = Style; M->Incomplete = 1; /* Insert the macro into the hash table */ HT_Insert (&MacroTab, &M->Node); /* Return the new macro struct */ return M; }
static Macro* NewMacro (const StrBuf* Name, unsigned char Style) /* Generate a new macro entry, initialize and return it */ { /* Allocate memory */ Macro* M = xmalloc (sizeof (Macro)); /* Initialize the macro struct */ InitHashNode (&M->Node, M); M->LocalCount = 0; M->Locals = 0; M->ParamCount = 0; M->Params = 0; M->TokCount = 0; M->TokRoot = 0; M->TokLast = 0; M->Style = Style; M->Name = AUTO_STRBUF_INITIALIZER; SB_Copy (&M->Name, Name); /* Insert the macro into the global macro list */ M->List = MacroRoot; MacroRoot = M; /* Insert the macro into the hash table */ HT_Insert (&MacroTab, &M->Node); /* Return the new macro struct */ return M; }
void TokSet (TokNode* T) /* Set the scanner token from the given token node */ { /* Set the values */ Tok = T->Tok; WS = T->WS; IVal = T->IVal; SB_Copy (&SVal, &T->SVal); }
static IdDesc* NewIdDesc (const StrBuf* Id) /* Create a new IdDesc, initialize and return it */ { /* Allocate memory */ IdDesc* ID = xmalloc (sizeof (IdDesc)); /* Initialize the struct */ ID->Next = 0; SB_Init (&ID->Id); SB_Copy (&ID->Id, Id); /* Return the new struct */ return ID; }
static IdDesc* NewIdDesc (const StrBuf* Id) /* Create a new IdDesc, initialize and return it */ { /* Allocate memory */ IdDesc* I = xmalloc (sizeof (IdDesc)); /* Initialize the struct */ I->Next = 0; I->Id = AUTO_STRBUF_INITIALIZER; SB_Copy (&I->Id, Id); /* Return the new struct */ return I; }
static void FuncConcat (void) /* Handle the .CONCAT function */ { StrBuf Buf = STATIC_STRBUF_INITIALIZER; /* Skip it */ NextTok (); /* Left paren expected */ ConsumeLParen (); /* Concatenate any number of strings */ while (1) { /* Next token must be a string */ if (!LookAtStrCon ()) { SB_Done (&Buf); return; } /* Append the string */ SB_Append (&Buf, &CurTok.SVal); /* Skip the string token */ NextTok (); /* Comma means another argument */ if (CurTok.Tok == TOK_COMMA) { NextTok (); } else { /* Done */ break; } } /* We expect a closing parenthesis, but will not skip it but replace it * by the string token just created. */ if (CurTok.Tok != TOK_RPAREN) { Error ("`)' expected"); } else { CurTok.Tok = TOK_STRCON; SB_Copy (&CurTok.SVal, &Buf); SB_Terminate (&CurTok.SVal); } /* Free the string buffer */ SB_Done (&Buf); }
TokNode* NewTokNode (void) /* Create and return a token node with the current token value */ { TokNode* T; /* Allocate memory */ T = xmalloc (sizeof (TokNode)); /* Initialize the token contents */ T->Next = 0; T->Tok = Tok; T->WS = WS; T->IVal = IVal; T->SVal = AUTO_STRBUF_INITIALIZER; SB_Copy (&T->SVal, &SVal); /* Return the node */ return T; }
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); }
SymTable* ParseScopedIdent (StrBuf* Name, StrBuf* FullName) /* Parse a (possibly scoped) identifer. The scope of the name must exist and * is returned as function result, while the last part (the identifier) which * may be either a symbol or a scope depending on the context is returned in * Name. FullName is a string buffer that is used to store the full name of * the identifier including the scope. It is used internally and may be used * by the caller for error messages or similar. */ { SymTable* Scope; /* Clear both passed string buffers */ SB_Clear (Name); SB_Clear (FullName); /* Get the starting table */ if (CurTok.Tok == TOK_NAMESPACE) { /* Start from the root scope */ Scope = RootScope; } else if (CurTok.Tok == TOK_IDENT) { /* Remember the name and skip it */ SB_Copy (Name, &CurTok.SVal); NextTok (); /* If no namespace symbol follows, we're already done */ if (CurTok.Tok != TOK_NAMESPACE) { SB_Terminate (FullName); return CurrentScope; } /* Pass the scope back to the caller */ SB_Append (FullName, Name); /* The scope must exist, so search for it starting with the current * scope. */ Scope = SymFindAnyScope (CurrentScope, Name); if (Scope == 0) { /* Scope not found */ SB_Terminate (FullName); Error ("No such scope: `%m%p'", FullName); return 0; } } else { /* Invalid token */ Error ("Identifier expected"); return 0; } /* Skip the namespace token that follows */ SB_AppendStr (FullName, "::"); NextTok (); /* Resolve scopes. */ while (1) { /* Next token must be an identifier. */ if (CurTok.Tok != TOK_IDENT) { Error ("Identifier expected"); return 0; } /* Remember and skip the identifier */ SB_Copy (Name, &CurTok.SVal); NextTok (); /* If a namespace token follows, we search for another scope, otherwise * the name is a symbol and we're done. */ if (CurTok.Tok != TOK_NAMESPACE) { /* Symbol */ return Scope; } /* Pass the scope back to the caller */ SB_Append (FullName, Name); /* Search for the child scope */ Scope = SymFindScope (Scope, Name, SYM_FIND_EXISTING); if (Scope == 0) { /* Scope not found */ Error ("No such scope: `%m%p'", FullName); return 0; } /* Skip the namespace token that follows */ SB_AppendStr (FullName, "::"); NextTok (); } }
static void FuncSPrintF (void) /* Handle the .SPRINTF function */ { StrBuf Format = STATIC_STRBUF_INITIALIZER; /* User supplied format */ StrBuf R = STATIC_STRBUF_INITIALIZER; /* Result string */ StrBuf F1 = STATIC_STRBUF_INITIALIZER; /* One format spec from F */ StrBuf R1 = STATIC_STRBUF_INITIALIZER; /* One result */ char C; int Done; long IVal; /* Integer value */ /* Skip the .SPRINTF token */ NextTok (); /* Left paren expected */ ConsumeLParen (); /* First argument is a format string. Remember and skip it */ if (!LookAtStrCon ()) { return; } SB_Copy (&Format, &CurTok.SVal); NextTok (); /* Walk over the format string, generating the function result in R */ while (1) { /* Get the next char from the format string and check for EOS */ if (SB_Peek (&Format) == '\0') { break; } /* Check for a format specifier */ if (SB_Peek (&Format) != '%') { /* No format specifier, just copy */ SB_AppendChar (&R, SB_Get (&Format)); continue; } SB_Skip (&Format); if (SB_Peek (&Format) == '%') { /* %% */ SB_AppendChar (&R, '%'); SB_Skip (&Format); continue; } if (SB_Peek (&Format) == '\0') { InvalidFormatString (); break; } /* Since a format specifier follows, we do expect anotehr argument for * the .sprintf function. */ ConsumeComma (); /* We will copy the format spec into F1 checking for the things we * support, and later use xsprintf to do the actual formatting. This * is easier than adding another printf implementation... */ SB_Clear (&F1); SB_AppendChar (&F1, '%'); /* Check for flags */ Done = 0; while ((C = SB_Peek (&Format)) != '\0' && !Done) { switch (C) { case '-': /* FALLTHROUGH */ case '+': /* FALLTHROUGH */ case ' ': /* FALLTHROUGH */ case '#': /* FALLTHROUGH */ case '0': SB_AppendChar (&F1, SB_Get (&Format)); break; default: Done = 1; break; } } /* We do only support a numerical width field */ while (IsDigit (SB_Peek (&Format))) { SB_AppendChar (&F1, SB_Get (&Format)); } /* Precision - only positive numerical fields supported */ if (SB_Peek (&Format) == '.') { SB_AppendChar (&F1, SB_Get (&Format)); while (IsDigit (SB_Peek (&Format))) { SB_AppendChar (&F1, SB_Get (&Format)); } } /* Length modifiers aren't supported, so read the conversion specs */ switch (SB_Peek (&Format)) { case 'd': case 'i': case 'o': case 'u': case 'X': case 'x': /* Our ints are actually longs, so we use the 'l' modifier when * calling xsprintf later. Terminate the format string. */ SB_AppendChar (&F1, 'l'); SB_AppendChar (&F1, SB_Get (&Format)); SB_Terminate (&F1); /* The argument must be a constant expression */ IVal = ConstExpression (); /* Format this argument according to the spec */ SB_Printf (&R1, SB_GetConstBuf (&F1), IVal); /* Append the formatted argument to the result */ SB_Append (&R, &R1); break; case 's': /* Add the format spec and terminate the format */ SB_AppendChar (&F1, SB_Get (&Format)); SB_Terminate (&F1); /* The argument must be a string constant */ if (!LookAtStrCon ()) { /* Make it one */ SB_CopyStr (&CurTok.SVal, "**undefined**"); } /* Format this argument according to the spec */ SB_Printf (&R1, SB_GetConstBuf (&F1), SB_GetConstBuf (&CurTok.SVal)); /* Skip the string constant */ NextTok (); /* Append the formatted argument to the result */ SB_Append (&R, &R1); break; case 'c': /* Add the format spec and terminate the format */ SB_AppendChar (&F1, SB_Get (&Format)); SB_Terminate (&F1); /* The argument must be a constant expression */ IVal = ConstExpression (); /* Check for a valid character range */ if (IVal <= 0 || IVal > 255) { Error ("Char argument out of range"); IVal = ' '; } /* Format this argument according to the spec. Be sure to pass * an int as the char value. */ SB_Printf (&R1, SB_GetConstBuf (&F1), (int) IVal); /* Append the formatted argument to the result */ SB_Append (&R, &R1); break; default: Error ("Invalid format string"); SB_Skip (&Format); break; } } /* Terminate the result string */ SB_Terminate (&R); /* We expect a closing parenthesis, but will not skip it but replace it * by the string token just created. */ if (CurTok.Tok != TOK_RPAREN) { Error ("`)' expected"); } else { CurTok.Tok = TOK_STRCON; SB_Copy (&CurTok.SVal, &R); SB_Terminate (&CurTok.SVal); } /* Delete the string buffers */ SB_Done (&Format); SB_Done (&R); SB_Done (&F1); SB_Done (&R1); }
static void FuncIdent (void) /* Handle the .IDENT function */ { StrBuf Buf = STATIC_STRBUF_INITIALIZER; token_t Id; unsigned I; /* Skip it */ NextTok (); /* Left paren expected */ ConsumeLParen (); /* The function expects a string argument */ if (!LookAtStrCon ()) { return; } /* Check that the string contains a valid identifier. While doing so, * determine if it is a cheap local, or global one. */ SB_Reset (&CurTok.SVal); /* Check for a cheap local symbol */ if (SB_Peek (&CurTok.SVal) == LocalStart) { SB_Skip (&CurTok.SVal); Id = TOK_LOCAL_IDENT; } else { Id = TOK_IDENT; } /* Next character must be a valid identifier start */ if (!IsIdStart (SB_Get (&CurTok.SVal))) { NoIdent (); return; } for (I = SB_GetIndex (&CurTok.SVal); I < SB_GetLen (&CurTok.SVal); ++I) { if (!IsIdChar (SB_AtUnchecked (&CurTok.SVal, I))) { NoIdent (); return; } } if (IgnoreCase) { UpcaseSVal (); } /* If anything is ok, save and skip the string. Check that the next token * is a right paren, then replace the token by an identifier token. */ SB_Copy (&Buf, &CurTok.SVal); NextTok (); if (CurTok.Tok != TOK_RPAREN) { Error ("`)' expected"); } else { CurTok.Tok = Id; SB_Copy (&CurTok.SVal, &Buf); SB_Terminate (&CurTok.SVal); } /* Free buffer memory */ SB_Done (&Buf); }