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

View file

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

View file

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

View file

@ -95,6 +95,8 @@ public:
char name[maxTokenLength+1];
};
class TInputScanner;
// 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.
// Don't expect too much in terms of OO design.
@ -104,7 +106,7 @@ public:
virtual ~TPpContext();
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);
@ -113,8 +115,6 @@ public:
int (*scan)(TPpContext*, struct InputSrc *, TPpToken *);
int (*getch)(TPpContext*, struct InputSrc *, TPpToken *);
void (*ungetch)(TPpContext*, struct InputSrc *, int, TPpToken *);
int name; /* atom */
int line;
};
struct TokenBlock {
@ -177,7 +177,6 @@ protected:
// Scanner data:
int mostRecentToken; // Most recent token seen by the scanner
int previous_token;
bool notAVersionToken; // used to make sure that #version is the first token seen in the file, if present
TParseContext& parseContext;
static const int maxMacroArgs = 64;
@ -195,6 +194,7 @@ protected:
};
InputSrc *currentInput;
bool errorOnVersion;
//
// from Pp.cpp
@ -289,7 +289,7 @@ protected:
//
struct StringInputSrc {
InputSrc base;
char *p;
TInputScanner* input;
};
int InitScanner(TPpContext *cpp);
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 "PpTokens.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
#include "Scan.h"
namespace glslang {
@ -115,79 +99,26 @@ int TPpContext::InitScanner(TPpContext *cpp)
return 0;
mostRecentToken = 0;
currentInput = &eof_inputsrc;
currentInput = 0;
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;
}
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: /////////////////////////////////
@ -332,7 +263,7 @@ int TPpContext::byte_scan(TPpContext* pp, InputSrc *in, TPpToken * ppToken)
ch = pp->currentInput->getch(pp, pp->currentInput, ppToken);
}
ppToken->loc = pp->parseContext.currentLoc;
ppToken->loc = pp->parseContext.getCurrentLoc();
len = 0;
switch (ch) {
default:
@ -696,6 +627,7 @@ int TPpContext::byte_scan(TPpContext* pp, InputSrc *in, TPpToken * ppToken)
return '.';
}
case '/':
// TODO: preprocessor: use the Scan.cpp comment scanner
ch = pp->currentInput->getch(pp, pp->currentInput, ppToken);
if (ch == '/') {
do {
@ -801,8 +733,6 @@ const char* TPpContext::tokenize(TPpToken* ppToken)
if (token == '\n')
continue;
notAVersionToken = true;
// expand macros
if (token == CPP_IDENTIFIER && MacroExpand(ppToken->atom, ppToken, 0) == 1)
continue;
@ -831,7 +761,7 @@ int TPpContext::check_EOF(int token)
{
if (token == EOF) {
if (ifdepth > 0)
parseContext.error(parseContext.currentLoc, "missing #endif", "#if", "");
parseContext.error(parseContext.getCurrentLoc(), "missing #endif", "#if", "");
return 1;
}
return 0;

View file

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