Exemplo n.º 1
0
static void VPrintMsg (const FilePos* Pos, const char* Desc,
                       const char* Format, va_list ap)
/* Format and output an error/warning message. */
{
    StrBuf S = STATIC_STRBUF_INITIALIZER;

    /* Format the actual message */
    StrBuf Msg = STATIC_STRBUF_INITIALIZER;
    SB_VPrintf (&Msg, Format, ap);
    SB_Terminate (&Msg);

    /* Format the message header */
    SB_Printf (&S, "%s(%u): %s: ",
               SB_GetConstBuf (GetFileName (Pos->Name)),
               Pos->Line,
               Desc);

    /* Append the message to the message header */
    SB_Append (&S, &Msg);

    /* Delete the formatted message */
    SB_Done (&Msg);

    /* Add a new line and terminate the generated full message */
    SB_AppendChar (&S, '\n');
    SB_Terminate (&S);

    /* Output the full message */
    fputs (SB_GetConstBuf (&S), stderr);

    /* Delete the buffer for the full message */
    SB_Done (&S);
}
Exemplo n.º 2
0
int SB_GetString (StrBuf* B, StrBuf* S)
/* Get a string from the string buffer. Returns 1 if a string was found and 0
** otherwise. Errors are only output in case of invalid strings (missing end
** of string).
*/
{
    char C;

    /* Clear S */
    SB_Clear (S);

    /* A string starts with quote marks */
    if (SB_Peek (B) == '\"') {

        /* String follows, be sure to concatenate strings */
        while (SB_Peek (B) == '\"') {

            /* Skip the quote char */
            SB_Skip (B);

            /* Read the actual string contents */
            while ((C = SB_Peek (B)) != '\"') {
                if (C == '\0') {
                    Error ("Unexpected end of string");
                    break;
                }
                SB_AppendChar (S, ParseChar (B));
            }

            /* Skip the closing quote char if there was one */
            SB_Skip (B);

            /* Skip white space, read new input */
            SB_SkipWhite (B);
        }

        /* Terminate the string */
        SB_Terminate (S);

        /* Success */
        return 1;

    } else {

        /* Not a string */
        SB_Terminate (S);
        return 0;
    }
}
Exemplo n.º 3
0
void SplitAddAttr (Collection* C, const char* Combined, const char* Name)
/* Split a combined name/value pair and add it as an attribute to C. Some
 * attributes may not need a name. If the name is missing, use Name. If
 * Name is NULL, terminate with an error.
 */
{
    /* Name and value are separated by an equal sign */
    const char* Pos = strchr (Combined, '=');
    if (Pos == 0) {
        /* Combined is actually a value */
        if (Name == 0) {
            Error ("Command line attribute `%s' doesn't contain a name", Combined);
        }
        AddAttr (C, Name, Combined);
    } else {
        /* Must split name and value */
        StrBuf N = AUTO_STRBUF_INITIALIZER;
        SB_CopyBuf (&N, Combined, Pos - Combined);
        SB_Terminate (&N);

        /* Add the attribute */
        AddAttr (C, SB_GetConstBuf (&N), Pos+1);

        /* Release memory */
        SB_Done (&N);
    }
}
Exemplo n.º 4
0
int SB_GetSym (StrBuf* B, StrBuf* Ident, const char* SpecialChars)
/* Get a symbol from the string buffer. If SpecialChars is not NULL, it
** points to a string that contains characters allowed within the string in
** addition to letters, digits and the underline. Note: The identifier must
** still begin with a letter.
** Returns 1 if a symbol was found and 0 otherwise but doesn't output any
** errors.
*/
{
    /* Handle a NULL argument for SpecialChars transparently */
    if (SpecialChars == 0) {
        SpecialChars = "";
    }

    /* Clear Ident */
    SB_Clear (Ident);

    if (IsIdent (SB_Peek (B))) {
        char C = SB_Peek (B);
        do {
            SB_AppendChar (Ident, C);
            SB_Skip (B);
            C = SB_Peek (B);
        } while (IsIdent (C) || IsDigit (C) || 
                 (C != '\0' && strchr (SpecialChars, C) != 0));
        SB_Terminate (Ident);
        return 1;
    } else {
        return 0;
    }
}
Exemplo n.º 5
0
char* SearchFile (const SearchPaths* P, const char* File)
/* Search for a file in a list of directories. Return a pointer to a malloced
** area that contains the complete path, if found, return 0 otherwise.
*/
{
    char* Name = 0;
    StrBuf PathName = AUTO_STRBUF_INITIALIZER;

    /* Start the search */
    unsigned I;
    for (I = 0; I < CollCount (P); ++I) {

        /* Copy the next path element into the buffer */
        SB_CopyStr (&PathName, CollConstAt (P, I));

        /* Add a path separator and the filename */
        if (SB_NotEmpty (&PathName)) {
            SB_AppendChar (&PathName, '/');
        }
        SB_AppendStr (&PathName, File);
        SB_Terminate (&PathName);

        /* Check if this file exists */
        if (access (SB_GetBuf (&PathName), 0) == 0) {
            /* The file exists, we're done */
            Name = xstrdup (SB_GetBuf (&PathName));
            break;
        }
    }

    /* Cleanup and return the result of the search */
    SB_Done (&PathName);
    return Name;
}
Exemplo n.º 6
0
void AddSubSearchPathFromEnv (SearchPaths* P, const char* EnvVar, const char* SubDir)
/* Add a search path from an environment variable, adding a subdirectory to
** the environment variable value.
*/
{
    StrBuf Dir = AUTO_STRBUF_INITIALIZER;

    const char* EnvVal = getenv (EnvVar);
    if (EnvVal == 0) {
        /* Not found */
        return;
    }

    /* Copy the environment variable to the buffer */
    SB_CopyStr (&Dir, EnvVal);

    /* Add a path separator if necessary */
    if (SB_NotEmpty (&Dir)) {
        if (SB_LookAtLast (&Dir) != '\\' && SB_LookAtLast (&Dir) != '/') {
            SB_AppendChar (&Dir, '/');
        }
    }

    /* Add the subdirectory and terminate the string */
    SB_AppendStr (&Dir, SubDir);
    SB_Terminate (&Dir);

    /* Add the search path */
    AddSearchPath (P, SB_GetConstBuf (&Dir));

    /* Free the temp buffer */
    SB_Done (&Dir);
}
Exemplo n.º 7
0
static void ReadStringConst (int StringTerm)
/* Read a string constant into SVal. */
{
    /* Skip the leading string terminator */
    NextChar ();

    /* Read the string */
    while (1) {
        if (C == StringTerm) {
            break;
        }
        if (C == '\n' || C == EOF) {
            Error ("Newline in string constant");
            break;
        }

        /* Append the char to the string */
        SB_AppendChar (&CurTok.SVal, C);

        /* Skip the character */
        NextChar ();
    }

    /* Skip the trailing terminator */
    NextChar ();

    /* Terminate the string */
    SB_Terminate (&CurTok.SVal);
}
Exemplo n.º 8
0
static void DoInclude (void)
/* Open an include file. */
{
    char        RTerm;
    InputType   IT;
    StrBuf      Filename = STATIC_STRBUF_INITIALIZER;


    /* Preprocess the remainder of the line */
    PreprocessLine ();

    /* Skip blanks */
    SkipWhitespace (0);

    /* Get the next char and check for a valid file name terminator. Setup
     * the include directory spec (SYS/USR) by looking at the terminator.
     */
    switch (CurC) {

        case '\"':
            RTerm   = '\"';
            IT = IT_USRINC;
            break;

        case '<':
            RTerm   = '>';
            IT = IT_SYSINC;
            break;

        default:
            PPError ("`\"' or `<' expected");
            goto Done;
    }
    NextChar ();

    /* Get a copy of the filename */
    while (CurC != '\0' && CurC != RTerm) {
        SB_AppendChar (&Filename, CurC);
        NextChar ();
    }
    SB_Terminate (&Filename);

    /* Check if we got a terminator */
    if (CurC == RTerm) {
        /* Open the include file */
        OpenIncludeFile (SB_GetConstBuf (&Filename), IT);
    } else if (CurC == '\0') {
        /* No terminator found */
        PPError ("#include expects \"FILENAME\" or <FILENAME>");
    }

Done:
    /* Free the allocated filename data */
    SB_Done (&Filename);

    /* Clear the remaining line so the next input will come from the new
     * file (if open)
     */
    ClearLine ();
}
Exemplo n.º 9
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");
}
Exemplo n.º 10
0
static AFile* NewAFile (IFile* IF, FILE* F)
/* Create a new AFile, push it onto the stack, add the path of the file to
 * the path search list, and finally return a pointer to the new AFile struct.
 */
{
    StrBuf Path = AUTO_STRBUF_INITIALIZER;

    /* Allocate a AFile structure */
    AFile* AF = (AFile*) xmalloc (sizeof (AFile));

    /* Initialize the fields */
    AF->Line  = 0;
    AF->F     = F;
    AF->Input = IF;

    /* Increment the usage counter of the corresponding IFile. If this
     * is the first use, set the file data and output debug info if
     * requested.
     */
    if (IF->Usage++ == 0) {

 	/* Get file size and modification time. There a race condition here,
         * since we cannot use fileno() (non standard identifier in standard
         * header file), and therefore not fstat. When using stat with the
         * file name, there's a risk that the file was deleted and recreated
         * while it was open. Since mtime and size are only used to check
         * if a file has changed in the debugger, we will ignore this problem
         * here.
         */
     	struct stat Buf;
 	if (FileStat (IF->Name, &Buf) != 0) {
 	    /* Error */
 	    Fatal ("Cannot stat `%s': %s", IF->Name, strerror (errno));
 	}
       	IF->Size  = (unsigned long) Buf.st_size;
 	IF->MTime = (unsigned long) Buf.st_mtime;

 	/* Set the debug data */
 	g_fileinfo (IF->Name, IF->Size, IF->MTime);
    }

    /* Insert the new structure into the AFile collection */
    CollAppend (&AFiles, AF);

    /* Get the path of this file and add it as an extra search path.
     * To avoid file search overhead, we will add one path only once.
     * This is checked by the PushSearchPath function.
     */
    SB_CopyBuf (&Path, IF->Name, FindName (IF->Name) - IF->Name);
    SB_Terminate (&Path);
    AF->SearchPath = PushSearchPath (UsrIncSearchPath, SB_GetConstBuf (&Path));
    SB_Done (&Path);

    /* Return the new struct */
    return AF;
}
Exemplo n.º 11
0
static void FileNameOption (const char* Opt, const char* Arg, StrBuf* Name)
/* Handle an option that remembers a file name for later */
{
    /* Cannot have the option twice */
    if (SB_NotEmpty (Name)) {
        AbEnd ("Cannot use option `%s' twice", Opt);
    }
    /* Remember the file name for later */
    SB_CopyStr (Name, Arg);
    SB_Terminate (Name);
}
Exemplo n.º 12
0
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);
}
Exemplo n.º 13
0
static int DoIf (int Skip)
/* Process #if directive */
{
    ExprDesc Expr;

    /* We're about to abuse the compiler expression parser to evaluate the
     * #if expression. Save the current tokens to come back here later.
     * NOTE: Yes, this is a hack, but it saves a complete separate expression
     * evaluation for the preprocessor.
     */
    Token SavedCurTok  = CurTok;
    Token SavedNextTok = NextTok;

    /* Make sure the line infos for the tokens won't get removed */
    if (SavedCurTok.LI) {
        UseLineInfo (SavedCurTok.LI);
    }
    if (SavedNextTok.LI) {
        UseLineInfo (SavedNextTok.LI);
    }

    /* Switch into special preprocessing mode */
    Preprocessing = 1;

    /* Expand macros in this line */
    PreprocessLine ();

    /* Add two semicolons as sentinels to the line, so the following
     * expression evaluation will eat these two tokens but nothing from
     * the following line.
     */
    SB_AppendStr (Line, ";;");
    SB_Terminate (Line);

    /* Load CurTok and NextTok with tokens from the new input */
    NextToken ();
    NextToken ();

    /* Call the expression parser */
    ConstExpr (hie1, &Expr);

    /* End preprocessing mode */
    Preprocessing = 0;

    /* Reset the old tokens */
    CurTok  = SavedCurTok;
    NextTok = SavedNextTok;

    /* Set the #if condition according to the expression result */
    return PushIf (Skip, 1, Expr.IVal != 0);
}
Exemplo n.º 14
0
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);
}
Exemplo n.º 15
0
Collection* ParseAttrList (const char* List, const char** NameList, unsigned NameCount)
/* Parse a list containing name/value pairs into a sorted collection. Some
 * attributes may not need a name, so NameList contains these names. If there
 * were no errors, the function returns a alphabetically sorted collection
 * containing Attr entries.
 */
{
    const char* Name;

    /* Create a new collection */
    Collection* C = NewCollection ();

    /* Name/value pairs are separated by commas */
    const char* L = List;
    StrBuf B = AUTO_STRBUF_INITIALIZER;
    while (1) {
        if (*L == ',' || *L == ':' || *L == '\0') {

            /* Terminate the string */
            SB_Terminate (&B);

            /* Determine the default name */
            if (CollCount (C) >= NameCount) {
                Name = 0;
            } else {
                Name = NameList[CollCount (C)];
            }

            /* Split and add this attribute/value pair */
            SplitAddAttr (C, SB_GetConstBuf (&B), Name);

            /* Done, clear the buffer. */
            SB_Clear (&B);
            if (*L == '\0') {
                break;
            }
        } else {
            SB_AppendChar (&B, *L);
        }
        ++L;
    }

    /* Free memory */
    SB_Done (&B);

    /* Return the collection with the attributes */
    return C;
}
Exemplo n.º 16
0
Arquivo: codeopt.c Projeto: coyxc/cc65
static void OpenDebugFile (const CodeSeg* S)
/* Open the debug file for the given segment if the flag is on */
{
    if (DebugOptOutput) {
        StrBuf Name = AUTO_STRBUF_INITIALIZER;
        if (S->Func) {
            SB_CopyStr (&Name, S->Func->Name);
        } else {
            SB_CopyStr (&Name, "global");
        }
        SB_AppendStr (&Name, ".opt");
        SB_Terminate (&Name);
        OpenDebugOutputFile (SB_GetConstBuf (&Name));
        SB_Done (&Name);
    }
}
Exemplo n.º 17
0
static void DefineSymbol (const char* Def)
/* Define a symbol from the command line */
{
    const char* P;
    long Val;
    StrBuf SymName = AUTO_STRBUF_INITIALIZER;


    /* The symbol must start with a character or underline */
    if (!IsIdStart (Def [0])) {
        InvDef (Def);
    }
    P = Def;

    /* Copy the symbol, checking the rest */
    while (IsIdChar (*P)) {
        SB_AppendChar (&SymName, *P++);
    }
    SB_Terminate (&SymName);

    /* Do we have a value given? */
    if (*P != '=') {
        if (*P != '\0') {
            InvDef (Def);
        }
        Val = 0;
    } else {
        /* We have a value */
        ++P;
        if (*P == '$') {
            ++P;
            if (sscanf (P, "%lx", &Val) != 1) {
                InvDef (Def);
            }
        } else {
            if (sscanf (P, "%li", &Val) != 1) {
                InvDef (Def);
            }
        }
    }

    /* Define the new symbol */
    NewSymbol (SB_GetConstBuf (&SymName), Val);

    /* Release string memory */
    SB_Done (&SymName);
}
Exemplo n.º 18
0
void Internal (const char* Format, ...)
/* Print a message about an internal assembler error and die. */
{
    va_list ap;
    StrBuf S = STATIC_STRBUF_INITIALIZER;

    va_start (ap, Format);
    SB_VPrintf (&S, Format, ap);
    SB_Terminate (&S);
    va_end (ap);

    fprintf (stderr, "Internal assembler error: %s\n", SB_GetConstBuf (&S));

    SB_Done (&S);

    exit (EXIT_FAILURE);
}
Exemplo n.º 19
0
static void ReadIdent (void)
/* Read an identifier from the current input position into Ident. Filling SVal
** starts at the current position with the next character in C. It is assumed
** that any characters already filled in are ok, and the character in C is
** checked.
*/
{
    /* Read the identifier */
    do {
        SB_AppendChar (&CurTok.SVal, C);
        NextChar ();
    } while (IsIdChar (C));
    SB_Terminate (&CurTok.SVal);

    /* If we should ignore case, convert the identifier to upper case */
    if (IgnoreCase) {
        UpcaseSVal ();
    }
}
Exemplo n.º 20
0
static void DefineSymbol (const char* Def)
/* Define a symbol from the command line */
{
    const char* P;
    long Val;
    StrBuf SymName = AUTO_STRBUF_INITIALIZER;


    /* The symbol must start with a character or underline */
    if (Def [0] != '_' && !IsAlpha (Def [0])) {
        InvDef (Def);
    }
    P = Def;

    /* Copy the symbol, checking the remainder */
    while (IsAlNum (*P) || *P == '_') {
        SB_AppendChar (&SymName, *P++);
    }
    SB_Terminate (&SymName);

    /* Do we have a value given? */
    if (*P != '=') {
        InvDef (Def);
    } else {
        /* We have a value */
        ++P;
        if (*P == '$') {
            ++P;
            if (sscanf (P, "%lx", &Val) != 1) {
                InvDef (Def);
            }
        } else {
            if (sscanf (P, "%li", &Val) != 1) {
                InvDef (Def);
            }
        }
    }

    /* Define the new symbol */
    CreateConstExport (GetStringId (SB_GetConstBuf (&SymName)), Val);
}
Exemplo n.º 21
0
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);
}
Exemplo n.º 22
0
int NextLine (void)
/* Get a line from the current input. Returns 0 on end of file. */
{
    AFile*     	Input;

    /* Clear the current line */
    ClearLine ();

    /* If there is no file open, bail out, otherwise get the current input file */
    if (CollCount (&AFiles) == 0) {
     	return 0;
    }
    Input = CollLast (&AFiles);

    /* Read characters until we have one complete line */
    while (1) {

        /* Read the next character */
        int C = fgetc (Input->F);

        /* Check for EOF */
        if (C == EOF) {

            /* Accept files without a newline at the end */
            if (SB_NotEmpty (Line)) {
                ++Input->Line;
                break;
            }

      	    /* Leave the current file */
      	    CloseIncludeFile ();

            /* If there is no file open, bail out, otherwise get the
             * previous input file and start over.
             */
            if (CollCount (&AFiles) == 0) {
                return 0;
            }
            Input = CollLast (&AFiles);
            continue;
        }

        /* Check for end of line */
        if (C == '\n') {

            /* We got a new line */
            ++Input->Line;

            /* If the \n is preceeded by a \r, remove the \r, so we can read
             * DOS/Windows files under *nix.
             */
            if (SB_LookAtLast (Line) == '\r') {
                SB_Drop (Line, 1);
            }

            /* If we don't have a line continuation character at the end,
             * we're done with this line. Otherwise replace the character
             * by a newline and continue reading.
             */
            if (SB_LookAtLast (Line) == '\\') {
                Line->Buf[Line->Len-1] = '\n';
            } else {
                break;
            }

        } else if (C != '\0') {         /* Ignore embedded NULs */

            /* Just some character, add it to the line */
            SB_AppendChar (Line, C);

        }
    }

    /* Add a termination character to the string buffer */
    SB_Terminate (Line);

    /* Initialize the current and next characters. */
    InitLine (Line);

    /* Create line information for this line */
    UpdateLineInfo (Input->Input, Input->Line, Line);

    /* Done */
    return 1;
}
Exemplo n.º 23
0
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 ();
    }
}
Exemplo n.º 24
0
void AsmInc (const char* Filename, char CommentStart, int IgnoreUnknown)
/* Read an assembler include file */
{
    char        Buf[1024];
    char*       L;
    const char* Comment;
    unsigned    Line;
    unsigned	Len;
    long        Val;
    unsigned    DVal;
    int         Sign;
    unsigned    Base;
    unsigned    Digits;
    StrBuf      Ident = STATIC_STRBUF_INITIALIZER;

    /* Try to open the file for reading */
    FILE* F = fopen (Filename, "r");
    if (F == 0) {
        Error ("Cannot open asm include file \"%s\": %s",
               Filename, strerror (errno));
    }

    /* Read line by line, check for NAME = VALUE lines */
    Line = 0;
    while ((L = fgets (Buf, sizeof (Buf), F)) != 0) {

        /* One more line read */
        ++Line;

        /* Ignore leading white space */
        while (IsBlank (*L)) {
            ++L;
        }

	/* Remove trailing whitespace */
	Len = strlen (L);
	while (Len > 0 && IsSpace (L[Len-1])) {
	    --Len;
	}
	L[Len] = '\0';

        /* If the line is empty or starts with a comment char, ignore it */
        if (*L == '\0' || *L == CommentStart) {
            continue;
        }

        /* Read an identifier */
        SB_Clear (&Ident);
        if (IsAlpha (*L) || *L == '_') {
            SB_AppendChar (&Ident, *L++);
            while (IsAlNum (*L) || *L == '_') {
                SB_AppendChar (&Ident, *L++);
            }
            SB_Terminate (&Ident);
        } else {
            if (!IgnoreUnknown) {
                Error ("%s(%u): Syntax error", Filename, Line);
            }
            continue;
        }

        /* Ignore white space */
        L = SkipWhitespace (L);

        /* Check for := or = */
        if (*L == '=') {
            ++L;
        } else if (*L == ':' && *++L == '=') {
            ++L;
        } else {
	    if (!IgnoreUnknown) {
	       	Error ("%s(%u): Missing `='", Filename, Line);
	    }
	    continue;
	}

        /* Allow white space once again */
        L = SkipWhitespace (L);

        /* A number follows. Read the sign. */
        if (*L == '-') {
            Sign = -1;
            ++L;
        } else {
            Sign = 1;
            if (*L == '+') {
                ++L;
            }
        }

        /* Determine the base of the number. Allow $ and % as prefixes for
         * hex and binary numbers respectively.
         */
        if (*L == '$') {
            Base = 16;
            ++L;
        } else if (*L == '%') {
            Base = 2;
            ++L;
        } else {
            Base = 10;
        }

        /* Decode the number */
        Digits = 0;
        Val = 0;
        while (IsXDigit (*L) && (DVal = DigitVal (*L)) < Base) {
            Val = (Val * Base) + DVal;
            ++Digits;
            ++L;
        }

        /* Must have at least one digit */
        if (Digits == 0) {
            if (!IgnoreUnknown) {
                Error ("%s(%u): Error in number format", Filename, Line);
            }
            continue;
        }

        /* Skip whitespace again */
        L = SkipWhitespace (L);

        /* Check for a comment */
        if (*L == CommentStart) {
            Comment = SkipWhitespace (L+1);
            if (*Comment == '\0') {
                Comment = 0;
            }
        } else {
            Comment = 0;
        }

        /* Check for a comment character or end of line */
        if (*L != CommentStart && *L != '\0') {
            if (!IgnoreUnknown) {
                Error ("%s(%u): Trailing garbage", Filename, Line);
            }
            continue;
        }

        /* Apply the sign */
        Val *= Sign;

        /* Define the symbol and the comment */
        AddExtLabel (Val, SB_GetConstBuf (&Ident));
        SetComment (Val, Comment);

    }

    /* Delete the string buffer contents */
    SB_Done (&Ident);

    /* Close the include file ignoring errors (we were just reading). */
    (void) fclose (F);
}
Exemplo n.º 25
0
static void IFNextChar (CharSource* S)
/* Read the next character from the input file */
{
    /* Check for end of line, read the next line if needed */
    while (SB_GetIndex (&S->V.File.Line) >= SB_GetLen (&S->V.File.Line)) {

        unsigned Len;

        /* End of current line reached, read next line */
        SB_Clear (&S->V.File.Line);
        while (1) {

            int N = fgetc (S->V.File.F);
            if (N == EOF) {
                /* End of file. Accept files without a newline at the end */
                if (SB_NotEmpty (&S->V.File.Line)) {
                    break;
                }

                /* No more data - add an empty line to the listing. This
                ** is a small hack needed to keep the PC output in sync.
                */
                NewListingLine (&EmptyStrBuf, S->V.File.Pos.Name, FCount);
                C = EOF;
                return;

            /* Check for end of line */
            } else if (N == '\n') {

                /* End of line */
                break;

            /* Collect other stuff */
            } else {

                /* Append data to line */
                SB_AppendChar (&S->V.File.Line, N);

            }
        }


        /* If we come here, we have a new input line. To avoid problems
        ** with strange line terminators, remove all whitespace from the
        ** end of the line, then add a single newline.
        */
        Len = SB_GetLen (&S->V.File.Line);
        while (Len > 0 && IsSpace (SB_AtUnchecked (&S->V.File.Line, Len-1))) {
            --Len;
        }
        SB_Drop (&S->V.File.Line, SB_GetLen (&S->V.File.Line) - Len);
        SB_AppendChar (&S->V.File.Line, '\n');

        /* Terminate the string buffer */
        SB_Terminate (&S->V.File.Line);

        /* One more line */
        S->V.File.Pos.Line++;

        /* Remember the new line for the listing */
        NewListingLine (&S->V.File.Line, S->V.File.Pos.Name, FCount);

    }

    /* Set the column pointer */
    S->V.File.Pos.Col = SB_GetIndex (&S->V.File.Line);

    /* Return the next character from the buffer */
    C = SB_Get (&S->V.File.Line);
}
Exemplo n.º 26
0
int NewInputFile (const char* Name)
/* Open a new input file. Returns true if the file could be successfully opened
** and false otherwise.
*/
{
    int         RetCode = 0;            /* Return code. Assume an error. */
    char*       PathName = 0;
    FILE*       F;
    struct stat Buf;
    StrBuf      NameBuf;                /* No need to initialize */
    StrBuf      Path = AUTO_STRBUF_INITIALIZER;
    unsigned    FileIdx;
    CharSource* S;


    /* If this is the main file, just try to open it. If it's an include file,
    ** search for it using the include path list.
    */
    if (FCount == 0) {
        /* Main file */
        F = fopen (Name, "r");
        if (F == 0) {
            Fatal ("Cannot open input file '%s': %s", Name, strerror (errno));
        }
    } else {
        /* We are on include level. Search for the file in the include
        ** directories.
        */
        PathName = SearchFile (IncSearchPath, Name);
        if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
            /* Not found or cannot open, print an error and bail out */
            Error ("Cannot open include file '%s': %s", Name, strerror (errno));
            goto ExitPoint;
        }

        /* Use the path name from now on */
        Name = PathName;
    }

    /* Stat the file and remember the values. There's a race condition here,
    ** since we cannot use fileno() (non-standard identifier in standard
    ** header file), and therefore not fstat. When using stat with the
    ** file name, there's a risk that the file was deleted and recreated
    ** while it was open. Since mtime and size are only used to check
    ** if a file has changed in the debugger, we will ignore this problem
    ** here.
    */
    if (FileStat (Name, &Buf) != 0) {
        Fatal ("Cannot stat input file '%s': %s", Name, strerror (errno));
    }

    /* Add the file to the input file table and remember the index */
    FileIdx = AddFile (SB_InitFromString (&NameBuf, Name),
                       (FCount == 0)? FT_MAIN : FT_INCLUDE,
                       Buf.st_size, (unsigned long) Buf.st_mtime);

    /* Create a new input source variable and initialize it */
    S                   = xmalloc (sizeof (*S));
    S->Func             = &IFFunc;
    S->V.File.F         = F;
    S->V.File.Pos.Line  = 0;
    S->V.File.Pos.Col   = 0;
    S->V.File.Pos.Name  = FileIdx;
    SB_Init (&S->V.File.Line);

    /* Push the path for this file onto the include search lists */
    SB_CopyBuf (&Path, Name, FindName (Name) - Name);
    SB_Terminate (&Path);
    S->V.File.IncSearchPath = PushSearchPath (IncSearchPath, SB_GetConstBuf (&Path));
    S->V.File.BinSearchPath = PushSearchPath (BinSearchPath, SB_GetConstBuf (&Path));
    SB_Done (&Path);

    /* Count active input files */
    ++FCount;

    /* Use this input source */
    UseCharSource (S);

    /* File successfully opened */
    RetCode = 1;

