gzdoom/src/parsecontext.cpp

357 lines
7.7 KiB
C++

/*
** parsecontext.cpp
** Base class for Lemon-based parsers
**
**---------------------------------------------------------------------------
** Copyright 1998-2008 Randy Heit
** Copyright 2008 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <string.h>
#include <ctype.h>
#include "w_wad.h"
#include "parsecontext.h"
#include "p_lnspec.h"
//==========================================================================
//
//
//
//==========================================================================
void FParseContext::AddSym (char *sym, int val)
{
FParseSymbol syme;
syme.Value = val;
strncpy (syme.Sym, sym, 79);
syme.Sym[79]=0;
symbols.Push(syme);
}
//==========================================================================
//
//
//
//==========================================================================
bool FParseContext::FindSym (char *sym, FParseSymbol **val)
{
for(unsigned i=0;i<symbols.Size(); i++)
{
if (strcmp (symbols[i].Sym, sym) == 0)
{
*val = &symbols[i];
return true;
}
}
return false;
}
//==========================================================================
//
//
//
//==========================================================================
int FParseContext::GetToken (char *&sourcep, FParseToken *yylval)
{
char token[80];
int toksize;
int c;
loop:
while (isspace (c = *sourcep++) && c != 0)
{
if (c == '\n')
SourceLine++;
}
if (c == 0)
{
return 0;
}
if (isdigit (c))
{
int buildup = c - '0';
if (c == '0')
{
c = *sourcep++;
if (c == 'x' || c == 'X')
{
yylval->val = (int)strtol(sourcep, &sourcep, 16);
return TokenTrans[NUM];
}
else
{
sourcep--;
}
}
char *endp;
sourcep--;
yylval->val = (int)strtol(sourcep, &endp, 10);
if (*endp == '.')
{
// It's a float
yylval->fval = strtod(sourcep, &sourcep);
return TokenTrans[FLOATVAL];
}
else
{
sourcep = endp;
return TokenTrans[NUM];
}
}
if (isalpha (c))
{
int buildup = 0;
token[0] = c;
toksize = 1;
while (toksize < 79 && (isalnum (c = *sourcep++) || c == '_'))
{
token[toksize++] = c;
}
token[toksize] = 0;
if (toksize == 79 && isalnum (c))
{
while (isalnum (c = *sourcep++))
;
}
sourcep--;
if (FindToken (token, &buildup))
{
return buildup;
}
if (FindSym (token, &yylval->symval))
{
yylval->val = yylval->symval->Value;
return TokenTrans[NUM];
}
if ((yylval->val = P_FindLineSpecial(token)) != 0)
{
return TokenTrans[NUM];
}
#if __GNUC__ == 4 && __GNUC_MINOR__ == 8
// Work around GCC 4.8 bug 54570 causing release build crashes.
asm("" : "+g" (yylval));
#endif
strcpy (yylval->sym, token);
return TokenTrans[SYM];
}
if (c == '/')
{
c = *sourcep++;
if (c == '*')
{
for (;;)
{
while ((c = *sourcep++) != '*' && c != 0)
{
if (c == '\n')
SourceLine++;
}
if (c == 0)
return 0;
if ((c = *sourcep++) == '/')
goto loop;
if (c == 0)
return 0;
sourcep--;
}
}
else if (c == '/')
{
while ((c = *sourcep++) != '\n' && c != 0)
;
if (c == '\n')
SourceLine++;
else if (c == EOF)
return 0;
goto loop;
}
else
{
sourcep--;
return TokenTrans[DIVIDE];
}
}
if (c == '"')
{
int tokensize = 0;
while ((c = *sourcep++) != '"' && c != 0)
{
yylval->string[tokensize++] = c;
}
yylval->string[tokensize] = 0;
return TokenTrans[STRING];
}
if (c == '|')
{
c = *sourcep++;
if (c == '=')
return TokenTrans[OR_EQUAL];
sourcep--;
return TokenTrans[OR];
}
if (c == '<')
{
c = *sourcep++;
if (c == '<')
{
c = *sourcep++;
if (c == '=')
{
return TokenTrans[LSHASSIGN];
}
sourcep--;
return 0;
}
c--;
return 0;
}
if (c == '>')
{
c = *sourcep++;
if (c == '>')
{
c = *sourcep++;
if (c == '=')
{
return TokenTrans[RSHASSIGN];
}
sourcep--;
return 0;
}
c--;
return 0;
}
if (c == '#')
{
if (!strnicmp(sourcep, "include", 7))
{
sourcep+=7;
return TokenTrans[INCLUDE];
}
if (!strnicmp(sourcep, "define", 6))
{
sourcep+=6;
return TokenTrans[DEFINE];
}
}
switch (c)
{
case '^': return TokenTrans[XOR];
case '&': return TokenTrans[AND];
case '-': return TokenTrans[MINUS];
case '+': return TokenTrans[PLUS];
case '*': return TokenTrans[MULTIPLY];
case '%': return TokenTrans[MODULUS];
case '(': return TokenTrans[LPAREN];
case ')': return TokenTrans[RPAREN];
case ',': return TokenTrans[COMMA];
case '{': return TokenTrans[LBRACE];
case '}': return TokenTrans[RBRACE];
case '=': return TokenTrans[EQUALS];
case ';': return TokenTrans[SEMICOLON];
case ':': return TokenTrans[COLON];
case '[': return TokenTrans[LBRACKET];
case ']': return TokenTrans[RBRACKET];
default: return 0;
}
}
//==========================================================================
//
//
//
//==========================================================================
int FParseContext::PrintError (const char *s)
{
if (SourceFile != NULL)
Printf ("%s, line %d: %s\n", SourceFile, SourceLine, s);
else
Printf ("%s\n", s);
return 0;
}
//==========================================================================
//
//
//
//==========================================================================
void FParseContext::ParseLump(const char *lumpname)
{
int tokentype;
int SavedSourceLine = SourceLine;
const char *SavedSourceFile = SourceFile;
FParseToken token;
int lumpno = Wads.CheckNumForFullName(lumpname, true);
if (lumpno == -1)
{
Printf ("%s, line %d: Lump '%s' not found\n", SourceFile, SourceLine, lumpname);
return;
}
// Read the lump into a buffer and add a 0-terminator
int lumplen = Wads.LumpLength(lumpno);
char *lumpdata = new char[lumplen+1];
Wads.ReadLump(lumpno, lumpdata);
lumpdata[lumplen] = 0;
SourceLine = 0;
SourceFile = lumpname;
char *sourcep = lumpdata;
while ( (tokentype = GetToken(sourcep, &token)) )
{
// It is much easier to handle include statements outside the main parser.
if (tokentype == TokenTrans[INCLUDE])
{
if (GetToken(sourcep, &token) != TokenTrans[STRING])
{
Printf("%s, line %d: Include: String parameter expected\n", SourceFile, SourceLine);
return;
}
ParseLump(token.string);
}
else
{
Parse(pParser, tokentype, token, this);
}
}
delete [] lumpdata;
SourceLine = SavedSourceLine;
SourceFile = SavedSourceFile;
}