Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
libcommon: Derived HexLex (class) from Hexen's script parser
A (common) lexical analyzer for Hexen definition/script syntaxes.

Todo: Cleanup
  • Loading branch information
danij-deng committed Jan 23, 2014
1 parent e1efab8 commit 29e810a
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 409 deletions.
2 changes: 2 additions & 0 deletions doomsday/plugins/common/common.pri
Expand Up @@ -22,6 +22,7 @@ HEADERS += \
$$common_inc/g_eventsequence.h \
$$common_inc/g_update.h \
$$common_inc/gl_drawpatch.h \
$$common_inc/hexlex.h \
$$common_inc/hu_automap.h \
$$common_inc/hu_chat.h \
$$common_inc/hu_inventory.h \
Expand Down Expand Up @@ -79,6 +80,7 @@ SOURCES += \
$$common_src/g_game.c \
$$common_src/g_update.c \
$$common_src/gl_drawpatch.c \
$$common_src/hexlex.cpp \
$$common_src/hu_automap.c \
$$common_src/hu_chat.c \
$$common_src/hu_inventory.c \
Expand Down
3 changes: 3 additions & 0 deletions doomsday/plugins/common/include/common.h
Expand Up @@ -42,6 +42,9 @@

#include "pause.h"

DENG_EXTERN_C dd_bool sc_FileScripts;
DENG_EXTERN_C char const *sc_ScriptsDir;

int Common_GetInteger(int id);

#endif // LIBCOMMON_GAME_INCLUDES
75 changes: 75 additions & 0 deletions doomsday/plugins/common/include/hexlex.h
@@ -0,0 +1,75 @@
/** @file hexlex.h Laxical analyzer for Hexen definition/script syntax.
*
* @authors Copyright © 2003-2013 Jaakko Keränen <jaakko.keranen@iki.fi>
* @authors Copyright © 2007-2013 Daniel Swanson <danij@dengine.net>
* @authors Copyright © 1999 Activision
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA</small>
*/

#ifndef LIBCOMMON_HEXLEX_H
#define LIBCOMMON_HEXLEX_H

#include "common.h"

/**
* Lexical analyzer for Hexen definition/script syntax.
*/
class HexLex
{
public:
HexLex();
~HexLex();

/**
* Prepare a new script for parsing. It is assumed that the @a script data
* remains available until parsing is completed (or the script is replaced).
*
* @param script The script source to be parsed.
* @param sourcePath Used to identify the script in log messages. A copy is made.
*/
void parse(Str const *script, Str const *sourcePath);

bool readToken();

Str const *token();

void unreadToken();

Str const *mustGetString();
int mustGetNumber();

int lineNumber() const;

void scriptError();
void scriptError(char const *message);

private:
void checkOpen();
bool atEnd();

Str _sourcePath; ///< Used to identify the source in error messages.

Str const *_script; ///< The start of the script being parsed.
int _readPos; ///< Current read position.
int _lineNumber;

Str _token;
int _tokenAsNumber;
bool _alreadyGot;
bool _multiline; ///< @c true= current token spans multiple lines.
};

#endif // LIBCOMMON_HEXLEX_H
225 changes: 225 additions & 0 deletions doomsday/plugins/common/src/hexlex.cpp
@@ -0,0 +1,225 @@
/** @file hexlex.cpp Hexen definition/script syntax.
*
* @authors Copyright © 2003-2013 Jaakko Keränen <jaakko.keranen@iki.fi>
* @authors Copyright © 2007-2013 Daniel Swanson <danij@dengine.net>
* @authors Copyright © 1999 Activision
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA</small>
*/

#include "hexlex.h"
#include <cstdlib>
#include <cstdio>
#include <cstring>

#define T_COMMENT ';' ///< Single-line comment.
#define T_QUOTE '"'

void HexLex::checkOpen()
{
if(!_script) Con_Error("RavHexParser: No script to parse!");
}

bool HexLex::atEnd()
{
checkOpen();
return (_readPos >= Str_Length(_script));
}

