Beispiel #1
0
    public static void Main()
    {
        string[]   ordinals       = { "First", "Second", "Third", "Fourth", "Fifth" };
        string[]   copiedOrdinals = new string[ordinals.Length];
        StringCopy copyOperation  = CopyStrings;

        copyOperation(ordinals, copiedOrdinals, 3);
        foreach (string ordinal in copiedOrdinals)
        {
            Console.WriteLine(string.IsNullOrEmpty(ordinal) ? "<None>" : ordinal);
        }
    }
        public TokenRec <T> GetNextToken()
        {
            int          C;
            TokenRec <T> Token;

            /* check for pushback */
            if (PushedBackToken != null)
            {
                TokenRec <T> Temp;

                Temp            = PushedBackToken;
                PushedBackToken = null;
                return(Temp);
            }

            /* get a character */
            C = GetCharacter();

            /* strip while space */
            bool cr = false;

            while (((C >= 0) && (C <= 32)) || (C == '#'))
            {
                if ((C == 13) || (C == 10))
                {
                    bool crPrev = cr;
                    cr = (C == 13);
                    if (!crPrev)
                    {
                        LineNumber++;
                    }
                }
                if (C == '#')
                {
                    /* comment */
                    while ((C != 13) && (C != 10) && (C != ENDOFTEXT))
                    {
                        C = GetCharacter();
                    }
                }
                else
                {
                    C = GetCharacter();
                }
            }

RestartParse:
            /* handle the end of text character */
            if (C == ENDOFTEXT)
            {
                Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenEndOfInput);
            }

            /* handle a string literal */
            else if (C == '\x22')
            {
                StringBuilder String = new StringBuilder();

                cr = false;
                C  = GetCharacter();
                while (C != '\x22')
                {
                    if (C == ENDOFTEXT)
                    {
                        goto BreakStringReadPoint;
                    }
                    if (C == '\\')
                    {
                        C = GetCharacter();
                        if (C == 'n')
                        {
                            String.Append(Environment.NewLine); // originally was '\n'
                            goto DoAnotherCharPoint;
                        }
                        else if ((C == '\x22') || (C == '\\') || (C == 10) || (C == 13))
                        {
                            /* keep these */
                        }
                        else
                        {
                            /* others become strange character */
                            C = '.';
                        }
                    }
                    String.Append((char)C);
                    if ((C == 10) || (C == 13))
                    {
                        bool crPrev = cr;
                        cr = (C == 13);
                        if (!crPrev)
                        {
                            LineNumber++;
                        }
                    }
DoAnotherCharPoint:
                    C = GetCharacter();
                }
BreakStringReadPoint:
                ;

                Token = new StringTokenRec <T>(String.ToString());
            }

            /* handle an identifier:  [a-zA-Z_][a-zA-Z0-9_]*  */
            else if (((C >= 'a') && (C <= 'z')) || ((C >= 'A') && (C <= 'Z')) || (C == '_'))
            {
                StringBuilder String       = new StringBuilder();
                int           KeywordIndex = -1; /* -1 == not a keyword */
                string        StringCopy;

                /* read the entire token */
                while (((C >= 'a') && (C <= 'z')) || ((C >= 'A') && (C <= 'Z')) || (C == '_') || ((C >= '0') && (C <= '9')))
                {
                    String.Append((char)C);
                    C = GetCharacter();
                }
                /* unget the character that made us stop */
                UngetCharacter();
                /* get the string out of the line buffer */
                StringCopy = String.ToString();

                /* figure out if it is a keyword (binary search) */
                int  LowBound            = 0;
                int  HighBoundPlusOne    = KeywordList.Length;
                bool ContinueLoopingFlag = true;
                while (ContinueLoopingFlag)
                {
                    int MidPoint;
                    int CompareResult;

                    if (LowBound > HighBoundPlusOne)
                    {
                        Debug.Assert(false);
                        throw new InvalidOperationException();
                    }

                    MidPoint = (LowBound + HighBoundPlusOne) / 2;

                    CompareResult = StringCopy.CompareTo(KeywordList[MidPoint].KeywordName);
                    /* CompareResult == 0  -->  found the target */
                    /* CompareResult < 0  --> in the first half of the list */
                    /* CompareResult > 0  --> in the second half of the list */

                    if (CompareResult == 0)
                    {
                        /* found the one */
                        KeywordIndex        = MidPoint;
                        ContinueLoopingFlag = false;
                    }
                    else
                    {
                        if (CompareResult < 0)
                        {
                            /* select first half of list */
                            HighBoundPlusOne = MidPoint;
                        }
                        else /* if (CompareResult > 0) */
                        {
                            /* select second half of list */
                            LowBound = MidPoint + 1;
                        }
                        /* termination condition:  if range in array collapses to an */
                        /* empty array, then there is no entry in the array */
                        if (LowBound == HighBoundPlusOne)
                        {
                            KeywordIndex        = -1; /* indicate there is no keyword */
                            ContinueLoopingFlag = false;
                        }
                    }
                }

                /* create the token */
                if (KeywordIndex == -1)
                {
                    /* no keyword; make a string containing token */
                    Token = new IdentifierTokenRec <T>(StringCopy);
                }
                else
                {
                    Token = new KeywordTokenRec <T>(KeywordList[KeywordIndex].TagValue);
                }
            }

            /* integer or floating?  [0-9]+  [0-9]+"."[0-9]+([Ee][+-]?[0-9]+)?[sdf]?  */
            else if (((C >= '0') && (C <= '9'))
                     // TODO: C# 2.0 hack - convert to elegant lambda evaluation after upgrade
                     || ((C == '.') && Eval(delegate() { int CC = GetCharacter(); UngetCharacter(); return((CC >= '0') || (CC <= '9')); })))
            {
                NumFormType   SpecifiedNumType = NumFormType.eTypeNotSpecified;
                NumStateType  NumberState      = NumStateType.eIntegerPart;
                StringBuilder String           = new StringBuilder();
                string        StringData;

                Token = null;

                while (((C >= '0') && (C <= '9')) || (C == '.') || (C == '+') || (C == '-') ||
                       (C == 's') || (C == 'd') || (C == 'f') || (C == 'e') || (C == 'E'))
                {
                    /* do some state changes */
                    if (C == '.')
                    {
                        if (NumberState != NumStateType.eIntegerPart)
                        {
                            Token = new ErrorTokenRec <T>(ScannerErrors.eScannerMalformedFloat);
                            goto AbortNumberErrorPoint;
                        }
                        else
                        {
                            NumberState = NumStateType.eFractionalPart;
                        }
                    }
                    else if ((C == 'e') || (C == 'E'))
                    {
                        if ((NumberState != NumStateType.eIntegerPart) && (NumberState != NumStateType.eFractionalPart))
                        {
                            Token = new ErrorTokenRec <T>(ScannerErrors.eScannerMalformedFloat);
                            goto AbortNumberErrorPoint;
                        }
                        else
                        {
                            NumberState = NumStateType.eExponentialPart;
                        }
                    }
                    else if ((C == '+') || (C == '-'))
                    {
                        if (NumberState != NumStateType.eExponentialPart)
                        {
                            /* this is not an error, since it could be a unary operator */
                            /* coming later, so we stop, but don't abort */
                            goto FinishNumberPoint; /* character ungot at target */
                        }
                        else
                        {
                            NumberState = NumStateType.eExponNumberPart;
                        }
                    }
                    else if ((C == 's') || (C == 'f'))
                    {
                        if (NumberState == NumStateType.eNumberFinished)
                        {
                            Token = new ErrorTokenRec <T>(ScannerErrors.eScannerMalformedFloat);
                            goto AbortNumberErrorPoint;
                        }
                        else
                        {
                            NumberState      = NumStateType.eNumberFinished;
                            SpecifiedNumType = NumFormType.eTypeSingle;
                            C = (char)32; /* so adding it to the string doesn't do damage */
                        }
                    }
                    else if (C == 'd')
                    {
                        if (NumberState == NumStateType.eNumberFinished)
                        {
                            Token = new ErrorTokenRec <T>(ScannerErrors.eScannerMalformedFloat);
                            goto AbortNumberErrorPoint;
                        }
                        else
                        {
                            NumberState      = NumStateType.eNumberFinished;
                            SpecifiedNumType = NumFormType.eTypeDouble;
                            C = (char)32;
                        }
                    }

                    /* actually save the character */
                    String.Append((char)C);

                    C = GetCharacter();
                }
FinishNumberPoint:
                UngetCharacter();

                StringData = String.ToString();

                /* if the token type is not specified, then see what we can guess */
                if (SpecifiedNumType == NumFormType.eTypeNotSpecified)
                {
                    if (NumberState == NumStateType.eIntegerPart)
                    {
                        /* if we only got as far as the integer part, then it's an int */
                        SpecifiedNumType = NumFormType.eTypeInteger;
                    }
                    else
                    {
                        /* otherwise, assume the highest precision type */
                        SpecifiedNumType = NumFormType.eTypeDouble;
                    }
                }

                /* create the token */
                switch (SpecifiedNumType)
                {
                default:
                    Debug.Assert(false);
                    throw new InvalidOperationException();

                case NumFormType.eTypeSingle:
                {
                    float v;
                    if (!Single.TryParse(StringData, out v))
                    {
                        // Reasons it could fail:
                        // 1: our scanner is more permissive than they are - accepting things like "."
                        // 2: number could be syntactically valid but out of range for the type.
                        Token = new ErrorTokenRec <T>(ScannerErrors.eScannerMalformedFloat);
                        goto AbortNumberErrorPoint;
                    }
                    Token = new SingleTokenRec <T>(v);
                }
                break;

                case NumFormType.eTypeDouble:
                {
                    double v;
                    if (!Double.TryParse(StringData, out v))
                    {
                        // Reasons it could fail:
                        // 1: our scanner is more permissive than they are - accepting things like "."
                        // 2: number could be syntactically valid but out of range for the type.
                        Token = new ErrorTokenRec <T>(ScannerErrors.eScannerMalformedFloat);
                        goto AbortNumberErrorPoint;
                    }
                    Token = new DoubleTokenRec <T>(v);
                }
                break;

                case NumFormType.eTypeInteger:
                {
                    int v;
                    if (!Int32.TryParse(StringData, out v))
                    {
                        // Reasons it could fail:
                        // 1: our scanner is more permissive than they are - accepting things like "."
                        // 2: number could be syntactically valid but out of range for the type.
                        Token = new ErrorTokenRec <T>(ScannerErrors.eScannerMalformedInteger);
                        goto AbortNumberErrorPoint;
                    }
                    Token = new IntegerTokenRec <T>(v);
                }
                break;
                }

                /* this is the escape point for when a bad character is encountered. */
AbortNumberErrorPoint:
                ;
            }

            /* handle a symbol */
            else
            {
                Token = null;

                switch (C)
                {
                default:
                    Token = new ErrorTokenRec <T>(ScannerErrors.eScannerUnknownCharacter);
                    break;

                case '(':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenOpenParen);
                    break;

                case ')':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenCloseParen);
                    break;

                case '[':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenOpenBracket);
                    break;

                case ']':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenCloseBracket);
                    break;

                case '{':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenOpenBrace);
                    break;

                case '}':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenCloseBrace);
                    break;

                case ':':
                    C = GetCharacter();
                    if (C == '=')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenColonEqual);
                    }
                    else
                    {
                        /* push the character back */
                        UngetCharacter();
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenColon);
                    }
                    break;

                case ';':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenSemicolon);
                    break;

                case ',':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenComma);
                    break;

                case '+':
                    C = GetCharacter();
                    if (C == '=')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenPlusEqual);
                    }
                    else if (C == '+')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenPlusPlus);
                    }
                    else
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenPlus);
                        UngetCharacter();
                    }
                    break;

                case '-':
                    C = GetCharacter();
                    if (C == '=')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenMinusEqual);
                    }
                    else if (C == '-')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenMinusMinus);
                    }
                    else if (C == '>')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenMinusGreater);
                    }
                    else
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenMinus);
                        UngetCharacter();
                    }
                    break;

                case '*':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenStar);
                    break;

                case '/':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenSlash);
                    break;

                case '=':
                    C = GetCharacter();
                    if (C == '=')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenEqualEqual);
                    }
                    else
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenEqual);
                        UngetCharacter();
                    }
                    break;

                case '<':
                    C = GetCharacter();
                    if (C == '>')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenLessGreater);
                    }
                    else if (C == '=')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenLessEqual);
                    }
                    else if (C == '<')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenLeftLeft);
                    }
                    else
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenLess);
                        UngetCharacter();
                    }
                    break;

                case '>':
                    C = GetCharacter();
                    if (C == '=')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenGreaterEqual);
                    }
                    else if (C == '>')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenRightRight);
                    }
                    else
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenGreater);
                        UngetCharacter();
                    }
                    break;

                case '^':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenCircumflex);
                    break;

                case '!':
                    C = GetCharacter();
                    if (C == '=')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenBangEqual);
                    }
                    else
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenBang);
                        UngetCharacter();
                    }
                    break;

                case '&':
                    C = GetCharacter();
                    if (C == '&')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenAmpersandAmpersand);
                    }
                    else
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenAmpersand);
                        UngetCharacter();
                    }
                    break;

                case '|':
                    C = GetCharacter();
                    if (C == '|')
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenPipePipe);
                    }
                    else
                    {
                        Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenPipe);
                        UngetCharacter();
                    }
                    break;

                case '~':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenTilde);
                    break;

                case '$':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenDollar);
                    break;

                case '@':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenAt);
                    break;

                case '%':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenPercent);
                    break;

                case '\\':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenBackslash);
                    break;

                case '?':
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenQuestion);
                    break;

                case '.':
                {
                    int CC = GetCharacter();
                    if ((CC >= '0') && (CC <= '9'))
                    {
                        UngetCharacter();
                        goto RestartParse;         // parse number
                    }
                }
                    Token = new UnqualifiedTokenRec <T>(TokenTypes.eTokenDot);
                    break;
                }
            }

            return(Token);
        }