/// <summary> /// Parse a shader source. /// </summary> /// <param name="source"> /// A <see cref="String"/> that specify the shader source text. It can contains multiple lines. /// </param> /// <returns> /// It returns the result of preprocessing of <paramref name="source"/>. /// </returns> public static List<string> Process(List<string> source) { Context ctx = new Context(); List<string> processedSource = new List<string>(); for (int sourceLineNumber = 0; sourceLineNumber < source.Count; sourceLineNumber++) { Match directiveMatch; string sourceLine = source[sourceLineNumber]; if ((directiveMatch = _RegexDirective.Match(sourceLine)).Success) { StringBuilder sb = new StringBuilder(); do { // Concatenate backslashed new line sb.AppendLine(sourceLine); // End of lines? if (++sourceLineNumber < source.Count) break; // Next line sourceLine = source[++sourceLineNumber]; } while (sourceLine.TrimEnd().EndsWith(@"\")); // Replace backslash-newline with newlines sourceLine = _RegexBackslashNewline.Replace(sb.ToString(), "\n"); // Remove C++ comments (still preserve new lines) sourceLine = _RegexCppComment.Replace(sourceLine, " "); // Remove C comments (still preserve new lines, except the commented ones) sourceLine = _RegexCComment.Replace(sourceLine, " "); // Build a single long directive line (discards new lines) sourceLine = _RegexNewline.Replace(sourceLine, String.Empty); // Parse preprocessor directive string directive = directiveMatch.Groups["Directive"].Value; if (directive == "define") { ParseDefineDirective(ctx, sourceLine); } else if (directive == "undef") { ParseUndef(ctx, sourceLine); } else if (directive == "if") { Context.ConditionalState conditionalState = new Context.ConditionalState(); conditionalState.ActiveBranch = ParseIntegerConditional(ctx, sourceLine); } else if (directive == "elif") { if (ctx.ConditionalNesting.Count == 0) throw new InvalidOperationException("#elif directive without matching #if"); Context.ConditionalState conditionalState = ctx.ConditionalNesting.Peek(); if (conditionalState.HadElseBranch) throw new InvalidOperationException("#elif directive after matching #else"); // Evaluate condition bool active = ParseIntegerConditional(ctx, sourceLine); if (conditionalState.HadActiveBranch == false) conditionalState.ActiveBranch = active; } else if ((directive == "ifdef") || (directive == "ifndef")) { Context.ConditionalState conditionalState = new Context.ConditionalState(); conditionalState.ActiveBranch = ParseSymbolConditional(ctx, sourceLine); } else if (directive == "else") { if (ctx.ConditionalNesting.Count == 0) throw new InvalidOperationException("#else directive without matching #if"); Context.ConditionalState conditionalState = ctx.ConditionalNesting.Peek(); if (conditionalState.HadElseBranch) throw new InvalidOperationException("multiple #else directive for matching #if"); conditionalState.HadElseBranch = true; conditionalState.ActiveBranch = !conditionalState.HadActiveBranch; } else if (directive == "endif") { if (ctx.ConditionalNesting.Count == 0) throw new InvalidOperationException("#endif directive without matching #if"); // Remove last branching state ctx.ConditionalNesting.Pop(); } else if (directive == "include") { } else throw new InvalidOperationException("unknown preprocessor directive"); // Append source line processedSource.Add(sourceLine); } else { // Append source line processedSource.Add(sourceLine); } } return (processedSource); }
/// <summary> /// Parse a shader source. /// </summary> /// <param name="source"> /// A <see cref="String"/> that specify the shader source text. It can contains multiple lines. /// </param> /// <returns> /// It returns the result of preprocessing of <paramref name="source"/>. /// </returns> public static List <string> Process(List <string> source) { Context ctx = new Context(); List <string> processedSource = new List <string>(); for (int sourceLineNumber = 0; sourceLineNumber < source.Count; sourceLineNumber++) { Match directiveMatch; string sourceLine = source[sourceLineNumber]; if ((directiveMatch = _RegexDirective.Match(sourceLine)).Success) { StringBuilder sb = new StringBuilder(); do { // Concatenate backslashed new line sb.AppendLine(sourceLine); // End of lines? if (++sourceLineNumber < source.Count) { break; } // Next line sourceLine = source[++sourceLineNumber]; } while (sourceLine.TrimEnd().EndsWith(@"\")); // Replace backslash-newline with newlines sourceLine = _RegexBackslashNewline.Replace(sb.ToString(), "\n"); // Remove C++ comments (still preserve new lines) sourceLine = _RegexCppComment.Replace(sourceLine, " "); // Remove C comments (still preserve new lines, except the commented ones) sourceLine = _RegexCComment.Replace(sourceLine, " "); // Build a single long directive line (discards new lines) sourceLine = _RegexNewline.Replace(sourceLine, String.Empty); // Parse preprocessor directive string directive = directiveMatch.Groups["Directive"].Value; if (directive == "define") { ParseDefineDirective(ctx, sourceLine); } else if (directive == "undef") { ParseUndef(ctx, sourceLine); } else if (directive == "if") { Context.ConditionalState conditionalState = new Context.ConditionalState(); conditionalState.ActiveBranch = ParseIntegerConditional(ctx, sourceLine); } else if (directive == "elif") { if (ctx.ConditionalNesting.Count == 0) { throw new InvalidOperationException("#elif directive without matching #if"); } Context.ConditionalState conditionalState = ctx.ConditionalNesting.Peek(); if (conditionalState.HadElseBranch) { throw new InvalidOperationException("#elif directive after matching #else"); } // Evaluate condition bool active = ParseIntegerConditional(ctx, sourceLine); if (conditionalState.HadActiveBranch == false) { conditionalState.ActiveBranch = active; } } else if ((directive == "ifdef") || (directive == "ifndef")) { Context.ConditionalState conditionalState = new Context.ConditionalState(); conditionalState.ActiveBranch = ParseSymbolConditional(ctx, sourceLine); } else if (directive == "else") { if (ctx.ConditionalNesting.Count == 0) { throw new InvalidOperationException("#else directive without matching #if"); } Context.ConditionalState conditionalState = ctx.ConditionalNesting.Peek(); if (conditionalState.HadElseBranch) { throw new InvalidOperationException("multiple #else directive for matching #if"); } conditionalState.HadElseBranch = true; conditionalState.ActiveBranch = !conditionalState.HadActiveBranch; } else if (directive == "endif") { if (ctx.ConditionalNesting.Count == 0) { throw new InvalidOperationException("#endif directive without matching #if"); } // Remove last branching state ctx.ConditionalNesting.Pop(); } else if (directive == "include") { } else { throw new InvalidOperationException("unknown preprocessor directive"); } // Append source line processedSource.Add(sourceLine); } else { // Append source line processedSource.Add(sourceLine); } } return(processedSource); }