/* At this point, we have consumed the first M_PASTE. * @see Macro#addPaste(Token) */ private void paste(Token ptok) { StringBuilder buf = new StringBuilder(); Token err = null; /* We know here that arg is null or expired, * since we cannot paste an expanded arg. */ int count = 2; for (int i = 0; i < count; i++) { if (!tokens.hasNext()) { /* XXX This one really should throw. */ error(ptok.getLine(), ptok.getColumn(), "Paste at end of expansion"); buf.append(' ').append(ptok.getText()); break; } Token tok = tokens.next(); // System.out.println("Paste " + tok); switch (tok.getType()) { case Token.M_PASTE: /* One extra to paste, plus one because the * paste token didn't count. */ count += 2; ptok = tok; break; case Token.M_ARG: int idx = (int)tok.getValue(); concat(buf, args.get(idx)); break; /* XXX Test this. */ case Token.CCOMMENT: case Token.CPPCOMMENT: break; default: buf.append(tok.getText()); break; } } /* Push and re-lex. */ /* * StringBuilder src = new StringBuilder(); * escape(src, buf); * StringLexerSource sl = new StringLexerSource(src.toString()); */ StringLexerSource sl = new StringLexerSource(buf.toString()); /* XXX Check that concatenation produces a valid token. */ arg = new SourceIterator(sl); }
/* At this point, we have consumed the first M_PASTE. * @see Macro#addPaste(Token) */ private void paste(Token ptok) { StringBuilder buf = new StringBuilder(); Token err = null; /* We know here that arg is null or expired, * since we cannot paste an expanded arg. */ int count = 2; for (int i = 0; i < count; i++) { if (!tokens.hasNext()) { /* XXX This one really should throw. */ error(ptok.getLine(), ptok.getColumn(), "Paste at end of expansion"); buf.append(' ').append(ptok.getText()); break; } Token tok = tokens.next(); // System.out.println("Paste " + tok); switch (tok.getType()) { case Token.M_PASTE: /* One extra to paste, plus one because the * paste token didn't count. */ count += 2; ptok = tok; break; case Token.M_ARG: int idx = (int)tok.getValue(); concat(buf, args.get(idx)); break; /* XXX Test this. */ case Token.CCOMMENT: case Token.CPPCOMMENT: break; default: buf.append(tok.getText()); break; } } /* Push and re-lex. */ /* StringBuilder src = new StringBuilder(); escape(src, buf); StringLexerSource sl = new StringLexerSource(src.toString()); */ StringLexerSource sl = new StringLexerSource(buf.toString()); /* XXX Check that concatenation produces a valid token. */ arg = new SourceIterator(sl); }
/** * Defines the given name as a macro. * * The String value is lexed into a token stream, which is * used as the macro expansion. */ public void addMacro(String name, String value) { try { Macro m = new Macro(name); StringLexerSource s = new StringLexerSource(value); for (;;) { Token tok = s.token(); if(tok.getType() == Token.EOF) break; m.addToken(tok); } addMacro(m); } catch (IOException e) { throw new LexerException(e); } }
/// <summary> /// Preprocesses the provided shader or effect source. /// </summary> /// <param name="shaderSource">An array of bytes containing the raw source of the shader or effect to preprocess.</param> /// <param name="sourceFileName">Name of the source file.</param> /// <param name="defines">A set of macros to define during preprocessing.</param> /// <param name="includeDirectories">The include directories used by the preprocessor.</param> /// <returns> /// The preprocessed shader source. /// </returns> public static string Run(string shaderSource, string sourceFileName, ShaderMacro[] defines = null, params string[] includeDirectories) { var cpp = new Preprocessor(); cpp.addFeature(Feature.DIGRAPHS); cpp.addWarning(Warning.IMPORT); cpp.addFeature(Feature.INCLUDENEXT); cpp.addFeature(Feature.LINEMARKERS); // TODO: Handle warning and errors properly instead of relying only on exception // Don't setup a listener and get any errors via exceptions cpp.setListener(new ErrorListener()); // Pass defines if (defines != null) { foreach (var define in defines) { if (!string.IsNullOrWhiteSpace(define.Name)) { cpp.addMacro(define.Name, define.Definition ?? string.Empty); } } } // Setup input directories. var tempDirectories = new List<string>() { Path.GetDirectoryName(sourceFileName) }; tempDirectories.AddRange(includeDirectories); cpp.setQuoteIncludePath(tempDirectories); var inputSource = new StringLexerSource(shaderSource, true, sourceFileName); cpp.addInput(inputSource); var textBuilder = new StringBuilder(); var isEndOfStream = false; while (!isEndOfStream) { Token tok = cpp.token(); switch (tok.getType()) { case Token.EOF: isEndOfStream = true; break; case Token.CCOMMENT: var strComment = tok.getText() ?? string.Empty; foreach (var commentChar in strComment) { textBuilder.Append(commentChar == '\n' ? '\n' : ' '); } break; case Token.CPPCOMMENT: break; default: var tokenText = tok.getText(); if (tokenText != null) { textBuilder.Append(tokenText); } break; } } return textBuilder.ToString(); }