- Started adding action function declarations to objects.

- Added integer constant declarations to objects.
- Added some new token-based functions to sc_man.cpp that know about keywords
  and record proper type information, so parsers don't need to treat
  everything as strings.
- Added a simple symbol table to PClass.


SVN r394 (trunk)
This commit is contained in:
Randy Heit 2006-11-29 04:51:16 +00:00
parent 30885e6d86
commit 4467cd6563
18 changed files with 5605 additions and 808 deletions

View file

@ -1,3 +1,8 @@
November 28, 2006
- Started adding action function declarations to objects.
- Added integer constant declarations to objects.
- Added a simple symbol table to PClass.
November 27, 2006 (Changes by Graf Zahl)
- Changed: When playing a shareware game no external WADs are loaded at all,
not even zvox.wad or the skins directory.

View file

@ -380,3 +380,92 @@ void CreatePath(const char * fn)
}
else DoCreatePath(fn);
}
// [RH] Replaces the escape sequences in a string with actual escaped characters.
// This operation is done in-place.
void strbin (char *str)
{
char *p = str, c;
int i;
while ( (c = *p++) ) {
if (c != '\\') {
*str++ = c;
} else {
switch (*p) {
case 'a':
*str++ = '\a';
break;
case 'b':
*str++ = '\b';
break;
case 'c':
*str++ = '\034'; // TEXTCOLOR_ESCAPE
break;
case 'f':
*str++ = '\f';
break;
case 'n':
*str++ = '\n';
break;
case 't':
*str++ = '\t';
break;
case 'r':
*str++ = '\r';
break;
case 'v':
*str++ = '\v';
break;
case '?':
*str++ = '\?';
break;
case '\n':
break;
case 'x':
case 'X':
c = 0;
p++;
for (i = 0; i < 2; i++) {
c <<= 4;
if (*p >= '0' && *p <= '9')
c += *p-'0';
else if (*p >= 'a' && *p <= 'f')
c += 10 + *p-'a';
else if (*p >= 'A' && *p <= 'F')
c += 10 + *p-'A';
else
break;
p++;
}
*str++ = c;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
c = 0;
for (i = 0; i < 3; i++) {
c <<= 3;
if (*p >= '0' && *p <= '7')
c += *p-'0';
else
break;
p++;
}
*str++ = c;
break;
default:
*str++ = *p;
break;
}
p++;
}
}
*str = 0;
}

View file

@ -51,6 +51,8 @@ void FormatGUID (char *text, const GUID &guid);
char *myasctime ();
void strbin (char *str);
void CreatePath(const char * fn);
#endif

View file

@ -1394,5 +1394,5 @@ DThinker *FDecalColorerAnim::CreateThinker (DBaseDecal *actor, side_t *wall) con
static fixed_t ReadScale ()
{
SC_MustGetFloat ();
return fixed_t(clamp (sc_Float * FRACUNIT, 256.f, 256.f*FRACUNIT));
return fixed_t(clamp (sc_Float * FRACUNIT, 256.0, 256.0*FRACUNIT));
}

View file

@ -664,7 +664,7 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
else if (SC_Compare ("Alpha"))
{
SC_MustGetFloat ();
defaults->alpha = int(clamp (sc_Float, 0.f, 1.f) * OPAQUE);
defaults->alpha = int(clamp (sc_Float, 0.0, 1.0) * OPAQUE);
}
else if (SC_Compare ("Scale"))
{

View file

@ -221,6 +221,7 @@ PClass *PClass::CreateDerivedClass (FName name, unsigned int size)
type->FlatPointers = NULL;
type->bRuntimeClass = true;
type->ActorInfo = NULL;
type->Symbols.SetParentTable (&this->Symbols);
type->InsertIntoHash();
// If this class has an actor info, then any classes derived from it
@ -302,3 +303,86 @@ void PClass::FreeStateList ()
}
}
// Symbol tables ------------------------------------------------------------
PSymbolTable::PSymbolTable ()
: ParentSymbolTable(NULL)
{
}
PSymbolTable::~PSymbolTable ()
{
for (unsigned int i = 0; i < Symbols.Size(); ++i)
{
delete Symbols[i];
}
}
void PSymbolTable::SetParentTable (PSymbolTable *parent)
{
ParentSymbolTable = parent;
}
PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const
{
int min, max;
min = 0;
max = (int)Symbols.Size() - 1;
while (min <= max)
{
unsigned int mid = (min + max) / 2;
PSymbol *sym = Symbols[mid];
if (sym->SymbolName == symname)
{
return sym;
}
else if (sym->SymbolName < symname)
{
min = mid + 1;
}
else
{
max = mid - 1;
}
}
if (searchparents && ParentSymbolTable != NULL)
{
return ParentSymbolTable->FindSymbol (symname, true);
}
return NULL;
}
PSymbol *PSymbolTable::AddSymbol (PSymbol *sym)
{
// Insert it in sorted order.
int min, max, mid;
min = 0;
max = (int)Symbols.Size() - 1;
while (min <= max)
{
mid = (min + max) / 2;
PSymbol *tsym = Symbols[mid];
if (tsym->SymbolName == sym->SymbolName)
{ // A symbol with this name already exists in the table
return NULL;
}
else if (tsym->SymbolName < sym->SymbolName)
{
min = mid + 1;
}
else
{
max = mid - 1;
}
}
// Good. The symbol is not in the table yet.
Symbols.Insert (MAX(min, max), sym);
return sym;
}

