Пример #1
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;
    }
}
Пример #2
0
static void PreprocessLine (void)
/* Translate one line. */
{
    /* Trim whitespace and remove comments. The function returns the number of
     * identifiers found. If there were any, we will have to check for macros.
     */
    SB_Clear (MLine);
    if (Pass1 (Line, MLine) > 0) {
        MLine = InitLine (MLine);
        SB_Reset (Line);
        SB_Clear (MLine);
        MacroReplacement (Line, MLine);
    }

    /* Read from the new line */
    SB_Reset (MLine);
    MLine = InitLine (MLine);
}
Пример #3
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;
    }
}
Пример #4
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;
}
Пример #5
0
void ClearLine (void)
/* Clear the current input line */
{
    unsigned I;

    /* Remove all pushed fragments from the input stack */
    for (I = 0; I < CollCount (&InputStack); ++I) {
        FreeStrBuf (CollAtUnchecked (&InputStack, I));
    }
    CollDeleteAll (&InputStack);

    /* Clear the contents of Line */
    SB_Clear (Line);
    CurC    = '\0';
    NextC   = '\0';
}
Пример #6
0
static void DoPragma (void)
/* Handle a #pragma line by converting the #pragma preprocessor directive into
 * the _Pragma() compiler operator.
 */
{
    /* Skip blanks following the #pragma directive */
    SkipWhitespace (0);

    /* Copy the remainder of the line into MLine removing comments and ws */
    SB_Clear (MLine);
    Pass1 (Line, MLine);

    /* Convert the directive into the operator */
    SB_CopyStr (Line, "_Pragma (");
    SB_Reset (MLine);
    Stringize (MLine, Line);
    SB_AppendChar (Line, ')');

    /* Initialize reading from line */
    SB_Reset (Line);
    InitLine (Line);
}
Пример #7
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 ();
    }
}
Пример #8
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);
}
Пример #9
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);
}
Пример #10
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);
}
Пример #11
0
void NextRawTok (void)
/* Read the next raw token from the input stream */
{
    Macro* M;

    /* If we've a forced end of assembly, don't read further */
    if (ForcedEnd) {
        CurTok.Tok = TOK_EOF;
        return;
    }

Restart:
    /* Check if we have tokens from another input source */
    if (InputFromStack ()) {
        if (CurTok.Tok == TOK_IDENT && (M = FindDefine (&CurTok.SVal)) != 0) {
            /* This is a define style macro - expand it */
            MacExpandStart (M);
            goto Restart;
        }
        return;
    }

Again:
    /* Skip whitespace, remember if we had some */
    if ((CurTok.WS = IsBlank (C)) != 0) {
        do {
            NextChar ();
        } while (IsBlank (C));
    }

    /* Mark the file position of the next token */
    Source->Func->MarkStart (Source);

    /* Clear the string attribute */
    SB_Clear (&CurTok.SVal);

    /* Generate line info for the current token */
    NewAsmLine ();

    /* Hex number or PC symbol? */
    if (C == '$') {
        NextChar ();

        /* Hex digit must follow or DollarIsPC must be enabled */
        if (!IsXDigit (C)) {
            if (DollarIsPC) {
                CurTok.Tok = TOK_PC;
                return;
            } else {
                Error ("Hexadecimal digit expected");
            }
        }

        /* Read the number */
        CurTok.IVal = 0;
        while (1) {
            if (UnderlineInNumbers && C == '_') {
                while (C == '_') {
                    NextChar ();
                }
                if (!IsXDigit (C)) {
                    Error ("Number may not end with underline");
                }
            }
            if (IsXDigit (C)) {
                if (CurTok.IVal & 0xF0000000) {
                    Error ("Overflow in hexadecimal number");
                    CurTok.IVal = 0;
                }
                CurTok.IVal = (CurTok.IVal << 4) + DigitVal (C);
                NextChar ();
            } else {
                break;
            }
        }

        /* This is an integer constant */
        CurTok.Tok = TOK_INTCON;
        return;
    }

    /* Binary number? */
    if (C == '%') {
        NextChar ();

        /* 0 or 1 must follow */
        if (!IsBDigit (C)) {
            Error ("Binary digit expected");
        }

        /* Read the number */
        CurTok.IVal = 0;
        while (1) {
            if (UnderlineInNumbers && C == '_') {
                while (C == '_') {
                    NextChar ();
                }
                if (!IsBDigit (C)) {
                    Error ("Number may not end with underline");
                }
            }
            if (IsBDigit (C)) {
                if (CurTok.IVal & 0x80000000) {
                    Error ("Overflow in binary number");
                    CurTok.IVal = 0;
                }
                CurTok.IVal = (CurTok.IVal << 1) + DigitVal (C);
                NextChar ();
            } else {
                break;
            }
        }

        /* This is an integer constant */
        CurTok.Tok = TOK_INTCON;
        return;
    }

    /* Number? */
    if (IsDigit (C)) {

        char Buf[16];
        unsigned Digits;
        unsigned Base;
        unsigned I;
        long     Max;
        unsigned DVal;

        /* Ignore leading zeros */
        while (C == '0') {
            NextChar ();
        }

        /* Read the number into Buf counting the digits */
        Digits = 0;
        while (1) {
            if (UnderlineInNumbers && C == '_') {
                while (C == '_') {
                    NextChar ();
                }
                if (!IsXDigit (C)) {
                    Error ("Number may not end with underline");
                }
            }
            if (IsXDigit (C)) {
                /* Buf is big enough to allow any decimal and hex number to
                ** overflow, so ignore excess digits here, they will be detected
                ** when we convert the value.
                */
                if (Digits < sizeof (Buf)) {
                    Buf[Digits++] = C;
                }
                NextChar ();
            } else {
                break;
            }
        }

        /* Allow zilog/intel style hex numbers with a 'h' suffix */
        if (C == 'h' || C == 'H') {
            NextChar ();
            Base = 16;
            Max  = 0xFFFFFFFFUL / 16;
        } else {
            Base = 10;
            Max  = 0xFFFFFFFFUL / 10;
        }

        /* Convert the number using the given base */
        CurTok.IVal = 0;
        for (I = 0; I < Digits; ++I) {
            if (CurTok.IVal > Max) {
                Error ("Number out of range");
                CurTok.IVal = 0;
                break;
            }
            DVal = DigitVal (Buf[I]);
            if (DVal >= Base) {
                Error ("Invalid digits in number");
                CurTok.IVal = 0;
                break;
            }
            CurTok.IVal = (CurTok.IVal * Base) + DVal;
        }

        /* This is an integer constant */
        CurTok.Tok = TOK_INTCON;
        return;
    }

    /* Control command? */
    if (C == '.') {

        /* Remember and skip the dot */
        NextChar ();

        /* Check if it's just a dot */
        if (!IsIdStart (C)) {

            /* Just a dot */
            CurTok.Tok = TOK_DOT;

        } else {

            /* Read the remainder of the identifier */
            SB_AppendChar (&CurTok.SVal, '.');
            ReadIdent ();

            /* Dot keyword, search for it */
            CurTok.Tok = FindDotKeyword ();
            if (CurTok.Tok == TOK_NONE) {

                /* Not found */
                if (!LeadingDotInIdents) {
                    /* Invalid pseudo instruction */
                    Error ("'%m%p' is not a recognized control command", &CurTok.SVal);
                    goto Again;
                }

                /* An identifier with a dot. Check if it's a define style
                ** macro.
                */
                if ((M = FindDefine (&CurTok.SVal)) != 0) {
                    /* This is a define style macro - expand it */
                    MacExpandStart (M);
                    goto Restart;
                }

                /* Just an identifier with a dot */
                CurTok.Tok = TOK_IDENT;
            }

        }
        return;
    }

    /* Indirect op for sweet16 cpu. Must check this before checking for local
    ** symbols, because these may also use the '@' symbol.
    */
    if (CPU == CPU_SWEET16 && C == '@') {
        NextChar ();
        CurTok.Tok = TOK_AT;
        return;
    }

    /* Local symbol? */
    if (C == LocalStart) {

        /* Read the identifier. */
        ReadIdent ();

        /* Start character alone is not enough */
        if (SB_GetLen (&CurTok.SVal) == 1) {
            Error ("Invalid cheap local symbol");
            goto Again;
        }

        /* A local identifier */
        CurTok.Tok = TOK_LOCAL_IDENT;
        return;
    }


    /* Identifier or keyword? */
    if (IsIdStart (C)) {

        /* Read the identifier */
        ReadIdent ();

        /* Check for special names. Bail out if we have identified the type of
        ** the token. Go on if the token is an identifier.
        */
        switch (SB_GetLen (&CurTok.SVal)) {
            case 1:
                switch (toupper (SB_AtUnchecked (&CurTok.SVal, 0))) {

                    case 'A':
                        if (C == ':') {
                            NextChar ();
                            CurTok.Tok = TOK_OVERRIDE_ABS;
                        } else {
                            CurTok.Tok = TOK_A;
                        }
                        return;

                    case 'F':
                        if (C == ':') {
                            NextChar ();
                            CurTok.Tok = TOK_OVERRIDE_FAR;
                            return;
                        }
                        break;

                    case 'S':
                        if ((CPU == CPU_4510) || (CPU == CPU_65816)) {
                            CurTok.Tok = TOK_S;
                            return;
                        }
                        break;

                    case 'X':
                        CurTok.Tok = TOK_X;
                        return;

                    case 'Y':
                        CurTok.Tok = TOK_Y;
                        return;

                    case 'Z':
                        if (C == ':') {
                            NextChar ();
                            CurTok.Tok = TOK_OVERRIDE_ZP;
                           return;
                        } else {
                            if (CPU == CPU_4510) {
                                CurTok.Tok = TOK_Z;
                                return;
                            }
                        }
                        break;

                    default:
                        break;
                }
                break;
            case 2:
                if ((CPU == CPU_4510) &&
                    (toupper (SB_AtUnchecked (&CurTok.SVal, 0)) == 'S') &&
                    (toupper (SB_AtUnchecked (&CurTok.SVal, 1)) == 'P')) {

                    CurTok.Tok = TOK_S;
                    return;
                }
                /* FALL THROUGH */
            default:
                if (CPU == CPU_SWEET16 &&
                   (CurTok.IVal = Sweet16Reg (&CurTok.SVal)) >= 0) {

                    /* A sweet16 register number in sweet16 mode */
                    CurTok.Tok = TOK_REG;
                    return;
                }
        }

        /* Check for define style macro */
        if ((M = FindDefine (&CurTok.SVal)) != 0) {
            /* Macro - expand it */
            MacExpandStart (M);
            goto Restart;
        } else {
            /* An identifier */
            CurTok.Tok = TOK_IDENT;
        }
        return;
    }

    /* Ok, let's do the switch */
CharAgain:
    switch (C) {

        case '+':
            NextChar ();
            CurTok.Tok = TOK_PLUS;
            return;

        case '-':
            NextChar ();
            CurTok.Tok = TOK_MINUS;
            return;

        case '/':
            NextChar ();
            if (C != '*') {
                CurTok.Tok = TOK_DIV;
            } else if (CComments) {
                /* Remember the position, then skip the '*' */
                Collection LineInfos = STATIC_COLLECTION_INITIALIZER;
                GetFullLineInfo (&LineInfos);
                NextChar ();
                do {
                    while (C !=  '*') {
                        if (C == EOF) {
                            LIError (&LineInfos, "Unterminated comment");
                            ReleaseFullLineInfo (&LineInfos);
                            DoneCollection (&LineInfos);
                            goto CharAgain;
                        }
                        NextChar ();
                    }
                    NextChar ();
                } while (C != '/');
                NextChar ();
                ReleaseFullLineInfo (&LineInfos);
                DoneCollection (&LineInfos);
                goto Again;
            }
            return;

        case '*':
            NextChar ();
            CurTok.Tok = TOK_MUL;
            return;

        case '^':
            NextChar ();
            CurTok.Tok = TOK_XOR;
            return;

        case '&':
            NextChar ();
            if (C == '&') {
                NextChar ();
                CurTok.Tok = TOK_BOOLAND;
            } else {
                CurTok.Tok = TOK_AND;
            }
            return;

        case '|':
            NextChar ();
            if (C == '|') {
                NextChar ();
                CurTok.Tok = TOK_BOOLOR;
            } else {
                CurTok.Tok = TOK_OR;
            }
            return;

        case ':':
            NextChar ();
            switch (C) {

                case ':':
                    NextChar ();
                    CurTok.Tok = TOK_NAMESPACE;
                    break;

                case '-':
                    CurTok.IVal = 0;
                    do {
                        --CurTok.IVal;
                        NextChar ();
                    } while (C == '-');
                    CurTok.Tok = TOK_ULABEL;
                    break;

                case '+':
                    CurTok.IVal = 0;
                    do {
                        ++CurTok.IVal;
                        NextChar ();
                    } while (C == '+');
                    CurTok.Tok = TOK_ULABEL;
                    break;

                case '=':
                    NextChar ();
                    CurTok.Tok = TOK_ASSIGN;
                    break;

                default:
                    CurTok.Tok = TOK_COLON;
                    break;
            }
            return;

        case ',':
            NextChar ();
            CurTok.Tok = TOK_COMMA;
            return;

        case ';':
            NextChar ();
            while (C != '\n' && C != EOF) {
                NextChar ();
            }
            goto CharAgain;

        case '#':
            NextChar ();
            CurTok.Tok = TOK_HASH;
            return;

        case '(':
            NextChar ();
            CurTok.Tok = TOK_LPAREN;
            return;

        case ')':
            NextChar ();
            CurTok.Tok = TOK_RPAREN;
            return;

        case '[':
            NextChar ();
            CurTok.Tok = TOK_LBRACK;
            return;

        case ']':
            NextChar ();
            CurTok.Tok = TOK_RBRACK;
            return;

        case '{':
            NextChar ();
            CurTok.Tok = TOK_LCURLY;
            return;

        case '}':
            NextChar ();
            CurTok.Tok = TOK_RCURLY;
            return;

        case '<':
            NextChar ();
            if (C == '=') {
                NextChar ();
                CurTok.Tok = TOK_LE;
            } else if (C == '<') {
                NextChar ();
                CurTok.Tok = TOK_SHL;
            } else if (C == '>') {
                NextChar ();
                CurTok.Tok = TOK_NE;
            } else {
                CurTok.Tok = TOK_LT;
            }
            return;

        case '=':
            NextChar ();
            CurTok.Tok = TOK_EQ;
            return;

        case '!':
            NextChar ();
            CurTok.Tok = TOK_BOOLNOT;
            return;

        case '>':
            NextChar ();
            if (C == '=') {
                NextChar ();
                CurTok.Tok = TOK_GE;
            } else if (C == '>') {
                NextChar ();
                CurTok.Tok = TOK_SHR;
            } else {
                CurTok.Tok = TOK_GT;
            }
            return;

        case '~':
            NextChar ();
            CurTok.Tok = TOK_NOT;
            return;

        case '\'':
            /* Hack: If we allow ' as terminating character for strings, read
            ** the following stuff as a string, and check for a one character
            ** string later.
            */
            if (LooseStringTerm) {
                ReadStringConst ('\'');
                if (SB_GetLen (&CurTok.SVal) == 1) {
                    CurTok.IVal = SB_AtUnchecked (&CurTok.SVal, 0);
                    CurTok.Tok = TOK_CHARCON;
                } else {
                    CurTok.Tok = TOK_STRCON;
                }
            } else {
                /* Always a character constant */
                NextChar ();
                if (C == EOF || IsControl (C)) {
                    Error ("Illegal character constant");
                    goto CharAgain;
                }
                CurTok.IVal = C;
                CurTok.Tok = TOK_CHARCON;
                NextChar ();
                if (C != '\'') {
                    if (!MissingCharTerm) {
                        Error ("Illegal character constant");
                    }
                } else {
                    NextChar ();
                }
            }
            return;

        case '\"':
            ReadStringConst ('\"');
            CurTok.Tok = TOK_STRCON;
            return;

        case '\\':
            /* Line continuation? */
            if (LineCont) {
                NextChar ();
                /* Next char should be a LF, if not, will result in an error later */
                if (C == '\n') {
                    /* Ignore the '\n' */
                    NextChar ();
                    goto Again;
                } else {
                    /* Make it clear what the problem is: */
                    Error ("EOL expected.");
                }
            }
            break;

        case '\n':
            NextChar ();
            CurTok.Tok = TOK_SEP;
            return;

        case EOF:
            CheckInputStack ();
            /* In case of the main file, do not close it, but return EOF. */
            if (Source && Source->Next) {
                DoneCharSource ();
                goto Again;
            } else {
                CurTok.Tok = TOK_EOF;
            }
            return;
    }

    /* If we go here, we could not identify the current character. Skip it
    ** and try again.
    */
    Error ("Invalid input character: 0x%02X", C & 0xFF);
    NextChar ();
    goto Again;
}
Пример #12
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);
}
Пример #13
0
void CfgNextTok (void)
/* Read the next token from the input stream */
{
Again:
    /* Skip whitespace */
    while (isspace (C)) {
        NextChar ();
    }

    /* Remember the current position */
    CfgErrorPos = InputPos;

    /* Identifier? */
    if (C == '_' || IsAlpha (C)) {

        /* Read the identifier */
        SB_Clear (&CfgSVal);
        while (C == '_' || IsAlNum (C)) {
            SB_AppendChar (&CfgSVal, C);
            NextChar ();
        }
        SB_Terminate (&CfgSVal);
        CfgTok = CFGTOK_IDENT;
        return;
    }

    /* Hex number? */
    if (C == '$') {
        NextChar ();
        if (!isxdigit (C)) {
            CfgError (&CfgErrorPos, "Hex digit expected");
        }
        CfgIVal = 0;
        while (isxdigit (C)) {
            CfgIVal = CfgIVal * 16 + DigitVal (C);
            NextChar ();
        }
        CfgTok = CFGTOK_INTCON;
        return;
    }

    /* Decimal number? */
    if (isdigit (C)) {
        CfgIVal = 0;
        while (isdigit (C)) {
            CfgIVal = CfgIVal * 10 + DigitVal (C);
            NextChar ();
        }
        CfgTok = CFGTOK_INTCON;
        return;
    }

    /* Other characters */
    switch (C) {

        case '-':
            NextChar ();
            CfgTok = CFGTOK_MINUS;
            break;

        case '+':
            NextChar ();
            CfgTok = CFGTOK_PLUS;
            break;

        case '*':
            NextChar ();
            CfgTok = CFGTOK_MUL;
            break;

        case '/':
            NextChar ();
            CfgTok = CFGTOK_DIV;
            break;

        case '(':
            NextChar ();
            CfgTok = CFGTOK_LPAR;
            break;

        case ')':
            NextChar ();
            CfgTok = CFGTOK_RPAR;
            break;

        case '{':
            NextChar ();
            CfgTok = CFGTOK_LCURLY;
            break;

        case '}':
            NextChar ();
            CfgTok = CFGTOK_RCURLY;
            break;

        case ';':
            NextChar ();
            CfgTok = CFGTOK_SEMI;
            break;

        case '.':
            NextChar ();
            CfgTok = CFGTOK_DOT;
            break;

        case ',':
            NextChar ();
            CfgTok = CFGTOK_COMMA;
            break;

        case '=':
            NextChar ();
            CfgTok = CFGTOK_EQ;
            break;

        case ':':
            NextChar ();
            CfgTok = CFGTOK_COLON;
            break;

        case '\"':
            StrVal ();
            break;

        case '#':
            /* Comment */
            while (C != '\n' && C != EOF) {
                NextChar ();
            }
            if (C != EOF) {
                goto Again;
            }
            CfgTok = CFGTOK_EOF;
            break;

        case '%':
            NextChar ();
            switch (C) {

                case 'O':
                    NextChar ();
                    if (OutputName) {
                        SB_CopyStr (&CfgSVal, OutputName);
                    } else {
                        SB_Clear (&CfgSVal);
                    }
                    SB_Terminate (&CfgSVal);
                    OutputNameUsed = 1;
                    CfgTok = CFGTOK_STRCON;
                    break;

                case 'S':
                    NextChar ();
                    CfgIVal = StartAddr;
                    CfgTok = CFGTOK_INTCON;
                    break;

                default:
                    CfgError (&CfgErrorPos, "Invalid format specification");
            }
            break;

        case EOF:
            CfgTok = CFGTOK_EOF;
            break;

        default:
            CfgError (&CfgErrorPos, "Invalid character `%c'", C);

    }
}
Пример #14
0
static void StrVal (void)
/* Parse a string value and expand escape sequences */
{
    /* Skip the starting double quotes */
    NextChar ();

    /* Read input chars */
    SB_Clear (&CfgSVal);
    while (C != '\"') {
        switch (C) {

            case EOF:
            case '\n':
                CfgError (&CfgErrorPos, "Unterminated string");
                break;

            case '%':
                NextChar ();
                switch (C) {

                    case EOF:
                    case '\n':
                    case '\"':
                        CfgError (&CfgErrorPos, "Unterminated '%%' escape sequence");
                        break;

                    case '%':
                        SB_AppendChar (&CfgSVal, '%');
                        NextChar ();
                        break;

                    case 'O':
                        /* Replace by output file */
                        if (OutputName) {
                            SB_AppendStr (&CfgSVal, OutputName);
                        }
                        OutputNameUsed = 1;
                        NextChar ();
                        break;

                    default:
                        CfgWarning (&CfgErrorPos,
                                    "Unkown escape sequence `%%%c'", C);
                        SB_AppendChar (&CfgSVal, '%');
                        SB_AppendChar (&CfgSVal, C);
                        NextChar ();
                        break;
                }
                break;

            default:
                SB_AppendChar (&CfgSVal, C);
                NextChar ();
        }
    }

    /* Skip the terminating double quotes */
    NextChar ();

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

    /* We've read a string value */
    CfgTok = CFGTOK_STRCON;
}