diff --git a/Install/Linux/README.txt b/Install/Linux/README.txt index fc5651c9..06e78a89 100644 --- a/Install/Linux/README.txt +++ b/Install/Linux/README.txt @@ -2,12 +2,12 @@ This directory contains linux binaries for the glslang validator. The main executable is glslangValidator, which requires use of the shared object file libglsang.so. -Installation: Executing the ./install script will copy these to /usr/local/* -so that they may be executed from any directory. - -Alternatively, you may put them where you wish, but will then need to use -something like: - +Installation: Executing the ./install script will copy these to /usr/local/* +so that they may be executed from any directory. + +Alternatively, you may put them where you wish, but will then need to use +something like: + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH: Usage: Execute glslangValidator with no arguments to get a usage statement. diff --git a/Install/Windows/glslangValidator.exe b/Install/Windows/glslangValidator.exe index 0dc01f9b..9e288e73 100644 Binary files a/Install/Windows/glslangValidator.exe and b/Install/Windows/glslangValidator.exe differ diff --git a/README.txt b/README.txt index e50c9026..3a2fe298 100644 --- a/README.txt +++ b/README.txt @@ -66,22 +66,54 @@ shell. Note: Despite appearances, the use of a DLL is currently disabled; it simply makes a standalone executable from a statically linked library. -Basic external programmatic interface -------------------------------------- +Programmatic Interfaces +----------------------- Another piece of software can programmatically translate shaders to an AST -using the C-style ShInitialize(), ShCompile(), et. al. interface. The main() in -StandAlone/StandAlone.cpp shows an example way of using these. +using one of two different interfaces: + - A new C++ class-oriented interface, or + - The original C functional interface -The Sh*() interface takes a "compiler" call-back object, which it calls after -building call back that is passed the AST and can then execute a backend on it. +The main() in StandAlone/StandAlone.cpp shows examples using both styles. -The following is a simplified resulting run-time call stack: +C++ Class Interface (new, preferred): - ShCompile(shader, compiler) -> compiler(AST) -> + This interface is in roughly the last 1/3 of ShaderLang.h. It is in the + glslang namespace and contains the following. -In practice, ShCompile() takes shader strings, default version, and -warning/error and other options for controling compilation. + const char* GetEsslVersionString(); + const char* GetGlslVersionString(); + bool InitializeProcess(); + void FinalizeProcess(); + + class TShader + bool parse(...); + void setStrings(...); + const char* getInfoLog(); + + class TProgram + void addShader(...); + bool link(...); + const char* getInfoLog(); + Reflection queries + + See ShaderLang.h and the usage of it in StandAlone/StandAlone.cpp for more + details. + +C Functional Interface (orginal): + + This interface is in roughly the first 2/3 of ShaderLang.h, and referred to + as the Sh*() interface, as all the entry points start "Sh". + + The Sh*() interface takes a "compiler" call-back object, which it calls after + building call back that is passed the AST and can then execute a backend on it. + + The following is a simplified resulting run-time call stack: + + ShCompile(shader, compiler) -> compiler(AST) -> + + In practice, ShCompile() takes shader strings, default version, and + warning/error and other options for controling compilation. Testing ------- @@ -100,7 +132,7 @@ missing, those tests just won't run. Basic Internal Operation ------------------------ - - Initial lexical analysis is done be the preprocessor in + - Initial lexical analysis is done by the preprocessor in MachineIndependent/Preprocessor, and then refined by a GLSL scanner in MachineIndependent/Scan.cpp. There is currently no use of flex. diff --git a/Test/baseResults/cppSimple.vert.out b/Test/baseResults/cppSimple.vert.out index a19885cd..2f542d63 100644 --- a/Test/baseResults/cppSimple.vert.out +++ b/Test/baseResults/cppSimple.vert.out @@ -67,12 +67,15 @@ ERROR: 7:14014: '#error' : line should be 14014 , string 7 ERROR: 12:14014: '#error' : line should be 14014 , string 12 ERROR: 12:14026: '#error' : line should be 14026 , string 12 ERROR: 12:1234: '#line' : unexpected tokens following directive +ERROR: 12:1237: '#line' : unexpected tokens following directive ERROR: 12:20001: '#error' : line should be 20001 ERROR: 12:20011: '#error' : line should be 20011 ERROR: 12:20021: '#error' : line should be 20021 ERROR: 12:20046: '#define' : Macro redefined; different substitutions: SPACE_IN_MIDDLE +ERROR: 12:20052: '#error' : good evaluation 1 +ERROR: 12:20056: '#error' : good evaluation 2 ERROR: 12:10003: '' : missing #endif -ERROR: 72 compilation errors. No code generated. +ERROR: 75 compilation errors. No code generated. ERROR: node is still EOpNull! diff --git a/Test/cppSimple.vert b/Test/cppSimple.vert index 8f1f8cb6..006d9ed7 100644 --- a/Test/cppSimple.vert +++ b/Test/cppSimple.vert @@ -251,11 +251,18 @@ double f = f1; #define F2 7 #line L1 + L2 #error line should be 14014, string 7 -#line L1 + L2 F1 + F2 +#line L1 + L2 F1 + F2 // antoeuh sat comment #error line should be 14014, string 12 #line L1 + L2 + F1 + F2 #error line should be 14026, string 12 #line 1234 F1 + F2 extra +#define empty_extra +#line 1235 F1 + F2 empty_extra +#define moreEmpty empty_extra +#line 1236 F1 + F2 moreEmpty empty_extra // okay, lots of nothin +#line 1237 F1 + F2 moreEmpty empty_extra extra // ERROR, 'extra' +#line 1238 F1 + F2 moreEmpty empty_extra +#line 1239 empty_extra F1 empty_extra + empty_extra F2 empty_extra moreEmpty empty_extra #line (20000) #error line should be 20001 #line (20000+10) @@ -288,6 +295,17 @@ void foo234() #define SPACE_IN_MIDDLE(a,b) space +in middle #define SPACE_IN_MIDDLE(a,b) space + in middle +#define FIRSTPART 17 +#define SECONDPART + 5 + +#if FIRSTPART SECONDPART == 22 +#error good evaluation 1 +#endif + +#if moreEmpty FIRSTPART moreEmpty SECONDPART moreEmpty == moreEmpty 22 moreEmpty +#error good evaluation 2 +#endif + #line 10000 #if 1 #else diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h index 5982b3fc..f974ed04 100644 --- a/glslang/Include/revision.h +++ b/glslang/Include/revision.h @@ -9,5 +9,5 @@ // source have to figure out how to create revision.h just to get a build // going. However, if it is not updated, it can be a version behind. -#define GLSLANG_REVISION "24400" -#define GLSLANG_DATE "2013/12/06 17:28:07" +#define GLSLANG_REVISION "24406" +#define GLSLANG_DATE "2013/12/08 17:37:46" diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp index 730ffe96..7b5a01cb 100644 --- a/glslang/MachineIndependent/ShaderLang.cpp +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -376,7 +376,7 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo } // A metecheck on the condition the compiler itself... - switch(version) { + switch (version) { case 100: case 300: diff --git a/glslang/MachineIndependent/preprocessor/Pp.cpp b/glslang/MachineIndependent/preprocessor/Pp.cpp index 9214c7fd..7fa5b929 100644 --- a/glslang/MachineIndependent/preprocessor/Pp.cpp +++ b/glslang/MachineIndependent/preprocessor/Pp.cpp @@ -473,28 +473,8 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo token = currentInput->scan(this, currentInput, ppToken); } } else { - int macroReturn = MacroExpand(ppToken->atom, ppToken, 1); - if (macroReturn == 0) { - parseContext.error(ppToken->loc, "can't evaluate expression", "preprocessor evaluation", ""); - err = true; - res = 0; - - return token; - } else { - if (macroReturn == -1) { - if (! shortCircuit && parseContext.profile == EEsProfile) { - const char* message = "undefined macro in expression not allowed in es profile"; - const char* name = GetAtomString(ppToken->atom); - if (parseContext.messages & EShMsgRelaxedErrors) - parseContext.warn(ppToken->loc, message, "preprocessor evaluation", name); - else - parseContext.error(ppToken->loc, message, "preprocessor evaluation", name); - } - } - token = currentInput->scan(this, currentInput, ppToken); - - return eval(token, precedence, shortCircuit, res, err, ppToken); - } + token = evalToToken(token, shortCircuit, res, err, ppToken); + return eval(token, precedence, shortCircuit, res, err, ppToken); } } else if (token == CPP_INTCONSTANT) { res = ppToken->ival; @@ -530,6 +510,10 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo return token; } } + + token = evalToToken(token, shortCircuit, res, err, ppToken); + + // Perform evaluation of binary operation, if there is one, otherwise we are done. while (! err) { if (token == ')' || token == '\n') break; @@ -558,6 +542,33 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo return token; } +// Expand macros, skipping empty expansions, to get to the first real token in those expansions. +int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken* ppToken) +{ + while (token == CPP_IDENTIFIER && ppToken->atom != definedAtom) { + int macroReturn = MacroExpand(ppToken->atom, ppToken, true); + if (macroReturn == 0) { + parseContext.error(ppToken->loc, "can't evaluate expression", "preprocessor evaluation", ""); + err = true; + res = 0; + break; + } + if (macroReturn == -1) { + if (! shortCircuit && parseContext.profile == EEsProfile) { + const char* message = "undefined macro in expression not allowed in es profile"; + const char* name = GetAtomString(ppToken->atom); + if (parseContext.messages & EShMsgRelaxedErrors) + parseContext.warn(ppToken->loc, message, "preprocessor evaluation", name); + else + parseContext.error(ppToken->loc, message, "preprocessor evaluation", name); + } + } + token = currentInput->scan(this, currentInput, ppToken); + } + + return token; +} + // Handle #if int TPpContext::CPPif(TPpToken* ppToken) { @@ -612,6 +623,10 @@ int TPpContext::CPPifdef(int defined, TPpToken* ppToken) // Handle #line int TPpContext::CPPline(TPpToken* ppToken) { + // "#line must have, after macro substitution, one of the following forms: + // "#line line + // "#line line source-string-number" + int token = currentInput->scan(this, currentInput, ppToken); if (token == '\n') { parseContext.error(ppToken->loc, "must by followed by an integral literal", "#line", ""); @@ -633,6 +648,7 @@ int TPpContext::CPPline(TPpToken* ppToken) parseContext.setCurrentString(fileRes); } } + token = extraTokenCheck(lineAtom, ppToken, token); return token; @@ -886,7 +902,7 @@ TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream *a, TPpToken* p PushEofSrc(); ReadFromTokenStream(a, 0, 0); while ((token = currentInput->scan(this, currentInput, ppToken)) > 0) { - if (token == CPP_IDENTIFIER && MacroExpand(ppToken->atom, ppToken, 0) == 1) + if (token == CPP_IDENTIFIER && MacroExpand(ppToken->atom, ppToken, false) == 1) continue; RecordToken(n, token, ppToken); } @@ -952,13 +968,13 @@ int TPpContext::zero_scan(TPpContext* pp, InputSrc *inInput, TPpToken* ppToken) /* ** Check an identifier (atom) to see if it is a macro that should be expanded. -** If it is, push an InputSrc that will produce the appropriate expansion +** If it is, and defined, push an InputSrc that will produce the appropriate expansion ** and return 1. -** If it is, but undefined, it should expand to 0, push an InputSrc that will +** If it is, but undefined, and expandUndef is requested, push an InputSrc that will ** expand to 0 and return -1. ** Otherwise, return 0. */ -int TPpContext::MacroExpand(int atom, TPpToken* ppToken, int expandUndef) +int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef) { Symbol *sym = LookUpSymbol(atom); MacroInputSrc *in; diff --git a/glslang/MachineIndependent/preprocessor/PpContext.h b/glslang/MachineIndependent/preprocessor/PpContext.h index 4fc2c87f..81dbe9c0 100644 --- a/glslang/MachineIndependent/preprocessor/PpContext.h +++ b/glslang/MachineIndependent/preprocessor/PpContext.h @@ -247,6 +247,7 @@ protected: int CPPelse(int matchelse, TPpToken * ppToken); int extraTokenCheck(int atom, TPpToken* ppToken, int token); int eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken * ppToken); + int evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken * ppToken); int CPPif (TPpToken * ppToken); int CPPifdef(int defined, TPpToken * ppToken); int CPPline(TPpToken * ppToken); @@ -260,7 +261,7 @@ protected: TokenStream* PrescanMacroArg(TokenStream *a, TPpToken * ppToken); static int macro_scan(TPpContext* pp, InputSrc *inInput, TPpToken * ppToken); static int zero_scan(TPpContext* pp, InputSrc *inInput, TPpToken * ppToken); - int MacroExpand(int atom, TPpToken* ppToken, int expandUndef); + int MacroExpand(int atom, TPpToken* ppToken, bool expandUndef); // // from PpSymbols.cpp diff --git a/glslang/MachineIndependent/preprocessor/PpScanner.cpp b/glslang/MachineIndependent/preprocessor/PpScanner.cpp index d29ac10e..1add7a27 100644 --- a/glslang/MachineIndependent/preprocessor/PpScanner.cpp +++ b/glslang/MachineIndependent/preprocessor/PpScanner.cpp @@ -744,7 +744,7 @@ const char* TPpContext::tokenize(TPpToken* ppToken) continue; // expand macros - if (token == CPP_IDENTIFIER && MacroExpand(ppToken->atom, ppToken, 0) == 1) + if (token == CPP_IDENTIFIER && MacroExpand(ppToken->atom, ppToken, false) == 1) continue; if (token == CPP_IDENTIFIER)