Improve preprocessor by using GLSL scanner, allowing read-only strings to be compiled, unifying of line # tracking, and correct detection that ES #version appeared after a comment.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23721 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2013-10-28 18:12:06 +00:00
parent 9497485e14
commit ea869fb403
20 changed files with 285 additions and 300 deletions

Binary file not shown.

View File

@ -92,12 +92,12 @@ ShBindingTable FixedAttributeTable = { 3, FixedAttributeBindings };
EShLanguage FindLanguage(const std::string& name); EShLanguage FindLanguage(const std::string& name);
bool CompileFile(const char *fileName, ShHandle, int options); bool CompileFile(const char *fileName, ShHandle, int options);
void usage(); void usage();
void FreeFileData(char **data); void FreeFileData(char** data);
char** ReadFileData(const char *fileName); char** ReadFileData(const char* fileName);
void InfoLogMsg(const char* msg, const char* name, const int num); void InfoLogMsg(const char* msg, const char* name, const int num);
// Use to test breaking up a single shader file into multiple strings. // Use to test breaking up a single shader file into multiple strings.
int NumShaderStrings = 1; int NumShaderStrings;
TBuiltInResource Resources; TBuiltInResource Resources;
std::string ConfigFile; std::string ConfigFile;
@ -205,7 +205,7 @@ void ProcessConfigFile()
char** configStrings = 0; char** configStrings = 0;
char *config = 0; char *config = 0;
if (ConfigFile.size() > 0) { if (ConfigFile.size() > 0) {
char** configStrings = ReadFileData(ConfigFile.c_str()); configStrings = ReadFileData(ConfigFile.c_str());
if (configStrings) if (configStrings)
config = *configStrings; config = *configStrings;
else { else {
@ -731,9 +731,11 @@ bool CompileFile(const char *fileName, ShHandle compiler, int Options)
for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) { for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
//ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, 100, false, messages); //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, 100, false, messages);
ret = ShCompile(compiler, shaderStrings, NumShaderStrings, 0, EShOptNone, &Resources, Options, 100, false, messages); ret = ShCompile(compiler, shaderStrings, NumShaderStrings, 0, EShOptNone, &Resources, Options, 100, false, messages);
//const char* multi[4] = { "# ve", "rsion", " 300 e", "s" }; //const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
// "or should be l", "ine 1", "string 5\n", "float glo", "bal",
// ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
//const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" }; //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
//ret = ShCompile(compiler, multi, 4, 0, EShOptNone, &Resources, Options, 100, false, messages); //ret = ShCompile(compiler, multi, 7, 0, EShOptNone, &Resources, Options, 100, false, messages);
} }
if (Options & EOptionMemoryLeakMode) if (Options & EOptionMemoryLeakMode)
@ -836,12 +838,13 @@ char** ReadFileData(const char *fileName)
} }
fdata[count] = '\0'; fdata[count] = '\0';
fclose(in); fclose(in);
if(count==0){ if (count == 0) {
return_data[0]=(char*)malloc(count+2); return_data[0]=(char*)malloc(count+2);
return_data[0][0]='\0'; return_data[0][0]='\0';
NumShaderStrings=0; NumShaderStrings = 0;
return return_data; return return_data;
} } else
NumShaderStrings = 1;
int len = (int)(ceil)((float)count/(float)NumShaderStrings); int len = (int)(ceil)((float)count/(float)NumShaderStrings);
int ptr_len=0,i=0; int ptr_len=0,i=0;

View File

@ -0,0 +1,30 @@
empty.frag
WARNING: #version: statement missing; use #version on first line of shader
0:? Sequence
0:? Linker Objects
empty2.frag
WARNING: #version: statement missing; use #version on first line of shader
0:? Sequence
0:? Linker Objects
empty3.frag
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:? Linker Objects
Linked fragment stage:
ERROR: Linking fragment stage: Cannot mix ES profile with non-ES profile shaders
ERROR: Linking fragment stage: Cannot mix ES profile with non-ES profile shaders
ERROR: Linking fragment stage: Missing entry point: Each stage requires one "void main()" entry point
0:? Sequence
0:? Linker Objects

View File

