Preprocessor: Implement skipping of macros that evaluate to nothing while evaluating expressions. They had been causing early termination of an expression's evaluation.
Also includes some unrelated updates of documentation. git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@24420 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
Binary file not shown.
42
README.txt
42
README.txt
@@ -66,12 +66,44 @@ shell.
|
|||||||
Note: Despite appearances, the use of a DLL is currently disabled; it
|
Note: Despite appearances, the use of a DLL is currently disabled; it
|
||||||
simply makes a standalone executable from a statically linked library.
|
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
|
Another piece of software can programmatically translate shaders to an AST
|
||||||
using the C-style ShInitialize(), ShCompile(), et. al. interface. The main() in
|
using one of two different interfaces:
|
||||||
StandAlone/StandAlone.cpp shows an example way of using these.
|
- A new C++ class-oriented interface, or
|
||||||
|
- The original C functional interface
|
||||||
|
|
||||||
|
The main() in StandAlone/StandAlone.cpp shows examples using both styles.
|
||||||
|
|
||||||
|
C++ Class Interface (new, preferred):
|
||||||
|
|
||||||
|
This interface is in roughly the last 1/3 of ShaderLang.h. It is in the
|
||||||
|
glslang namespace and contains the following.
|
||||||
|
|
||||||
|
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
|
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.
|
building call back that is passed the AST and can then execute a backend on it.
|
||||||
@@ -100,7 +132,7 @@ missing, those tests just won't run.
|
|||||||
Basic Internal Operation
|
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
|
MachineIndependent/Preprocessor, and then refined by a GLSL scanner
|
||||||
in MachineIndependent/Scan.cpp. There is currently no use of flex.
|
in MachineIndependent/Scan.cpp. There is currently no use of flex.
|
||||||
|
|
||||||
|
|||||||
@@ -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:14014: '#error' : line should be 14014 , string 12
|
||||||
ERROR: 12:14026: '#error' : line should be 14026 , string 12
|
ERROR: 12:14026: '#error' : line should be 14026 , string 12
|
||||||
ERROR: 12:1234: '#line' : unexpected tokens following directive
|
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:20001: '#error' : line should be 20001
|
||||||
ERROR: 12:20011: '#error' : line should be 20011
|
ERROR: 12:20011: '#error' : line should be 20011
|
||||||
ERROR: 12:20021: '#error' : line should be 20021
|
ERROR: 12:20021: '#error' : line should be 20021
|
||||||
ERROR: 12:20046: '#define' : Macro redefined; different substitutions: SPACE_IN_MIDDLE
|
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: 12:10003: '' : missing #endif
|
||||||
ERROR: 72 compilation errors. No code generated.
|
ERROR: 75 compilation errors. No code generated.
|
||||||
|
|
||||||
|
|
||||||
ERROR: node is still EOpNull!
|
ERROR: node is still EOpNull!
|
||||||
|
|||||||
@@ -251,11 +251,18 @@ double f = f1;
|
|||||||
#define F2 7
|
#define F2 7
|
||||||
#line L1 + L2
|
#line L1 + L2
|
||||||
#error line should be 14014, string 7
|
#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
|
#error line should be 14014, string 12
|
||||||
#line L1 + L2 + F1 + F2
|
#line L1 + L2 + F1 + F2
|
||||||
#error line should be 14026, string 12
|
#error line should be 14026, string 12
|
||||||
#line 1234 F1 + F2 extra
|
#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)
|
#line (20000)
|
||||||
#error line should be 20001
|
#error line should be 20001
|
||||||
#line (20000+10)
|
#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 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
|
#line 10000
|
||||||
#if 1
|
#if 1
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -9,5 +9,5 @@
|
|||||||
// source have to figure out how to create revision.h just to get a build
|
// 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.
|
// going. However, if it is not updated, it can be a version behind.
|
||||||
|
|
||||||
#define GLSLANG_REVISION "24400"
|
#define GLSLANG_REVISION "24406"
|
||||||
#define GLSLANG_DATE "2013/12/06 17:28:07"
|
#define GLSLANG_DATE "2013/12/08 17:37:46"
|
||||||
|
|||||||
@@ -473,29 +473,9 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo
|
|||||||
token = currentInput->scan(this, currentInput, ppToken);
|
token = currentInput->scan(this, currentInput, ppToken);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int macroReturn = MacroExpand(ppToken->atom, ppToken, 1);
|
token = evalToToken(token, shortCircuit, res, err, ppToken);
|
||||||
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);
|
return eval(token, precedence, shortCircuit, res, err, ppToken);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if (token == CPP_INTCONSTANT) {
|
} else if (token == CPP_INTCONSTANT) {
|
||||||
res = ppToken->ival;
|
res = ppToken->ival;
|
||||||
token = currentInput->scan(this, currentInput, ppToken);
|
token = currentInput->scan(this, currentInput, ppToken);
|
||||||
@@ -530,6 +510,10 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
token = evalToToken(token, shortCircuit, res, err, ppToken);
|
||||||
|
|
||||||
|
// Perform evaluation of binary operation, if there is one, otherwise we are done.
|
||||||
while (! err) {
|
while (! err) {
|
||||||
if (token == ')' || token == '\n')
|
if (token == ')' || token == '\n')
|
||||||
break;
|
break;
|
||||||
@@ -558,6 +542,33 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo
|
|||||||
return token;
|
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
|
// Handle #if
|
||||||
int TPpContext::CPPif(TPpToken* ppToken)
|
int TPpContext::CPPif(TPpToken* ppToken)
|
||||||
{
|
{
|
||||||
@@ -612,6 +623,10 @@ int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
|
|||||||
// Handle #line
|
// Handle #line
|
||||||
int TPpContext::CPPline(TPpToken* ppToken)
|
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);
|
int token = currentInput->scan(this, currentInput, ppToken);
|
||||||
if (token == '\n') {
|
if (token == '\n') {
|
||||||
parseContext.error(ppToken->loc, "must by followed by an integral literal", "#line", "");
|
parseContext.error(ppToken->loc, "must by followed by an integral literal", "#line", "");
|
||||||
@@ -633,6 +648,7 @@ int TPpContext::CPPline(TPpToken* ppToken)
|
|||||||
parseContext.setCurrentString(fileRes);
|
parseContext.setCurrentString(fileRes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
token = extraTokenCheck(lineAtom, ppToken, token);
|
token = extraTokenCheck(lineAtom, ppToken, token);
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
@@ -886,7 +902,7 @@ TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream *a, TPpToken* p
|
|||||||
PushEofSrc();
|
PushEofSrc();
|
||||||
ReadFromTokenStream(a, 0, 0);
|
ReadFromTokenStream(a, 0, 0);
|
||||||
while ((token = currentInput->scan(this, currentInput, ppToken)) > 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;
|
continue;
|
||||||
RecordToken(n, token, ppToken);
|
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.
|
** 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.
|
** 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.
|
** expand to 0 and return -1.
|
||||||
** Otherwise, return 0.
|
** 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);
|
Symbol *sym = LookUpSymbol(atom);
|
||||||
MacroInputSrc *in;
|
MacroInputSrc *in;
|
||||||
|
|||||||
@@ -247,6 +247,7 @@ protected:
|
|||||||
int CPPelse(int matchelse, TPpToken * ppToken);
|
int CPPelse(int matchelse, TPpToken * ppToken);
|
||||||
int extraTokenCheck(int atom, TPpToken* ppToken, int token);
|
int extraTokenCheck(int atom, TPpToken* ppToken, int token);
|
||||||
int eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken * ppToken);
|
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 CPPif (TPpToken * ppToken);
|
||||||
int CPPifdef(int defined, TPpToken * ppToken);
|
int CPPifdef(int defined, TPpToken * ppToken);
|
||||||
int CPPline(TPpToken * ppToken);
|
int CPPline(TPpToken * ppToken);
|
||||||
@@ -260,7 +261,7 @@ protected:
|
|||||||
TokenStream* PrescanMacroArg(TokenStream *a, TPpToken * ppToken);
|
TokenStream* PrescanMacroArg(TokenStream *a, TPpToken * ppToken);
|
||||||
static int macro_scan(TPpContext* pp, InputSrc *inInput, TPpToken * ppToken);
|
static int macro_scan(TPpContext* pp, InputSrc *inInput, TPpToken * ppToken);
|
||||||
static int zero_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
|
// from PpSymbols.cpp
|
||||||
|
|||||||
@@ -744,7 +744,7 @@ const char* TPpContext::tokenize(TPpToken* ppToken)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// expand macros
|
// expand macros
|
||||||
if (token == CPP_IDENTIFIER && MacroExpand(ppToken->atom, ppToken, 0) == 1)
|
if (token == CPP_IDENTIFIER && MacroExpand(ppToken->atom, ppToken, false) == 1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (token == CPP_IDENTIFIER)
|
if (token == CPP_IDENTIFIER)
|
||||||
|
|||||||
Reference in New Issue
Block a user