View file

@ -5,6 +5,80 @@
#error You must #include "dobject.h" to get dobjtype.h
#endif
// Symbol information -------------------------------------------------------
enum ESymbolType
{
SYM_Const,
SYM_ActionFunction
};
struct PSymbol
{
ESymbolType SymbolType;
FName SymbolName;
};
// A constant value ---------------------------------------------------------
struct PSymbolConst : public PSymbol
{
int Value;
};
// An action function -------------------------------------------------------
//
// The Arguments string is a string of characters as understood by
// the DECORATE parser:
//
// If the letter is uppercase, it is required. Lowercase letters are optional.
// i = integer
// f = fixed point
// s = sound name
// m = actor name
// t = string
// l = jump label
// c = color
// x = expression
// y = expression
// If the final character is a +, the previous parameter is repeated indefinitely,
// and an "imaginary" first parameter is inserted containing the total number of
// parameters passed.
struct PSymbolActionFunction : public PSymbol
{
FString Arguments;
void (*Function)(AActor*);
};
// A symbol table -----------------------------------------------------------
class PSymbolTable
{
public:
PSymbolTable();
~PSymbolTable();
// Sets the table to use for searches if this one doesn't contain the
// requested symbol.
void SetParentTable (PSymbolTable *parent);
// Finds a symbol in the table, optionally searching parent tables
// as well.
PSymbol *FindSymbol (FName symname, bool searchparents) const;
// Places the symbol in the table and returns a pointer to it or NULL if
// a symbol with the same name is already in the table. This symbol is
// not copied and will be freed when the symbol table is destroyed.
PSymbol *AddSymbol (PSymbol *sym);
private:
PSymbolTable *ParentSymbolTable;
TArray<PSymbol *> Symbols;
};
// Meta-info for every class derived from DObject ---------------------------
struct PClass
{
static void StaticInit ();
@ -23,6 +97,7 @@ struct PClass
BYTE *Defaults;
bool bRuntimeClass; // class was defined at run-time, not compile-time
unsigned short ClassIndex;
PSymbolTable Symbols;
void (*ConstructNative)(void *);

View file

@ -3,6 +3,7 @@ xx(None)
xx(Super)
xx(Object)
xx(Actor)
xx(Untranslated)
@ -178,4 +179,22 @@ xx(Massacre) // For death by a cheater!
// a damage type if you wanted to force an extreme death.
xx(Extreme)
// Special names for thingdef_exp.cpp
xx(Random)
xx(Random2)
xx(Cos)
xx(Sin)
xx(Alpha)
xx(Angle)
xx(Args)
xx(CeilingZ)
xx(FloorZ)
xx(Health)
xx(Pitch)
xx(Special)
xx(TID)
xx(TIDtoHate)
xx(WaterLevel)
xx(X)
xx(Y)
xx(Z)

View file

@ -1479,8 +1479,6 @@ void FBehavior::StaticStopMyScripts (AActor *actor)
//---- The ACS Interpreter ----//
void strbin (char *str);
IMPLEMENT_CLASS (DACSThinker)
DACSThinker *DACSThinker::ActiveThinker = NULL;
@ -5288,77 +5286,6 @@ void P_TerminateScript (int script, char *map)
SetScriptState (script, DLevelScript::SCRIPT_PleaseRemove);
}
void strbin (char *str)
{
char *p = str, c;
int i;
while ( (c = *p++) ) {
if (c != '\\') {
*str++ = c;
} else {
switch (*p) {
case 'c':
*str++ = TEXTCOLOR_ESCAPE;
break;
case 'n':
*str++ = '\n';
break;
case 't':
*str++ = '\t';
break;
case 'r':
*str++ = '\r';
break;
case '\n':
break;
case 'x':
case 'X':
c = 0;
p++;
for (i = 0; i < 2; i++) {
c <<= 4;
if (*p >= '0' && *p <= '9')
c += *p-'0';
else if (*p >= 'a' && *p <= 'f')
c += 10 + *p-'a';
else if (*p >= 'A' && *p <= 'F')
c += 10 + *p-'A';
else
break;
p++;
}
*str++ = c;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
c = 0;
for (i = 0; i < 3; i++) {
c <<= 3;
if (*p >= '0' && *p <= '7')
c += *p-'0';
else
break;
p++;
}
*str++ = c;
break;
default:
*str++ = *p;
break;
}
p++;
}
}
*str = 0;
}
FArchive &operator<< (FArchive &arc, acsdefered_s *&defertop)
{
BYTE more;

View file

@ -491,8 +491,8 @@ static void ReadEAX ()
{
SC_MustGetFloat ();
props.*EAXFields[i].Float = clamp (sc_Float,
float(EAXFields[i].Min)/1000.f,
float(EAXFields[i].Max)/1000.f);
double(EAXFields[i].Min)/1000,
double(EAXFields[i].Max)/1000);
}
else if (EAXFields[i].Int)
{

View file

@ -45,16 +45,19 @@
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void SC_PrepareScript (void);
static bool SC_ScanString (bool tokens);
static void CheckOpen (void);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
int sc_TokenType;
char *sc_String;
int sc_StringLen;
unsigned int sc_StringLen;
int sc_Number;
float sc_Float;
double sc_Float;
FName sc_Name;
int sc_Line;
bool sc_End;
bool sc_Crossed;
@ -71,6 +74,8 @@ static char StringBuffer[MAX_STRING_SIZE];
static bool ScriptOpen = false;
static int ScriptSize;
static bool AlreadyGot = false;
static bool LastGotToken = false;
static char *LastGotPtr;
static bool FreeScript = false;
static char *SavedScriptPtr;
static int SavedScriptLine;
@ -108,7 +113,10 @@ void SC_OpenFile (const char *name)
SC_Close ();
ScriptSize = M_ReadFile (name, &filebuf);
ScriptBuffer = (char *)filebuf;
ScriptBuffer = new char[ScriptSize + 1];
memcpy (ScriptBuffer, filebuf, ScriptSize);
ScriptBuffer[ScriptSize++] = '\n';
delete[] filebuf;
ScriptName = name; // This is used for error messages so the full file name is preferable
FreeScript = true;
SC_PrepareScript ();
@ -119,7 +127,8 @@ void SC_OpenFile (const char *name)
// SC_OpenMem
//
// Prepares a script that is already in memory for parsing. The caller is
// responsible for freeing it, if needed.
// responsible for freeing it, if needed. You MUST ensure that the script
// ends with the newline character '\n'.
//
//==========================================================================
@ -145,8 +154,9 @@ void SC_OpenLumpNum (int lump, const char *name)
{
SC_Close ();
ScriptSize = Wads.LumpLength (lump);
ScriptBuffer = new char[ScriptSize];
ScriptBuffer = new char[ScriptSize + 1];
Wads.ReadLump (lump, ScriptBuffer);
ScriptBuffer[ScriptSize++] = '\n';
ScriptName = name;
FreeScript = true;
SC_PrepareScript ();
@ -169,6 +179,8 @@ static void SC_PrepareScript (void)
ScriptOpen = true;
sc_String = StringBuffer;
AlreadyGot = false;
LastGotToken = false;
LastGotPtr = NULL;
SavedScriptPtr = NULL;
CMode = false;
Escape = true;
@ -234,6 +246,7 @@ void SC_RestorePos (void)
sc_Line = SavedScriptLine;
sc_End = false;
AlreadyGot = false;
LastGotToken = false;
}
}
@ -267,20 +280,28 @@ void SC_SetEscape (bool esc)
//==========================================================================
//
// SC_GetString
// SC_ScanString
//
// Set tokens true if you want sc_TokenType to be set.
//
//==========================================================================
bool SC_GetString ()
static bool SC_ScanString (bool tokens)
{
char *marker, *tok;
bool return_val;
CheckOpen();
if (AlreadyGot)
{
AlreadyGot = false;
if (!tokens || LastGotToken)
{
return true;
}
ScriptPtr = LastGotPtr;
}
sc_Crossed = false;
if (ScriptPtr >= ScriptEndPtr)
{
@ -288,9 +309,24 @@ bool SC_GetString ()
return false;
}
LastGotPtr = ScriptPtr;
// In case the generated scanner does not use marker, avoid compiler warnings.
marker;
#include "sc_man_scanner.h"
LastGotToken = tokens;
return return_val;
}
//==========================================================================
//
// SC_GetString
//
//==========================================================================
bool SC_GetString ()
{
return SC_ScanString (false);
}
//==========================================================================
@ -343,6 +379,93 @@ bool SC_CheckString (const char *name)
return false;
}
//==========================================================================
//
// SC_GetToken
//
// Sets sc_Float, sc_Number, and sc_Name based on sc_TokenType.
//
//==========================================================================
bool SC_GetToken ()
{
if (SC_ScanString (true))
{
if (sc_TokenType == TK_Identifier || sc_TokenType == TK_NameConst)
{
sc_Name = FName(sc_String);
}
else if (sc_TokenType == TK_IntConst)
{
char *stopper;
sc_Number = strtol(sc_String, &stopper, 0);
sc_Float = sc_Number;
}
else if (sc_TokenType == TK_FloatConst)
{
char *stopper;
sc_Float = strtod(sc_String, &stopper);
}
else if (sc_TokenType == TK_StringConst)
{
strbin (sc_String);
}
return true;
}
return false;
}
//==========================================================================
//
// SC_MustGetAnyToken
//
//==========================================================================
void SC_MustGetAnyToken (void)
{
if (SC_GetToken () == false)
{
SC_ScriptError ("Missing token (unexpected end of file).");
}
}
//==========================================================================
//
// SC_MustGetToken
//
//==========================================================================
void SC_MustGetToken (int token)
{
SC_MustGetAnyToken ();
if (sc_TokenType != token)
{
SC_ScriptError ("Expected %s but got %s instead.",
SC_TokenName(token), SC_TokenName(sc_TokenType, sc_String));
}
}
//==========================================================================
//
// SC_CheckToken
//
// Checks if the next token matches the specified token. Returns true if
// it does. If it doesn't, it ungets it and returns false.
//==========================================================================
bool SC_CheckToken (int token)
{
if (SC_GetToken ())
{
if (sc_TokenType == token)
{
return true;
}
SC_UnGet ();
}
return false;
}
//==========================================================================
//
// SC_GetNumber
@ -603,6 +726,153 @@ bool SC_Compare (const char *text)
return (stricmp (text, sc_String) == 0);
}
//==========================================================================
//
// SC_TokenName
//
// Returns the name of a token.
//
//==========================================================================
FString SC_TokenName (int token, const char *string)
{
static const char *const names[] =
{
"an identifier",
"a string constant",
"a name constant",
"an integer constant",
"a float constant",
"'...'",
"'>>='",
"'<<='",
"'+='",
"'-='",
"'*='",
"'/='",
"'%='",
"'&='",
"'^='",
"'|='",
"'>>'",
"'<<'",
"'++'",
"'--'",
"'&&'",
"'||'",
"'<='",
"'>='",
"'=='",
"'!="
"'break'",
"'case'",
"'const'",
"'continue'",
"'default'",
"'do'",
"'else'",
"'for'",
"'if'",
"'return'",
"'states'",
"'switch'",
"'until'",
"'while'",
"'bool'",
"'float'",
"'double'",
"'char'",
"'byte'",
"'sbyte'",
"'short'",
"'ushort'",
"'int'",
"'uint'",
"'long'",
"'ulong'",
"'void'",
"'struct'",
"'class'",
"'mode'",
"'enum'",
"'name'",
"'string'",
"'sound'",
"'state'",
"'color'",
"'goto'",
"'abstract'",
"'foreach'",
"'true'",
"'false'",
"'none'",
"'new'",
"'instanceof'",
"'auto'",
"'exec'",
"'defaultproperties'",
"'native'",
"'out'",
"'ref'",
"'event'",
"'static'",
"'transient'",
"'volatile'",
"'final'",
"'throws'",
"'extends'",
"'public'",
"'protected'",
"'private'",
"'dot'",
"'cross'",
"'ignores'",
"'localized'",
"'latent'",
"'singular'",
"'config'",
"'coerce'",
"'iterator'",
"'optional'",
"'export'",
"'virtual'",
"'super'",
"'global'",
"'self'",
"'stop'",
"'eval'",
"'evalnot'",
};
FString work;
if (token > ' ' && token < 256)
{
work = '\'';
work += token;
work += '\'';
}
else if (token >= TK_Identifier && token < TK_LastToken)
{
work = names[token - TK_Identifier];
if (string != NULL && token >= TK_Identifier && token <= TK_FloatConst)
{
work += ' ';
char quote = (token == TK_StringConst) ? '"' : '\'';
work += quote;
work += string;
work += quote;
}
}
else
{
FString work;
work.Format ("Unknown(%d)", token);
return work;
}
return work;
}
//==========================================================================
//
// SC_ScriptError
@ -723,5 +993,6 @@ void SC_RestoreScriptState()
Escape = ss.Escape;
SavedScripts.ShrinkToFit();
AlreadyGot = false;
LastGotToken = false;
}
}