@ -1,5 +1,6 @@
ERROR: #version: statement must appear first in es-profile shader; before comments or newlines ERROR: #version: statement must appear first in es-profile shader; before comments or newlines
ERROR: 1 compilation errors. No code generated. ERROR: 0:34: '#version' : must occur first in shader
ERROR: 2 compilation errors. No code generated.
ERROR: node is still EOpNull! ERROR: node is still EOpNull!
0:41 Function Definition: main( (void) 0:41 Function Definition: main( (void)

0
Test/empty.frag Normal file
View File

1
Test/empty2.frag Normal file
View File

@ -0,0 +1 @@

1
Test/empty3.frag Normal file
View File

@ -0,0 +1 @@
#version 110

View File

@ -41,6 +41,7 @@ runLinkTest recurse1.vert recurse1.frag recurse2.frag
runLinkTest 300link.frag runLinkTest 300link.frag
runLinkTest 300link2.frag runLinkTest 300link2.frag
runLinkTest 300link3.frag runLinkTest 300link3.frag
runLinkTest empty.frag empty2.frag empty3.frag
# #
# multi-threaded test # multi-threaded test

View File

@ -35,6 +35,7 @@
// //
#include "ParseHelper.h" #include "ParseHelper.h"
#include "Scan.h"
#include "osinclude.h" #include "osinclude.h"
#include <stdarg.h> #include <stdarg.h>
@ -51,12 +52,10 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb,
intermediate(interm), symbolTable(symt), infoSink(is), language(L), intermediate(interm), symbolTable(symt), infoSink(is), language(L),
version(v), profile(p), forwardCompatible(fc), messages(m), version(v), profile(p), forwardCompatible(fc), messages(m),
contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0),
tokensBeforeEOF(false), tokensBeforeEOF(false), currentScanner(0),
numErrors(0), parsingBuiltins(pb), afterEOF(false) numErrors(0), parsingBuiltins(pb), afterEOF(false),
anyIndexLimits(false)
{ {
currentLoc.line = 1;
currentLoc.string = 0;
// ensure we always have a linkage node, even if empty, to simplify tree topology algorithms // ensure we always have a linkage node, even if empty, to simplify tree topology algorithms
linkage = new TIntermAggregate; linkage = new TIntermAggregate;
@ -106,43 +105,9 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb,
globalOutputDefaults.layoutStream = 0; globalOutputDefaults.layoutStream = 0;
} }
// void TParseContext::setLimits(const TLimits& L)
// Parse an array of strings using yyparse, going through the
// preprocessor to tokenize the shader strings, then through
// the GLSL scanner.
//
// Returns true for successful acceptance of the shader, false if any errors.
//
bool TParseContext::parseShaderStrings(TPpContext& ppContext, char* strings[], size_t lengths[], int numStrings)
{ {
// empty shaders are okay limits = L;
if (! strings || numStrings == 0 || lengths[0] == 0)
return true;
for (int i = 0; i < numStrings; ++i) {
if (! strings[i]) {
TSourceLoc loc;
loc.string = i;
loc.line = 1;
error(loc, "Null shader source string", "", "");
return false;
}
}
if (getPreamble())
ppContext.setPreamble(getPreamble(), strlen(getPreamble()));
ppContext.setShaderStrings(strings, lengths, numStrings);
// TODO: desktop PP: a shader containing nothing but white space and comments is valid, even though it has no parse tokens
size_t len = 0;
while (strings[0][len] == ' ' ||
strings[0][len] == '\t' ||
strings[0][len] == '\n' ||
strings[0][len] == '\r') {
if (++len >= lengths[0])
return true;
}
anyIndexLimits = ! limits.generalAttributeMatrixVectorIndexing || anyIndexLimits = ! limits.generalAttributeMatrixVectorIndexing ||
! limits.generalConstantMatrixVectorIndexing || ! limits.generalConstantMatrixVectorIndexing ||
@ -150,10 +115,21 @@ bool TParseContext::parseShaderStrings(TPpContext& ppContext, char* strings[], s
! limits.generalUniformIndexing || ! limits.generalUniformIndexing ||
! limits.generalVariableIndexing || ! limits.generalVariableIndexing ||
! limits.generalVaryingIndexing; ! limits.generalVaryingIndexing;
}
//
// Parse an array of strings using yyparse, going through the
// preprocessor to tokenize the shader strings, then through
// the GLSL scanner.
//
// Returns true for successful acceptance of the shader, false if any errors.
//
bool TParseContext::parseShaderStrings(TPpContext& ppContext, TInputScanner& input, bool versionWillBeError)
{
currentScanner = &input;
ppContext.setInput(input, versionWillBeError);
yyparse((void*)this); yyparse((void*)this);
finalErrorCheck();
finalize();
return numErrors == 0; return numErrors == 0;
} }
@ -163,21 +139,21 @@ void TParseContext::parserError(const char *s)
{ {
if (afterEOF) { if (afterEOF) {
if (tokensBeforeEOF == 1) if (tokensBeforeEOF == 1)
error(currentLoc, "", "pre-mature EOF", s, ""); error(getCurrentLoc(), "", "pre-mature EOF", s, "");
} else } else
error(currentLoc, "", "", s, ""); error(getCurrentLoc(), "", "", s, "");
} }
void TParseContext::handlePragma(const char **tokens, int numTokens) void TParseContext::handlePragma(const char **tokens, int numTokens)
{ {
if (!strcmp(tokens[0], "optimize")) { if (!strcmp(tokens[0], "optimize")) {
if (numTokens != 4) { if (numTokens != 4) {
error(currentLoc, "optimize pragma syntax is incorrect", "#pragma", ""); error(getCurrentLoc(), "optimize pragma syntax is incorrect", "#pragma", "");
return; return;
} }
if (strcmp(tokens[1], "(")) { if (strcmp(tokens[1], "(")) {
error(currentLoc, "\"(\" expected after 'optimize' keyword", "#pragma", ""); error(getCurrentLoc(), "\"(\" expected after 'optimize' keyword", "#pragma", "");
return; return;
} }
@ -186,22 +162,22 @@ void TParseContext::handlePragma(const char **tokens, int numTokens)
else if (!strcmp(tokens[2], "off")) else if (!strcmp(tokens[2], "off"))
contextPragma.optimize = false; contextPragma.optimize = false;
else { else {
error(currentLoc, "\"on\" or \"off\" expected after '(' for 'optimize' pragma", "#pragma", ""); error(getCurrentLoc(), "\"on\" or \"off\" expected after '(' for 'optimize' pragma", "#pragma", "");
return; return;
} }
if (strcmp(tokens[3], ")")) { if (strcmp(tokens[3], ")")) {
error(currentLoc, "\")\" expected to end 'optimize' pragma", "#pragma", ""); error(getCurrentLoc(), "\")\" expected to end 'optimize' pragma", "#pragma", "");
return; return;
} }
} else if (!strcmp(tokens[0], "debug")) { } else if (!strcmp(tokens[0], "debug")) {
if (numTokens != 4) { if (numTokens != 4) {
error(currentLoc, "debug pragma syntax is incorrect", "#pragma", ""); error(getCurrentLoc(), "debug pragma syntax is incorrect", "#pragma", "");
return; return;
} }
if (strcmp(tokens[1], "(")) { if (strcmp(tokens[1], "(")) {
error(currentLoc, "\"(\" expected after 'debug' keyword", "#pragma", ""); error(getCurrentLoc(), "\"(\" expected after 'debug' keyword", "#pragma", "");
return; return;
} }
@ -210,12 +186,12 @@ void TParseContext::handlePragma(const char **tokens, int numTokens)
else if (!strcmp(tokens[2], "off")) else if (!strcmp(tokens[2], "off"))
contextPragma.debug = false; contextPragma.debug = false;
else { else {
error(currentLoc, "\"on\" or \"off\" expected after '(' for 'debug' pragma", "#pragma", ""); error(getCurrentLoc(), "\"on\" or \"off\" expected after '(' for 'debug' pragma", "#pragma", "");
return; return;
} }
if (strcmp(tokens[3], ")")) { if (strcmp(tokens[3], ")")) {
error(currentLoc, "\")\" expected to end 'debug' pragma", "#pragma", ""); error(getCurrentLoc(), "\")\" expected to end 'debug' pragma", "#pragma", "");
return; return;
} }
} else { } else {
@ -2282,7 +2258,7 @@ void TParseContext::inductiveLoopCheck(TSourceLoc loc, TIntermNode* init, TInter
// //
// Do any additional error checking, etc., once we know the parsing is done. // Do any additional error checking, etc., once we know the parsing is done.
// //
void TParseContext::finalize() void TParseContext::finalErrorCheck()
{ {
// Check on array indexes for ES 2.0 (version 100) limitations. // Check on array indexes for ES 2.0 (version 100) limitations.
for (size_t i = 0; i < needsIndexLimitationChecking.size(); ++i) for (size_t i = 0; i < needsIndexLimitationChecking.size(); ++i)

View File

@ -40,6 +40,7 @@
#include "../Include/ShHandle.h" #include "../Include/ShHandle.h"
#include "SymbolTable.h" #include "SymbolTable.h"
#include "localintermediate.h" #include "localintermediate.h"
#include "Scan.h"
namespace glslang { namespace glslang {
@ -64,9 +65,10 @@ public:
TParseContext(TSymbolTable&, TIntermediate&, bool parsingBuiltins, int version, EProfile, EShLanguage, TInfoSink&, TParseContext(TSymbolTable&, TIntermediate&, bool parsingBuiltins, int version, EProfile, EShLanguage, TInfoSink&,
bool forwardCompatible = false, EShMessages messages = EShMsgDefault); bool forwardCompatible = false, EShMessages messages = EShMsgDefault);
public: void setLimits(const TLimits&);
bool parseShaderStrings(TPpContext&, char* strings[], size_t strLen[], int numStrings); bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false);
void parserError(const char *s); // for bison's yyerror void parserError(const char *s); // for bison's yyerror
const char* getPreamble();
void C_DECL error(TSourceLoc, const char *szReason, const char *szToken, void C_DECL error(TSourceLoc, const char *szReason, const char *szToken,
const char *szExtraInfoFormat, ...); const char *szExtraInfoFormat, ...);
@ -163,6 +165,9 @@ public:
TPpContext* getPpContext() const { return ppContext; } TPpContext* getPpContext() const { return ppContext; }
void addError() { ++numErrors; } void addError() { ++numErrors; }
int getNumErrors() const { return numErrors; } int getNumErrors() const { return numErrors; }
const TSourceLoc& getCurrentLoc() const { return currentScanner->getSourceLoc(); }
void setCurrentLine(int line) { currentScanner->setLine(line); }
void setCurrentString(int string) { currentScanner->setString(string); }
// The following are implemented in Versions.cpp to localize version/profile/stage/extensions control // The following are implemented in Versions.cpp to localize version/profile/stage/extensions control
void initializeExtensionBehavior(); void initializeExtensionBehavior();
@ -177,14 +182,13 @@ public:
void doubleCheck(TSourceLoc, const char* op); void doubleCheck(TSourceLoc, const char* op);
protected: protected:
const char* getPreamble();
void nonInitConstCheck(TSourceLoc, TString& identifier, TType& type); void nonInitConstCheck(TSourceLoc, TString& identifier, TType& type);
TVariable* declareNonArray(TSourceLoc, TString& identifier, TType&, bool& newDeclaration); TVariable* declareNonArray(TSourceLoc, TString& identifier, TType&, bool& newDeclaration);
void declareArray(TSourceLoc, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration); void declareArray(TSourceLoc, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration);
TIntermNode* executeInitializer(TSourceLoc, TString& identifier, TIntermTyped* initializer, TVariable* variable); TIntermNode* executeInitializer(TSourceLoc, TString& identifier, TIntermTyped* initializer, TVariable* variable);
TIntermTyped* convertInitializerList(TSourceLoc, const TType&, TIntermTyped* initializer); TIntermTyped* convertInitializerList(TSourceLoc, const TType&, TIntermTyped* initializer);
TOperator mapTypeToConstructorOp(const TType&); TOperator mapTypeToConstructorOp(const TType&);
void finalize(); void finalErrorCheck();
public: public:
// //
@ -213,13 +217,13 @@ public:
TQualifier currentBlockQualifier; TQualifier currentBlockQualifier;
TIntermAggregate *linkage; // aggregate node of objects the linker may need, if not referenced by the rest of the AST TIntermAggregate *linkage; // aggregate node of objects the linker may need, if not referenced by the rest of the AST
TPrecisionQualifier defaultPrecision[EbtNumTypes]; TPrecisionQualifier defaultPrecision[EbtNumTypes];
TSourceLoc currentLoc;
bool tokensBeforeEOF; bool tokensBeforeEOF;
TLimits limits; TLimits limits;
protected: protected:
TScanContext* scanContext; TScanContext* scanContext;
TPpContext* ppContext; TPpContext* ppContext;
TInputScanner* currentScanner;
int numErrors; // number of compile-time errors encountered int numErrors; // number of compile-time errors encountered
bool parsingBuiltins; // true if parsing built-in symbols/functions bool parsingBuiltins; // true if parsing built-in symbols/functions
TMap<TString, TExtensionBehavior> extensionBehavior; // for each extension string, what its current behavior is set to TMap<TString, TExtensionBehavior> extensionBehavior; // for each extension string, what its current behavior is set to

View File

@ -40,12 +40,12 @@
#include <string.h> #include <string.h>
#include "Scan.h"
#include "../Include/Types.h" #include "../Include/Types.h"
#include "SymbolTable.h" #include "SymbolTable.h"
#include "glslang_tab.cpp.h" #include "glslang_tab.cpp.h"
#include "ParseHelper.h" #include "ParseHelper.h"
#include "ScanContext.h" #include "ScanContext.h"
#include "Scan.h"
// preprocessor includes // preprocessor includes
#include "preprocessor/PpContext.h" #include "preprocessor/PpContext.h"
@ -54,37 +54,37 @@
namespace glslang { namespace glslang {
// read past any white space // read past any white space
void ConsumeWhiteSpace(TInputScanner& input, bool& foundNonSpaceTab) void TInputScanner::consumeWhiteSpace(bool& foundNonSpaceTab)
{ {
char c = input.peek(); // don't accidentally consume anything other than whitespace char c = peek(); // don't accidentally consume anything other than whitespace
while (c == ' ' || c == '\t' || c == '\r' || c == '\n') { while (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
if (c == '\r' || c == '\n') if (c == '\r' || c == '\n')
foundNonSpaceTab = true; foundNonSpaceTab = true;
input.get(); get();
c = input.peek(); c = peek();
} }
} }
// return true if a comment was actually consumed // return true if a comment was actually consumed
bool ConsumeComment(TInputScanner& input) bool TInputScanner::consumeComment()
{ {
if (input.peek() != '/') if (peek() != '/')
return false; return false;
input.get(); // consume the '/' get(); // consume the '/'
char c = input.peek(); char c = peek();
if (c == '/') { if (c == '/') {
// a '//' style comment // a '//' style comment
input.get(); // consume the second '/' get(); // consume the second '/'
c = input.get(); c = get();
do { do {
while (c > 0 && c != '\\' && c != '\r' && c != '\n') while (c > 0 && c != '\\' && c != '\r' && c != '\n')
c = input.get(); c = get();
if (c <= 0 || c == '\r' || c == '\n') { if (c <= 0 || c == '\r' || c == '\n') {
while (c == '\r' || c == '\n') while (c == '\r' || c == '\n')
c = input.get(); c = get();
// we reached the end of the comment // we reached the end of the comment
break; break;
@ -92,30 +92,30 @@ bool ConsumeComment(TInputScanner& input)
// it's a '\', so we need to keep going, after skipping what's escaped // it's a '\', so we need to keep going, after skipping what's escaped
// read the skipped character // read the skipped character
c = input.get(); c = get();
// if it's a two-character newline, skip both characters // if it's a two-character newline, skip both characters
if (c == '\r' && input.peek() == '\n') if (c == '\r' && peek() == '\n')
input.get(); get();
c = input.get(); c = get();
} }
} while (true); } while (true);
// put back the last non-comment character // put back the last non-comment character
if (c > 0) if (c > 0)
input.unget(); unget();
return true; return true;
} else if (c == '*') { } else if (c == '*') {
// a '/*' style comment // a '/*' style comment
input.get(); // consume the '*' get(); // consume the '*'
c = input.get(); c = get();
do { do {
while (c > 0 && c != '*') while (c > 0 && c != '*')
c = input.get(); c = get();
if (c == '*') { if (c == '*') {
c = input.get(); c = get();
if (c == '/') if (c == '/')
break; // end of comment break; // end of comment
// not end of comment // not end of comment
@ -126,26 +126,26 @@ bool ConsumeComment(TInputScanner& input)
return true; return true;
} else { } else {
// it's not a comment, put the '/' back // it's not a comment, put the '/' back
input.unget(); unget();
return false; return false;
} }
} }
// skip whitespace, then skip a comment, rinse, repeat // skip whitespace, then skip a comment, rinse, repeat
void ConsumeWhitespaceComment(TInputScanner& input, bool& foundNonSpaceTab) void TInputScanner::consumeWhitespaceComment(bool& foundNonSpaceTab)
{ {
do { do {
ConsumeWhiteSpace(input, foundNonSpaceTab); consumeWhiteSpace(foundNonSpaceTab);
// if not starting a comment now, then done // if not starting a comment now, then done
char c = input.peek(); char c = peek();
if (c != '/' || c < 0) if (c != '/' || c < 0)
return; return;
// skip potential comment // skip potential comment
foundNonSpaceTab = true; foundNonSpaceTab = true;
if (! ConsumeComment(input)) if (! consumeComment())
return; return;
} while (true); } while (true);
@ -159,9 +159,9 @@ void ConsumeWhitespaceComment(TInputScanner& input, bool& foundNonSpaceTab)
// is that scanning will start anew, following the rules for the chosen version/profile, // is that scanning will start anew, following the rules for the chosen version/profile,
// and with a corresponding parsing context. // and with a corresponding parsing context.
// //
bool ScanVersion(TInputScanner& input, int& version, EProfile& profile) bool TInputScanner::scanVersion(int& version, EProfile& profile)
{ {
// This function doesn't have to get all the semantics correct, // This function doesn't have to get all the semantics correct,
// just find the #version if there is a correct one present. // just find the #version if there is a correct one present.
// The preprocessor will have the responsibility of getting all the semantics right. // The preprocessor will have the responsibility of getting all the semantics right.
@ -169,43 +169,43 @@ bool ScanVersion(TInputScanner& input, int& version, EProfile& profile)
profile = ENoProfile; profile = ENoProfile;
bool foundNonSpaceTab = false; bool foundNonSpaceTab = false;
ConsumeWhitespaceComment(input, foundNonSpaceTab); consumeWhitespaceComment(foundNonSpaceTab);
// # // #
if (input.get() != '#') if (get() != '#')
return true; return true;
// whitespace // whitespace
char c; char c;
do { do {
c = input.get(); c = get();
} while (c == ' ' || c == '\t'); } while (c == ' ' || c == '\t');
if ( c != 'v' || if ( c != 'v' ||
input.get() != 'e' || get() != 'e' ||
input.get() != 'r' || get() != 'r' ||
input.get() != 's' || get() != 's' ||
input.get() != 'i' || get() != 'i' ||
input.get() != 'o' || get() != 'o' ||
input.get() != 'n') get() != 'n')
return true; return true;
// whitespace // whitespace
do { do {
c = input.get(); c = get();
} while (c == ' ' || c == '\t'); } while (c == ' ' || c == '\t');
// version number // version number
while (c >= '0' && c <= '9') { while (c >= '0' && c <= '9') {
version = 10 * version + (c - '0'); version = 10 * version + (c - '0');
c = input.get(); c = get();
} }
if (version == 0) if (version == 0)
return true; return true;
// whitespace // whitespace
while (c == ' ' || c == '\t') while (c == ' ' || c == '\t')
c = input.get(); c = get();
// profile // profile
const int maxProfileLength = 13; // not including any 0 const int maxProfileLength = 13; // not including any 0
@ -215,7 +215,7 @@ bool ScanVersion(TInputScanner& input, int& version, EProfile& profile)
if (c < 0 || c == ' ' || c == '\t' || c == '\n' || c == '\r') if (c < 0 || c == ' ' || c == '\t' || c == '\n' || c == '\r')
break; break;
profileString[profileLength] = c; profileString[profileLength] = c;
c = input.get(); c = get();
} }
if (c > 0 && c != ' ' && c != '\t' && c != '\n' && c != '\r') if (c > 0 && c != ' ' && c != '\t' && c != '\n' && c != '\r')
return true; return true;

View File

@ -33,6 +33,8 @@
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//POSSIBILITY OF SUCH DAMAGE. //POSSIBILITY OF SUCH DAMAGE.
// //
#ifndef _GLSLANG_SCAN_INCLUDED_
#define _GLSLANG_SCAN_INCLUDED_
#include "Versions.h" #include "Versions.h"
@ -44,7 +46,17 @@ namespace glslang {
// //
class TInputScanner { class TInputScanner {
public: public:
TInputScanner(int n, const char* const i[], size_t L[]) : numSources(n), sources(i), lengths(L), currentSource(0), currentChar(0) { } TInputScanner(int n, const char* const s[], size_t L[], int b = 0) :
numSources(n), sources(s), lengths(L), currentSource(0), currentChar(0), stringBias(b)
{
loc = new TSourceLoc[numSources];
loc[currentSource].string = -stringBias;
loc[currentSource].line = 1;
}
virtual ~TInputScanner()
{
delete [] loc;
}
// return of -1 means end of strings, // return of -1 means end of strings,
// anything else is the next character // anything else is the next character
@ -56,23 +68,13 @@ public:
return -1; return -1;
char ret = sources[currentSource][currentChar]; char ret = sources[currentSource][currentChar];
if (ret == '\n')
++loc[currentSource].line;
advance(); advance();
return ret; return ret;
} }
// advance one character
void advance()
{
++currentChar;
if (currentChar >= static_cast<int>(lengths[currentSource])) {
++currentSource;
currentChar = 0;
while (currentSource < numSources && lengths[currentSource] == 0)
++currentSource;
}
}
// retrieve the next character, no advance // retrieve the next character, no advance
char peek() char peek()
{ {
@ -95,21 +97,58 @@ public:
if (currentChar < 0) if (currentChar < 0)
currentChar = 0; currentChar = 0;
} }
if (peek() == '\n')
--loc[currentSource].line;
} }
// for #line override
void setLine(int newLine) { loc[currentSource].line = newLine; }
void setString(int newString) { loc[currentSource].string = newString; }
const TSourceLoc& getSourceLoc() const { return loc[currentSource]; }
void consumeWhiteSpace(bool& foundNonSpaceTab);
bool consumeComment();
void consumeWhitespaceComment(bool& foundNonSpaceTab);
bool scanVersion(int& version, EProfile& profile);
protected: protected:
// advance one character
void advance()
{
++currentChar;
if (currentChar >= static_cast<int>(lengths[currentSource])) {
++currentSource;
if (currentSource < numSources) {
loc[currentSource].string = loc[currentSource - 1].string + 1;
loc[currentSource].line = 1;
}
while (currentSource < numSources && lengths[currentSource] == 0) {
++currentSource;
if (currentSource < numSources) {
loc[currentSource].string = loc[currentSource - 1].string + 1;
loc[currentSource].line = 1;
}
}
currentChar = 0;
}
}
int numSources; // number of strings in source int numSources; // number of strings in source
const char* const *sources; // array of strings const char* const *sources; // array of strings
const size_t *lengths; // length of each string const size_t *lengths; // length of each string
int currentSource; int currentSource;
int currentChar; int currentChar;
// This is for reporting what string/line an error occurred on, and can be overridden by #line.
// It remembers the last state of each source string as it is left for the next one, so unget()
// can restore that state.
TSourceLoc* loc; // an array
int stringBias; // the first string that is the user's string number 0
}; };
// TODO: The location of these is still pending a grand design for going to a singular
// scanner for version finding, preprocessing, and tokenizing:
void ConsumeWhiteSpace(TInputScanner& input, bool& foundNonSpaceTab);
bool ConsumeComment(TInputScanner& input);
void ConsumeWhitespaceComment(TInputScanner& input, bool& foundNonSpaceTab);
bool ScanVersion(TInputScanner& input, int& version, EProfile& profile);
} // end namespace glslang } // end namespace glslang
#endif // _GLSLANG_SCAN_INCLUDED_

View File

@ -143,7 +143,8 @@ bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profil
builtInShaders[0] = builtIns.c_str(); builtInShaders[0] = builtIns.c_str();
builtInLengths[0] = builtIns.size(); builtInLengths[0] = builtIns.size();
if (! parseContext.parseShaderStrings(ppContext, const_cast<char**>(builtInShaders), builtInLengths, 1) != 0) { TInputScanner input(1, builtInShaders, builtInLengths);
if (! parseContext.parseShaderStrings(ppContext, input) != 0) {
infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins"); infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
printf("Unable to parse built-ins\n%s\n", infoSink.info.c_str()); printf("Unable to parse built-ins\n%s\n", infoSink.info.c_str());
@ -420,27 +421,42 @@ bool CompileDeferred(
if (! InitThread()) if (! InitThread())
return false; return false;
if (numStrings == 0)
return true;
// This must be undone (.pop()) by the caller, after it finishes consuming the created tree. // This must be undone (.pop()) by the caller, after it finishes consuming the created tree.
GetThreadPoolAllocator().push(); GetThreadPoolAllocator().push();
if (numStrings == 0)
return true;
// move to length-based strings, rather than null-terminated strings // Move to length-based strings, rather than null-terminated strings.
size_t* lengths = new size_t[numStrings]; // Also, add strings to include the preamble and to ensure the shader is not null,
// which lets the grammar accept what was a null (post preprocessing) shader.
//
// Shader will look like
// string 0: preamble
// string 1...numStrings: user's shader
// string numStrings+1: "int;"
//
size_t* lengths = new size_t[numStrings + 2];
const char** strings = new const char*[numStrings + 2];
for (int s = 0; s < numStrings; ++s) { for (int s = 0; s < numStrings; ++s) {
strings[s + 1] = shaderStrings[s];
if (inputLengths == 0 || inputLengths[s] < 0) if (inputLengths == 0 || inputLengths[s] < 0)
lengths[s] = strlen(shaderStrings[s]); lengths[s + 1] = strlen(shaderStrings[s]);
else else
lengths[s] = inputLengths[s]; lengths[s + 1] = inputLengths[s];
} }
// First, without using the preprocessor or parser, find the #version, so we know what
// symbol tables, processing rules, etc. to set up. This does not need the extra strings
// outlined above, just the user shader.
int version; int version;
EProfile profile; EProfile profile;
glslang::TInputScanner input(numStrings, shaderStrings, lengths); glslang::TInputScanner userInput(numStrings, &strings[1], &lengths[1]); // no preamble
bool versionNotFirst = ScanVersion(input, version, profile); bool versionNotFirst = userInput.scanVersion(version, profile);
bool versionNotFound = version == 0;
bool goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(), versionNotFirst, defaultVersion, version, profile); bool goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(), versionNotFirst, defaultVersion, version, profile);
bool versionWillBeError = (versionNotFound || (profile == EEsProfile && versionNotFirst));
intermediate.setVersion(version); intermediate.setVersion(version);
intermediate.setProfile(profile); intermediate.setProfile(profile);
SetupBuiltinSymbolTable(version, profile); SetupBuiltinSymbolTable(version, profile);
@ -458,31 +474,36 @@ bool CompileDeferred(
// Add built-in symbols that are potentially context dependent; // Add built-in symbols that are potentially context dependent;
// they get popped again further down. // they get popped again further down.
AddContextSpecificSymbols(resources, compiler->infoSink, symbolTable, version, profile, compiler->getLanguage()); AddContextSpecificSymbols(resources, compiler->infoSink, symbolTable, version, profile, compiler->getLanguage());
//
// Now we can process the full shader under proper symbols and rules.
//
TParseContext parseContext(symbolTable, intermediate, false, version, profile, compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages); TParseContext parseContext(symbolTable, intermediate, false, version, profile, compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
glslang::TScanContext scanContext(parseContext); glslang::TScanContext scanContext(parseContext);
TPpContext ppContext(parseContext); TPpContext ppContext(parseContext);
parseContext.setScanContext(&scanContext); parseContext.setScanContext(&scanContext);
parseContext.setPpContext(&ppContext); parseContext.setPpContext(&ppContext);
parseContext.limits = resources->limits; parseContext.setLimits(resources->limits);
if (! goodVersion) if (! goodVersion)
parseContext.addError(); parseContext.addError();
parseContext.initializeExtensionBehavior(); parseContext.initializeExtensionBehavior();
//
// Parse the application's shaders. All the following symbol table
// work will be throw-away, so push a new allocation scope that can
// be thrown away, then push a scope for the current shader's globals.
//
bool success = true; bool success = true;
symbolTable.push(); // Fill in the strings as outlined above.
if (! symbolTable.atGlobalLevel()) strings[0] = parseContext.getPreamble();
parseContext.infoSink.info.message(EPrefixInternalError, "Wrong symbol table level"); lengths[0] = strlen(strings[0]);
strings[numStrings + 1] = "\n int;";
lengths[numStrings + 1] = strlen(strings[numStrings + 1]);
TInputScanner fullInput(numStrings + 2, strings, lengths, 1);
bool ret = parseContext.parseShaderStrings(ppContext, const_cast<char**>(shaderStrings), lengths, numStrings); // Push a new symbol allocation scope that can for the shader's globals.
if (! ret) symbolTable.push();
// Parse the full shader.
if (! parseContext.parseShaderStrings(ppContext, fullInput, versionWillBeError))
success = false; success = false;
intermediate.addSymbolLinkageNodes(parseContext.linkage, parseContext.language, symbolTable); intermediate.addSymbolLinkageNodes(parseContext.linkage, parseContext.language, symbolTable);
@ -503,6 +524,7 @@ bool CompileDeferred(
intermediate.outputTree(parseContext.infoSink); intermediate.outputTree(parseContext.infoSink);
delete [] lengths; delete [] lengths;
delete [] strings;
return success; return success;
} }

View File

@ -330,14 +330,14 @@ void TParseContext::updateExtensionBehavior(const char* extName, const char* beh
else if (! strcmp("warn", behaviorString)) else if (! strcmp("warn", behaviorString))
behavior = EBhWarn; behavior = EBhWarn;
else else
error(currentLoc, "behavior not supported", "#extension", behaviorString); error(getCurrentLoc(), "behavior not supported", "#extension", behaviorString);
// Update the current behavior // Update the current behavior
TMap<TString, TExtensionBehavior>::iterator iter; TMap<TString, TExtensionBehavior>::iterator iter;
if (! strcmp(extName, "all")) { if (! strcmp(extName, "all")) {
// special case for the 'all' extension; apply it to every extension present // special case for the 'all' extension; apply it to every extension present
if (behavior == EBhRequire || behavior == EBhEnable) { if (behavior == EBhRequire || behavior == EBhEnable) {
error(currentLoc, "extension 'all' cannot have 'require' or 'enable' behavior", "#extension", ""); error(getCurrentLoc(), "extension 'all' cannot have 'require' or 'enable' behavior", "#extension", "");
return; return;
} else { } else {
for (iter = extensionBehavior.begin(); iter != extensionBehavior.end(); ++iter) for (iter = extensionBehavior.begin(); iter != extensionBehavior.end(); ++iter)
@ -349,12 +349,12 @@ void TParseContext::updateExtensionBehavior(const char* extName, const char* beh
if (iter == extensionBehavior.end()) { if (iter == extensionBehavior.end()) {
switch (behavior) { switch (behavior) {
case EBhRequire: case EBhRequire:
error(currentLoc, "extension not supported", "#extension", extName); error(getCurrentLoc(), "extension not supported", "#extension", extName);
break; break;
case EBhEnable: case EBhEnable:
case EBhWarn: case EBhWarn:
case EBhDisable: case EBhDisable:
warn(currentLoc, "extension not supported", "#extension", extName); warn(getCurrentLoc(), "extension not supported", "#extension", extName);
break; break;
default: default:
assert(0 && "unexpected behavior"); assert(0 && "unexpected behavior");

View File

@ -134,7 +134,7 @@ int TPpContext::FinalCPP()
mem_FreePool(pool); mem_FreePool(pool);
if (ifdepth) if (ifdepth)
parseContext.error(parseContext.currentLoc, "missing #endif", "#if", ""); parseContext.error(parseContext.getCurrentLoc(), "missing #endif", "#if", "");
return 1; return 1;
} }
@ -552,21 +552,21 @@ int TPpContext::CPPline(TPpToken * ppToken)
return token; return token;
} }
else if (token == CPP_INTCONSTANT) { else if (token == CPP_INTCONSTANT) {
parseContext.currentLoc.line = atoi(ppToken->name); parseContext.setCurrentLine(atoi(ppToken->name));
token = currentInput->scan(this, currentInput, ppToken); token = currentInput->scan(this, currentInput, ppToken);
if (token == CPP_INTCONSTANT) { if (token == CPP_INTCONSTANT) {
parseContext.currentLoc.string = atoi(ppToken->name); parseContext.setCurrentString(atoi(ppToken->name));
token = currentInput->scan(this, currentInput, ppToken); token = currentInput->scan(this, currentInput, ppToken);
if (token != '\n') if (token != '\n')
parseContext.error(parseContext.currentLoc, "cannot be followed by more than two integral literals", "#line", ""); parseContext.error(parseContext.getCurrentLoc(), "cannot be followed by more than two integral literals", "#line", "");
} else if (token == '\n') } else if (token == '\n')
return token; return token;
else else
parseContext.error(parseContext.currentLoc, "second argument can only be an integral literal", "#line", ""); parseContext.error(parseContext.getCurrentLoc(), "second argument can only be an integral literal", "#line", "");
} else } else
parseContext.error(parseContext.currentLoc, "first argument can only be an integral literal", "#line", ""); parseContext.error(parseContext.getCurrentLoc(), "first argument can only be an integral literal", "#line", "");
return token; return token;
} }
@ -662,8 +662,8 @@ int TPpContext::CPPversion(TPpToken * ppToken)
{ {
int token = currentInput->scan(this, currentInput, ppToken); int token = currentInput->scan(this, currentInput, ppToken);
if (notAVersionToken) if (errorOnVersion)
parseContext.error(ppToken->loc, "must occur before any other statement in the program", "#version", ""); parseContext.error(ppToken->loc, "must occur first in shader", "#version", "");
if (token == '\n') { if (token == '\n') {
parseContext.error(ppToken->loc, "must be followed by version number", "#version", ""); parseContext.error(ppToken->loc, "must be followed by version number", "#version", "");
@ -759,7 +759,6 @@ int TPpContext::readCPPline(TPpToken * ppToken)
} else { } else {
parseContext.error(ppToken->loc, "#else after a #else", "#else", ""); parseContext.error(ppToken->loc, "#else after a #else", "#else", "");
ifdepth = 0; ifdepth = 0;
notAVersionToken = true;
return 0; return 0;
} }
} else if (ppToken->atom == elifAtom) { } else if (ppToken->atom == elifAtom) {
@ -805,8 +804,6 @@ int TPpContext::readCPPline(TPpToken * ppToken)
token = currentInput->scan(this, currentInput, ppToken); token = currentInput->scan(this, currentInput, ppToken);
} }
notAVersionToken = ! isVersion;
return token; return token;
} // readCPPline } // readCPPline
@ -931,7 +928,7 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, int expandUndef)
int depth = 0; int depth = 0;
if (atom == __LINE__Atom) { if (atom == __LINE__Atom) {
ppToken->ival = parseContext.currentLoc.line; ppToken->ival = parseContext.getCurrentLoc().line;
sprintf(ppToken->name, "%d", ppToken->ival); sprintf(ppToken->name, "%d", ppToken->ival);
UngetToken(CPP_INTCONSTANT, ppToken); UngetToken(CPP_INTCONSTANT, ppToken);
@ -939,7 +936,7 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, int expandUndef)
} }
if (atom == __FILE__Atom) { if (atom == __FILE__Atom) {
ppToken->ival = parseContext.currentLoc.string; ppToken->ival = parseContext.getCurrentLoc().string;
sprintf(ppToken->name, "%d", ppToken->ival); sprintf(ppToken->name, "%d", ppToken->ival);
UngetToken(CPP_INTCONSTANT, ppToken); UngetToken(CPP_INTCONSTANT, ppToken);
@ -964,8 +961,6 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, int expandUndef)
in = (MacroInputSrc*)malloc(sizeof(*in)); in = (MacroInputSrc*)malloc(sizeof(*in));
memset(in, 0, sizeof(*in)); memset(in, 0, sizeof(*in));
in->base.line = currentInput->line;
in->base.name = currentInput->name;
if ((! sym || sym->mac.undef) && expandUndef) { if ((! sym || sym->mac.undef) && expandUndef) {
// push input // push input

View File

@ -84,7 +84,7 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace glslang { namespace glslang {
TPpContext::TPpContext(TParseContext& pc) : TPpContext::TPpContext(TParseContext& pc) :
preamble(0), strings(0), notAVersionToken(false), parseContext(pc) preamble(0), strings(0), parseContext(pc)
{ {
InitAtomTable(); InitAtomTable();
InitScanner(this); InitScanner(this);
@ -101,28 +101,17 @@ TPpContext::~TPpContext()
delete [] preamble; delete [] preamble;
} }
void TPpContext::setPreamble(const char* p, size_t l) void TPpContext::setInput(TInputScanner& input, bool versionWillBeError)
{ {
if (p && l > 0) { StringInputSrc *in = (StringInputSrc *)malloc(sizeof(StringInputSrc));
// preAmble could be a hard-coded string; make writable copy memset(in, 0, sizeof(StringInputSrc));
// TODO: efficiency PP: make it not need writable strings in->input = &input;
preambleLength = l; in->base.scan = byte_scan;
preamble = new char[preambleLength + 1]; in->base.getch = (int (*)(TPpContext*, InputSrc *, TPpToken *))str_getch;
memcpy(preamble, p, preambleLength + 1); // TODO: PP: assuming nul-terminated strings in->base.ungetch = (void (*)(TPpContext*, InputSrc *, int, TPpToken *))str_ungetch;
ScanFromString(preamble); in->base.prev = currentInput;
currentString = -1; currentInput = &in->base;
} errorOnVersion = versionWillBeError;
}
void TPpContext::setShaderStrings(char* s[], size_t l[], int n)
{
strings = s;
lengths = l;
numStrings = n;
if (! preamble) {
ScanFromString(strings[0]);
currentString = 0;
}
} }
} // end namespace glslang } // end namespace glslang

View File

@ -95,6 +95,8 @@ public:
char name[maxTokenLength+1]; char name[maxTokenLength+1];
}; };
class TInputScanner;
// This class is the result of turning a huge pile of C code communicating through globals // This class is the result of turning a huge pile of C code communicating through globals
// into a class. This was done to allowing instancing to attain thread safety. // into a class. This was done to allowing instancing to attain thread safety.
// Don't expect too much in terms of OO design. // Don't expect too much in terms of OO design.
@ -104,7 +106,7 @@ public:
virtual ~TPpContext(); virtual ~TPpContext();
void setPreamble(const char* preamble, size_t length); void setPreamble(const char* preamble, size_t length);
void setShaderStrings(char* strings[], size_t lengths[], int numStrings); void setInput(TInputScanner& input, bool versionWillBeError);
const char* tokenize(TPpToken* ppToken); const char* tokenize(TPpToken* ppToken);
@ -113,8 +115,6 @@ public:
int (*scan)(TPpContext*, struct InputSrc *, TPpToken *); int (*scan)(TPpContext*, struct InputSrc *, TPpToken *);
int (*getch)(TPpContext*, struct InputSrc *, TPpToken *); int (*getch)(TPpContext*, struct InputSrc *, TPpToken *);
void (*ungetch)(TPpContext*, struct InputSrc *, int, TPpToken *); void (*ungetch)(TPpContext*, struct InputSrc *, int, TPpToken *);
int name; /* atom */
int line;
}; };
struct TokenBlock { struct TokenBlock {
@ -177,7 +177,6 @@ protected:
// Scanner data: // Scanner data:
int mostRecentToken; // Most recent token seen by the scanner int mostRecentToken; // Most recent token seen by the scanner
int previous_token; int previous_token;
bool notAVersionToken; // used to make sure that #version is the first token seen in the file, if present
TParseContext& parseContext; TParseContext& parseContext;
static const int maxMacroArgs = 64; static const int maxMacroArgs = 64;
@ -195,6 +194,7 @@ protected:
}; };
InputSrc *currentInput; InputSrc *currentInput;
bool errorOnVersion;
// //
// from Pp.cpp // from Pp.cpp
@ -289,7 +289,7 @@ protected:
// //
struct StringInputSrc { struct StringInputSrc {
InputSrc base; InputSrc base;
char *p; TInputScanner* input;
}; };
int InitScanner(TPpContext *cpp); int InitScanner(TPpContext *cpp);
static int str_getch(TPpContext*, StringInputSrc *in); static int str_getch(TPpContext*, StringInputSrc *in);

View File

@ -88,23 +88,7 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "PpContext.h" #include "PpContext.h"
#include "PpTokens.h" #include "PpTokens.h"
#include "Scan.h"
namespace {
using namespace glslang;
int eof_scan(TPpContext*, TPpContext::InputSrc*, TPpToken*)
{
return EOF;
}
void noop(TPpContext*, TPpContext::InputSrc *in, int ch, TPpToken * ppToken)
{
}
TPpContext::InputSrc eof_inputsrc = { 0, &eof_scan, &eof_scan, &noop };
} // end anonymous namespace
namespace glslang { namespace glslang {
@ -115,79 +99,26 @@ int TPpContext::InitScanner(TPpContext *cpp)
return 0; return 0;
mostRecentToken = 0; mostRecentToken = 0;
currentInput = &eof_inputsrc; currentInput = 0;
previous_token = '\n'; previous_token = '\n';
notAVersionToken = false;
return 1;
} // InitScanner
/*
* str_getch()
* takes care of reading from multiple strings.
* returns the next-char from the input stream.
* returns EOF when the complete shader is parsed.
*/
int TPpContext::str_getch(TPpContext* pp, StringInputSrc *in)
{
for(;;) {
if (*in->p) {
if (*in->p == '\n') {
in->base.line++;
++pp->parseContext.currentLoc.line;
}
return *in->p++;
}
if (pp->currentString < 0) {
// we only parsed the built-in pre-amble; start with clean slate for user code
pp->notAVersionToken = false;
}
if (++(pp->currentString) < pp->numStrings) {
free(in);
pp->parseContext.currentLoc.string = pp->currentString;
pp->parseContext.currentLoc.line = 1;
pp->ScanFromString(pp->strings[pp->currentString]);
in=(StringInputSrc*)pp->currentInput;
continue;
} else {
pp->currentInput = in->base.prev;
pp->currentString = 0;
free(in);
return EOF;
}
}
} // str_getch
void TPpContext::str_ungetch(TPpContext* pp, StringInputSrc *in, int ch, TPpToken *type)
{
if (in->p[-1] == ch)in->p--;
else {
*(in->p)='\0'; //this would take care of shifting to the previous string.
pp->currentString--;
pp->parseContext.currentLoc.string = pp->currentString;
}
if (ch == '\n') {
in->base.line--;
--pp->parseContext.currentLoc.line;
}
} // str_ungetch
int TPpContext::ScanFromString(char *s)
{
StringInputSrc *in = (StringInputSrc *)malloc(sizeof(StringInputSrc));
memset(in, 0, sizeof(StringInputSrc));
in->p = s;
in->base.line = 1;
in->base.scan = byte_scan;
in->base.getch = (int (*)(TPpContext*, InputSrc *, TPpToken *))str_getch;
in->base.ungetch = (void (*)(TPpContext*, InputSrc *, int, TPpToken *))str_ungetch;
in->base.prev = currentInput;
currentInput = &in->base;
return 1; return 1;
} }
int TPpContext::str_getch(TPpContext* pp, StringInputSrc *in)
{
int ch = in->input->get();
if (ch == EOF)
free(in);
return ch;
}
void TPpContext::str_ungetch(TPpContext* pp, StringInputSrc *in, int ch, TPpToken *type)
{
in->input->unget();
}
/////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// Floating point constants: ///////////////////////////////// /////////////////////////////////// Floating point constants: /////////////////////////////////
@ -332,7 +263,7 @@ int TPpContext::byte_scan(TPpContext* pp, InputSrc *in, TPpToken * ppToken)
ch = pp->currentInput->getch(pp, pp->currentInput, ppToken); ch = pp->currentInput->getch(pp, pp->currentInput, ppToken);
} }
ppToken->loc = pp->parseContext.currentLoc; ppToken->loc = pp->parseContext.getCurrentLoc();
len = 0; len = 0;
switch (ch) { switch (ch) {
default: default:
@ -696,6 +627,7 @@ int TPpContext::byte_scan(TPpContext* pp, InputSrc *in, TPpToken * ppToken)
return '.'; return '.';
} }
case '/': case '/':
// TODO: preprocessor: use the Scan.cpp comment scanner
ch = pp->currentInput->getch(pp, pp->currentInput, ppToken); ch = pp->currentInput->getch(pp, pp->currentInput, ppToken);
if (ch == '/') { if (ch == '/') {
do { do {
@ -801,8 +733,6 @@ const char* TPpContext::tokenize(TPpToken* ppToken)
if (token == '\n') if (token == '\n')
continue; continue;
notAVersionToken = true;
// expand macros // expand macros
if (token == CPP_IDENTIFIER && MacroExpand(ppToken->atom, ppToken, 0) == 1) if (token == CPP_IDENTIFIER && MacroExpand(ppToken->atom, ppToken, 0) == 1)
continue; continue;
@ -831,7 +761,7 @@ int TPpContext::check_EOF(int token)
{ {
if (token == EOF) { if (token == EOF) {
if (ifdepth > 0) if (ifdepth > 0)
parseContext.error(parseContext.currentLoc, "missing #endif", "#if", ""); parseContext.error(parseContext.getCurrentLoc(), "missing #endif", "#if", "");
return 1; return 1;
} }
return 0; return 0;

View File

@ -306,7 +306,7 @@ int TPpContext::ReadToken(TokenStream *pTok, TPpToken *ppToken)
char ch; char ch;
ltoken = lReadByte(pTok); ltoken = lReadByte(pTok);
ppToken->loc = parseContext.currentLoc; ppToken->loc = parseContext.getCurrentLoc();
if (ltoken >= 0) { if (ltoken >= 0) {
if (ltoken > 127) if (ltoken > 127)
ltoken += 128; ltoken += 128;
@ -399,12 +399,9 @@ int TPpContext::scan_token(TPpContext* pp, TokenInputSrc *in, TPpToken * ppToken
{ {
int token = pp->ReadToken(in->tokens, ppToken); int token = pp->ReadToken(in->tokens, ppToken);
int (*final)(TPpContext *); int (*final)(TPpContext *);
if (token == '\n') {
in->base.line++;
return token;
}
if (token > 0) if (token > 0)
return token; return token;
pp->currentInput = in->base.prev; pp->currentInput = in->base.prev;
final = in->final; final = in->final;
free(in); free(in);
@ -418,10 +415,8 @@ int TPpContext::ReadFromTokenStream(TokenStream *ts, int name, int (*final)(TPpC
{ {
TokenInputSrc *in = (TokenInputSrc *) malloc(sizeof(TokenInputSrc)); TokenInputSrc *in = (TokenInputSrc *) malloc(sizeof(TokenInputSrc));
memset(in, 0, sizeof(TokenInputSrc)); memset(in, 0, sizeof(TokenInputSrc));
in->base.name = name;
in->base.prev = currentInput; in->base.prev = currentInput;
in->base.scan = (int (*)(TPpContext*, InputSrc*, TPpToken*))scan_token; in->base.scan = (int (*)(TPpContext*, InputSrc*, TPpToken*))scan_token;
in->base.line = 1;
in->tokens = ts; in->tokens = ts;
in->final = final; in->final = final;
RewindTokenStream(ts); RewindTokenStream(ts);
@ -449,8 +444,6 @@ void TPpContext::UngetToken(int token, TPpToken * ppToken)
t->lval = *ppToken; t->lval = *ppToken;
t->base.scan = (int(*)(TPpContext*, struct InputSrc *, TPpToken *))reget_token; t->base.scan = (int(*)(TPpContext*, struct InputSrc *, TPpToken *))reget_token;
t->base.prev = currentInput; t->base.prev = currentInput;
t->base.name = currentInput->name;
t->base.line = currentInput->line;
currentInput = &t->base; currentInput = &t->base;
} }

View File

@ -270,7 +270,7 @@ class TShader {
public: public:
explicit TShader(EShLanguage); explicit TShader(EShLanguage);
virtual ~TShader(); virtual ~TShader();
void setStrings(char** s, int n) { strings = s; numStrings = n; } void setStrings(const char* const* s, int n) { strings = s; numStrings = n; }
bool parse(const TBuiltInResource*, int defaultVersion, bool forwardCompatible, EShMessages); bool parse(const TBuiltInResource*, int defaultVersion, bool forwardCompatible, EShMessages);
const char* getInfoLog(); const char* getInfoLog();
const char* getInfoDebugLog(); const char* getInfoDebugLog();
@ -280,7 +280,7 @@ protected:
TCompiler* compiler; TCompiler* compiler;
TIntermediate* intermediate; TIntermediate* intermediate;
TInfoSink* infoSink; TInfoSink* infoSink;
char** strings; const char* const* strings;
int numStrings; int numStrings;
friend class TProgram; friend class TProgram;