示例#1
0
文件: input.c 项目: eakmeister/cc65
static void GetInputChar (void)
/* Read the next character from the input stream and make CurC and NextC
 * valid. If end of line is reached, both are set to NUL, no more lines
 * are read by this function.
 */
{
    /* Drop all pushed fragments that don't have data left */
    while (SB_GetIndex (Line) >= SB_GetLen (Line)) {
        /* Cannot read more from this line, check next line on stack if any */
        if (CollCount (&InputStack) == 0) {
            /* This is THE line */
            break;
        }
        FreeStrBuf (Line);
        Line = CollPop (&InputStack);
    }

    /* Now get the next characters from the line */
    if (SB_GetIndex (Line) >= SB_GetLen (Line)) {
        CurC = NextC = '\0';
    } else {
        CurC = SB_AtUnchecked (Line, SB_GetIndex (Line));
        if (SB_GetIndex (Line) + 1 < SB_GetLen (Line)) {
            /* NextC comes from this fragment */
            NextC = SB_AtUnchecked (Line, SB_GetIndex (Line) + 1);
        } else {
            /* NextC comes from next fragment */
            if (CollCount (&InputStack) > 0) {
                NextC = ' ';
            } else {
                NextC = '\0';
            }
        }
    }
}
示例#2
0
文件: input.c 项目: eakmeister/cc65
StrBuf* InitLine (StrBuf* Buf)
/* Initialize Line from Buf and read CurC and NextC from the new input line.
 * The function returns the old input line.
 */
{
    StrBuf* OldLine = Line;
    Line  = Buf;
    CurC  = SB_LookAt (Buf, SB_GetIndex (Buf));
    NextC = SB_LookAt (Buf, SB_GetIndex (Buf) + 1);
    return OldLine;
}
示例#3
0
static int HasStr (StrBuf* B, const char* E)
/* Checks if E follows in B. If so, skips it and returns true */
{
    unsigned Len = strlen (E);
    if (SB_GetLen (B) - SB_GetIndex (B) >= Len) {
        if (strncmp (SB_GetConstBuf (B) + SB_GetIndex (B), E, Len) == 0) {
            /* Found */
            SB_SkipMultiple (B, Len);
            return 1;
        }
    }
    return 0;
}
示例#4
0
static void DoWarning (void)
/* Print a warning */
{
    SkipWhitespace (0);
    if (CurC == '\0') {
        PPError ("Invalid #warning directive");
    } else {
        PPWarning ("#warning: %s", SB_GetConstBuf (Line) + SB_GetIndex (Line));
    }

    /* Clear the rest of line */
    ClearLine ();
}
示例#5
0
static void DoError (void)
/* Print an error */
{
    SkipWhitespace (0);
    if (CurC == '\0') {
        PPError ("Invalid #error directive");
    } else {
        PPError ("#error: %s", SB_GetConstBuf (Line) + SB_GetIndex (Line));
    }

    /* Clear the rest of line */
    ClearLine ();
}
示例#6
0
static PushPopResult ParsePushPop (StrBuf* B)
/* Check for and parse the "push" and "pop" keywords. In case of "push", a
 * following comma is expected and skipped.
 */
{
    StrBuf Ident      = AUTO_STRBUF_INITIALIZER;
    PushPopResult Res = PP_NONE;

    /* Remember the current string index, so we can go back in case of errors */
    unsigned Index = SB_GetIndex (B);

    /* Try to read an identifier */
    if (SB_GetSym (B, &Ident, 0)) {

        /* Check if we have a first argument named "pop" */
        if (SB_CompareStr (&Ident, "pop") == 0) {

            Res = PP_POP;

        /* Check if we have a first argument named "push" */
        } else if (SB_CompareStr (&Ident, "push") == 0) {

            Res = PP_PUSH;

            /* Skip the following comma */
            if (!GetComma (B)) {
                /* Error already flagged by GetComma */
                Res = PP_ERROR;
            }

        } else {

            /* Unknown keyword, roll back */
            SB_SetIndex (B, Index);
        }
    }

    /* Free the string buffer and return the result */
    SB_Done (&Ident);
    return Res;
}
示例#7
0
static void MacroArgSubst (MacroExp* E)
/* Argument substitution according to ISO/IEC 9899:1999 (E), 6.10.3.1ff */
{
    ident       Ident;
    int         ArgIdx;
    StrBuf*     OldSource;
    StrBuf*     Arg;
    int         HaveSpace;


    /* Remember the current input and switch to the macro replacement. */
    int OldIndex = SB_GetIndex (&E->M->Replacement);
    SB_Reset (&E->M->Replacement);
    OldSource = InitLine (&E->M->Replacement);

    /* Argument handling loop */
    while (CurC != '\0') {

        /* If we have an identifier, check if it's a macro */
        if (IsSym (Ident)) {

            /* Check if it's a macro argument */
            if ((ArgIdx = FindMacroArg (E->M, Ident)) >= 0) {

                /* A macro argument. Get the corresponding actual argument. */
                Arg = ME_GetActual (E, ArgIdx);

                /* Copy any following whitespace */
                HaveSpace = SkipWhitespace (0);

                /* If a ## operator follows, we have to insert the actual
                 * argument as is, otherwise it must be macro replaced.
                 */
                if (CurC == '#' && NextC == '#') {

                    /* ### Add placemarker if necessary */
                    SB_Append (&E->Replacement, Arg);

                } else {

                    /* Replace the formal argument by a macro replaced copy
                     * of the actual.
                     */
                    SB_Reset (Arg);
                    MacroReplacement (Arg, &E->Replacement);

                    /* If we skipped whitespace before, re-add it now */
                    if (HaveSpace) {
                        SB_AppendChar (&E->Replacement, ' ');
                    }
                }


            } else {

                /* An identifier, keep it */
                SB_AppendStr (&E->Replacement, Ident);

            }

        } else if (CurC == '#' && NextC == '#') {

            /* ## operator. */
            NextChar ();
            NextChar ();
            SkipWhitespace (0);

            /* Since we need to concatenate the token sequences, remove
             * any whitespace that was added to target, since it must come
             * from the input.
             */
            while (IsSpace (SB_LookAtLast (&E->Replacement))) {
                SB_Drop (&E->Replacement, 1);
            }

            /* If the next token is an identifier which is a macro argument,
             * replace it, otherwise do nothing.
             */
            if (IsSym (Ident)) {

                /* Check if it's a macro argument */
                if ((ArgIdx = FindMacroArg (E->M, Ident)) >= 0) {

                    /* Get the corresponding actual argument and add it. */
                    SB_Append (&E->Replacement, ME_GetActual (E, ArgIdx));

                } else {

                    /* Just an ordinary identifier - add as is */
                    SB_AppendStr (&E->Replacement, Ident);

                }
            }

        } else if (CurC == '#' && E->M->ArgCount >= 0) {

            /* A # operator within a macro expansion of a function like
             * macro. Read the following identifier and check if it's a
             * macro parameter.
             */
            NextChar ();
            SkipWhitespace (0);
            if (!IsSym (Ident) || (ArgIdx = FindMacroArg (E->M, Ident)) < 0) {
                PPError ("`#' is not followed by a macro parameter");
            } else {
                /* Make a valid string from Replacement */
                Arg = ME_GetActual (E, ArgIdx);
                SB_Reset (Arg);
                Stringize (Arg, &E->Replacement);
            }

        } else if (IsQuote (CurC)) {
            CopyQuotedString (&E->Replacement);
        } else {
            SB_AppendChar (&E->Replacement, CurC);
            NextChar ();
        }
    }

#if 0
    /* Remove whitespace from the end of the line */
    while (IsSpace (SB_LookAtLast (&E->Replacement))) {
        SB_Drop (&E->Replacement, 1);
    }
#endif

    /* Switch back the input */
    InitLine (OldSource);
    SB_SetIndex (&E->M->Replacement, OldIndex);
}
示例#8
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);
}
示例#9
0
文件: scanner.c 项目: pfusik/cc65
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);
}
示例#10
0
int SB_GetNumber (StrBuf* B, long* Val)
/* Get a number from the string buffer. Accepted formats are decimal, octal,
** hex and character constants. Numeric constants may be preceeded by a
** minus or plus sign. The function returns 1 if a number was found and
** zero otherwise. Errors are only output for invalid numbers.
*/
{
    int      Sign;
    char     C;
    unsigned Base;
    unsigned DigitVal;


    /* Initialize Val */
    *Val = 0;

    /* Handle character constants */
    if (SB_Peek (B) == '\'') {

        /* Character constant */
        SB_Skip (B);
        *Val = SignExtendChar (TgtTranslateChar (ParseChar (B)));
        if (SB_Peek (B) != '\'') {
            Error ("`\'' expected");
            return 0;
        } else {
            /* Skip the quote */
            SB_Skip (B);
            return 1;
        }
    }

    /* Check for a sign. A sign must be followed by a digit, otherwise it's
    ** not a number
    */
    Sign = 1;
    switch (SB_Peek (B)) {
        case '-':
            Sign = -1;
            /* FALLTHROUGH */
        case '+':
            if (!IsDigit (SB_LookAt (B, SB_GetIndex (B) + 1))) {
                return 0;
            }
            SB_Skip (B);
            break;
    }

    /* We must have a digit now, otherwise its not a number */
    C = SB_Peek (B);
    if (!IsDigit (C)) {
        return 0;
    }

    /* Determine the base */
    if (C == '0') {
        /* Hex or octal */
        SB_Skip (B);
        if (tolower (SB_Peek (B)) == 'x') {
            SB_Skip (B);
            Base = 16;
            if (!IsXDigit (SB_Peek (B))) {
                Error ("Invalid hexadecimal number");
                return 0;
            }
        } else {
            Base = 8;
        }
    } else {
        Base = 10;
    }

    /* Read the number */
    while (IsXDigit (C = SB_Peek (B)) && (DigitVal = HexVal (C)) < Base) {
        *Val = (*Val * Base) + DigitVal;
        SB_Skip (B);
    }

    /* Allow optional 'U' and 'L' modifiers */
    C = SB_Peek (B);
    if (C == 'u' || C == 'U') {
        SB_Skip (B);
        C = SB_Peek (B);
        if (C == 'l' || C == 'L') {
            SB_Skip (B);
        }
    } else if (C == 'l' || C == 'L') {
        SB_Skip (B);
        C = SB_Peek (B);
        if (C == 'u' || C == 'U') {
            SB_Skip (B);
        }
    }

    /* Success, value read is in Val */
    *Val *= Sign;
    return 1;
}