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); }