View file

@ -10,10 +10,16 @@ void SC_SetCMode (bool cmode);
void SC_SetEscape (bool esc);
void SC_SavePos (void);
void SC_RestorePos (void);
FString SC_TokenName (int token, const char *string=NULL);
bool SC_GetString (void);
void SC_MustGetString (void);
void SC_MustGetStringName (const char *name);
bool SC_CheckString (const char *name);
bool SC_GetToken (void);
void SC_MustGetAnyToken (void);
void SC_MustGetToken (int token);
bool SC_CheckToken (int token);
bool SC_CheckTokenId (ENamedName id);
bool SC_GetNumber (void);
void SC_MustGetNumber (void);
bool SC_CheckNumber (void);
@ -29,10 +35,122 @@ void STACK_ARGS SC_ScriptError (const char *message, ...);
void SC_SaveScriptState();
void SC_RestoreScriptState();
enum
{
TK_Identifier = 257,
TK_StringConst,
TK_NameConst,
TK_IntConst,
TK_FloatConst,
TK_Ellipsis, // ...
TK_RShiftEq, // >>=
TK_LShiftEq, // <<=
TK_AddEq, // +=
TK_SubEq, // -=
TK_MulEq, // *=
TK_DivEq, // /=
TK_ModEq, // %=
TK_AndEq, // &=
TK_XorEq, // ^=
TK_OrEq, // |=
TK_RShift, // >>
TK_LShift, // <<
TK_Incr, // ++
TK_Decr, // --
TK_AndAnd, // &&
TK_OrOr, // ||
TK_Leq, // <=
TK_Geq, // >=
TK_Eq, // ==
TK_Neq, // !=
TK_Break,
TK_Case,
TK_Const,
TK_Continue,
TK_Default,
TK_Do,
TK_Else,
TK_For,
TK_If,
TK_Return,
TK_States,
TK_Switch,
TK_Until,
TK_While,
TK_Bool,
TK_Float,
TK_Double,
TK_Char,
TK_Byte,
TK_SByte,
TK_Short,
TK_UShort,
TK_Int,
TK_UInt,
TK_Long,
TK_ULong,
TK_Void,
TK_Struct,
TK_Class,
TK_Mode,
TK_Enum,
TK_Name,
TK_String,
TK_Sound,
TK_State,
TK_Color,
TK_Goto,
TK_Abstract,
TK_ForEach,
TK_True,
TK_False,
TK_None,
TK_New,
TK_InstanceOf,
TK_Auto,
TK_Exec,
TK_DefaultProperties,
TK_Native,
TK_Out,
TK_Ref,
TK_Event,
TK_Static,
TK_Transient,
TK_Volatile,
TK_Final,
TK_Throws,
TK_Extends,
TK_Public,
TK_Protected,
TK_Private,
TK_Dot,
TK_Cross,
TK_Ignores,
TK_Localized,
TK_Latent,
TK_Singular,
TK_Config,
TK_Coerce,
TK_Iterator,
TK_Optional,
TK_Export,
TK_Virtual,
TK_Super,
TK_Global,
TK_Self,
TK_Stop,
TK_Eval,
TK_EvalNot,
TK_LastToken
};
extern int sc_TokenType;
extern char *sc_String;
extern int sc_StringLen;
extern unsigned int sc_StringLen;
extern int sc_Number;
extern float sc_Float;
extern double sc_Float;
extern FName sc_Name;
extern int sc_Line;
extern bool sc_End;
extern bool sc_Crossed;

