Ejemplo n.º 1
0
        public override Maybe <Token> NextToken()
        {
            do
            {
                Maybe <Token> t_ = Lexer.NextToken();
redo:
                if (!t_.HasValue)
                {
                    break;
                }
                var t = t_.Value;
                if (t.IsWhitespace)
                {
                    AddWSToken(t);
                    continue;
                }
                else if (t.Kind == TokenKind.Other)
                {
                    switch (t.Type())
                    {
                    case TokenType.PPdefine:
                    case TokenType.PPundef:
                        ReadRest(_rest);
                        bool undef = t.Type() == TokenType.PPundef;
                        if (_rest.Count == 1 && _rest[0].Type() == TokenType.Id)
                        {
                            if (undef)
                            {
                                DefinedSymbols.Remove((Symbol)_rest[0].Value);
                            }
                            else
                            {
                                DefinedSymbols.Add((Symbol)_rest[0].Value);
                            }
                        }
                        else
                        {
                            ErrorSink.Error(t.ToSourceRange(SourceFile), "'{0}' should be followed by a single, simple identifier", undef ? "#undef" : "#define");
                        }
                        continue;

                    case TokenType.PPif:
                        var   tree = ReadRestAsTokenTree();
                        LNode expr = ParseExpr(tree);

                        var cond = Evaluate(expr) ?? false;
                        _ifRegions.Push(Pair.Create(t, cond));
                        t_ = SaveDirectiveAndAutoSkip(t, cond);
                        goto redo;

                    case TokenType.PPelse:
                    case TokenType.PPelif:
                        var tree_ = ReadRestAsTokenTree();

                        if (_ifRegions.Count == 0)
                        {
                            ErrorSink.Error(t.ToSourceRange(SourceFile),
                                            "Missing #if clause before '{0}'", t);
                            _ifRegions.Push(Pair.Create(t, false));
                        }
                        bool isElif = t.Type() == TokenType.PPelif, hasExpr = tree_.HasIndex(0);
                        if (hasExpr != isElif)
                        {
                            Error(t, isElif ? "Missing condition on #elif" : "Unexpected tokens after #else");
                        }
                        bool cond_ = true;
                        if (hasExpr)
                        {
                            LNode expr_ = ParseExpr(tree_);
                            cond_ = Evaluate(expr_) ?? false;
                        }
                        if (_ifRegions.Peek().B)
                        {
                            cond_ = false;
                        }
                        t_ = SaveDirectiveAndAutoSkip(t, cond_);
                        if (cond_)
                        {
                            _ifRegions.Push(Pair.Create(_ifRegions.Pop().A, cond_));
                        }
                        goto redo;

                    case TokenType.PPendif:
                        var tree__ = ReadRestAsTokenTree();
                        if (_ifRegions.Count == 0)
                        {
                            Error(t, "Missing #if before #endif");
                        }
                        else
                        {
                            _ifRegions.Pop();
                            if (tree__.Count > 0)
                            {
                                Error(t, "Unexpected tokens after #endif");
                            }
                        }
                        _triviaList.Add(t);
                        continue;

                    case TokenType.PPerror:
                        _triviaList.Add(t);
                        Error(t, t.Value.ToString());
                        continue;

                    case TokenType.PPwarning:
                        _triviaList.Add(t);
                        ErrorSink.Warning(t.ToSourceRange(SourceFile), t.Value.ToString());
                        continue;

                    case TokenType.PPregion:
                        _triviaList.Add(t);
                        _regions.Push(t);
                        continue;

                    case TokenType.PPendregion:
                        _triviaList.Add(t);
                        if (_regions.Count == 0)
                        {
                            ErrorSink.Warning(t.ToSourceRange(SourceFile), "#endregion without matching #region");
                        }
                        else
                        {
                            _regions.Pop();
                        }
                        continue;

                    case TokenType.PPline:
                        _triviaList.Add(new Token(t.TypeInt, t.StartIndex, Lexer.InputPosition));
                        var rest = ReadRestAsTokenTree();
                        // TODO: use LineRemapper
                        ErrorSink.Write(Severity.Note, t.ToSourceRange(SourceFile), "Support for #line is not implemented");
                        continue;

                    case TokenType.PPpragma:
                        _triviaList.Add(new Token(t.TypeInt, t.StartIndex, Lexer.InputPosition));
                        var rest_ = ReadRestAsTokenTree();
                        // TODO
                        ErrorSink.Write(Severity.Note, t.ToSourceRange(SourceFile), "Support for #pragma is not implemented");
                        continue;
                    }
                }
                return(t_);
            } while (true);
            // end of stream
            if (_ifRegions.Count > 0)
            {
                ErrorSink.Error(_ifRegions.Peek().A.ToSourceRange(SourceFile), "#if without matching #endif");
            }
            if (_regions.Count > 0)
            {
                ErrorSink.Warning(_regions.Peek().ToSourceRange(SourceFile), "#region without matching #endregion");
            }
            return(Maybe <Token> .NoValue);
        }