/// <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);
		}
Ejemplo n.º 2
0
        /// <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);
        }