File diff suppressed because it is too large Load diff

View file

@ -2,19 +2,21 @@
#define YYCURSOR cursor
#define YYLIMIT limit
#define YYMARKER marker
#define YYFILL(n) {}
#if 0 // As long as the buffer ends with '\n', we need do nothing special for YYFILL.
// This buffer must be as large as the largest YYFILL call
YYCTYPE eofbuf[3];
YYCTYPE eofbuf[9];
#define YYFILL(n) \
{ if(!sc_End) { \
if(n == 2) { eofbuf[0] = *cursor; } \
else if(n == 3) { eofbuf[0] = *cursor; eofbuf[1] = *(cursor + 1); } \
else if(n >= 3 && n <= 9) { memcpy(eofbuf, cursor, n-1); } \
eofbuf[n-1] = '\n'; \
cursor = eofbuf; \
limit = eofbuf + n - 1; \
sc_End = true; } \
} \
assert(n <= 3) // Semicolon intentionally omitted
assert(n <= sizeof eofbuf) // Semicolon intentionally omitted
#endif
//#define YYDEBUG(s,c) { Printf ("%d: %02x\n", s, c); }
#define YYDEBUG(s,c)
@ -29,8 +31,14 @@ std2:
any = [\000-\377];
WSP = ([\000- ]\[\n]);
NWS = (any\[\000- ]);
O = [0-7];
D = [0-9];
X = [0-9A-Fa-f];
L = [a-zA-Z_];
H = [a-fA-F0-9];
E = [Ee] [+-]? D+;
FS = [fFlL];
IS = [uUlL];
ESC = [\\] ([abcfnrtv?'"\\] | "x" H+ | O+);
TOK1 = [{}|=];
TOKC = [{}|=/`~!@#$%^&*()\[\]\\?\-=+;:<>,.];
@ -41,7 +49,169 @@ std2:
TOK2 = (NWS\STOP1);
TOKC2 = (NWS\STOPC);
*/
if (!CMode)
if (tokens) // A well-defined scanner, based on the c.re example.
{
#define RET(x) sc_TokenType = x; goto normal_token;
/*!re2c
"/*" { goto comment; } /* C comment */
"//" (any\"\n")* "\n" { goto newline; } /* C++ comment */
/* C Keywords */
'break' { RET(TK_Break); }
'case' { RET(TK_Case); }
'const' { RET(TK_Const); }
'continue' { RET(TK_Continue); }
'default' { RET(TK_Default); }
'do' { RET(TK_Do); }
'else' { RET(TK_Else); }
'for' { RET(TK_For); }
'goto' { RET(TK_Goto); }
'if' { RET(TK_If); }
'return' { RET(TK_Return); }
'states' { RET(TK_States); }
'switch' { RET(TK_Switch); }
'until' { RET(TK_Until); }
'volatile' { RET(TK_Volatile); }
'while' { RET(TK_While); }
/* Type names */
'bool' { RET(TK_Bool); }
'float' { RET(TK_Float); }
'double' { RET(TK_Double); }
'char' { RET(TK_Char); }
'byte' { RET(TK_Byte); }
'sbyte' { RET(TK_SByte); }
'short' { RET(TK_Short); }
'ushort' { RET(TK_UShort); }
'int' { RET(TK_Int); }
'uint' { RET(TK_UInt); }
'long' { RET(TK_Long); }
'ulong' { RET(TK_ULong); }
'void' { RET(TK_Void); }
'struct' { RET(TK_Struct); }
'class' { RET(TK_Class); }
'mode' { RET(TK_Mode); }
'enum' { RET(TK_Enum); }
'name' { RET(TK_Name); }
'string' { RET(TK_String); }
'sound' { RET(TK_Sound); }
'state' { RET(TK_State); }
'color' { RET(TK_Color); }
/* Other keywords from UnrealScript */
'abstract' { RET(TK_Abstract); }
'foreach' { RET(TK_ForEach); }
'true' { RET(TK_True); }
'false' { RET(TK_False); }
'none' { RET(TK_None); }
'new' { RET(TK_New); }
'instanceof' { RET(TK_InstanceOf); }
'auto' { RET(TK_Auto); }
'exec' { RET(TK_Exec); }
'defaultproperties' { RET(TK_DefaultProperties); }
'native' { RET(TK_Native); }
'out' { RET(TK_Out); }
'ref' { RET(TK_Ref); }
'event' { RET(TK_Event); }
'static' { RET(TK_Static); }
'transient' { RET(TK_Transient); }
'final' { RET(TK_Final); }
'throws' { RET(TK_Throws); }
'extends' { RET(TK_Extends); }
'public' { RET(TK_Public); }
'protected' { RET(TK_Protected); }
'private' { RET(TK_Private); }
'dot' { RET(TK_Dot); }
'cross' { RET(TK_Cross); }
'ignores' { RET(TK_Ignores); }
'localized' { RET(TK_Localized); }
'latent' { RET(TK_Latent); }
'singular' { RET(TK_Singular); }
'config' { RET(TK_Config); }
'coerce' { RET(TK_Coerce); }
'iterator' { RET(TK_Iterator); }
'optional' { RET(TK_Optional); }
'export' { RET(TK_Export); }
'virtual' { RET(TK_Virtual); }
'super' { RET(TK_Super); }
'global' { RET(TK_Global); }
'self' { RET(TK_Self); }
'stop' { RET(TK_Stop); }
/* Needed for decorate action functions */
"eval" { RET(TK_Eval); }
"evalnot" { RET(TK_EvalNot); }
L (L|D)* { RET(TK_Identifier); }
("0" [xX] H+ IS?) | ("0" D+ IS?) | (D+ IS?)
{ RET(TK_IntConst); }
(D+ E FS?) | (D* "." D+ E? FS?) | (D+ "." D* E? FS?)
{ RET(TK_FloatConst); }
(["] (ESC|any\[\n\\"])* ["])
{ RET(TK_StringConst); }
(['] (any\[\n'])* ['])
{ RET(TK_NameConst); }
"..." { RET(TK_Ellipsis); }
">>=" { RET(TK_RShiftEq); }
"<<=" { RET(TK_LShiftEq); }
"+=" { RET(TK_AddEq); }
"-=" { RET(TK_SubEq); }
"*=" { RET(TK_MulEq); }
"/=" { RET(TK_DivEq); }
"%=" { RET(TK_ModEq); }
"&=" { RET(TK_AndEq); }
"^=" { RET(TK_XorEq); }
"|=" { RET(TK_OrEq); }
">>" { RET(TK_RShift); }
"<<" { RET(TK_LShift); }
"++" { RET(TK_Incr); }
"--" { RET(TK_Decr); }
"&&" { RET(TK_AndAnd); }
"||" { RET(TK_OrOr); }
"<=" { RET(TK_Leq); }
">=" { RET(TK_Geq); }
"==" { RET(TK_Eq); }
"!=" { RET(TK_Neq); }
";" { RET(';'); }
"{" { RET('{'); }
"}" { RET('}'); }
"," { RET(','); }
":" { RET(':'); }
"=" { RET('='); }
"(" { RET('('); }
")" { RET(')'); }
"[" { RET('['); }
"]" { RET(']'); }
"." { RET('.'); }
"&" { RET('&'); }
"!" { RET('!'); }
"~" { RET('~'); }
"-" { RET('-'); }
"+" { RET('+'); }
"*" { RET('*'); }
"/" { RET('/'); }
"%" { RET('%'); }
"<" { RET('<'); }
">" { RET('>'); }
"^" { RET('^'); }
"|" { RET('|'); }
"?" { RET('?'); }
[ \t\v\f\r]+ { goto std1; }
"\n" { goto newline; }
any
{
SC_ScriptError ("Unexpected character: %c (ASCII %d)\n", *tok, *tok);
goto std1;
}
*/
}
if (!CMode) // The classic Hexen scanner.
{
/*!re2c
"/*" { goto comment; } /* C comment */
@ -59,7 +229,7 @@ std2:
any { goto normal_token; } /* unknown character */
*/
}
else
else // A modified Hexen scanner for DECORATE.
{
/*!re2c
"/*" { goto comment; } /* C comment */
@ -87,6 +257,7 @@ std2:
negative_check:
// re2c doesn't have enough state to handle '-' as the start of a negative number
// and as its own token, so help it out a little.
sc_TokenType = '-';
if (YYCURSOR >= YYLIMIT)
{
goto normal_token;
@ -112,7 +283,8 @@ comment:
if (YYCURSOR >= YYLIMIT)
{
ScriptPtr = ScriptEndPtr;
return false;
return_val = false;
goto end;
}
goto std1;
}
@ -121,7 +293,8 @@ comment:
if (YYCURSOR >= YYLIMIT)
{
ScriptPtr = ScriptEndPtr;
return false;
return_val = false;
goto end;
}
sc_Line++;
sc_Crossed = true;
@ -134,7 +307,8 @@ newline:
if (YYCURSOR >= YYLIMIT)
{
ScriptPtr = ScriptEndPtr;
return false;
return_val = false;
goto end;
}
sc_Line++;
sc_Crossed = true;
@ -143,15 +317,25 @@ newline:
normal_token:
ScriptPtr = (YYCURSOR >= YYLIMIT) ? ScriptEndPtr : cursor;
sc_StringLen = MIN (ScriptPtr - tok, MAX_STRING_SIZE-1);
if (tokens && (sc_TokenType == TK_StringConst || sc_TokenType == TK_NameConst))
{
sc_StringLen -= 2;
memcpy (sc_String, tok+1, sc_StringLen);
}
else
{
memcpy (sc_String, tok, sc_StringLen);
}
sc_String[sc_StringLen] = '\0';
return true;
return_val = true;
goto end;
string:
if (YYLIMIT != ScriptEndPtr)
{
ScriptPtr = ScriptEndPtr;
return false;
return_val = false;
goto end;
}
ScriptPtr = cursor;
for (sc_StringLen = 0; cursor < YYLIMIT; ++cursor)
@ -191,4 +375,5 @@ string:
}
ScriptPtr = cursor + 1;
sc_String[sc_StringLen] = '\0';
return true;
return_val = true;
end:

View file

@ -361,7 +361,6 @@ static flagdef *FindFlag (const PClass *type, const char *part1, const char *par
return NULL;
}
int EvalExpressionI (int id, AActor *self);
//===========================================================================
//
// A_ChangeFlag
@ -1589,7 +1588,7 @@ bool DoSpecialFunctions(FState & state, bool multistate, int * statecount, Bagga
{
for (i = 0; i < 5;)
{
StateParameters[paramindex+i+1]=ParseExpression (false);
StateParameters[paramindex+i+1]=ParseExpression (false, bag.Info->Class);
i++;
if (!SC_CheckString (",")) break;
}
@ -1851,6 +1850,16 @@ do_stop:
goto endofstate;
}
//AFuncDesc * afd = FindFunction(sc_String);
//PSymbolActionFunction *sym = bag.Info->Class->Symbols.FindSymbol (FName(sc_String, true), true);
//if (sym != NULL && sym->SymbolType == SYM_ActionFunction)
//{
// PSymbolActionFunction *afd = static_cast<PSymbolActionFunction *>(sym);
// state.Action = afd->Function;
// if (!afd->Arguments.IsEmpty())
// {
// const char *params = afd->Arguments.GetChars();
// int numparams = afd->Arguments.Len();
AFuncDesc * afd = FindFunction(sc_String);
if (afd != NULL)
{
@ -1859,6 +1868,7 @@ do_stop:
{
const char * params = afd->parameters;
int numparams = (int)strlen(params);
int v;
if (!islower(*params))
@ -1883,31 +1893,6 @@ do_stop:
{
switch(*params)
{
/*
case 'A':
case 'a': // Angle
SC_MustGetFloat();
v=(int)angle_t(sc_Float*ANGLE_1);
break;
case 'B':
case 'b': // Byte
SC_MustGetNumber();
v=clamp<int>(sc_Number, 0, 255);
break;
case '9': // 90 degree angle as integer
SC_MustGetNumber();
v=clamp<int>(sc_Number, 0, 90);
break;
case '!': // not boolean (to simulate parameters which default to 1)
SC_MustGetNumber();
v=!sc_Number;
break;
*/
case 'I':
case 'i': // Integer
SC_MustGetNumber();
@ -2038,12 +2023,12 @@ do_stop:
case 'X':
case 'x':
v = ParseExpression (false);
v = ParseExpression (false, bag.Info->Class);
break;
case 'Y':
case 'y':
v = ParseExpression (true);
v = ParseExpression (true, bag.Info->Class);
break;
default:
@ -2543,6 +2528,153 @@ static void StatePropertyIsDeprecated (const char *actorname, const char *prop)
//
//==========================================================================
//==========================================================================
//
// ActorConstDef
//
// Parses a constant definition.
//
//==========================================================================
static void ActorConstDef (AActor *defaults, Baggage &bag)
{
// Read the type and make sure it's int.
// (Maybe there will be other types later.)
SC_MustGetToken(TK_Int);
SC_MustGetToken(TK_Identifier);
FName symname = sc_Name;
SC_MustGetToken('=');
int expr = ParseExpression (false, bag.Info->Class);
SC_MustGetToken(';');
int val = EvalExpressionI (expr, NULL, bag.Info->Class);
PSymbolConst *sym = new PSymbolConst;
sym->SymbolName = symname;
sym->SymbolType = SYM_Const;
sym->Value = val;
if (bag.Info->Class->Symbols.AddSymbol (sym) == NULL)
{
delete sym;
SC_ScriptError ("'%s' is already defined in class '%s'.",
symname.GetChars(), bag.Info->Class->TypeName.GetChars());
}
}
//==========================================================================
//
// ActorActionDef
//
// Parses an action function definition.
//
//==========================================================================
static void ActorActionDef (AActor *defaults, Baggage &bag)
{
#define OPTIONAL 1
#define EVAL 2
#define EVALNOT 4
FName funcname;
FString args;
SC_MustGetToken(TK_Identifier);
funcname = sc_Name;
SC_MustGetToken('(');
while (sc_TokenType != ')')
{
int flags = 0;
char type = '@';
// Retrieve flags before type name
for (;;)
{
if (SC_CheckToken(TK_Optional))
{
flags |= OPTIONAL;
}
else if (SC_CheckToken(TK_Eval))
{
flags |= EVAL;
}
else if (SC_CheckToken(TK_EvalNot))
{
flags |= EVALNOT;
}
else if (SC_CheckToken(TK_Coerce) || SC_CheckToken(TK_Native))
{
}
else
{
break;
}
}
if (flags != 0)
{
SC_MustGetAnyToken();
}
switch (sc_TokenType)
{
case TK_Int: type = 'i'; break;
case TK_Float: type = 'f'; break;
case TK_Sound: type = 's'; break;
case TK_String: type = 't'; break;
case TK_State: type = 'l'; break;
case TK_Color: type = 'c'; break;
case TK_Class:
SC_MustGetToken('<');
SC_MustGetToken(TK_Identifier);
if (sc_Name != NAME_Actor)
{
SC_ScriptError ("Sorry, you can only use class<actor>");
}
SC_MustGetToken('>');
type = 'm';
break;
case TK_Ellipsis:
type = '+';
SC_MustGetToken(')');
SC_UnGet();
break;
default:
SC_ScriptError ("Unknown variable type %s", SC_TokenName(sc_TokenType, sc_String).GetChars());
break;
}
if (flags & EVALNOT)
{
type = 'y';
}
else if (flags & EVAL)
{
type = 'x';
}
if (!(flags & OPTIONAL))
{
type -= 'a' - 'A';
break;
}
#undef OPTIONAL
#undef EVAL
#undef EVALNOT
args += type;
SC_MustGetAnyToken();
if (sc_TokenType != ',' && sc_TokenType != ')')
{
SC_ScriptError ("Expected ',' or ')' but got %s instead", SC_TokenName(sc_TokenType, sc_String).GetChars());
}
}
PSymbolActionFunction *sym = new PSymbolActionFunction;
sym->SymbolName = funcname;
sym->SymbolType = SYM_ActionFunction;
sym->Arguments = args;
sym->Function = NULL;
if (bag.Info->Class->Symbols.AddSymbol (sym) == NULL)
{
delete sym;
SC_ScriptError ("'%s' is already defined in class '%s'.",
funcname.GetChars(), bag.Info->Class->TypeName.GetChars());
}
}
//==========================================================================
//
//==========================================================================
@ -2699,7 +2831,7 @@ static void ActorDamage (AActor *defaults, Baggage &bag)
if (SC_CheckString ("("))
{
defaults->Damage = 0x40000000 | ParseExpression (false);
defaults->Damage = 0x40000000 | ParseExpression (false, bag.Info->Class);
SC_MustGetStringName(")");
}
else
@ -3997,7 +4129,7 @@ static void PlayerScoreIcon (APlayerPawn *defaults, Baggage &bag)
static void PlayerCrouchSprite (APlayerPawn *defaults, Baggage &bag)
{
SC_MustGetString ();
for (int i = 0; i < sc_StringLen; i++) sc_String[i] = toupper (sc_String[i]);
for (unsigned int i = 0; i < sc_StringLen; i++) sc_String[i] = toupper (sc_String[i]);
defaults->crouchsprite = GetSpriteIndex (sc_String);
}
@ -4115,6 +4247,7 @@ static const ActorProps props[] =
{
{ "+", ActorFlagSetOrReset, RUNTIME_CLASS(AActor) },
{ "-", ActorFlagSetOrReset, RUNTIME_CLASS(AActor) },
{ "action", ActorActionDef, RUNTIME_CLASS(AActor) },
{ "activesound", ActorActiveSound, RUNTIME_CLASS(AActor) },
{ "alpha", ActorAlpha, RUNTIME_CLASS(AActor) },
{ "ammo.backpackamount", (apf)AmmoBackpackAmount, RUNTIME_CLASS(AAmmo) },
@ -4131,6 +4264,7 @@ static const ActorProps props[] =
{ "burnheight", ActorBurnHeight, RUNTIME_CLASS(AActor) },
{ "cameraheight", ActorCameraheight, RUNTIME_CLASS(AActor) },
{ "clearflags", ActorClearFlags, RUNTIME_CLASS(AActor) },
{ "const", ActorConstDef, RUNTIME_CLASS(AActor) },
{ "conversationid", ActorConversationID, RUNTIME_CLASS(AActor) },
{ "crash", ActorCrashState, RUNTIME_CLASS(AActor) },
{ "crush", ActorCrushState, RUNTIME_CLASS(AActor) },

View file

@ -26,11 +26,11 @@ extern TArray<int> StateParameters;
extern TArray<int> JumpParameters;
int ParseExpression (bool _not);
int ParseExpression (bool _not, PClass *cls);
int EvalExpressionI (int id, AActor *self);
float EvalExpressionF (int id, AActor *self);
bool EvalExpressionN (int id, AActor *self);
int EvalExpressionI (int id, AActor *self, const PClass *cls=NULL);
float EvalExpressionF (int id, AActor *self, const PClass *cls=NULL);
bool EvalExpressionN (int id, AActor *self, const PClass *cls=NULL);
void ClearStateLabels();
void AddState (const char * statename, FState * state);

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Version="8.00"
Name="updaterevision"
ProjectGUID="{6077B7D6-349F-4077-B552-3BC302EF5859}"
RootNamespace="updaterevision"
@ -96,6 +96,82 @@
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|x64"
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
@ -173,82 +249,6 @@
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|x64"
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|x64"
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"