HexLex::HexLex()
: _script(0)
, _readPos(0)
, _lineNumber(0)
, _tokenAsNumber(0)
, _alreadyGot(false)
, _multiline(false)
{
Str_InitStd(&_sourcePath);
Str_InitStd(&_token);
}

HexLex::~HexLex()
{
Str_Free(&_sourcePath);
Str_Free(&_token);
}

void HexLex::parse(Str const *script, Str const *sourcePath)
{
_script = script;

if(!sourcePath)
{
Str_Clear(&_sourcePath);
}
else
{
Str_Copy(&_sourcePath, sourcePath);
}

Str_Clear(&_token);
_readPos = 0;
_lineNumber = 1;
_alreadyGot = false;
}

bool HexLex::readToken()
{
checkOpen();
if(_alreadyGot)
{
_alreadyGot = false;
return true;
}

_multiline = false;

if(atEnd())
{
return false;
}

bool foundToken = false;
while(!foundToken)
{
while(Str_At(_script, _readPos) <= ' ')
{
if(atEnd())
{
return false;
}

if(Str_At(_script, _readPos++) == '\n')
{
_lineNumber++;
_multiline = true;
}
}

if(atEnd())
{
return false;
}

if(Str_At(_script, _readPos) != T_COMMENT)
{
// Found a token
foundToken = true;
}
else
{
// Skip comment.
while(Str_At(_script, _readPos++) != '\n')
{
if(atEnd())
{
return false;
}
}

_lineNumber++;
_multiline = true;
}
}

Str_Clear(&_token);
if(Str_At(_script, _readPos) == T_QUOTE)
{
// Quoted string.
_readPos++;
while(Str_At(_script, _readPos) != T_QUOTE)
{
Str_AppendChar(&_token, Str_At(_script, _readPos++));
if(atEnd())
{
break;
}
}
_readPos++;
}
else
{
// Normal string.
while(Str_At(_script, _readPos) > ' ' &&
Str_At(_script, _readPos) != T_COMMENT)
{
Str_AppendChar(&_token, Str_At(_script, _readPos++));
if(atEnd())
{
break;
}
}
}

return true;
}

Str const *HexLex::mustGetString()
{
if(!readToken())
{
scriptError("Missing string");
}
return &_token;
}

int HexLex::mustGetNumber()
{
checkOpen();

if(!readToken())
{
scriptError("Missing integer");
}

char *stopper;
_tokenAsNumber = strtol(Str_Text(&_token), &stopper, 0);
if(*stopper != 0)
{
Con_Error("RavHexParser: Bad numeric constant \"%s\".\n"
"File: \"%s\", Line: %i",
Str_Text(&_token), F_PrettyPath(Str_Text(&_sourcePath)), _lineNumber);
}

return _tokenAsNumber;
}

/// @note Assumes there is a valid string in sc_String.
void HexLex::unreadToken()
{
_alreadyGot = true;
}

Str const *HexLex::token()
{
return &_token;
}

int HexLex::lineNumber() const
{
return _lineNumber;
}

void HexLex::scriptError(char const *message)
{
Con_Error("RavHexParser: Error in script \"%s\" on line #%i.\n%s",
F_PrettyPath(Str_Text(&_sourcePath)), _lineNumber, message);
}

void HexLex::scriptError()
{
AutoStr *msg = Str_Appendf(AutoStr_NewStd(), "Unexpected token '%s'", Str_Text(&_token));
scriptError(Str_Text(msg));
}
1 change: 0 additions & 1 deletion doomsday/plugins/hexen/hexen.pro
Expand Up @@ -59,7 +59,6 @@ HEADERS += \
include/r_defs.h \
include/r_local.h \
include/s_sequence.h \
include/sc_man.h \
include/st_stuff.h \
include/textdefs.h \
include/version.h \
Expand Down
35 changes: 0 additions & 35 deletions doomsday/plugins/hexen/include/sc_man.h

This file was deleted.

0 comments on commit 29e810a

Please sign in to comment.