ExitPoint:
    /* Free an allocated name buffer */
    xfree (PathName);

    /* Return the success code */
    return RetCode;
}
Exemplo n.º 27
0
static void NumericConst (void)
/* Parse a numeric constant */
{
    unsigned Base;              /* Temporary number base */
    unsigned Prefix;            /* Base according to prefix */
    StrBuf   S = STATIC_STRBUF_INITIALIZER;
    int      IsFloat;
    char     C;
    unsigned DigitVal;
    unsigned long IVal;         /* Value */

    /* Check for a leading hex or octal prefix and determine the possible
    ** integer types.
    */
    if (CurC == '0') {
        /* Gobble 0 and examine next char */
        NextChar ();
        if (toupper (CurC) == 'X') {
            Base = Prefix = 16;
            NextChar ();        /* gobble "x" */
        } else {
            Base = 10;          /* Assume 10 for now - see below */
            Prefix = 8;         /* Actual prefix says octal */
        }
    } else {
        Base  = Prefix = 10;
    }

    /* Because floating point numbers don't have octal prefixes (a number
    ** with a leading zero is decimal), we first have to read the number
    ** before converting it, so we can determine if it's a float or an
    ** integer.
    */
    while (IsXDigit (CurC) && HexVal (CurC) < Base) {
        SB_AppendChar (&S, CurC);
        NextChar ();
    }
    SB_Terminate (&S);

    /* The following character tells us if we have an integer or floating
    ** point constant. Note: Hexadecimal floating point constants aren't
    ** supported in C89.
    */
    IsFloat = (CurC == '.' ||
               (Base == 10 && toupper (CurC) == 'E') ||
               (Base == 16 && toupper (CurC) == 'P' && IS_Get (&Standard) >= STD_C99));

    /* If we don't have a floating point type, an octal prefix results in an
    ** octal base.
    */
    if (!IsFloat && Prefix == 8) {
        Base = 8;
    }

    /* Since we do now know the correct base, convert the remembered input
    ** into a number.
    */
    SB_Reset (&S);
    IVal = 0;
    while ((C = SB_Get (&S)) != '\0') {
        DigitVal = HexVal (C);
        if (DigitVal >= Base) {
            Error ("Numeric constant contains digits beyond the radix");
        }
        IVal = (IVal * Base) + DigitVal;
    }

    /* We don't need the string buffer any longer */
    SB_Done (&S);

    /* Distinguish between integer and floating point constants */
    if (!IsFloat) {

        unsigned Types;
        int      HaveSuffix;

        /* Check for a suffix and determine the possible types */
        HaveSuffix = 1;
        if (toupper (CurC) == 'U') {
            /* Unsigned type */
            NextChar ();
            if (toupper (CurC) != 'L') {
                Types = IT_UINT | IT_ULONG;
            } else {
                NextChar ();
                Types = IT_ULONG;
            }
        } else if (toupper (CurC) == 'L') {
            /* Long type */
            NextChar ();
            if (toupper (CurC) != 'U') {
                Types = IT_LONG | IT_ULONG;
            } else {
                NextChar ();
                Types = IT_ULONG;
            }
        } else {
            HaveSuffix = 0;
            if (Prefix == 10) {
                /* Decimal constants are of any type but uint */
                Types = IT_INT | IT_LONG | IT_ULONG;
            } else {
                /* Octal or hex constants are of any type */
                Types = IT_INT | IT_UINT | IT_LONG | IT_ULONG;
            }
        }

        /* Check the range to determine the type */
        if (IVal > 0x7FFF) {
            /* Out of range for int */
            Types &= ~IT_INT;
            /* If the value is in the range 0x8000..0xFFFF, unsigned int is not
            ** allowed, and we don't have a type specifying suffix, emit a
            ** warning, because the constant is of type long.
            */
            if (IVal <= 0xFFFF && (Types & IT_UINT) == 0 && !HaveSuffix) {
                Warning ("Constant is long");
            }
        }
        if (IVal > 0xFFFF) {
            /* Out of range for unsigned int */
            Types &= ~IT_UINT;
        }
        if (IVal > 0x7FFFFFFF) {
            /* Out of range for long int */
            Types &= ~IT_LONG;
        }

        /* Now set the type string to the smallest type in types */
        if (Types & IT_INT) {
            NextTok.Type = type_int;
        } else if (Types & IT_UINT) {
            NextTok.Type = type_uint;
        } else if (Types & IT_LONG) {
            NextTok.Type = type_long;
        } else {
            NextTok.Type = type_ulong;
        }

        /* Set the value and the token */
        NextTok.IVal = IVal;
        NextTok.Tok  = TOK_ICONST;

    } else {

        /* Float constant */
        Double FVal = FP_D_FromInt (IVal);      /* Convert to double */

        /* Check for a fractional part and read it */
        if (CurC == '.') {

            Double Scale;

            /* Skip the dot */
            NextChar ();

            /* Read fractional digits */
            Scale  = FP_D_Make (1.0);
            while (IsXDigit (CurC) && (DigitVal = HexVal (CurC)) < Base) {
                /* Get the value of this digit */
                Double FracVal = FP_D_Div (FP_D_FromInt (DigitVal * Base), Scale);
                /* Add it to the float value */
                FVal = FP_D_Add (FVal, FracVal);
                /* Scale base */
                Scale = FP_D_Mul (Scale, FP_D_FromInt (DigitVal));
                /* Skip the digit */
                NextChar ();
            }
        }

        /* Check for an exponent and read it */
        if ((Base == 16 && toupper (CurC) == 'F') ||
            (Base == 10 && toupper (CurC) == 'E')) {

            unsigned Digits;
            unsigned Exp;

            /* Skip the exponent notifier */
            NextChar ();

            /* Read an optional sign */
            if (CurC == '-') {
                NextChar ();
            } else if (CurC == '+') {
                NextChar ();
            }

            /* Read exponent digits. Since we support only 32 bit floats
            ** with a maximum exponent of +-/127, we read the exponent
            ** part as integer with up to 3 digits and drop the remainder.
            ** This avoids an overflow of Exp. The exponent is always
            ** decimal, even for hex float consts.
            */
            Digits = 0;
            Exp    = 0;
            while (IsDigit (CurC)) {
                if (++Digits <= 3) {
                    Exp = Exp * 10 + HexVal (CurC);
                }
                NextChar ();
            }

            /* Check for errors: We must have exponent digits, and not more
            ** than three.
            */
            if (Digits == 0) {
                Error ("Floating constant exponent has no digits");
            } else if (Digits > 3) {
                Warning ("Floating constant exponent is too large");
            }

            /* Scale the exponent and adjust the value accordingly */
            if (Exp) {
                FVal = FP_D_Mul (FVal, FP_D_Make (pow (10, Exp)));
            }
        }

        /* Check for a suffix and determine the type of the constant */
        if (toupper (CurC) == 'F') {
            NextChar ();
            NextTok.Type = type_float;
        } else {
            NextTok.Type = type_double;
        }

        /* Set the value and the token */
        NextTok.FVal = FVal;
        NextTok.Tok  = TOK_FCONST;

    }
}
Exemplo n.º 28
0
static void ReadStringConst (int StringTerm)
/* Read a string constant into SVal. */
{
    /* Skip the leading string terminator */
    NextChar ();

    /* Read the string */
    while (1) {
        if (C == StringTerm) {
            break;
        }
        if (C == '\n' || C == EOF) {
            Error ("Newline in string constant");
            break;
        }

        if (C == '\\' && StringEscapes) {
            NextChar ();

            switch (C) {
                case EOF:
                    Error ("Unterminated escape sequence in string constant");
                    break;
                case '\\':
                case '\'':
                case '"':
                    break;
                case 't':
                    C = '\x09';
                    break;
                case 'r':
                    C = '\x0D';
                    break;
                case 'n':
                    C = '\x0A';
                    break;
                case 'x':
                    NextChar ();
                    if (IsXDigit (C)) {
                        char high_nibble = DigitVal (C) << 4;
                        NextChar ();
                        if (IsXDigit (C)) {
                            C = high_nibble | DigitVal (C);
                            break;
                        }
                    }
                    /* otherwise, fall through */
                default:
                    Error ("Unsupported escape sequence in string constant");
                    break;
            }
        }

        /* Append the char to the string */
        SB_AppendChar (&CurTok.SVal, C);

        /* Skip the character */
        NextChar ();
    }

    /* Skip the trailing terminator */
    NextChar ();

    /* Terminate the string */
    SB_Terminate (&CurTok.SVal);
}
Exemplo n.º 29
0
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);
}
Exemplo n.º 30
0
Arquivo: scanner.c Projeto: cc65/cc65
static void LineMarkerOrComment ()
/* Handle a line beginning with '#'. Possible interpretations are:
** - #line <lineno> ["<filename>"]          (C preprocessor input)
** - # <lineno> "<filename>" [<flag>]...    (gcc preprocessor output)
** - #<comment>
*/
{
    unsigned long LineNo = 0;
    int LineDirective = 0;
    StrBuf SrcNameBuf = AUTO_STRBUF_INITIALIZER;

    /* Skip the first "# " */
    NextChar ();
    SkipBlanks (1);

    /* Check "line" */
    if (C == 'l') {
        char MaybeLine [6];
        unsigned I;
        for (I = 0; I < sizeof MaybeLine - 1 && C != EOF && IsAlNum (C); ++I) {
            MaybeLine [I] = C;
            NextChar ();
        }
        MaybeLine [I] = 0;
        if (strcmp (MaybeLine, "line") != 0) {
            goto NotMarker;
        }
        LineDirective = 1;
        SkipBlanks (1);
    }

    /* Get line number */
    if (C == EOF || !IsDigit (C)) {
        goto NotMarker;
    }
    LineNo = GetDecimalToken ();
    SkipBlanks (1);

    /* Get the source file name */
    if (C != '\"') {
        /* The source file name is missing */
        if (LineDirective && C == '\n') {
            /* got #line <lineno> */
            NextChar ();
            InputLine = LineNo;
            goto Last;
        } else {
            goto NotMarker;
        }
    }
    NextChar ();
    while (C != EOF && C != '\n' && C != '\"') {
        char DecodeBuf [2];
        unsigned I = 0;
        if (GetEncodedChar (DecodeBuf, &I, sizeof DecodeBuf) < 0) {
            goto BadMarker;
        }
        SB_AppendBuf (&SrcNameBuf, DecodeBuf, I);
    }
    if (C != '\"') {
        goto BadMarker;
    }
    NextChar ();

    /* Ignore until the end of line */
    while (C != EOF && C != '\n') {
        NextChar ();
    }

    /* Accepted a line marker */
    SB_Terminate (&SrcNameBuf);
    xfree (InputSrcName);
    InputSrcName = SB_GetBuf (&SrcNameBuf);
    SB_Init (&SrcNameBuf);
    InputLine = (unsigned)LineNo;
    NextChar ();
    goto Last;

BadMarker:
    InfoWarning ("Bad line marker");
NotMarker:
    while (C != EOF && C != '\n') {
        NextChar ();
    }
    NextChar ();
Last:
    SB_Done (&SrcNameBuf);
}