Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
PreprocessorHelper.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System.Linq;
4 using System.Text;
5 using System.Text.RegularExpressions;
6 using SiliconStudio.Shaders;
7 using SiliconStudio.Shaders.Parser;
8 
9 namespace SiliconStudio.Paradox.VisualStudio.Commands.Shaders
10 {
11  public class PreprocessorHelper
12  {
13  private static Regex concatenateTokensRegex = new Regex(@"(\w+)?\s*#(#)?\s*(\w+)");
14 
15  private static string[] preprocessorKeywords = new[] { "if", "else", "elif", "endif", "define", "undef", "ifdef", "ifndef", "line", "error", "pragma", "include" };
16 
17  private static string TransformToken(string token, ShaderMacro[] macros = null, bool emptyIfNotFound = false)
18  {
19  if (macros == null) return token;
20 
21  foreach (var macro in macros)
22  {
23  if (macro.Name == token) return macro.Definition;
24  }
25 
26  return emptyIfNotFound ? string.Empty : token;
27  }
28 
29  private static string EscapeString(string s)
30  {
31  return s.Replace("\\", "\\\\").Replace("\"", "\\\"");
32  }
33 
34  private static string ConcatenateTokens(string source, ShaderMacro[] macros = null)
35  {
36  var stringBuilder = new StringBuilder(source.Length);
37  int position = 0;
38 
39  // Process every A ## B ## C ## ... patterns
40  // Find first match
41  var match = concatenateTokensRegex.Match(source, position);
42 
43  // Early exit
44  if (!match.Success) return source;
45 
46  while (match.Success)
47  {
48  // Add what was before regex
49  stringBuilder.Append(source, position, match.Index - position);
50 
51  // Check if # (stringify) or ## (concat)
52  bool stringify = !match.Groups[2].Success;
53 
54  var token = match.Groups[3].Value;
55  if (stringify && preprocessorKeywords.Contains(token))
56  {
57  // Ignore some special preprocessor tokens
58  stringBuilder.Append(match.Groups[0].Value);
59  }
60  else
61  {
62  // Expand and add first macro
63  stringBuilder.Append(TransformToken(match.Groups[1].Value, macros));
64 
65 
66  if (stringify) // stringification
67  {
68  stringBuilder.Append('"');
69  // TODO: Escape string
70  stringBuilder.Append(EscapeString(TransformToken(token, macros, true)));
71  stringBuilder.Append('"');
72  }
73  else // concatenation
74  {
75  stringBuilder.Append(TransformToken(match.Groups[3].Value, macros));
76  }
77  }
78 
79  // Find next match
80  position = match.Groups[3].Index + match.Groups[3].Length;
81  match = concatenateTokensRegex.Match(source, position);
82  }
83 
84  // Add what is after regex
85  stringBuilder.Append(source, position, source.Length - position);
86 
87  return stringBuilder.ToString();
88  }
89 
90  public static string Preprocess(string shaderSource, string filename, ShaderMacro[] macros)
91  {
92  // Preprocess
93  // First, perform token concatenation (not supported by D3DX)
94  // Check for either TOKEN ## or ## TOKEN
95  var preprocessedSource = ConcatenateTokens(shaderSource, macros);
96  return PreProcessor.Run(preprocessedSource, filename, macros);
97  }
98  }
99 }
Macro to be used with PreProcessor.
Definition: ShaderMacro.cs:11
function s(a)
static string Preprocess(string shaderSource, string filename, ShaderMacro[] macros)