// pp-newline
private PPNode parsePreprocessorDirective() throws FeatureNotSupportedException {
        PPNode result = null;
        int startLine = lineCount;
        inPPDirective = true;
        advance(); // over hash
        IdentifierExpression ie = parseIdentifierOrKeyword();
        String ppKind = ie.Identifier[0];
        byte id = PreprocessorID.Empty;
        if (preprocessor.containsKey(ppKind)) {
            id = preprocessor.get(ppKind);
        } else {
            ReportError("Preprocessor directive must be valid identifier, rather than \"" + ppKind + "\".");
        }
        switch (id) {
            case PreprocessorID.Define:
                // conditional-symbol pp-newline
                IdentifierExpression def = parseIdentifierOrKeyword();
                if (!ppDefs.containsKey(def.Identifier[0])) {
                    ppDefs.put(def.Identifier[0], PreprocessorID.Empty);
                }
                result = new PPDefineNode(def);
                break;
            case PreprocessorID.Undef:
                // conditional-symbol pp-newline
                IdentifierExpression undef = parseIdentifierOrKeyword();
                if (ppDefs.containsKey(undef.Identifier[0])) {
                    ppDefs.remove(undef.Identifier[0]);
                }
                result = new PPDefineNode(undef);
                break;
            case PreprocessorID.If:
                // pp-expression pp-newline conditional-section(opt)
                if (curtok.id == TokenID.LParen) {
                    advance();
                }
                int startCount = lineCount;
                ppCondition = false;
                // todo: account for true, false, ||, &&, ==, !=, !
                IdentifierExpression ifexpr = parseIdentifierOrKeyword();
                if (ppDefs.containsKey(ifexpr.Identifier[0])) {
                    ppCondition = true;
                }
                //result = new PPIfNode(ParseExpressionToNewline());
                if (curtok.id == TokenID.RParen) {
                    advance();
                }
                if (ppCondition == false) {
                    // skip this block
                    SkipToElseOrEndIf();
                }
                break;
            case PreprocessorID.Elif:
                // pp-expression pp-newline conditional-section(opt)
                SkipToEOL(startLine);
                break;
            case PreprocessorID.Else:
                // pp-newline conditional-section(opt)
                if (ppCondition == true) {
                    // skip this block
                    SkipToElseOrEndIf();
                }
                break;
            case PreprocessorID.Endif:
                // pp-newline
                result = new PPEndIfNode();
                ppCondition = false;
                break;
            case PreprocessorID.Line:
                // line-indicator pp-newline
                SkipToEOL(startLine);
                break;
            case PreprocessorID.Error:
                // pp-message
                SkipToEOL(startLine);
                break;
            case PreprocessorID.Warning:
                // pp-message
                SkipToEOL(startLine);
                break;
            case PreprocessorID.Region:
                // pp-message
                SkipToEOL(startLine);
                break;
            case PreprocessorID.Endregion:
                // pp-message
                SkipToEOL(startLine);
                break;
            case PreprocessorID.Pragma:
                // pp-message
                SkipToEOL(startLine);
                break;
            default:
                break;
        }
        inPPDirective = false;
        return result;
    }
break;
case PreprocessorID.Else:
// pp-newline conditional-section(opt)
if (ppCondition == true) {
// skip this block
if (ppCondition == false) {
// skip this block
SkipToElseOrEndIf();
}
break;
case PreprocessorID.Elif:
// pp-expression pp-newline conditional-section(opt)
SkipToEOL(startLine);
break;
case PreprocessorID.Else:
// pp-newline conditional-section(opt)
if (ppCondition == true) {
// skip this block
SkipToElseOrEndIf();
}
break;
case PreprocessorID.Endif:
// pp-newline
result = new PPEndIfNode();
ppCondition = false;
break;
ppCondition = false;
// todo: account for true, false, ||, &&, ==, !=, !
IdentifierExpression ifexpr = parseIdentifierOrKeyword();
if (ppDefs.containsKey(ifexpr.Identifier[0])) {
ppCondition = true;
}
//result = new PPIfNode(ParseExpressionToNewline());
if (curtok.id == TokenID.RParen) {
advance();
}
if (ppCondition == false) {
// skip this block
SkipToElseOrEndIf();
}
break;
case PreprocessorID.Elif:
// pp-expression pp-newline conditional-section(opt)
SkipToEOL(startLine);
break;
case PreprocessorID.Else:
// pp-newline conditional-section(opt)
if (ppCondition == true) {
// skip this block
SkipToElseOrEndIf();
}
break;
case PreprocessorID.Endif:
// pp-newline
result = new PPEndIfNode();
ppCondition = false;
break;
case PreprocessorID.Line:
// line-indicator pp-newline
SkipToEOL(startLine);
break;
case PreprocessorID.Error:
// pp-message
SkipToEOL(startLine);
break;
case PreprocessorID.Warning:
// pp-message