Пример #1
0
static void CheckSymTable (SymTable* Tab)
/* Check a symbol table for open references, unused symbols ... */
{
    SymEntry* Entry = Tab->SymHead;
    while (Entry) {

        /* Get the storage flags for tne entry */
        unsigned Flags = Entry->Flags;

        /* Ignore typedef entries */
        if (!SymIsTypeDef (Entry)) {

            /* Check if the symbol is one with storage, and it if it was
            ** defined but not used.
            */
            if (((Flags & SC_AUTO) || (Flags & SC_STATIC)) && (Flags & SC_EXTERN) == 0) {
                if (SymIsDef (Entry) && !SymIsRef (Entry) &&
                    !SymHasAttr (Entry, atUnused)) {
                    if (Flags & SC_PARAM) {
                        if (IS_Get (&WarnUnusedParam)) {
                            Warning ("Parameter `%s' is never used", Entry->Name);
                        }
                    } else {
                        if (IS_Get (&WarnUnusedVar)) {
                            Warning ("`%s' is defined but never used", Entry->Name);
                        }
                    }
                }
            }

            /* If the entry is a label, check if it was defined in the function */
            if (Flags & SC_LABEL) {
                if (!SymIsDef (Entry)) {
                    /* Undefined label */
                    Error ("Undefined label: `%s'", Entry->Name);
                } else if (!SymIsRef (Entry)) {
                    /* Defined but not used */
                    if (IS_Get (&WarnUnusedLabel)) {
                        Warning ("`%s' is defined but never used", Entry->Name);
                    }
                }
            }

        }

        /* Next entry */
        Entry = Entry->NextSym;
    }
}
Пример #2
0
int F_AllocRegVar (Function* F, const Type* Type)
/* Allocate a register variable for the given variable type. If the allocation
 * was successful, return the offset of the register variable in the register
 * bank (zero page storage). If there is no register space left, return -1.
 */
{
    /* Allow register variables only on top level and if enabled */
    if (IS_Get (&EnableRegVars) && GetLexicalLevel () == LEX_LEVEL_FUNCTION) {

        /* Get the size of the variable */
        unsigned Size = CheckedSizeOf (Type);

        /* Do we have space left? */
        if (F->RegOffs >= Size) {
            /* Space left. We allocate the variables from high to low addresses,
             * so the adressing is compatible with the saved values on stack.
             * This allows shorter code when saving/restoring the variables.
             */
            F->RegOffs -= Size;
            return F->RegOffs;
        }
    }

    /* No space left or no allocation */
    return -1;
}
Пример #3
0
int SignExtendChar (int C)
/* Do correct sign extension of a character */
{
    if (IS_Get (&SignedChars) && (C & 0x80) != 0) {
        return C | ~0xFF;
    } else {
        return C & 0xFF;
    }
}
Пример #4
0
Literal* UseLiteral (Literal* L)
/* Increase the reference counter for the literal and return it */
{
    /* Increase the reference count */
    ++L->RefCount;

    /* If --local-strings was given, immediately output the literal */
    if (IS_Get (&LocalStrings)) {
        /* Switch to the proper data segment */
        if (IS_Get (&WritableStrings)) {
            g_usedata ();
        } else {
            g_userodata ();
        }
        /* Output the literal */
        OutputLiteral (L);
    }

    /* Return the literal */
    return L;
}
Пример #5
0
static token_t FindKey (const char* Key)
/* Find a keyword and return the token. Return IDENT if the token is not a
** keyword.
*/
{
    struct Keyword* K;
    K = bsearch (Key, Keywords, KEY_COUNT, sizeof (Keywords [0]), CmpKey);
    if (K && (K->Std & (0x01 << IS_Get (&Standard))) != 0) {
        return K->Tok;
    } else {
        return TOK_IDENT;
    }
}
Пример #6
0
CodeSeg* NewCodeSeg (const char* SegName, SymEntry* Func)
/* Create a new code segment, initialize and return it */
{
    unsigned I;
    const Type* RetType;

    /* Allocate memory */
    CodeSeg* S = xmalloc (sizeof (CodeSeg));

    /* Initialize the fields */
    S->SegName  = xstrdup (SegName);
    S->Func	= Func;
    InitCollection (&S->Entries);
    InitCollection (&S->Labels);
    for (I = 0; I < sizeof(S->LabelHash) / sizeof(S->LabelHash[0]); ++I) {
	S->LabelHash[I] = 0;
    }

    /* If we have a function given, get the return type of the function.
     * Assume ANY return type besides void will use the A and X registers.
     */
    if (S->Func && !IsTypeVoid ((RetType = GetFuncReturn (Func->Type)))) {
	if (SizeOf (RetType) == SizeOf (type_long)) {
	    S->ExitRegs = REG_EAX;
	} else {
	    S->ExitRegs = REG_AX;
	}
    } else {
	S->ExitRegs = REG_NONE;
    }

    /* Copy the global optimization settings */
    S->Optimize       = (unsigned char) IS_Get (&Optimize);
    S->CodeSizeFactor = (unsigned) IS_Get (&CodeSizeFactor);

    /* Return the new struct */
    return S;
}
Пример #7
0
static void IntWarning (const char* Filename, unsigned LineNo, const char* Msg, va_list ap)
/* Print warning message - internal function. */
{
    if (!IS_Get (&WarnDisable)) {
       	fprintf (stderr, "%s(%u): Warning: ", Filename, LineNo);
     	vfprintf (stderr, Msg, ap);
     	fprintf (stderr, "\n");

        if (Line) {
     	    Print (stderr, 1, "Input: %.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line));
        }
     	++WarningCount;
    }
}
Пример #8
0
static void CharMapPragma (StrBuf* B)
/* Change the character map */
{
    long Index, C;

    /* Read the character index */
    if (!GetNumber (B, &Index)) {
        return;
    }
    if (Index < 0 || Index > 255) {
        Error ("Character index out of range");
        return;
    }

    /* Comma follows */
    if (!GetComma (B)) {
        return;
    }

    /* Read the character code */
    if (!GetNumber (B, &C)) {
        return;
    }
    if (C < 0 || C > 255) {
        Error ("Character code out of range");
        return;
    }

    /* Warn about remapping character code 0x00
    ** (except when remapping it back to itself).
    */
    if (Index + C != 0 && IS_Get (&WarnRemapZero)) {
        if (Index == 0) {
            Warning ("Remapping from 0 is dangerous with string functions");
        }
        else if (C == 0) {
            Warning ("Remapping to 0 can make string functions stop unexpectedly");
        }
    }

    /* Remap the character */
    TgtTranslateSet ((unsigned) Index, (unsigned char) C);
}
Пример #9
0
static void LoadConstant (unsigned Flags, ExprDesc* Expr)
/* Load the primary register with some constant value. */
{
    switch (ED_GetLoc (Expr)) {

        case E_LOC_ABS:
            /* Number constant */
            g_getimmed (Flags | TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0);
            break;

        case E_LOC_GLOBAL:
            /* Global symbol, load address */
            g_getimmed ((Flags | CF_EXTERNAL) & ~CF_CONST, Expr->Name, Expr->IVal);
            break;

        case E_LOC_STATIC:
        case E_LOC_LITERAL:
            /* Static symbol or literal, load address */
            g_getimmed ((Flags | CF_STATIC) & ~CF_CONST, Expr->Name, Expr->IVal);
            break;

        case E_LOC_REGISTER:
            /* Register variable. Taking the address is usually not
             * allowed.
             */
            if (IS_Get (&AllowRegVarAddr) == 0) {
                Error ("Cannot take the address of a register variable");
            }
            g_getimmed ((Flags | CF_REGVAR) & ~CF_CONST, Expr->Name, Expr->IVal);
            break;

        case E_LOC_STACK:
            g_leasp (Expr->IVal);
            break;

        default:
            Internal ("Unknown constant type: %04X", Expr->Flags);
    }
}
Пример #10
0
void DumpLiteralPool (void)
/* Dump the literal pool */
{
    /* If nothing there, exit... */
    if (SB_GetLen (&LiteralPool) == 0) {
        return;
    }

    /* Switch to the data segment */
    if (IS_Get (&WritableStrings)) {
        g_usedata ();
    } else {
        g_userodata ();
    }

    /* Define the label */
    g_defdatalabel (LiteralPoolLabel);

    /* Translate the buffer contents into the target charset */
    TranslateLiteralPool (0);

    /* Output the buffer data */
    g_defbytes (SB_GetConstBuf (&LiteralPool), SB_GetLen (&LiteralPool));
}
Пример #11
0
void NewFunc (SymEntry* Func)
/* Parse argument declarations and function body. */
{
    int         C99MainFunc = 0;/* Flag for C99 main function returning int */
    SymEntry*   Param;

    /* Get the function descriptor from the function entry */
    FuncDesc* D = Func->V.F.Func;

    /* Allocate the function activation record for the function */
    CurrentFunc = NewFunction (Func);

    /* Reenter the lexical level */
    ReenterFunctionLevel (D);

    /* Check if the function header contains unnamed parameters. These are
     * only allowed in cc65 mode.
     */
    if ((D->Flags & FD_UNNAMED_PARAMS) != 0 && (IS_Get (&Standard) != STD_CC65)) {
        Error ("Parameter name omitted");
    }

    /* Declare two special functions symbols: __fixargs__ and __argsize__.
     * The latter is different depending on the type of the function (variadic
     * or not).
     */
    AddConstSym ("__fixargs__", type_uint, SC_DEF | SC_CONST, D->ParamSize);
    if (D->Flags & FD_VARIADIC) {
        /* Variadic function. The variable must be const. */
        static const Type T[] = { TYPE(T_UCHAR | T_QUAL_CONST), TYPE(T_END) };
        AddLocalSym ("__argsize__", T, SC_DEF | SC_REF | SC_AUTO, 0);
    } else {
        /* Non variadic */
        AddConstSym ("__argsize__", type_uchar, SC_DEF | SC_CONST, D->ParamSize);
    }

    /* Function body now defined */
    Func->Flags |= SC_DEF;

    /* Special handling for main() */
    if (strcmp (Func->Name, "main") == 0) {

        /* Mark this as the main function */
        CurrentFunc->Flags |= FF_IS_MAIN;

        /* Main cannot be a fastcall function */
        if (IsQualFastcall (Func->Type)) {
            Error ("`main' cannot be declared as __fastcall__");
        }

        /* If cc65 extensions aren't enabled, don't allow a main function that
         * doesn't return an int.
         */
        if (IS_Get (&Standard) != STD_CC65 && CurrentFunc->ReturnType[0].C != T_INT) {
            Error ("`main' must always return an int");
        }

        /* Add a forced import of a symbol that is contained in the startup
         * code. This will force the startup code to be linked in.
         */
        g_importstartup ();

        /* If main() takes parameters, generate a forced import to a function
         * that will setup these parameters. This way, programs that do not
         * need the additional code will not get it.
         */
        if (D->ParamCount > 0 || (D->Flags & FD_VARIADIC) != 0) {
            g_importmainargs ();
        }

        /* Determine if this is a main function in a C99 environment that
         * returns an int.
         */
        if (IsTypeInt (F_GetReturnType (CurrentFunc)) &&
            IS_Get (&Standard) == STD_C99) {
            C99MainFunc = 1;
        }
    }

    /* Allocate code and data segments for this function */
    Func->V.F.Seg = PushSegments (Func);

    /* Allocate a new literal pool */
    PushLiteralPool (Func);

    /* If this is a fastcall function, push the last parameter onto the stack */
    if (IsQualFastcall (Func->Type) && D->ParamCount > 0) {

        unsigned Flags;

        /* Fastcall functions may never have an ellipsis or the compiler is buggy */
        CHECK ((D->Flags & FD_VARIADIC) == 0);

        /* Generate the push */
        if (IsTypeFunc (D->LastParam->Type)) {
            /* Pointer to function */
            Flags = CF_PTR;
        } else {
            Flags = TypeOf (D->LastParam->Type) | CF_FORCECHAR;
        }
        g_push (Flags, 0);
    }

    /* Generate function entry code if needed */
    g_enter (TypeOf (Func->Type), F_GetParamSize (CurrentFunc));

    /* If stack checking code is requested, emit a call to the helper routine */
    if (IS_Get (&CheckStack)) {
        g_stackcheck ();
    }

    /* Setup the stack */
    StackPtr = 0;

    /* Walk through the parameter list and allocate register variable space
     * for parameters declared as register. Generate code to swap the contents
     * of the register bank with the save area on the stack.
     */
    Param = D->SymTab->SymHead;
    while (Param && (Param->Flags & SC_PARAM) != 0) {

        /* Check for a register variable */
        if (SymIsRegVar (Param)) {

            /* Allocate space */
            int Reg = F_AllocRegVar (CurrentFunc, Param->Type);

            /* Could we allocate a register? */
            if (Reg < 0) {
                /* No register available: Convert parameter to auto */
                CvtRegVarToAuto (Param);
            } else {
                /* Remember the register offset */
                Param->V.R.RegOffs = Reg;

                /* Generate swap code */
                g_swap_regvars (Param->V.R.SaveOffs, Reg, CheckedSizeOf (Param->Type));
            }
        }

        /* Next parameter */
        Param = Param->NextSym;
    }

    /* Need a starting curly brace */
    ConsumeLCurly ();

    /* Parse local variable declarations if any */
    DeclareLocals ();

    /* Remember the current stack pointer. All variables allocated elsewhere
     * must be dropped when doing a return from an inner block.
     */
    CurrentFunc->TopLevelSP = StackPtr;

    /* Now process statements in this block */
    while (CurTok.Tok != TOK_RCURLY && CurTok.Tok != TOK_CEOF) {
        Statement (0);
    }

    /* If this is not a void function, and not the main function in a C99
     * environment returning int, output a warning if we didn't see a return
     * statement.
     */
    if (!F_HasVoidReturn (CurrentFunc) && !F_HasReturn (CurrentFunc) && !C99MainFunc) {
        Warning ("Control reaches end of non-void function");
    }

    /* If this is the main function in a C99 environment returning an int, let
     * it always return zero. Note: Actual return statements jump to the return
     * label defined below.
     * The code is removed by the optimizer if unused.
     */
    if (C99MainFunc) {
        g_getimmed (CF_INT | CF_CONST, 0, 0);
    }

    /* Output the function exit code label */
    g_defcodelabel (F_GetRetLab (CurrentFunc));

    /* Restore the register variables */
    F_RestoreRegVars (CurrentFunc);

    /* Generate the exit code */
    g_leave ();

    /* Emit references to imports/exports */
    EmitExternals ();

    /* Emit function debug info */
    F_EmitDebugInfo ();
    EmitDebugInfo ();

    /* Leave the lexical level */
    LeaveFunctionLevel ();

    /* Eat the closing brace */
    ConsumeRCurly ();

    /* Restore the old literal pool, remembering the one for the function */
    Func->V.F.LitPool = PopLiteralPool ();

    /* Switch back to the old segments */
    PopSegments ();

    /* Reset the current function pointer */
    FreeFunction (CurrentFunc);
    CurrentFunc = 0;
}
Пример #12
0
static void ParsePragma (void)
/* Parse the contents of the _Pragma statement */
{
    pragma_t Pragma;
    StrBuf   Ident = AUTO_STRBUF_INITIALIZER;

    /* Create a string buffer from the string literal */
    StrBuf B = AUTO_STRBUF_INITIALIZER;
    SB_Append (&B, GetLiteralStrBuf (CurTok.SVal));

    /* Skip the string token */
    NextToken ();

    /* Get the pragma name from the string */
    SB_SkipWhite (&B);
    if (!SB_GetSym (&B, &Ident, "-")) {
        Error ("Invalid pragma");
        goto ExitPoint;
    }

    /* Search for the name */
    Pragma = FindPragma (&Ident);

    /* Do we know this pragma? */
    if (Pragma == PRAGMA_ILLEGAL) {
        /* According to the ANSI standard, we're not allowed to generate errors
         * for unknown pragmas, but warn about them if enabled (the default).
         */
        if (IS_Get (&WarnUnknownPragma)) {
            Warning ("Unknown pragma `%s'", SB_GetConstBuf (&Ident));
        }
        goto ExitPoint;
    }

    /* Check for an open paren */
    SB_SkipWhite (&B);
    if (SB_Get (&B) != '(') {
        Error ("'(' expected");
        goto ExitPoint;
    }

    /* Skip white space before the argument */
    SB_SkipWhite (&B);

    /* Switch for the different pragmas */
    switch (Pragma) {

        case PRAGMA_ALIGN:
            IntPragma (&B, &DataAlignment, 1, 4096);
            break;

        case PRAGMA_BSSSEG:
            Warning ("#pragma bssseg is obsolete, please use #pragma bss-name instead");
            /* FALLTHROUGH */
        case PRAGMA_BSS_NAME:
            SegNamePragma (&B, SEG_BSS);
            break;

        case PRAGMA_CHARMAP:
            CharMapPragma (&B);
            break;

        case PRAGMA_CHECKSTACK:
            Warning ("#pragma checkstack is obsolete, please use #pragma check-stack instead");
            /* FALLTHROUGH */
        case PRAGMA_CHECK_STACK:
            FlagPragma (&B, &CheckStack);
            break;

        case PRAGMA_CODESEG:
            Warning ("#pragma codeseg is obsolete, please use #pragma code-name instead");
            /* FALLTHROUGH */
        case PRAGMA_CODE_NAME:
            SegNamePragma (&B, SEG_CODE);
            break;

        case PRAGMA_CODESIZE:
            IntPragma (&B, &CodeSizeFactor, 10, 1000);
            break;

        case PRAGMA_DATASEG:
            Warning ("#pragma dataseg is obsolete, please use #pragma data-name instead");
            /* FALLTHROUGH */
        case PRAGMA_DATA_NAME:
            SegNamePragma (&B, SEG_DATA);
            break;

        case PRAGMA_LOCAL_STRINGS:
            FlagPragma (&B, &LocalStrings);
            break;

        case PRAGMA_OPTIMIZE:
            FlagPragma (&B, &Optimize);
            break;

        case PRAGMA_REGVARADDR:
            FlagPragma (&B, &AllowRegVarAddr);
            break;

        case PRAGMA_REGVARS:
            Warning ("#pragma regvars is obsolete, please use #pragma register-vars instead");
            /* FALLTHROUGH */
        case PRAGMA_REGISTER_VARS:
            FlagPragma (&B, &EnableRegVars);
            break;

        case PRAGMA_RODATASEG:
            Warning ("#pragma rodataseg is obsolete, please use #pragma rodata-name instead");
            /* FALLTHROUGH */
        case PRAGMA_RODATA_NAME:
            SegNamePragma (&B, SEG_RODATA);
            break;

        case PRAGMA_SIGNEDCHARS:
            Warning ("#pragma signedchars is obsolete, please use #pragma signed-chars instead");
            /* FALLTHROUGH */
        case PRAGMA_SIGNED_CHARS:
            FlagPragma (&B, &SignedChars);
            break;

        case PRAGMA_STATICLOCALS:
            Warning ("#pragma staticlocals is obsolete, please use #pragma static-locals instead");
            /* FALLTHROUGH */
        case PRAGMA_STATIC_LOCALS:
            FlagPragma (&B, &StaticLocals);
            break;

        case PRAGMA_WARN:
            WarnPragma (&B);
            break;

        case PRAGMA_WRITABLE_STRINGS:
            FlagPragma (&B, &WritableStrings);
            break;

        case PRAGMA_ZPSYM:
            StringPragma (&B, MakeZPSym);
            break;

        default:
            Internal ("Invalid pragma");
    }

    /* Closing paren expected */
    SB_SkipWhite (&B);
    if (SB_Get (&B) != ')') {
        Error ("')' expected");
        goto ExitPoint;
    }
    SB_SkipWhite (&B);

    /* Allow an optional semicolon to be compatible with the old syntax */
    if (SB_Peek (&B) == ';') {
        SB_Skip (&B);
        SB_SkipWhite (&B);
    }

    /* Make sure nothing follows */
    if (SB_Peek (&B) != '\0') {
        Error ("Unexpected input following pragma directive");
    }

ExitPoint:
    /* Release the string buffers */
    SB_Done (&B);
    SB_Done (&Ident);
}
Пример #13
0
int Statement (int* PendingToken)
/* Statement parser. Returns 1 if the statement does a return/break, returns
** 0 otherwise. If the PendingToken pointer is not NULL, the function will
** not skip the terminating token of the statement (closing brace or
** semicolon), but store true if there is a pending token, and false if there
** is none. The token is always checked, so there is no need for the caller to
** check this token, it must be skipped, however. If the argument pointer is
** NULL, the function will skip the token.
*/
{
    ExprDesc Expr;
    int GotBreak;
    CodeMark Start, End;

    /* Assume no pending token */
    if (PendingToken) {
        *PendingToken = 0;
    }

    /* Check for a label. A label is always part of a statement, it does not
    ** replace one.
    */
    while (CurTok.Tok == TOK_IDENT && NextTok.Tok == TOK_COLON) {
        /* Handle the label */
        DoLabel ();
        if (CheckLabelWithoutStatement ()) {
            return 0;
        }
    }

    switch (CurTok.Tok) {

        case TOK_LCURLY:
            NextToken ();
            GotBreak = CompoundStatement ();
            CheckTok (TOK_RCURLY, "`{' expected", PendingToken);
            return GotBreak;

        case TOK_IF:
            return IfStatement ();

        case TOK_WHILE:
            WhileStatement ();
            break;

        case TOK_DO:
            DoStatement ();
            break;

        case TOK_SWITCH:
            SwitchStatement ();
            break;

        case TOK_RETURN:
            ReturnStatement ();
            CheckSemi (PendingToken);
            return 1;

        case TOK_BREAK:
            BreakStatement ();
            CheckSemi (PendingToken);
            return 1;

        case TOK_CONTINUE:
            ContinueStatement ();
            CheckSemi (PendingToken);
            return 1;

        case TOK_FOR:
            ForStatement ();
            break;

        case TOK_GOTO:
            GotoStatement ();
            CheckSemi (PendingToken);
            return 1;

        case TOK_SEMI:
            /* Ignore it */
            CheckSemi (PendingToken);
            break;

        case TOK_PRAGMA:
            DoPragma ();
            break;

        case TOK_CASE:
            CaseLabel ();
            CheckLabelWithoutStatement ();
            break;

        case TOK_DEFAULT:
            DefaultLabel ();
            CheckLabelWithoutStatement ();
            break;

        default:
            /* Remember the current code position */
            GetCodePos (&Start);
            /* Actual statement */
            ExprWithCheck (hie0, &Expr);
            /* Load the result only if it is an lvalue and the type is
            ** marked as volatile. Otherwise the load is useless.
            */
            if (ED_IsLVal (&Expr) && IsQualVolatile (Expr.Type)) {
                LoadExpr (CF_NONE, &Expr);
            }
            /* If the statement didn't generate code, and is not of type
            ** void, emit a warning.
            */
            GetCodePos (&End);
            if (CodeRangeIsEmpty (&Start, &End) &&
                !IsTypeVoid (Expr.Type)         &&
                IS_Get (&WarnNoEffect)) {
                Warning ("Statement has no effect");
            }
            CheckSemi (PendingToken);
    }
    return 0;
}
Пример #14
0
TypeCode GetDefaultChar (void)
/* Return the default char type (signed/unsigned) depending on the settings */
{
    return IS_Get (&SignedChars)? T_SCHAR : T_UCHAR;
}
Пример #15
0
static unsigned Pass1 (StrBuf* Source, StrBuf* Target)
/* Preprocessor pass 1. Remove whitespace. Handle old and new style comments
 * and the "defined" operator.
 */
{
    unsigned    IdentCount;
    ident       Ident;
    int         HaveParen;

    /* Switch to the new input source */
    StrBuf* OldSource = InitLine (Source);

    /* Loop removing ws and comments */
    IdentCount = 0;
    while (CurC != '\0') {
        if (SkipWhitespace (0)) {
            /* Squeeze runs of blanks */
            if (!IsSpace (SB_LookAtLast (Target))) {
                SB_AppendChar (Target, ' ');
            }
        } else if (IsSym (Ident)) {
            if (Preprocessing && strcmp (Ident, "defined") == 0) {
                /* Handle the "defined" operator */
                SkipWhitespace (0);
                HaveParen = 0;
                if (CurC == '(') {
                    HaveParen = 1;
                    NextChar ();
                    SkipWhitespace (0);
                }
                if (IsSym (Ident)) {
                    SB_AppendChar (Target, IsMacro (Ident)? '1' : '0');
                    if (HaveParen) {
                        SkipWhitespace (0);
                        if (CurC != ')') {
                            PPError ("`)' expected");
                        } else {
                            NextChar ();
                        }
                    }
                } else {
                    PPError ("Identifier expected");
                    SB_AppendChar (Target, '0');
                }
            } else {
                ++IdentCount;
                SB_AppendStr (Target, Ident);
            }
        } else if (IsQuote (CurC)) {
            CopyQuotedString (Target);
        } else if (CurC == '/' && NextC == '*') {
            if (!IsSpace (SB_LookAtLast (Target))) {
                SB_AppendChar (Target, ' ');
            }
            OldStyleComment ();
        } else if (IS_Get (&Standard) >= STD_C99 && CurC == '/' && NextC == '/') {
            if (!IsSpace (SB_LookAtLast (Target))) {
                SB_AppendChar (Target, ' ');
            }
            NewStyleComment ();
        } else {
            SB_AppendChar (Target, CurC);
            NextChar ();
        }
    }

    /* Switch back to the old source */
    InitLine (OldSource);

    /* Return the number of identifiers found in the line */
    return IdentCount;
}
Пример #16
0
static void DefineMacro (void)
/* Handle a macro definition. */
{
    ident       Ident;
    Macro*      M;
    Macro*      Existing;
    int         C89;

    /* Read the macro name */
    SkipWhitespace (0);
    if (!MacName (Ident)) {
        return;
    }

    /* Remember if we're in C89 mode */
    C89 = (IS_Get (&Standard) == STD_C89);

    /* Get an existing macro definition with this name */
    Existing = FindMacro (Ident);

    /* Create a new macro definition */
    M = NewMacro (Ident);

    /* Check if this is a function like macro */
    if (CurC == '(') {

        /* Skip the left paren */
        NextChar ();

        /* Set the marker that this is a function like macro */
        M->ArgCount = 0;

        /* Read the formal parameter list */
        while (1) {

            /* Skip white space and check for end of parameter list */
            SkipWhitespace (0);
            if (CurC == ')') {
                break;
            }

            /* The next token must be either an identifier, or - if not in
             * C89 mode - the ellipsis.
             */
            if (!C89 && CurC == '.') {
                /* Ellipsis */
                NextChar ();
                if (CurC != '.' || NextC != '.') {
                    PPError ("`...' expected");
                    ClearLine ();
                    return;
                }
                NextChar ();
                NextChar ();

                /* Remember that the macro is variadic and use __VA_ARGS__ as
                 * the argument name.
                 */
                AddMacroArg (M, "__VA_ARGS__");
                M->Variadic = 1;

            } else {
                /* Must be macro argument name */
                if (MacName (Ident) == 0) {
                    return;
                }

                /* __VA_ARGS__ is only allowed in C89 mode */
                if (!C89 && strcmp (Ident, "__VA_ARGS__") == 0) {
                    PPWarning ("`__VA_ARGS__' can only appear in the expansion "
                               "of a C99 variadic macro");
                }

                /* Add the macro argument */
                AddMacroArg (M, Ident);
            }

            /* If we had an ellipsis, or the next char is not a comma, we've
             * reached the end of the macro argument list.
             */
            SkipWhitespace (0);
            if (M->Variadic || CurC != ',') {
                break;
            }
            NextChar ();
        }

        /* Check for a right paren and eat it if we find one */
        if (CurC != ')') {
            PPError ("`)' expected");
            ClearLine ();
            return;
        }
        NextChar ();
    }

    /* Skip whitespace before the macro replacement */
    SkipWhitespace (0);

    /* Insert the macro into the macro table and allocate the ActualArgs array */
    InsertMacro (M);

    /* Remove whitespace and comments from the line, store the preprocessed
     * line into the macro replacement buffer.
     */
    Pass1 (Line, &M->Replacement);

    /* Remove whitespace from the end of the line */
    while (IsSpace (SB_LookAtLast (&M->Replacement))) {
        SB_Drop (&M->Replacement, 1);
    }
#if 0
    printf ("%s: <%.*s>\n", M->Name, SB_GetLen (&M->Replacement), SB_GetConstBuf (&M->Replacement));
#endif

    /* If we have an existing macro, check if the redefinition is identical.
     * Print a diagnostic if not.
     */
    if (Existing && MacroCmp (M, Existing) != 0) {
        PPError ("Macro redefinition is not identical");
    }
}
Пример #17
0
static void ReadMacroArgs (MacroExp* E)
/* Identify the arguments to a macro call */
{
    unsigned    Parens;         /* Number of open parenthesis */
    StrBuf      Arg = STATIC_STRBUF_INITIALIZER;

    /* Read the actual macro arguments */
    Parens = 0;
    while (1) {
        if (CurC == '(') {

            /* Nested parenthesis */
            SB_AppendChar (&Arg, CurC);
            NextChar ();
            ++Parens;

        } else if (IsQuote (CurC)) {

            /* Quoted string - just copy */
            CopyQuotedString (&Arg);

        } else if (CurC == ',' || CurC == ')') {

            if (Parens) {
                /* Comma or right paren inside nested parenthesis */
                if (CurC == ')') {
                    --Parens;
                }
                SB_AppendChar (&Arg, CurC);
                NextChar ();
            } else if (CurC == ',' && ME_ArgIsVariadic (E)) {
                /* It's a comma, but we're inside a variadic macro argument, so
                 * just copy it and proceed.
                 */
                SB_AppendChar (&Arg, CurC);
                NextChar ();
            } else {
                /* End of actual argument. Remove whitespace from the end. */
                while (IsSpace (SB_LookAtLast (&Arg))) {
                    SB_Drop (&Arg, 1);
                }

                /* If this is not the single empty argument for a macro with
                 * an empty argument list, remember it.
                 */
                if (CurC != ')' || SB_NotEmpty (&Arg) || E->M->ArgCount > 0) {
                    ME_AppendActual (E, &Arg);
                }

                /* Check for end of macro param list */
                if (CurC == ')') {
                    NextChar ();
                    break;
                }

                /* Start the next param */
                NextChar ();
                SB_Clear (&Arg);
            }
        } else if (SkipWhitespace (1)) {
            /* Squeeze runs of blanks within an arg */
            if (SB_NotEmpty (&Arg)) {
                SB_AppendChar (&Arg, ' ');
            }
        } else if (CurC == '/' && NextC == '*') {
            if (SB_NotEmpty (&Arg)) {
                SB_AppendChar (&Arg, ' ');
            }
            OldStyleComment ();
        } else if (IS_Get (&Standard) >= STD_C99 && CurC == '/' && NextC == '/') {
            if (SB_NotEmpty (&Arg)) {
                SB_AppendChar (&Arg, ' ');
            }
            NewStyleComment ();
        } else if (CurC == '\0') {
            /* End of input inside macro argument list */
            PPError ("Unterminated argument list invoking macro `%s'", E->M->Name);

            ClearLine ();
            break;
        } else {
            /* Just copy the character */
            SB_AppendChar (&Arg, CurC);
            NextChar ();
        }
    }

    /* Deallocate string buf resources */
    SB_Done (&Arg);
}
Пример #18
0
void Preprocess (void)
/* Preprocess a line */
{
    int         Skip;
    ident       Directive;

    /* Create the output buffer if we don't already have one */
    if (MLine == 0) {
        MLine = NewStrBuf ();
    }

    /* Skip white space at the beginning of the line */
    SkipWhitespace (0);

    /* Check for stuff to skip */
    Skip = 0;
    while (CurC == '\0' || CurC == '#' || Skip) {

        /* Check for preprocessor lines lines */
        if (CurC == '#') {
            NextChar ();
            SkipWhitespace (0);
            if (CurC == '\0') {
                /* Ignore the empty preprocessor directive */
                continue;
            }
            if (!IsSym (Directive)) {
                PPError ("Preprocessor directive expected");
                ClearLine ();
            } else {
                switch (FindPPToken (Directive)) {

                    case PP_DEFINE:
                        if (!Skip) {
                            DefineMacro ();
                        }
                        break;

                    case PP_ELIF:
                        if (IfIndex >= 0) {
                            if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {

                                /* Handle as #else/#if combination */
                                if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
                                    Skip = !Skip;
                                }
                                IfStack[IfIndex] |= IFCOND_ELSE;
                                Skip = DoIf (Skip);

                                /* #elif doesn't need a terminator */
                                IfStack[IfIndex] &= ~IFCOND_NEEDTERM;
                            } else {
                                PPError ("Duplicate #else/#elif");
                            }
                        } else {
                            PPError ("Unexpected #elif");
                        }
                        break;

                    case PP_ELSE:
                        if (IfIndex >= 0) {
                            if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {
                                if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
                                    Skip = !Skip;
                                }
                                IfStack[IfIndex] |= IFCOND_ELSE;
                            } else {
                                PPError ("Duplicate #else");
                            }
                        } else {
                            PPError ("Unexpected `#else'");
                        }
                        break;

                    case PP_ENDIF:
                        if (IfIndex >= 0) {
                            /* Remove any clauses on top of stack that do not
                             * need a terminating #endif.
                             */
                            while (IfIndex >= 0 && (IfStack[IfIndex] & IFCOND_NEEDTERM) == 0) {
                                --IfIndex;
                            }

                            /* Stack may not be empty here or something is wrong */
                            CHECK (IfIndex >= 0);

                            /* Remove the clause that needs a terminator */
                            Skip = (IfStack[IfIndex--] & IFCOND_SKIP) != 0;
                        } else {
                            PPError ("Unexpected `#endif'");
                        }
                        break;

                    case PP_ERROR:
                        if (!Skip) {
                            DoError ();
                        }
                        break;

                    case PP_IF:
                        Skip = DoIf (Skip);
                        break;

                    case PP_IFDEF:
                        Skip = DoIfDef (Skip, 1);
                        break;

                    case PP_IFNDEF:
                        Skip = DoIfDef (Skip, 0);
                        break;

                    case PP_INCLUDE:
                        if (!Skip) {
                            DoInclude ();
                        }
                        break;

                    case PP_LINE:
                        /* Should do something in C99 at least, but we ignore it */
                        if (!Skip) {
                            ClearLine ();
                        }
                        break;

                    case PP_PRAGMA:
                        if (!Skip) {
                            DoPragma ();
                            goto Done;
                        }
                        break;

                    case PP_UNDEF:
                        if (!Skip) {
                            DoUndef ();
                        }
                        break;

                    case PP_WARNING:
                        /* #warning is a non standard extension */
                        if (IS_Get (&Standard) > STD_C99) {
                            if (!Skip) {
                                DoWarning ();
                            }
                        } else {
                            if (!Skip) {
                                PPError ("Preprocessor directive expected");
                            }
                            ClearLine ();
                        }
                        break;

                    default:
                        if (!Skip) {
                            PPError ("Preprocessor directive expected");
                        }
                        ClearLine ();
                }
            }

        }
        if (NextLine () == 0) {
            if (IfIndex >= 0) {
                PPError ("`#endif' expected");
            }
            return;
        }
        SkipWhitespace (0);
    }

    PreprocessLine ();

Done:
    if (Verbosity > 1 && SB_NotEmpty (Line)) {
        printf ("%s(%u): %.*s\n", GetCurrentFile (), GetCurrentLine (),
                (int) SB_GetLen (Line), SB_GetConstBuf (Line));
    }
}
Пример #19
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;

    }
}